Annotation of src/usr.bin/tmux/tty-features.c, Revision 1.11
1.11 ! nicm 1: /* $OpenBSD: tty-features.c,v 1.10 2020/05/16 14:31:35 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);
1.8 nicm 29: * - focus events (under XT and focus-events option);
1.1 nicm 30: * - default colours (under AX or op capabilities);
31: * - AIX colours (under colors >= 16);
32: * - alternate escape (under XT).
33: *
34: * Also:
1.6 nicm 35: * - XT is used to decide whether to send DA and XDA;
1.7 nicm 36: * - DECFRA uses a flag instead of capabilities;
1.1 nicm 37: * - UTF-8 is a separate flag on the client; needed for unattached clients.
38: */
39:
40: /* A named terminal feature. */
41: struct tty_feature {
42: const char *name;
43: const char **capabilities;
44: int flags;
45: };
46:
47: /* Terminal has xterm(1) title setting. */
48: static const char *tty_feature_title_capabilities[] = {
49: "tsl=\\E]0;", /* should be using TS really */
50: "fsl=\\a",
51: NULL
52: };
53: static struct tty_feature tty_feature_title = {
54: "title",
55: tty_feature_title_capabilities,
56: 0
57: };
58:
59: /* Terminal can set the clipboard with OSC 52. */
60: static const char *tty_feature_clipboard_capabilities[] = {
61: "Ms=\\E]52;%p1%s;%p2%s\\a",
62: NULL
63: };
64: static struct tty_feature tty_feature_clipboard = {
65: "clipboard",
66: tty_feature_clipboard_capabilities,
67: 0
68: };
69:
70: /*
71: * Terminal supports RGB colour. This replaces setab and setaf also since
72: * terminals with RGB have versions that do not allow setting colours from the
73: * 256 palette.
74: */
75: static const char *tty_feature_rgb_capabilities[] = {
1.4 nicm 76: "AX",
1.1 nicm 77: "setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm",
78: "setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm",
79: "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
80: "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
81: NULL
82: };
83: static struct tty_feature tty_feature_rgb = {
84: "RGB",
85: tty_feature_rgb_capabilities,
1.7 nicm 86: TERM_256COLOURS|TERM_RGBCOLOURS
1.1 nicm 87: };
88:
89: /* Terminal supports 256 colours. */
90: static const char *tty_feature_256_capabilities[] = {
1.4 nicm 91: "AX",
1.1 nicm 92: "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
93: "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
94: NULL
95: };
96: static struct tty_feature tty_feature_256 = {
97: "256",
98: tty_feature_256_capabilities,
99: TERM_256COLOURS
100: };
101:
102: /* Terminal supports overline. */
103: static const char *tty_feature_overline_capabilities[] = {
104: "Smol=\\E[53m",
105: NULL
106: };
107: static struct tty_feature tty_feature_overline = {
108: "overline",
109: tty_feature_overline_capabilities,
110: 0
111: };
112:
113: /* Terminal supports underscore styles. */
114: static const char *tty_feature_usstyle_capabilities[] = {
115: "Smulx=\E[4::%p1%dm",
116: "Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
117: NULL
118: };
119: static struct tty_feature tty_feature_usstyle = {
120: "usstyle",
121: tty_feature_usstyle_capabilities,
122: 0
123: };
124:
1.11 ! nicm 125: /* Terminal supports cursor bracketed paste. */
! 126: static const char *tty_feature_bpaste_capabilities[] = {
! 127: "Enbp=\E[?2004h",
! 128: "Dsbp=\\E[?2004l",
! 129: NULL
! 130: };
! 131: static struct tty_feature tty_feature_bpaste = {
! 132: "bpaste",
! 133: tty_feature_bpaste_capabilities,
! 134: 0
! 135: };
! 136:
1.1 nicm 137: /* Terminal supports cursor styles. */
138: static const char *tty_feature_cstyle_capabilities[] = {
139: "Ss=\\E[%p1%d q",
140: "Se=\\E[2 q",
141: NULL
142: };
143: static struct tty_feature tty_feature_cstyle = {
144: "cstyle",
145: tty_feature_cstyle_capabilities,
146: 0
147: };
148:
149: /* Terminal supports cursor colours. */
150: static const char *tty_feature_ccolour_capabilities[] = {
151: "Cs=\\E]12;%p1%s\\a",
152: "Cr=\\E]112\\a",
153: NULL
154: };
155: static struct tty_feature tty_feature_ccolour = {
156: "ccolour",
157: tty_feature_ccolour_capabilities,
158: 0
159: };
160:
1.10 nicm 161: /* Terminal supports strikethrough. */
162: static const char *tty_feature_strikethrough_capabilities[] = {
163: "smxx=\\E[9m",
164: NULL
165: };
166: static struct tty_feature tty_feature_strikethrough = {
167: "strikethrough",
168: tty_feature_strikethrough_capabilities,
169: 0
170: };
171:
1.1 nicm 172: /* Terminal supports synchronized updates. */
173: static const char *tty_feature_sync_capabilities[] = {
1.2 nicm 174: "Sync=\\EP=%p1%ds\\E\\\\",
1.1 nicm 175: NULL
176: };
177: static struct tty_feature tty_feature_sync = {
178: "sync",
179: tty_feature_sync_capabilities,
180: 0
181: };
182:
183: /* Terminal supports DECSLRM margins. */
1.7 nicm 184: static const char *tty_feature_margins_capabilities[] = {
185: "Enmg=\\E[?69h",
186: "Dsmg=\\E[?69l",
187: "Clmg=\\E[s",
188: "Cmg=\\E[%i%p1%d;%p2%ds",
189: NULL
190: };
1.1 nicm 191: static struct tty_feature tty_feature_margins = {
192: "margins",
1.7 nicm 193: tty_feature_margins_capabilities,
1.1 nicm 194: TERM_DECSLRM
195: };
196:
197: /* Terminal supports DECFRA rectangle fill. */
198: static struct tty_feature tty_feature_rectfill = {
199: "rectfill",
200: NULL,
201: TERM_DECFRA
202: };
203:
204: /* Available terminal features. */
205: static const struct tty_feature *tty_features[] = {
206: &tty_feature_256,
1.11 ! nicm 207: &tty_feature_bpaste,
1.1 nicm 208: &tty_feature_clipboard,
209: &tty_feature_ccolour,
210: &tty_feature_cstyle,
211: &tty_feature_margins,
212: &tty_feature_overline,
213: &tty_feature_rectfill,
214: &tty_feature_rgb,
1.10 nicm 215: &tty_feature_strikethrough,
1.1 nicm 216: &tty_feature_sync,
217: &tty_feature_title,
218: &tty_feature_usstyle
219: };
220:
221: void
222: tty_add_features(int *feat, const char *s, const char *separators)
223: {
224: const struct tty_feature *tf;
225: char *next, *loop, *copy;
226: u_int i;
1.7 nicm 227:
1.9 nicm 228: log_debug("adding terminal features %s", s);
1.1 nicm 229:
230: loop = copy = xstrdup(s);
231: while ((next = strsep(&loop, separators)) != NULL) {
232: for (i = 0; i < nitems(tty_features); i++) {
233: tf = tty_features[i];
234: if (strcasecmp(tf->name, next) == 0)
235: break;
236: }
237: if (i == nitems(tty_features)) {
238: log_debug("unknown terminal feature: %s", next);
239: break;
240: }
241: if (~(*feat) & (1 << i)) {
242: log_debug("adding terminal feature: %s", tf->name);
243: (*feat) |= (1 << i);
244: }
245: }
246: free(copy);
247: }
248:
249: const char *
250: tty_get_features(int feat)
251: {
252: const struct tty_feature *tf;
253: static char s[512];
254: u_int i;
255:
256: *s = '\0';
257: for (i = 0; i < nitems(tty_features); i++) {
258: if (~feat & (1 << i))
259: continue;
260: tf = tty_features[i];
261:
262: strlcat(s, tf->name, sizeof s);
263: strlcat(s, ",", sizeof s);
264: }
265: if (*s != '\0')
266: s[strlen(s) - 1] = '\0';
267: return (s);
268: }
269:
1.3 nicm 270: int
1.1 nicm 271: tty_apply_features(struct tty_term *term, int feat)
272: {
273: const struct tty_feature *tf;
274: const char **capability;
275: u_int i;
276:
277: if (feat == 0)
1.3 nicm 278: return (0);
1.1 nicm 279: log_debug("applying terminal features: %s", tty_get_features(feat));
280:
281: for (i = 0; i < nitems(tty_features); i++) {
282: if ((term->features & (1 << i)) || (~feat & (1 << i)))
283: continue;
284: tf = tty_features[i];
285:
286: log_debug("applying terminal feature: %s", tf->name);
287: if (tf->capabilities != NULL) {
288: capability = tf->capabilities;
289: while (*capability != NULL) {
290: log_debug("adding capability: %s", *capability);
291: tty_term_apply(term, *capability, 1);
292: capability++;
293: }
294: }
295: term->flags |= tf->flags;
296: }
1.3 nicm 297: if ((term->features | feat) == term->features)
298: return (0);
1.1 nicm 299: term->features |= feat;
1.3 nicm 300: return (1);
1.9 nicm 301: }
302:
303: void
304: tty_default_features(int *feat, const char *name, u_int version)
305: {
306: static struct {
307: const char *name;
308: u_int version;
309: const char *features;
310: } table[] = {
311: { .name = "mintty",
1.11 ! nicm 312: .features = "256,RGB,bpaste,ccolour,clipboard,cstyle,margins,overline,strikethrough,title"
1.9 nicm 313: },
314: { .name = "tmux",
1.11 ! nicm 315: .features = "256,RGB,bpaste,ccolour,clipboard,cstyle,overline,strikethough,title,usstyle"
1.9 nicm 316: },
317: { .name = "rxvt-unicode",
318: .features = "256,title"
319: },
320: { .name = "iTerm2",
1.11 ! nicm 321: .features = "256,RGB,bpaste,clipboard,cstyle,margins,strikethrough,sync,title"
1.9 nicm 322: },
323: { .name = "XTerm",
1.11 ! nicm 324: .features = "256,RGB,bpaste,ccolour,clipboard,cstyle,margins,rectfill,strikethrough,title"
1.9 nicm 325: }
326: };
327: u_int i;
328:
329: for (i = 0; i < nitems(table); i++) {
330: if (strcmp(table[i].name, name) != 0)
331: continue;
332: if (version != 0 && version < table[i].version)
333: continue;
334: tty_add_features(feat, table[i].features, ",");
335: }
336:
1.1 nicm 337: }