Annotation of src/usr.bin/tmux/tty-features.c, Revision 1.19
1.19 ! nicm 1: /* $OpenBSD: tty-features.c,v 1.18 2020/10/05 09:53:01 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
26: /*
27: * Still hardcoded:
28: * - mouse (under kmous capability);
29: * - default colours (under AX or op capabilities);
30: * - AIX colours (under colors >= 16);
1.13 nicm 31: * - alternate escape (if terminal is VT100-like).
1.1 nicm 32: *
33: * Also:
1.7 nicm 34: * - DECFRA uses a flag instead of capabilities;
1.1 nicm 35: * - UTF-8 is a separate flag on the client; needed for unattached clients.
36: */
37:
38: /* A named terminal feature. */
39: struct tty_feature {
40: const char *name;
41: const char **capabilities;
42: int flags;
43: };
44:
45: /* Terminal has xterm(1) title setting. */
46: static const char *tty_feature_title_capabilities[] = {
47: "tsl=\\E]0;", /* should be using TS really */
48: "fsl=\\a",
49: NULL
50: };
1.12 nicm 51: static const struct tty_feature tty_feature_title = {
1.1 nicm 52: "title",
53: tty_feature_title_capabilities,
54: 0
55: };
56:
57: /* Terminal can set the clipboard with OSC 52. */
58: static const char *tty_feature_clipboard_capabilities[] = {
59: "Ms=\\E]52;%p1%s;%p2%s\\a",
60: NULL
61: };
1.12 nicm 62: static const struct tty_feature tty_feature_clipboard = {
1.1 nicm 63: "clipboard",
64: tty_feature_clipboard_capabilities,
65: 0
66: };
67:
68: /*
69: * Terminal supports RGB colour. This replaces setab and setaf also since
70: * terminals with RGB have versions that do not allow setting colours from the
71: * 256 palette.
72: */
73: static const char *tty_feature_rgb_capabilities[] = {
1.4 nicm 74: "AX",
1.1 nicm 75: "setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm",
76: "setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm",
77: "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
78: "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
79: NULL
80: };
1.12 nicm 81: static const struct tty_feature tty_feature_rgb = {
1.1 nicm 82: "RGB",
83: tty_feature_rgb_capabilities,
1.7 nicm 84: TERM_256COLOURS|TERM_RGBCOLOURS
1.1 nicm 85: };
86:
87: /* Terminal supports 256 colours. */
88: static const char *tty_feature_256_capabilities[] = {
1.4 nicm 89: "AX",
1.1 nicm 90: "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
91: "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
92: NULL
93: };
1.12 nicm 94: static const struct tty_feature tty_feature_256 = {
1.1 nicm 95: "256",
96: tty_feature_256_capabilities,
97: TERM_256COLOURS
98: };
99:
100: /* Terminal supports overline. */
101: static const char *tty_feature_overline_capabilities[] = {
102: "Smol=\\E[53m",
103: NULL
104: };
1.12 nicm 105: static const struct tty_feature tty_feature_overline = {
1.1 nicm 106: "overline",
107: tty_feature_overline_capabilities,
108: 0
109: };
110:
111: /* Terminal supports underscore styles. */
112: static const char *tty_feature_usstyle_capabilities[] = {
1.17 daniel 113: "Smulx=\\E[4::%p1%dm",
114: "Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
1.18 nicm 115: "ol=\\E[59m",
1.1 nicm 116: NULL
117: };
1.12 nicm 118: static const struct tty_feature tty_feature_usstyle = {
1.1 nicm 119: "usstyle",
120: tty_feature_usstyle_capabilities,
121: 0
122: };
123:
1.12 nicm 124: /* Terminal supports bracketed paste. */
1.11 nicm 125: static const char *tty_feature_bpaste_capabilities[] = {
1.12 nicm 126: "Enbp=\\E[?2004h",
1.11 nicm 127: "Dsbp=\\E[?2004l",
128: NULL
129: };
1.12 nicm 130: static const struct tty_feature tty_feature_bpaste = {
1.11 nicm 131: "bpaste",
132: tty_feature_bpaste_capabilities,
133: 0
134: };
135:
1.12 nicm 136: /* Terminal supports focus reporting. */
137: static const char *tty_feature_focus_capabilities[] = {
138: "Enfcs=\\E[?1004h",
139: "Dsfcs=\\E[?1004l",
140: NULL
141: };
142: static const struct tty_feature tty_feature_focus = {
143: "focus",
144: tty_feature_focus_capabilities,
145: 0
146: };
147:
1.1 nicm 148: /* Terminal supports cursor styles. */
149: static const char *tty_feature_cstyle_capabilities[] = {
150: "Ss=\\E[%p1%d q",
151: "Se=\\E[2 q",
152: NULL
153: };
1.12 nicm 154: static const struct tty_feature tty_feature_cstyle = {
1.1 nicm 155: "cstyle",
156: tty_feature_cstyle_capabilities,
157: 0
158: };
159:
160: /* Terminal supports cursor colours. */
161: static const char *tty_feature_ccolour_capabilities[] = {
162: "Cs=\\E]12;%p1%s\\a",
163: "Cr=\\E]112\\a",
164: NULL
165: };
1.12 nicm 166: static const struct tty_feature tty_feature_ccolour = {
1.1 nicm 167: "ccolour",
168: tty_feature_ccolour_capabilities,
169: 0
170: };
171:
1.10 nicm 172: /* Terminal supports strikethrough. */
173: static const char *tty_feature_strikethrough_capabilities[] = {
174: "smxx=\\E[9m",
175: NULL
176: };
1.12 nicm 177: static const struct tty_feature tty_feature_strikethrough = {
1.10 nicm 178: "strikethrough",
179: tty_feature_strikethrough_capabilities,
180: 0
181: };
182:
1.1 nicm 183: /* Terminal supports synchronized updates. */
184: static const char *tty_feature_sync_capabilities[] = {
1.2 nicm 185: "Sync=\\EP=%p1%ds\\E\\\\",
1.1 nicm 186: NULL
187: };
1.12 nicm 188: static const struct tty_feature tty_feature_sync = {
1.1 nicm 189: "sync",
190: tty_feature_sync_capabilities,
191: 0
192: };
193:
1.14 nicm 194: /* Terminal supports extended keys. */
195: static const char *tty_feature_extkeys_capabilities[] = {
196: "Eneks=\\E[>4;1m",
197: "Dseks=\\E[>4m",
198: NULL
199: };
200: static const struct tty_feature tty_feature_extkeys = {
201: "extkeys",
202: tty_feature_extkeys_capabilities,
203: 0
204: };
205:
1.1 nicm 206: /* Terminal supports DECSLRM margins. */
1.7 nicm 207: static const char *tty_feature_margins_capabilities[] = {
208: "Enmg=\\E[?69h",
209: "Dsmg=\\E[?69l",
210: "Clmg=\\E[s",
211: "Cmg=\\E[%i%p1%d;%p2%ds",
212: NULL
213: };
1.12 nicm 214: static const struct tty_feature tty_feature_margins = {
1.1 nicm 215: "margins",
1.7 nicm 216: tty_feature_margins_capabilities,
1.1 nicm 217: TERM_DECSLRM
218: };
219:
220: /* Terminal supports DECFRA rectangle fill. */
1.19 ! nicm 221: static const char *tty_feature_rectfill_capabilities[] = {
! 222: "Rect",
! 223: NULL
! 224: };
1.12 nicm 225: static const struct tty_feature tty_feature_rectfill = {
1.1 nicm 226: "rectfill",
1.19 ! nicm 227: tty_feature_rectfill_capabilities,
1.1 nicm 228: TERM_DECFRA
229: };
230:
231: /* Available terminal features. */
232: static const struct tty_feature *tty_features[] = {
233: &tty_feature_256,
1.11 nicm 234: &tty_feature_bpaste,
1.12 nicm 235: &tty_feature_ccolour,
1.1 nicm 236: &tty_feature_clipboard,
237: &tty_feature_cstyle,
1.14 nicm 238: &tty_feature_extkeys,
1.12 nicm 239: &tty_feature_focus,
1.1 nicm 240: &tty_feature_margins,
241: &tty_feature_overline,
242: &tty_feature_rectfill,
243: &tty_feature_rgb,
1.10 nicm 244: &tty_feature_strikethrough,
1.1 nicm 245: &tty_feature_sync,
246: &tty_feature_title,
247: &tty_feature_usstyle
248: };
249:
250: void
251: tty_add_features(int *feat, const char *s, const char *separators)
252: {
253: const struct tty_feature *tf;
254: char *next, *loop, *copy;
255: u_int i;
1.7 nicm 256:
1.9 nicm 257: log_debug("adding terminal features %s", s);
1.1 nicm 258:
259: loop = copy = xstrdup(s);
260: while ((next = strsep(&loop, separators)) != NULL) {
261: for (i = 0; i < nitems(tty_features); i++) {
262: tf = tty_features[i];
263: if (strcasecmp(tf->name, next) == 0)
264: break;
265: }
266: if (i == nitems(tty_features)) {
267: log_debug("unknown terminal feature: %s", next);
268: break;
269: }
270: if (~(*feat) & (1 << i)) {
271: log_debug("adding terminal feature: %s", tf->name);
272: (*feat) |= (1 << i);
273: }
274: }
275: free(copy);
276: }
277:
278: const char *
279: tty_get_features(int feat)
280: {
281: const struct tty_feature *tf;
282: static char s[512];
283: u_int i;
284:
285: *s = '\0';
286: for (i = 0; i < nitems(tty_features); i++) {
287: if (~feat & (1 << i))
288: continue;
289: tf = tty_features[i];
290:
291: strlcat(s, tf->name, sizeof s);
292: strlcat(s, ",", sizeof s);
293: }
294: if (*s != '\0')
295: s[strlen(s) - 1] = '\0';
296: return (s);
297: }
298:
1.3 nicm 299: int
1.1 nicm 300: tty_apply_features(struct tty_term *term, int feat)
301: {
302: const struct tty_feature *tf;
303: const char **capability;
304: u_int i;
305:
306: if (feat == 0)
1.3 nicm 307: return (0);
1.1 nicm 308: log_debug("applying terminal features: %s", tty_get_features(feat));
309:
310: for (i = 0; i < nitems(tty_features); i++) {
311: if ((term->features & (1 << i)) || (~feat & (1 << i)))
312: continue;
313: tf = tty_features[i];
314:
315: log_debug("applying terminal feature: %s", tf->name);
316: if (tf->capabilities != NULL) {
317: capability = tf->capabilities;
318: while (*capability != NULL) {
319: log_debug("adding capability: %s", *capability);
320: tty_term_apply(term, *capability, 1);
321: capability++;
322: }
323: }
324: term->flags |= tf->flags;
325: }
1.3 nicm 326: if ((term->features | feat) == term->features)
327: return (0);
1.1 nicm 328: term->features |= feat;
1.3 nicm 329: return (1);
1.9 nicm 330: }
331:
332: void
333: tty_default_features(int *feat, const char *name, u_int version)
334: {
335: static struct {
336: const char *name;
337: u_int version;
338: const char *features;
339: } table[] = {
1.16 nicm 340: #define TTY_FEATURES_BASE_MODERN_XTERM \
341: "256,RGB,bpaste,clipboard,strikethrough,title"
1.9 nicm 342: { .name = "mintty",
1.16 nicm 343: .features = TTY_FEATURES_BASE_MODERN_XTERM
1.18 nicm 344: ",ccolour,cstyle,extkeys,margins,overline,usstyle"
1.9 nicm 345: },
346: { .name = "tmux",
1.16 nicm 347: .features = TTY_FEATURES_BASE_MODERN_XTERM
348: ",ccolour,cstyle,focus,overline,usstyle"
1.9 nicm 349: },
350: { .name = "rxvt-unicode",
1.12 nicm 351: .features = "256,bpaste,ccolour,cstyle,title"
1.9 nicm 352: },
353: { .name = "iTerm2",
1.16 nicm 354: .features = TTY_FEATURES_BASE_MODERN_XTERM
355: ",cstyle,extkeys,margins,sync"
1.9 nicm 356: },
357: { .name = "XTerm",
1.19 ! nicm 358: /*
! 359: * xterm also supports DECSLRM and DECFRA, but they can be
! 360: * disabled so not set it here - they will be added if
! 361: * secondary DA shows VT420.
! 362: */
1.16 nicm 363: .features = TTY_FEATURES_BASE_MODERN_XTERM
1.19 ! nicm 364: ",ccolour,cstyle,extkeys,focus"
1.9 nicm 365: }
366: };
367: u_int i;
368:
369: for (i = 0; i < nitems(table); i++) {
370: if (strcmp(table[i].name, name) != 0)
371: continue;
372: if (version != 0 && version < table[i].version)
373: continue;
374: tty_add_features(feat, table[i].features, ",");
375: }
1.1 nicm 376: }