Allow features to be disabled using @ suffix in terminal-features, from

Michael Grant.
This commit is contained in:
nicm
2026-08-17 14:47:41 +00:00
committed by tmux update bot
parent 1729bb8e8a
commit a18d4e0067
7 changed files with 89 additions and 57 deletions

8
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $OpenBSD: tmux.1,v 1.1155 2026/08/06 09:05:04 nicm Exp $
.\" $OpenBSD: tmux.1,v 1.1156 2026/08/17 14:47:41 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: August 6 2026 $
.Dd $Mdocdate: August 17 2026 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -5045,6 +5045,10 @@ This is an array option where each entry is a colon-separated string made up
of a terminal type pattern (matched using
.Xr glob 7
patterns) followed by a list of terminal features.
A feature may be suffixed with
.Ql @
to disable it; for example,
.Ql xterm*:sync@ .
The available features are:
.Bl -tag -width Ds
.It 256

6
tmux.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tmux.c,v 1.222 2026/07/19 19:09:30 nicm Exp $ */
/* $OpenBSD: tmux.c,v 1.223 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -418,7 +418,7 @@ main(int argc, char **argv)
while ((opt = getopt(argc, argv, "2c:CDdf:hlL:NqS:T:uUvV")) != -1) {
switch (opt) {
case '2':
tty_add_features(&feat, "256", ":,");
tty_parse_features("256", ":,", &feat, NULL);
break;
case 'c':
shell_command = optarg;
@@ -466,7 +466,7 @@ main(int argc, char **argv)
path = xstrdup(optarg);
break;
case 'T':
tty_add_features(&feat, optarg, ":,");
tty_parse_features(optarg, ":,", &feat, NULL);
break;
case 'u':
flags |= CLIENT_UTF8;

16
tmux.h
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tmux.h,v 1.1423 2026/08/17 07:56:56 nicm Exp $ */
/* $OpenBSD: tmux.h,v 1.1424 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1684,7 +1684,7 @@ struct key_event {
struct tty_term {
char *name;
struct tty *tty;
int features;
int applied_features;
char acs[UCHAR_MAX + 1][2];
@@ -2185,6 +2185,7 @@ struct client {
char *term_name;
int term_features;
int term_nofeatures;
char *term_type;
char **term_caps;
u_int term_ncaps;
@@ -2954,8 +2955,7 @@ extern struct tty_terms tty_terms;
u_int tty_term_ncodes(void);
void tty_term_apply(struct tty_term *, const char *, int);
void tty_term_apply_overrides(struct tty_term *);
struct tty_term *tty_term_create(struct tty *, char *, char **, u_int, int *,
char **);
struct tty_term *tty_term_create(struct tty *, char *, char **, u_int, char **);
void tty_term_free(struct tty_term *);
int tty_term_read_list(const char *, int, char ***, u_int *,
char **);
@@ -2977,11 +2977,13 @@ 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 *);
void tty_parse_client_features(struct client *, const char *,
const char *);
void tty_parse_features(const char *, const char *, int *, int *);
const char *tty_get_features(int);
int tty_feature_present(struct tty_term *, const char *);
int tty_apply_features(struct tty_term *, int);
void tty_default_features(int *, const char *, u_int);
int tty_apply_features(struct tty_term *);
void tty_default_features(struct client *, const char *, u_int);
/* tty-acs.c */
int tty_acs_needed(struct tty *);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tty-features.c,v 1.41 2026/08/17 07:52:16 nicm Exp $ */
/* $OpenBSD: tty-features.c,v 1.42 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -383,17 +383,29 @@ static const struct tty_feature *const tty_features[] = {
&tty_feature_usstyle
};
/* Parse features for client. */
void
tty_add_features(int *feat, const char *s, const char *separators)
tty_parse_client_features(struct client *c, const char *s, const char *sep)
{
tty_parse_features(s, sep, &c->term_features, &c->term_nofeatures);
}
/* Parse features list. */
void
tty_parse_features(const char *s, const char *sep, int *enabled, int *disabled)
{
const struct tty_feature *tf;
char *next, *loop, *copy;
u_int i;
int remove;
log_debug("adding terminal features %s", s);
loop = copy = xstrdup(s);
while ((next = strsep(&loop, separators)) != NULL) {
while ((next = strsep(&loop, sep)) != NULL) {
remove = (*next != '\0' && next[strlen(next) - 1] == '@');
if (remove)
next[strlen(next) - 1] = '\0';
for (i = 0; i < nitems(tty_features); i++) {
tf = tty_features[i];
if (strcasecmp(tf->name, next) == 0)
@@ -403,14 +415,24 @@ tty_add_features(int *feat, const char *s, const char *separators)
log_debug("unknown terminal feature: %s", next);
break;
}
if (~(*feat) & (1 << i)) {
if (remove) {
log_debug("removing terminal feature: %s", tf->name);
*enabled &= ~(1 << i);
if (disabled != NULL)
*disabled |= 1 << i;
continue;
}
if (disabled != NULL && *disabled & (1 << i))
continue;
if (~(*enabled) & (1 << i)) {
log_debug("adding terminal feature: %s", tf->name);
(*feat) |= (1 << i);
(*enabled) |= (1 << i);
}
}
free(copy);
}
/* Get features as string. */
const char *
tty_get_features(int feat)
{
@@ -432,6 +454,7 @@ tty_get_features(int feat)
return (s);
}
/* Check if feature is present. */
int
tty_feature_present(struct tty_term *term, const char *name)
{
@@ -443,8 +466,8 @@ tty_feature_present(struct tty_term *term, const char *name)
for (i = 0; i < nitems(tty_features); i++) {
tf = tty_features[i];
if (strcmp(tf->name, name) == 0) {
if (term->features & (1 << i))
return (1);
if (term->applied_features & (1 << i))
return (1);
break;
}
}
@@ -471,19 +494,23 @@ tty_feature_present(struct tty_term *term, const char *name)
return (1);
}
/* Apply featurs to terminal. */
int
tty_apply_features(struct tty_term *term, int feat)
tty_apply_features(struct tty_term *term)
{
struct client *c = term->tty->client;
const struct tty_feature *tf;
const char *const *capability;
int feat;
u_int i;
feat = (c->term_features & ~c->term_nofeatures);
if (feat == 0)
return (0);
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)))
if ((term->applied_features & (1 << i)) || (~feat & (1 << i)))
continue;
tf = tty_features[i];
@@ -498,14 +525,15 @@ tty_apply_features(struct tty_term *term, int feat)
}
term->flags |= tf->flags;
}
if ((term->features | feat) == term->features)
if ((term->applied_features|feat) == term->applied_features)
return (0);
term->features |= feat;
term->applied_features |= feat;
return (1);
}
/* Add default features for a terminal identified by name and version. */
void
tty_default_features(int *feat, const char *name, u_int version)
tty_default_features(struct client *c, const char *name, u_int version)
{
static const struct {
const char *name;
@@ -618,6 +646,6 @@ tty_default_features(int *feat, const char *name, u_int version)
continue;
if (version != 0 && version < table[i].version)
continue;
tty_add_features(feat, table[i].features, ",");
tty_parse_client_features(c, table[i].features, ",");
}
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tty-keys.c,v 1.212 2026/08/17 07:52:16 nicm Exp $ */
/* $OpenBSD: tty-keys.c,v 1.213 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1447,7 +1447,6 @@ 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[128], *endptr, p[32] = { 0 }, *cp, *next;
@@ -1504,13 +1503,13 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
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", ",");
tty_parse_client_features(c, "sixel", ",");
if (p[i] == 21)
tty_add_features(features, "margins", ",");
tty_parse_client_features(c, "margins", ",");
if (p[i] == 28)
tty_add_features(features, "rectfill", ",");
tty_parse_client_features(c, "rectfill", ",");
if (p[i] == 52)
tty_add_features(features, "clipboard", ",");
tty_parse_client_features(c, "clipboard", ",");
}
break;
}
@@ -1531,7 +1530,6 @@ 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;
@@ -1585,13 +1583,13 @@ tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len,
*/
switch (p[0]) {
case 'M': /* mintty */
tty_default_features(features, "mintty", 0);
tty_default_features(c, "mintty", 0);
break;
case 'T': /* tmux */
tty_default_features(features, "tmux", 0);
tty_default_features(c, "tmux", 0);
break;
case 'U': /* rxvt-unicode */
tty_default_features(features, "rxvt-unicode", 0);
tty_default_features(c, "rxvt-unicode", 0);
break;
}
log_debug("%s: received secondary DA %.*s", c->name, (int)*size, buf);
@@ -1611,7 +1609,6 @@ 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];
@@ -1654,21 +1651,21 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
/* Add terminal features. */
if (strncmp(tmp, "iTerm2 ", 7) == 0)
tty_default_features(features, "iTerm2", 0);
tty_default_features(c, "iTerm2", 0);
else if (strncmp(tmp, "tmux ", 5) == 0)
tty_default_features(features, "tmux", 0);
tty_default_features(c, "tmux", 0);
else if (strncmp(tmp, "XTerm(", 6) == 0)
tty_default_features(features, "XTerm", 0);
tty_default_features(c, "XTerm", 0);
else if (strncmp(tmp, "mintty ", 7) == 0)
tty_default_features(features, "mintty", 0);
tty_default_features(c, "mintty", 0);
else if (strncmp(tmp, "foot(", 5) == 0)
tty_default_features(features, "foot", 0);
tty_default_features(c, "foot", 0);
else if (strncmp(tmp, "WezTerm ", 7) == 0)
tty_default_features(features, "WezTerm", 0);
tty_default_features(c, "WezTerm", 0);
else if (strncmp(tmp, "ghostty ", 8) == 0)
tty_default_features(features, "ghostty", 0);
tty_default_features(c, "ghostty", 0);
else if (strncmp(tmp, "Rio ", 4) == 0)
tty_default_features(features, "Rio", 0);
tty_default_features(c, "Rio", 0);
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
free(c->term_type);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tty-term.c,v 1.107 2026/08/05 08:54:56 nicm Exp $ */
/* $OpenBSD: tty-term.c,v 1.108 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -541,8 +541,9 @@ tty_term_validate(struct tty_term *term)
struct tty_term *
tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
int *feat, char **cause)
char **cause)
{
struct client *c = tty->client;
struct tty_term *term;
const struct tty_term_code_entry *ent;
struct tty_code *code;
@@ -614,19 +615,19 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
offset = 0;
first = tty_term_override_next(s, &offset);
if (first != NULL && fnmatch(first, term->name, 0) == 0)
tty_add_features(feat, s + offset, ":");
tty_parse_client_features(c, s + offset, ":");
a = options_array_next(a);
}
/* Check for COLORTERM. */
envent = environ_find(tty->client->environ, "COLORTERM");
envent = environ_find(c->environ, "COLORTERM");
if (envent != NULL) {
log_debug("%s COLORTERM=%s", tty->client->name, envent->value);
log_debug("%s COLORTERM=%s", c->name, envent->value);
if (strcasecmp(envent->value, "truecolor") == 0 ||
strcasecmp(envent->value, "24bit") == 0)
tty_add_features(feat, "RGB", ",");
tty_parse_client_features(c, "RGB", ",");
else if (strstr(envent->value, "256") != NULL)
tty_add_features(feat, "256", ",");
tty_parse_client_features(c, "256", ",");
}
/* Apply overrides so any capabilities used for features are changed. */
@@ -657,17 +658,17 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
s = tty_term_string(term, TTYC_CLEAR);
if (tty_term_flag(term, TTYC_XT) || strncmp(s, "\033[", 2) == 0) {
term->flags |= TERM_VT100LIKE;
tty_add_features(feat, "bpaste,focus,title", ",");
tty_parse_client_features(c, "bpaste,focus,title", ",");
}
/* 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", ",");
tty_parse_client_features(c, "RGB", ",");
/* Apply the features and overrides again. */
if (tty_apply_features(term, *feat))
if (tty_apply_features(term))
tty_term_apply_overrides(term);
/* Log the capabilities. */

6
tty.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tty.c,v 1.477 2026/07/17 12:42:51 nicm Exp $ */
/* $OpenBSD: tty.c,v 1.478 2026/08/17 14:47:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -272,7 +272,7 @@ tty_open(struct tty *tty, char **cause)
struct client *c = tty->client;
tty->term = tty_term_create(tty, c->term_name, c->term_caps,
c->term_ncaps, &c->term_features, cause);
c->term_ncaps, cause);
if (tty->term == NULL) {
tty_close(tty);
return (-1);
@@ -531,7 +531,7 @@ tty_update_features(struct tty *tty)
{
struct client *c = tty->client;
if (tty_apply_features(tty->term, c->term_features))
if (tty_apply_features(tty->term))
tty_term_apply_overrides(tty->term);
if (tty_use_margin(tty))