From c91b4b2e142b5b3fc9ca88afec6bfa9b2711e01b Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 20 Apr 2020 13:25:36 +0000 Subject: [PATCH 1/2] Tidy up the terminal detection and feature code and add named sets of terminal features, each of which are defined in one place and map to a builtin set of terminfo(5) capabilities. Features can be specified based on TERM with a new terminal-features option or with the -T flag when running tmux. tmux will also detect a few common terminals from the DA and DSR responses. This is intended to make it easier to configure tmux's use of terminfo(5) even in the presence of outdated ncurses(3) or terminfo(5) databases or for features which do not yet have a terminfo(5) entry. Instead of having to grok terminfo(5) capability names and what they should be set to in the terminal-overrides option, the user can hopefully just give tmux a feature name and let it do the right thing. The terminal-overrides option remains both for backwards compatibility and to allow tweaks of individual capabilities. tmux already did much of this already, this makes it tidier and simpler to configure. --- Makefile | 1 + client.c | 9 +- cmd-show-messages.c | 14 ++- format.c | 7 +- options-table.c | 13 ++- server-client.c | 24 ++-- tmux.1 | 92 +++++++++++---- tmux.c | 20 ++-- tmux.h | 30 ++--- tty-acs.c | 2 +- tty-features.c | 264 ++++++++++++++++++++++++++++++++++++++++++++ tty-keys.c | 62 ++++++++--- tty-term.c | 104 +++++++++-------- tty.c | 121 ++++++-------------- 14 files changed, 540 insertions(+), 223 deletions(-) create mode 100644 tty-features.c diff --git a/Makefile b/Makefile index 24117bf1..0f1c94c4 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,7 @@ SRCS= alerts.c \ style.c \ tmux.c \ tty-acs.c \ + tty-features.c \ tty-keys.c \ tty-term.c \ tty.c \ diff --git a/client.c b/client.c index c1d6e1b5..98565c5d 100644 --- a/client.c +++ b/client.c @@ -57,7 +57,7 @@ static struct client_files client_files = RB_INITIALIZER(&client_files); static __dead void client_exec(const char *,const char *); static int client_get_lock(char *); static int client_connect(struct event_base *, const char *, int); -static void client_send_identify(const char *, const char *); +static void client_send_identify(const char *, const char *, int); static void client_signal(int); static void client_dispatch(struct imsg *, void *); static void client_dispatch_attached(struct imsg *); @@ -233,7 +233,7 @@ client_exit(void) /* Client main loop. */ int -client_main(struct event_base *base, int argc, char **argv, int flags) +client_main(struct event_base *base, int argc, char **argv, int flags, int feat) { struct cmd_parse_result *pr; struct msg_command *data; @@ -340,7 +340,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags) } /* Send identify messages. */ - client_send_identify(ttynam, cwd); + client_send_identify(ttynam, cwd, feat); /* Send first command. */ if (msg == MSG_COMMAND) { @@ -406,7 +406,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags) /* Send identify messages to server. */ static void -client_send_identify(const char *ttynam, const char *cwd) +client_send_identify(const char *ttynam, const char *cwd, int feat) { const char *s; char **ss; @@ -419,6 +419,7 @@ client_send_identify(const char *ttynam, const char *cwd) if ((s = getenv("TERM")) == NULL) s = ""; proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); + proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat); proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1); diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 78e5859c..d734ca65 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -43,22 +43,24 @@ const struct cmd_entry cmd_show_messages_entry = { .exec = cmd_show_messages_exec }; -static int cmd_show_messages_terminals(struct cmdq_item *, int); - static int -cmd_show_messages_terminals(struct cmdq_item *item, int blank) +cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank) { + struct args *args = cmd_get_args(self); + struct client *tc = cmdq_get_target_client(item); struct tty_term *term; u_int i, n; n = 0; LIST_FOREACH(term, &tty_terms, entry) { + if (args_has(args, 't') && term != tc->tty.term) + continue; if (blank) { cmdq_print(item, "%s", ""); blank = 0; } - cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:", - n, term->name, term->references, term->flags); + cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n, + term->name, term->tty->client->name, term->flags); n++; for (i = 0; i < tty_term_ncodes(); i++) cmdq_print(item, "%s", tty_term_describe(term, i)); @@ -77,7 +79,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item) done = blank = 0; if (args_has(args, 'T')) { - blank = cmd_show_messages_terminals(item, blank); + blank = cmd_show_messages_terminals(self, item, blank); done = 1; } if (args_has(args, 'J')) { diff --git a/format.c b/format.c index df610a50..f1f52895 100644 --- a/format.c +++ b/format.c @@ -2553,8 +2553,9 @@ format_defaults_client(struct format_tree *ft, struct client *c) format_add(ft, "client_control_mode", "%d", !!(c->flags & CLIENT_CONTROL)); - if (tty->term_name != NULL) - format_add(ft, "client_termname", "%s", tty->term_name); + format_add(ft, "client_termname", "%s", c->term_name); + format_add(ft, "client_termfeatures", "%s", + tty_get_features(c->term_features)); format_add_tv(ft, "client_created", &c->creation_time); format_add_tv(ft, "client_activity", &c->activity_time); @@ -2569,7 +2570,7 @@ format_defaults_client(struct format_tree *ft, struct client *c) format_add(ft, "client_prefix", "%d", 1); format_add(ft, "client_key_table", "%s", c->keytable->name); - if (tty_get_flags(tty) & TERM_UTF8) + if (c->flags & CLIENT_UTF8) format_add(ft, "client_utf8", "%d", 1); else format_add(ft, "client_utf8", "%d", 0); diff --git a/options-table.c b/options-table.c index 1401f05d..722429f7 100644 --- a/options-table.c +++ b/options-table.c @@ -261,9 +261,16 @@ const struct options_table_entry options_table[] = { .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, .flags = OPTIONS_TABLE_IS_ARRAY, - .default_str = "xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" - ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007" - ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT", + .default_str = "tmux*:XT,screen*:XT", + .separator = "," + }, + + { .name = "terminal-features", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .flags = OPTIONS_TABLE_IS_ARRAY, + .default_str = "xterm*:clipboard:ccolour:cstyle:title," + "screen*:title", .separator = "," }, diff --git a/server-client.c b/server-client.c index 1df1a77f..cd850593 100644 --- a/server-client.c +++ b/server-client.c @@ -296,7 +296,7 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); free(c->ttyname); - free(c->term); + free(c->term_name); status_free(c); @@ -1845,6 +1845,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) datalen = imsg->hdr.len - IMSG_HEADER_SIZE; switch (imsg->hdr.type) { + case MSG_IDENTIFY_FEATURES: case MSG_IDENTIFY_FLAGS: case MSG_IDENTIFY_TERM: case MSG_IDENTIFY_TTYNAME: @@ -2003,7 +2004,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) { const char *data, *home; size_t datalen; - int flags; + int flags, feat; char *name; if (c->flags & CLIENT_IDENTIFIED) @@ -2013,6 +2014,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) datalen = imsg->hdr.len - IMSG_HEADER_SIZE; switch (imsg->hdr.type) { + case MSG_IDENTIFY_FEATURES: + if (datalen != sizeof feat) + fatalx("bad MSG_IDENTIFY_FEATURES size"); + memcpy(&feat, data, sizeof feat); + c->term_features |= feat; + log_debug("client %p IDENTIFY_FEATURES %s", c, + tty_get_features(feat)); + break; case MSG_IDENTIFY_FLAGS: if (datalen != sizeof flags) fatalx("bad MSG_IDENTIFY_FLAGS size"); @@ -2023,7 +2032,10 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) case MSG_IDENTIFY_TERM: if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_TERM string"); - c->term = xstrdup(data); + if (*data == '\0') + c->term_name = xstrdup("unknown"); + else + c->term_name = xstrdup(data); log_debug("client %p IDENTIFY_TERM %s", c, data); break; case MSG_IDENTIFY_TTYNAME: @@ -2084,14 +2096,10 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) control_start(c); c->tty.fd = -1; } else if (c->fd != -1) { - if (tty_init(&c->tty, c, c->fd, c->term) != 0) { + if (tty_init(&c->tty, c, c->fd) != 0) { close(c->fd); c->fd = -1; } else { - if (c->flags & CLIENT_UTF8) - c->tty.term_flags |= TERM_UTF8; - if (c->flags & CLIENT_256COLOURS) - c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); c->flags |= CLIENT_TERMINAL; } diff --git a/tmux.1 b/tmux.1 index 325ccd98..ca4e30e0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -28,6 +28,7 @@ .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path +.Op Fl T Ar features .Op Ar command Op Ar flags .Ek .Sh DESCRIPTION @@ -98,6 +99,8 @@ The options are as follows: Force .Nm to assume the terminal supports 256 colours. +This is equivalent to +.Fl T Ar 256 . .It Fl C Start in control mode (see the .Sx CONTROL MODE @@ -186,6 +189,14 @@ that is set does not contain .Qq UTF-8 or .Qq UTF8 . +This is equivalent to +.Fl T Ar UTF-8 . +.It Fl T Ar features +Set terminal features for the client. +This is a comma-separated list of features. +See the +.Ic terminal-features +option. .It Fl v Request verbose logging. Log messages will be saved into @@ -3166,6 +3177,63 @@ disallowedWindowOps: 20,21,SetXprop Or changing this property from the .Xr xterm 1 interactive menu when required. +.It Ic terminal-features[] Ar string +Set terminal features for terminal types read from +.Xr terminfo 5 . +.Nm +has a set of named terminal features. +Each will apply appropriate changes to the +.Xr terminfo 5 +entry in use. +.Pp +.Nm +can detect features for a few common terminals; this option can be used to +easily tell tmux about features supported by terminals it cannot detect. +The +.Ic terminal-overrides +option allows individual +.Xr terminfo 5 +capabilities to be set instead, +.Ic terminal-features +is intended for classes of functionality supported in a standard way but not +reported by +.Xr terminfo 5 . +Care must be taken only to configure this with features the terminal actually +support. +.Pp +This is an array option where each entry is a colon-separated string made up +of a terminal type pattern (matched using +.Xr fnmatch 3 ) +followed by a list of terminal features. +The available features are: +.Bl -tag -width Ds +.It 256 +Supports 256 colours with the SGR escape sequences. +.It clipboard +Allows setting the system clipboard. +.It ccolour +Allows setting the cursor colour. +.It cstyle +Allows setting the cursor style. +.It margins +Supports DECSLRM margins. +.It overline +Supports the overline SGR attribute. +.It rectfill +Supports the DECFRA rectangle fill escape sequence. +.It RGB +Supports RGB colour with the SGR escape sequences. +.It sync +Supports synchronized updates. +.It title +Supports +.Xr xterm 1 +title setting. +.It usstyle +Allows underscore style and colour to be set. +.It UTF-8 +Is able to handle UTF-8 output. +.El .It Ic terminal-overrides[] Ar string Allow terminal descriptions read using .Xr terminfo 5 @@ -4383,6 +4451,7 @@ The following variables are available, where appropriate: .It Li "client_readonly" Ta "" Ta "1 if client is readonly" .It Li "client_session" Ta "" Ta "Name of the client's session" .It Li "client_termname" Ta "" Ta "Terminal name of client" +.It Li "client_termfeatures" Ta "" Ta "Terminal features of client" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client" .It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8" .It Li "client_width" Ta "" Ta "Width of client" @@ -5465,7 +5534,10 @@ The server crashed or otherwise exited without telling the client the reason. .Sh TERMINFO EXTENSIONS .Nm understands some unofficial extensions to -.Xr terminfo 5 : +.Xr terminfo 5. +It is not normally necessary to set these manually, instead the +.Ic terminal-features +option should be used. .Bl -tag -width Ds .It Em \&Cs , Cr Set the cursor colour. @@ -5479,33 +5551,15 @@ $ printf '\e033]12;red\e033\e\e' .Ed .It Em \&Smol Enable the overline attribute. -The capability is usually SGR 53 and can be added to -.Ic terminal-overrides -as: -.Bd -literal -offset indent -Smol=\eE[53m -.Ed .It Em \&Smulx Set a styled underscore. The single parameter is one of: 0 for no underscore, 1 for normal underscore, 2 for double underscore, 3 for curly underscore, 4 for dotted underscore and 5 for dashed underscore. -The capability can typically be added to -.Ic terminal-overrides -as: -.Bd -literal -offset indent -Smulx=\eE[4::%p1%dm -.Ed .It Em \&Setulc Set the underscore colour. The argument is (red * 65536) + (green * 256) + blue where each is between 0 and 255. -The capability can typically be added to -.Ic terminal-overrides -as: -.Bd -literal -offset indent -Setulc=\eE[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m -.Ed .It Em \&Ss , Se Set or reset the cursor style. If set, a sequence such as this may be used diff --git a/tmux.c b/tmux.c index c9678d9e..515f1543 100644 --- a/tmux.c +++ b/tmux.c @@ -58,7 +58,7 @@ usage(void) { fprintf(stderr, "usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n" - " [-S socket-path] [command [flags]]\n", + " [-S socket-path] [-T features] [command [flags]]\n", getprogname()); exit(1); } @@ -242,9 +242,11 @@ getversion(void) int main(int argc, char **argv) { - char *path, *label, *cause, **var; + char *path = NULL, *label = NULL; + char *cause, **var; const char *s, *shell, *cwd; - int opt, flags, keys; + int opt, flags = 0, keys; + int feat = 0; const struct options_table_entry *oe; if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL && @@ -261,14 +263,11 @@ main(int argc, char **argv) if (**argv == '-') flags = CLIENT_LOGIN; - else - flags = 0; - label = path = NULL; - while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUvV")) != -1) { + while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:T:uUvV")) != -1) { switch (opt) { case '2': - flags |= CLIENT_256COLOURS; + tty_add_features(&feat, "256", ":,"); break; case 'c': shell_command = optarg; @@ -298,6 +297,9 @@ main(int argc, char **argv) free(path); path = xstrdup(optarg); break; + case 'T': + tty_add_features(&feat, optarg, ":,"); + break; case 'u': flags |= CLIENT_UTF8; break; @@ -405,5 +407,5 @@ main(int argc, char **argv) free(label); /* Pass control to the client. */ - exit(client_main(event_init(), argc, argv, flags)); + exit(client_main(event_init(), argc, argv, flags, feat)); } diff --git a/tmux.h b/tmux.h index bbac756b..3853b09f 100644 --- a/tmux.h +++ b/tmux.h @@ -474,6 +474,7 @@ enum msgtype { MSG_IDENTIFY_DONE, MSG_IDENTIFY_CLIENTPID, MSG_IDENTIFY_CWD, + MSG_IDENTIFY_FEATURES, MSG_COMMAND = 200, MSG_DETACH, @@ -1176,7 +1177,8 @@ struct tty_key { struct tty_code; struct tty_term { char *name; - u_int references; + struct tty *tty; + int features; char acs[UCHAR_MAX + 1][2]; @@ -1187,8 +1189,6 @@ struct tty_term { #define TERM_DECSLRM 0x4 #define TERM_DECFRA 0x8 #define TERM_RGBCOLOURS 0x10 -#define TERM_SYNC 0x20 -#define TERM_UTF8 0x40 int flags; LIST_ENTRY(tty_term) entry; @@ -1252,8 +1252,6 @@ struct tty { int flags; struct tty_term *term; - char *term_name; - int term_flags; u_int mouse_last_x; u_int mouse_last_y; @@ -1267,7 +1265,6 @@ struct tty { struct event key_timer; struct tty_key *key_tree; }; -#define tty_term_flags(tty) (tty->term->flags|tty->term_flags) /* TTY command context. */ struct tty_ctx { @@ -1498,7 +1495,9 @@ struct client { char *title; const char *cwd; - char *term; + char *term_name; + int term_features; + char *ttyname; struct tty tty; @@ -1531,7 +1530,7 @@ struct client { #define CLIENT_CONTROLCONTROL 0x4000 #define CLIENT_FOCUSED 0x8000 #define CLIENT_UTF8 0x10000 -#define CLIENT_256COLOURS 0x20000 +/* 0x20000 unused */ #define CLIENT_IDENTIFIED 0x40000 #define CLIENT_STATUSFORCE 0x80000 #define CLIENT_DOUBLECLICK 0x100000 @@ -1953,7 +1952,7 @@ void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *, void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_putn(struct tty *, const void *, size_t, u_int); -int tty_init(struct tty *, struct client *, int, char *); +int tty_init(struct tty *, struct client *, int); void tty_resize(struct tty *); void tty_set_size(struct tty *, u_int, u_int, u_int, u_int); void tty_start_tty(struct tty *); @@ -1968,8 +1967,7 @@ void tty_sync_end(struct tty *); int tty_open(struct tty *, char **); void tty_close(struct tty *); void tty_free(struct tty *); -void tty_set_flags(struct tty *, int); -int tty_get_flags(struct tty *); +void tty_update_features(struct tty *); void tty_write(void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); @@ -1999,7 +1997,8 @@ void tty_cmd_syncend(struct tty *, const struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; u_int tty_term_ncodes(void); -struct tty_term *tty_term_find(char *, int, char **); +void tty_term_apply(struct tty_term *, const char *, int); +struct tty_term *tty_term_create(struct tty *, char *, int *, int, char **); void tty_term_free(struct tty_term *); int tty_term_has(struct tty_term *, enum tty_code_code); const char *tty_term_string(struct tty_term *, enum tty_code_code); @@ -2016,6 +2015,11 @@ int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); const char *tty_term_describe(struct tty_term *, enum tty_code_code); +/* tty-features.c */ +void tty_add_features(int *, const char *, const char *); +const char *tty_get_features(int); +void tty_apply_features(struct tty_term *, int); + /* tty-acs.c */ int tty_acs_needed(struct tty *); const char *tty_acs_get(struct tty *, u_char); @@ -2161,7 +2165,7 @@ void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...); void cmd_wait_for_flush(void); /* client.c */ -int client_main(struct event_base *, int, char **, int); +int client_main(struct event_base *, int, char **, int, int); /* key-bindings.c */ struct key_table *key_bindings_get_table(const char *, int); diff --git a/tty-acs.c b/tty-acs.c index f5352d3e..3e811103 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -99,7 +99,7 @@ tty_acs_needed(struct tty *tty) tty_term_number(tty->term, TTYC_U8) == 0) return (1); - if (tty_get_flags(tty) & TERM_UTF8) + if (tty->client->flags & CLIENT_UTF8) return (0); return (1); } diff --git a/tty-features.c b/tty-features.c new file mode 100644 index 00000000..58cbae7b --- /dev/null +++ b/tty-features.c @@ -0,0 +1,264 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2020 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "tmux.h" + +/* + * Still hardcoded: + * - bracket paste (sent if application asks for it); + * - mouse (under kmous capability); + * - focus events (under focus-events option); + * - default colours (under AX or op capabilities); + * - AIX colours (under colors >= 16); + * - alternate escape (under XT). + * + * Also: + * - XT is used to decide whether to send DA and DSR, + * - DECSLRM and DECFRA use a flag instead of capabilities. + * - Sync is a flag rather than a string capability. + * - UTF-8 is a separate flag on the client; needed for unattached clients. + */ + +/* A named terminal feature. */ +struct tty_feature { + const char *name; + const char **capabilities; + int flags; +}; + +/* Terminal has xterm(1) title setting. */ +static const char *tty_feature_title_capabilities[] = { + "tsl=\\E]0;", /* should be using TS really */ + "fsl=\\a", + NULL +}; +static struct tty_feature tty_feature_title = { + "title", + tty_feature_title_capabilities, + 0 +}; + +/* Terminal can set the clipboard with OSC 52. */ +static const char *tty_feature_clipboard_capabilities[] = { + "Ms=\\E]52;%p1%s;%p2%s\\a", + NULL +}; +static struct tty_feature tty_feature_clipboard = { + "clipboard", + tty_feature_clipboard_capabilities, + 0 +}; + +/* + * Terminal supports RGB colour. This replaces setab and setaf also since + * terminals with RGB have versions that do not allow setting colours from the + * 256 palette. + */ +static const char *tty_feature_rgb_capabilities[] = { + "setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm", + "setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm", + "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", + "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", + NULL +}; +static struct tty_feature tty_feature_rgb = { + "RGB", + tty_feature_rgb_capabilities, + (TERM_256COLOURS|TERM_RGBCOLOURS) +}; + +/* Terminal supports 256 colours. */ +static const char *tty_feature_256_capabilities[] = { + "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m", + "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m", + NULL +}; +static struct tty_feature tty_feature_256 = { + "256", + tty_feature_256_capabilities, + TERM_256COLOURS +}; + +/* Terminal supports overline. */ +static const char *tty_feature_overline_capabilities[] = { + "Smol=\\E[53m", + NULL +}; +static struct tty_feature tty_feature_overline = { + "overline", + tty_feature_overline_capabilities, + 0 +}; + +/* Terminal supports underscore styles. */ +static const char *tty_feature_usstyle_capabilities[] = { + "Smulx=\E[4::%p1%dm", + "Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m", + NULL +}; +static struct tty_feature tty_feature_usstyle = { + "usstyle", + tty_feature_usstyle_capabilities, + 0 +}; + +/* Terminal supports cursor styles. */ +static const char *tty_feature_cstyle_capabilities[] = { + "Ss=\\E[%p1%d q", + "Se=\\E[2 q", + NULL +}; +static struct tty_feature tty_feature_cstyle = { + "cstyle", + tty_feature_cstyle_capabilities, + 0 +}; + +/* Terminal supports cursor colours. */ +static const char *tty_feature_ccolour_capabilities[] = { + "Cs=\\E]12;%p1%s\\a", + "Cr=\\E]112\\a", + NULL +}; +static struct tty_feature tty_feature_ccolour = { + "ccolour", + tty_feature_ccolour_capabilities, + 0 +}; + +/* Terminal supports synchronized updates. */ +static const char *tty_feature_sync_capabilities[] = { + "Sync", + NULL +}; +static struct tty_feature tty_feature_sync = { + "sync", + tty_feature_sync_capabilities, + 0 +}; + +/* Terminal supports DECSLRM margins. */ +static struct tty_feature tty_feature_margins = { + "margins", + NULL, + TERM_DECSLRM +}; + +/* Terminal supports DECFRA rectangle fill. */ +static struct tty_feature tty_feature_rectfill = { + "rectfill", + NULL, + TERM_DECFRA +}; + +/* Available terminal features. */ +static const struct tty_feature *tty_features[] = { + &tty_feature_256, + &tty_feature_clipboard, + &tty_feature_ccolour, + &tty_feature_cstyle, + &tty_feature_margins, + &tty_feature_overline, + &tty_feature_rectfill, + &tty_feature_rgb, + &tty_feature_sync, + &tty_feature_title, + &tty_feature_usstyle +}; + +void +tty_add_features(int *feat, const char *s, const char *separators) +{ + const struct tty_feature *tf; + char *next, *loop, *copy; + u_int i; + + loop = copy = xstrdup(s); + while ((next = strsep(&loop, separators)) != NULL) { + for (i = 0; i < nitems(tty_features); i++) { + tf = tty_features[i]; + if (strcasecmp(tf->name, next) == 0) + break; + } + if (i == nitems(tty_features)) { + log_debug("unknown terminal feature: %s", next); + break; + } + if (~(*feat) & (1 << i)) { + log_debug("adding terminal feature: %s", tf->name); + (*feat) |= (1 << i); + } + } + free(copy); +} + +const char * +tty_get_features(int feat) +{ + const struct tty_feature *tf; + static char s[512]; + u_int i; + + *s = '\0'; + for (i = 0; i < nitems(tty_features); i++) { + if (~feat & (1 << i)) + continue; + tf = tty_features[i]; + + strlcat(s, tf->name, sizeof s); + strlcat(s, ",", sizeof s); + } + if (*s != '\0') + s[strlen(s) - 1] = '\0'; + return (s); +} + +void +tty_apply_features(struct tty_term *term, int feat) +{ + const struct tty_feature *tf; + const char **capability; + u_int i; + + if (feat == 0) + return; + log_debug("applying terminal features: %s", tty_get_features(feat)); + + for (i = 0; i < nitems(tty_features); i++) { + if ((term->features & (1 << i)) || (~feat & (1 << i))) + continue; + tf = tty_features[i]; + + log_debug("applying terminal feature: %s", tf->name); + if (tf->capabilities != NULL) { + capability = tf->capabilities; + while (*capability != NULL) { + log_debug("adding capability: %s", *capability); + tty_term_apply(term, *capability, 1); + capability++; + } + } + term->flags |= tf->flags; + } + term->features |= feat; +} diff --git a/tty-keys.c b/tty-keys.c index 10c9c670..14952c05 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1020,7 +1020,6 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, struct client *c = tty->client; u_int i, n = 0; char tmp[64], *endptr, p[32] = { 0 }, *cp, *next; - int flags = 0; *size = 0; if (tty->flags & TTY_HAVEDA) @@ -1060,24 +1059,42 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, n++; } - /* Set terminal flags. */ + /* Add terminal features. */ switch (p[0]) { case 41: /* VT420 */ - flags |= (TERM_DECFRA|TERM_DECSLRM); + tty_add_features(&c->term_features, + "margins," + "rectfill", + ","); break; case 'M': /* mintty */ - flags |= (TERM_256COLOURS|TERM_RGBCOLOURS); + tty_add_features(&c->term_features, + "256," + "RGB," + "title", + ","); break; - case 'T': /* tmux - new versons reply to DSR which will set RGB */ - flags |= (TERM_UTF8|TERM_256COLOURS); + case 'T': /* tmux */ + tty_add_features(&c->term_features, + "256," + "RGB," + "ccolour," + "cstyle," + "overline," + "title," + "usstyle", + ","); break; case 'U': /* rxvt-unicode */ - flags |= (TERM_UTF8); + tty_add_features(&c->term_features, + "256," + "title", + ","); break; } log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf); - tty_set_flags(tty, flags); + tty_update_features(tty); tty->flags |= TTY_HAVEDA; return (0); @@ -1094,7 +1111,6 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, struct client *c = tty->client; u_int i; char tmp[64]; - int flags = 0; *size = 0; if (tty->flags & TTY_HAVEDSR) @@ -1125,15 +1141,31 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, tmp[i] = '\0'; *size = 3 + i; - /* Set terminal flags. */ + /* Add terminal features. */ if (strncmp(tmp, "ITERM2 ", 7) == 0) { - flags |= (TERM_UTF8|TERM_DECSLRM|TERM_SYNC|TERM_256COLOURS| - TERM_RGBCOLOURS); - } else if (strncmp(tmp, "TMUX ", 5) == 0) - flags |= (TERM_UTF8|TERM_256COLOURS|TERM_RGBCOLOURS); + tty_add_features(&c->term_features, + "256," + "RGB," + "clipboard," + "cstyle," + "margins," + "sync," + "title,", + ","); + } else if (strncmp(tmp, "TMUX ", 5) == 0) { + tty_add_features(&c->term_features, + "256," + "RGB," + "ccolour," + "cstyle," + "overline," + "title," + "usstyle", + ","); + } log_debug("%s: received DSR %.*s", c->name, (int)*size, buf); - tty_set_flags(tty, flags); + tty_update_features(tty); tty->flags |= TTY_HAVEDSR; return (0); diff --git a/tty-term.c b/tty-term.c index d6faa6ff..1c87ac15 100644 --- a/tty-term.c +++ b/tty-term.c @@ -27,7 +27,6 @@ #include "tmux.h" -static void tty_term_override(struct tty_term *, const char *); static char *tty_term_strip(const char *); struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms); @@ -335,22 +334,18 @@ tty_term_override_next(const char *s, size_t *offset) return (value); } -static void -tty_term_override(struct tty_term *term, const char *override) +void +tty_term_apply(struct tty_term *term, const char *capabilities, int quiet) { const struct tty_term_code_entry *ent; struct tty_code *code; size_t offset = 0; char *cp, *value, *s; - const char *errstr; + const char *errstr, *name = term->name; u_int i; int n, remove; - s = tty_term_override_next(override, &offset); - if (s == NULL || fnmatch(s, term->name, 0) != 0) - return; - - while ((s = tty_term_override_next(override, &offset)) != NULL) { + while ((s = tty_term_override_next(capabilities, &offset)) != NULL) { if (*s == '\0') continue; value = NULL; @@ -369,12 +364,14 @@ tty_term_override(struct tty_term *term, const char *override) } else value = xstrdup(""); - if (remove) - log_debug("%s override: %s@", term->name, s); - else if (*value == '\0') - log_debug("%s override: %s", term->name, s); - else - log_debug("%s override: %s=%s", term->name, s, value); + if (!quiet) { + if (remove) + log_debug("%s override: %s@", name, s); + else if (*value == '\0') + log_debug("%s override: %s", name, s); + else + log_debug("%s override: %s=%s", name, s, value); + } for (i = 0; i < tty_term_ncodes(); i++) { ent = &tty_term_codes[i]; @@ -414,7 +411,7 @@ tty_term_override(struct tty_term *term, const char *override) } struct tty_term * -tty_term_find(char *name, int fd, char **cause) +tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause) { struct tty_term *term; const struct tty_term_code_entry *ent; @@ -425,19 +422,14 @@ tty_term_find(char *name, int fd, char **cause) u_int i; int n, error; const char *s, *acs; + size_t offset; + char *first; - LIST_FOREACH(term, &tty_terms, entry) { - if (strcmp(term->name, name) == 0) { - term->references++; - return (term); - } - } - log_debug("new term: %s", name); + log_debug("adding term %s", name); - term = xmalloc(sizeof *term); + term = xcalloc(1, sizeof *term); + term->tty = tty; term->name = xstrdup(name); - term->references = 1; - term->flags = 0; term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes); LIST_INSERT_HEAD(&tty_terms, term, entry); @@ -495,12 +487,31 @@ tty_term_find(char *name, int fd, char **cause) } } + /* Apply terminal features. */ + o = options_get_only(global_options, "terminal-features"); + a = options_array_first(o); + while (a != NULL) { + ov = options_array_item_value(a); + s = ov->string; + + offset = 0; + first = tty_term_override_next(s, &offset); + if (first != NULL && fnmatch(first, term->name, 0) == 0) + tty_add_features(feat, s + offset, ":"); + a = options_array_next(a); + } + /* Apply terminal overrides. */ o = options_get_only(global_options, "terminal-overrides"); a = options_array_first(o); while (a != NULL) { ov = options_array_item_value(a); - tty_term_override(term, ov->string); + s = ov->string; + + offset = 0; + first = tty_term_override_next(s, &offset); + if (first != NULL && fnmatch(first, term->name, 0) == 0) + tty_term_apply(term, s + offset, 0); a = options_array_next(a); } @@ -523,19 +534,18 @@ tty_term_find(char *name, int fd, char **cause) goto error; } - /* Set flag if terminal has 256 colours. */ - if (tty_term_number(term, TTYC_COLORS) >= 256) - term->flags |= TERM_256COLOURS; + /* Add RGB feature if terminal has RGB colours. */ + if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) && + (!tty_term_has(term, TTYC_SETRGBF) || + !tty_term_has(term, TTYC_SETRGBB))) + tty_add_features(feat, "RGB", ":,"); - /* Set flag if terminal has RGB colours. */ - if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) || - (tty_term_has(term, TTYC_SETRGBF) && - tty_term_has(term, TTYC_SETRGBB))) - term->flags |= TERM_RGBCOLOURS; + /* Add feature if terminal has XT. */ + if (tty_term_flag(term, TTYC_XT)) + tty_add_features(feat, "title", ":,"); - /* Set flag if terminal has synchronized updates. */ - if (tty_term_flag(term, TTYC_SYNC)) - term->flags |= TERM_SYNC; + /* Apply the features. */ + tty_apply_features(term, *feat); /* * Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 @@ -559,18 +569,6 @@ tty_term_find(char *name, int fd, char **cause) for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) term->acs[(u_char) acs[0]][0] = acs[1]; - /* On terminals with xterm titles (XT), fill in tsl and fsl. */ - if (tty_term_flag(term, TTYC_XT) && - !tty_term_has(term, TTYC_TSL) && - !tty_term_has(term, TTYC_FSL)) { - code = &term->codes[TTYC_TSL]; - code->value.string = xstrdup("\033]0;"); - code->type = TTYCODE_STRING; - code = &term->codes[TTYC_FSL]; - code->value.string = xstrdup("\007"); - code->type = TTYCODE_STRING; - } - /* Log the capabilities. */ for (i = 0; i < tty_term_ncodes(); i++) log_debug("%s%s", name, tty_term_describe(term, i)); @@ -587,10 +585,7 @@ tty_term_free(struct tty_term *term) { u_int i; - if (--term->references != 0) - return; - - LIST_REMOVE(term, entry); + log_debug("removing term %s", term->name); for (i = 0; i < tty_term_ncodes(); i++) { if (term->codes[i].type == TTYCODE_STRING) @@ -598,6 +593,7 @@ tty_term_free(struct tty_term *term) } free(term->codes); + LIST_REMOVE(term, entry); free(term->name); free(term); } diff --git a/tty.c b/tty.c index cdfedf6c..dfc35873 100644 --- a/tty.c +++ b/tty.c @@ -74,7 +74,7 @@ static void tty_default_attributes(struct tty *, struct window_pane *, u_int); #define tty_use_margin(tty) \ - (tty_get_flags(tty) & TERM_DECSLRM) + (tty->term->flags & TERM_DECSLRM) #define tty_pane_full_width(tty, ctx) \ ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) @@ -96,27 +96,19 @@ tty_create_log(void) } int -tty_init(struct tty *tty, struct client *c, int fd, char *term) +tty_init(struct tty *tty, struct client *c, int fd) { if (!isatty(fd)) return (-1); memset(tty, 0, sizeof *tty); - if (term == NULL || *term == '\0') - tty->term_name = xstrdup("unknown"); - else - tty->term_name = xstrdup(term); - tty->fd = fd; tty->client = c; tty->cstyle = 0; tty->ccolour = xstrdup(""); - tty->flags = 0; - tty->term_flags = 0; - return (0); } @@ -256,7 +248,10 @@ tty_write_callback(__unused int fd, __unused short events, void *data) int tty_open(struct tty *tty, char **cause) { - tty->term = tty_term_find(tty->term_name, tty->fd, cause); + struct client *c = tty->client; + + tty->term = tty_term_create(tty, c->term_name, &c->term_features, + tty->fd, cause); if (tty->term == NULL) { tty_close(tty); return (-1); @@ -466,28 +461,20 @@ void tty_free(struct tty *tty) { tty_close(tty); - free(tty->ccolour); - free(tty->term_name); } void -tty_set_flags(struct tty *tty, int flags) +tty_update_features(struct tty *tty) { - tty->term_flags |= flags; + struct client *c = tty->client; + + tty_apply_features(tty->term, c->term_features); if (tty_use_margin(tty)) tty_puts(tty, "\033[?69h"); /* DECLRMM */ } -int -tty_get_flags(struct tty *tty) -{ - if (tty->term != NULL) - return (tty->term->flags|tty->term_flags); - return (tty->term_flags); -} - void tty_raw(struct tty *tty, const char *s) { @@ -585,7 +572,7 @@ tty_putc(struct tty *tty, u_char ch) { const char *acs; - if ((tty_get_flags(tty) & TERM_NOXENL) && + if ((tty->term->flags & TERM_NOXENL) && ch >= 0x20 && ch != 0x7f && tty->cy == tty->sy - 1 && tty->cx + 1 >= tty->sx) @@ -611,7 +598,7 @@ tty_putc(struct tty *tty, u_char ch) * where we think it should be after a line wrap - this * means it works on sensible terminals as well. */ - if (tty_get_flags(tty) & TERM_NOXENL) + if (tty->term->flags & TERM_NOXENL) tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); } else tty->cx++; @@ -621,7 +608,7 @@ tty_putc(struct tty *tty, u_char ch) void tty_putn(struct tty *tty, const void *buf, size_t len, u_int width) { - if ((tty_get_flags(tty) & TERM_NOXENL) && + if ((tty->term->flags & TERM_NOXENL) && tty->cy == tty->sy - 1 && tty->cx + len >= tty->sx) len = tty->sx - tty->cx - 1; @@ -1179,7 +1166,7 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny, * background colour isn't default (because it doesn't work * after SGR 0). */ - if ((tty_get_flags(tty) & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) { + if ((tty->term->flags & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) { xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x", py + 1, px + 1, py + ny, px + nx); tty_puts(tty, tmp); @@ -1258,7 +1245,7 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) return (gc); /* UTF-8 terminal and a UTF-8 character - fine. */ - if (tty_get_flags(tty) & TERM_UTF8) + if (tty->client->flags & CLIENT_UTF8) return (gc); /* Replace by the right number of underscores. */ @@ -1440,7 +1427,7 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s, void tty_sync_start(struct tty *tty) { - if ((~tty->flags & TTY_SYNCING) && (tty_get_flags(tty) & TERM_SYNC)) { + if ((~tty->flags & TTY_SYNCING) && tty_term_has(tty->term, TTYC_SYNC)) { tty_puts(tty, "\033P=1s\033\\"); tty->flags |= TTY_SYNCING; } @@ -1449,7 +1436,7 @@ tty_sync_start(struct tty *tty) void tty_sync_end(struct tty *tty) { - if (tty_get_flags(tty) & TERM_SYNC) { + if ((tty->flags & TTY_SYNCING) && tty_term_has(tty->term, TTYC_SYNC)) { tty_puts(tty, "\033P=2s\033\\"); tty->flags &= ~TTY_SYNCING; } @@ -1916,7 +1903,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) { if (!ctx->wrapped || !tty_pane_full_width(tty, ctx) || - (tty_get_flags(tty) & TERM_NOXENL) || + (tty->term->flags & TERM_NOXENL) || ctx->xoff + ctx->ocx != 0 || ctx->yoff + ctx->ocy != tty->cy + 1 || tty->cx < tty->sx || @@ -1977,7 +1964,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp) const struct grid_cell *gcp; /* Skip last character if terminal is stupid. */ - if ((tty_get_flags(tty) & TERM_NOXENL) && + if ((tty->term->flags & TERM_NOXENL) && tty->cy == tty->sy - 1 && tty->cx == tty->sx - 1) return; @@ -2140,7 +2127,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx, { if (!ctx->wrapped || !tty_pane_full_width(tty, ctx) || - (tty_get_flags(tty) & TERM_NOXENL) || + (tty->term->flags & TERM_NOXENL) || ctx->xoff + cx != 0 || ctx->yoff + cy != tty->cy + 1 || tty->cx < tty->sx || @@ -2480,14 +2467,14 @@ tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc) /* Is this a 24-bit colour? */ if (gc->fg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ - if (tty_get_flags(tty) & TERM_RGBCOLOURS) + if (tty->term->flags & TERM_RGBCOLOURS) return; colour_split_rgb(gc->fg, &r, &g, &b); gc->fg = colour_find_rgb(r, g, b); } /* How many colours does this terminal have? */ - if (tty_get_flags(tty) & TERM_256COLOURS) + if (tty->term->flags & TERM_256COLOURS) colours = 256; else colours = tty_term_number(tty->term, TTYC_COLORS); @@ -2529,14 +2516,14 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc) /* Is this a 24-bit colour? */ if (gc->bg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ - if (tty_get_flags(tty) & TERM_RGBCOLOURS) + if (tty->term->flags & TERM_RGBCOLOURS) return; colour_split_rgb(gc->bg, &r, &g, &b); gc->bg = colour_find_rgb(r, g, b); } /* How many colours does this terminal have? */ - if (tty_get_flags(tty) & TERM_256COLOURS) + if (tty->term->flags & TERM_256COLOURS) colours = 256; else colours = tty_term_number(tty->term, TTYC_COLORS); @@ -2597,7 +2584,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) /* Is this an aixterm bright colour? */ if (gc->fg >= 90 && gc->fg <= 97) { - if (tty_get_flags(tty) & TERM_256COLOURS) { + if (tty->term->flags & TERM_256COLOURS) { xsnprintf(s, sizeof s, "\033[%dm", gc->fg); tty_puts(tty, s); } else @@ -2629,7 +2616,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) /* Is this an aixterm bright colour? */ if (gc->bg >= 90 && gc->bg <= 97) { - if (tty_get_flags(tty) & TERM_256COLOURS) { + if (tty->term->flags & TERM_256COLOURS) { xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10); tty_puts(tty, s); } else @@ -2674,67 +2661,25 @@ static int tty_try_colour(struct tty *tty, int colour, const char *type) { u_char r, g, b; - char s[32]; if (colour & COLOUR_FLAG_256) { - /* - * If the user has specified -2 to the client (meaning - * TERM_256COLOURS is set), setaf and setab may not work (or - * they may not want to use them), so send the usual sequence. - * - * Also if RGB is set, setaf and setab do not support the 256 - * colour palette so use the sequences directly there too. - */ - if ((tty_get_flags(tty) & TERM_256COLOURS) || - tty_term_has(tty->term, TTYC_RGB)) - goto fallback_256; - - /* - * If the terminfo entry has 256 colours and setaf and setab - * exist, assume that they work correctly. - */ - if (tty_get_flags(tty) & TERM_256COLOURS) { - if (*type == '3') { - if (!tty_term_has(tty->term, TTYC_SETAF)) - goto fallback_256; - tty_putcode1(tty, TTYC_SETAF, colour & 0xff); - } else { - if (!tty_term_has(tty->term, TTYC_SETAB)) - goto fallback_256; - tty_putcode1(tty, TTYC_SETAB, colour & 0xff); - } - return (0); - } - goto fallback_256; + if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF)) + tty_putcode1(tty, TTYC_SETAF, colour & 0xff); + else if (tty_term_has(tty->term, TTYC_SETAB)) + tty_putcode1(tty, TTYC_SETAB, colour & 0xff); + return (0); } if (colour & COLOUR_FLAG_RGB) { colour_split_rgb(colour & 0xffffff, &r, &g, &b); - if (*type == '3') { - if (!tty_term_has(tty->term, TTYC_SETRGBF)) - goto fallback_rgb; + if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF)) tty_putcode3(tty, TTYC_SETRGBF, r, g, b); - } else { - if (!tty_term_has(tty->term, TTYC_SETRGBB)) - goto fallback_rgb; + else if (tty_term_has(tty->term, TTYC_SETRGBB)) tty_putcode3(tty, TTYC_SETRGBB, r, g, b); - } return (0); } return (-1); - -fallback_256: - xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff); - log_debug("%s: 256 colour fallback: %s", tty->client->name, s); - tty_puts(tty, s); - return (0); - -fallback_rgb: - xsnprintf(s, sizeof s, "\033[%s;2;%d;%d;%dm", type, r, g, b); - log_debug("%s: RGB colour fallback: %s", tty->client->name, s); - tty_puts(tty, s); - return (0); } static void From 135bb1edeeab3faae8001100aa7c173be9aa91e1 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 20 Apr 2020 13:38:48 +0000 Subject: [PATCH 2/2] Change the Sync capability to be a string instead of a flag. --- tmux.1 | 2 +- tty-features.c | 3 +-- tty-term.c | 2 +- tty.c | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tmux.1 b/tmux.1 index ca4e30e0..648aed4d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5572,7 +5572,7 @@ If .Em Se is not set, \&Ss with argument 0 will be used to reset the cursor style instead. .It Em \&Sync -Show that the terminal supports synchronized updates. +Start (parameter is 1) or end (parameter is 2) a synchronized update. .It Em \&Tc Indicate that the terminal supports the .Ql direct colour diff --git a/tty-features.c b/tty-features.c index 58cbae7b..b6934673 100644 --- a/tty-features.c +++ b/tty-features.c @@ -35,7 +35,6 @@ * Also: * - XT is used to decide whether to send DA and DSR, * - DECSLRM and DECFRA use a flag instead of capabilities. - * - Sync is a flag rather than a string capability. * - UTF-8 is a separate flag on the client; needed for unattached clients. */ @@ -148,7 +147,7 @@ static struct tty_feature tty_feature_ccolour = { /* Terminal supports synchronized updates. */ static const char *tty_feature_sync_capabilities[] = { - "Sync", + "Sync=\\EP=%p1%ds\\E\\\\", NULL }; static struct tty_feature tty_feature_sync = { diff --git a/tty-term.c b/tty-term.c index 1c87ac15..e1b026ea 100644 --- a/tty-term.c +++ b/tty-term.c @@ -259,7 +259,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" }, - [TTYC_SYNC] = { TTYCODE_FLAG, "Sync" }, + [TTYC_SYNC] = { TTYCODE_STRING, "Sync" }, [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, [TTYC_U8] = { TTYCODE_NUMBER, "U8" }, diff --git a/tty.c b/tty.c index dfc35873..e1c629ec 100644 --- a/tty.c +++ b/tty.c @@ -1428,7 +1428,7 @@ void tty_sync_start(struct tty *tty) { if ((~tty->flags & TTY_SYNCING) && tty_term_has(tty->term, TTYC_SYNC)) { - tty_puts(tty, "\033P=1s\033\\"); + tty_putcode1(tty, TTYC_SYNC, 1); tty->flags |= TTY_SYNCING; } } @@ -1437,7 +1437,7 @@ void tty_sync_end(struct tty *tty) { if ((tty->flags & TTY_SYNCING) && tty_term_has(tty->term, TTYC_SYNC)) { - tty_puts(tty, "\033P=2s\033\\"); + tty_putcode1(tty, TTYC_SYNC, 2); tty->flags &= ~TTY_SYNCING; } }