Do not allow paste into panes which have exited, from Romain Francoise
[tmux-openbsd.git] / tty-features.c
blob42f83f4175a5b8c3b2b4bb4a4acc7347a40041c1
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * Still hardcoded:
28 * - default colours (under AX or op capabilities);
29 * - AIX colours (under colors >= 16);
30 * - alternate escape (if terminal is VT100-like).
32 * Also:
33 * - DECFRA uses a flag instead of capabilities;
34 * - UTF-8 is a separate flag on the client; needed for unattached clients.
37 /* A named terminal feature. */
38 struct tty_feature {
39 const char *name;
40 const char *const *capabilities;
41 int flags;
44 /* Terminal has xterm(1) title setting. */
45 static const char *const tty_feature_title_capabilities[] = {
46 "tsl=\\E]0;", /* should be using TS really */
47 "fsl=\\a",
48 NULL
50 static const struct tty_feature tty_feature_title = {
51 "title",
52 tty_feature_title_capabilities,
56 /* Terminal has OSC 7 working directory. */
57 static const char *const tty_feature_osc7_capabilities[] = {
58 "Swd=\\E]7;",
59 "fsl=\\a",
60 NULL
62 static const struct tty_feature tty_feature_osc7 = {
63 "osc7",
64 tty_feature_osc7_capabilities,
68 /* Terminal has mouse support. */
69 static const char *const tty_feature_mouse_capabilities[] = {
70 "kmous=\\E[M",
71 NULL
73 static const struct tty_feature tty_feature_mouse = {
74 "mouse",
75 tty_feature_mouse_capabilities,
79 /* Terminal can set the clipboard with OSC 52. */
80 static const char *const tty_feature_clipboard_capabilities[] = {
81 "Ms=\\E]52;%p1%s;%p2%s\\a",
82 NULL
84 static const struct tty_feature tty_feature_clipboard = {
85 "clipboard",
86 tty_feature_clipboard_capabilities,
90 /* Terminal supports OSC 8 hyperlinks. */
91 static const char *const tty_feature_hyperlinks_capabilities[] = {
92 "*:Hls=\\E]8;%?%p1%l%tid=%p1%s%;;%p2%s\\E\\\\",
93 NULL
95 static const struct tty_feature tty_feature_hyperlinks = {
96 "hyperlinks",
97 tty_feature_hyperlinks_capabilities,
102 * Terminal supports RGB colour. This replaces setab and setaf also since
103 * terminals with RGB have versions that do not allow setting colours from the
104 * 256 palette.
106 static const char *const tty_feature_rgb_capabilities[] = {
107 "AX",
108 "setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm",
109 "setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm",
110 "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
111 "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
112 NULL
114 static const struct tty_feature tty_feature_rgb = {
115 "RGB",
116 tty_feature_rgb_capabilities,
117 TERM_256COLOURS|TERM_RGBCOLOURS
120 /* Terminal supports 256 colours. */
121 static const char *const tty_feature_256_capabilities[] = {
122 "AX",
123 "setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
124 "setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
125 NULL
127 static const struct tty_feature tty_feature_256 = {
128 "256",
129 tty_feature_256_capabilities,
130 TERM_256COLOURS
133 /* Terminal supports overline. */
134 static const char *const tty_feature_overline_capabilities[] = {
135 "Smol=\\E[53m",
136 NULL
138 static const struct tty_feature tty_feature_overline = {
139 "overline",
140 tty_feature_overline_capabilities,
144 /* Terminal supports underscore styles. */
145 static const char *const tty_feature_usstyle_capabilities[] = {
146 "Smulx=\\E[4::%p1%dm",
147 "Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
148 "Setulc1=\\E[58::5::%p1%dm",
149 "ol=\\E[59m",
150 NULL
152 static const struct tty_feature tty_feature_usstyle = {
153 "usstyle",
154 tty_feature_usstyle_capabilities,
158 /* Terminal supports bracketed paste. */
159 static const char *const tty_feature_bpaste_capabilities[] = {
160 "Enbp=\\E[?2004h",
161 "Dsbp=\\E[?2004l",
162 NULL
164 static const struct tty_feature tty_feature_bpaste = {
165 "bpaste",
166 tty_feature_bpaste_capabilities,
170 /* Terminal supports focus reporting. */
171 static const char *const tty_feature_focus_capabilities[] = {
172 "Enfcs=\\E[?1004h",
173 "Dsfcs=\\E[?1004l",
174 NULL
176 static const struct tty_feature tty_feature_focus = {
177 "focus",
178 tty_feature_focus_capabilities,
182 /* Terminal supports cursor styles. */
183 static const char *const tty_feature_cstyle_capabilities[] = {
184 "Ss=\\E[%p1%d q",
185 "Se=\\E[2 q",
186 NULL
188 static const struct tty_feature tty_feature_cstyle = {
189 "cstyle",
190 tty_feature_cstyle_capabilities,
194 /* Terminal supports cursor colours. */
195 static const char *const tty_feature_ccolour_capabilities[] = {
196 "Cs=\\E]12;%p1%s\\a",
197 "Cr=\\E]112\\a",
198 NULL
200 static const struct tty_feature tty_feature_ccolour = {
201 "ccolour",
202 tty_feature_ccolour_capabilities,
206 /* Terminal supports strikethrough. */
207 static const char *const tty_feature_strikethrough_capabilities[] = {
208 "smxx=\\E[9m",
209 NULL
211 static const struct tty_feature tty_feature_strikethrough = {
212 "strikethrough",
213 tty_feature_strikethrough_capabilities,
217 /* Terminal supports synchronized updates. */
218 static const char *const tty_feature_sync_capabilities[] = {
219 "Sync=\\E[?2026%?%p1%{1}%-%tl%eh%;",
220 NULL
222 static const struct tty_feature tty_feature_sync = {
223 "sync",
224 tty_feature_sync_capabilities,
228 /* Terminal supports extended keys. */
229 static const char *const tty_feature_extkeys_capabilities[] = {
230 "Eneks=\\E[>4;1m",
231 "Dseks=\\E[>4m",
232 NULL
234 static const struct tty_feature tty_feature_extkeys = {
235 "extkeys",
236 tty_feature_extkeys_capabilities,
240 /* Terminal supports DECSLRM margins. */
241 static const char *const tty_feature_margins_capabilities[] = {
242 "Enmg=\\E[?69h",
243 "Dsmg=\\E[?69l",
244 "Clmg=\\E[s",
245 "Cmg=\\E[%i%p1%d;%p2%ds",
246 NULL
248 static const struct tty_feature tty_feature_margins = {
249 "margins",
250 tty_feature_margins_capabilities,
251 TERM_DECSLRM
254 /* Terminal supports DECFRA rectangle fill. */
255 static const char *const tty_feature_rectfill_capabilities[] = {
256 "Rect",
257 NULL
259 static const struct tty_feature tty_feature_rectfill = {
260 "rectfill",
261 tty_feature_rectfill_capabilities,
262 TERM_DECFRA
265 /* Use builtin function keys only. */
266 static const char *const tty_feature_ignorefkeys_capabilities[] = {
267 "kf0@",
268 "kf1@",
269 "kf2@",
270 "kf3@",
271 "kf4@",
272 "kf5@",
273 "kf6@",
274 "kf7@",
275 "kf8@",
276 "kf9@",
277 "kf10@",
278 "kf11@",
279 "kf12@",
280 "kf13@",
281 "kf14@",
282 "kf15@",
283 "kf16@",
284 "kf17@",
285 "kf18@",
286 "kf19@",
287 "kf20@",
288 "kf21@",
289 "kf22@",
290 "kf23@",
291 "kf24@",
292 "kf25@",
293 "kf26@",
294 "kf27@",
295 "kf28@",
296 "kf29@",
297 "kf30@",
298 "kf31@",
299 "kf32@",
300 "kf33@",
301 "kf34@",
302 "kf35@",
303 "kf36@",
304 "kf37@",
305 "kf38@",
306 "kf39@",
307 "kf40@",
308 "kf41@",
309 "kf42@",
310 "kf43@",
311 "kf44@",
312 "kf45@",
313 "kf46@",
314 "kf47@",
315 "kf48@",
316 "kf49@",
317 "kf50@",
318 "kf51@",
319 "kf52@",
320 "kf53@",
321 "kf54@",
322 "kf55@",
323 "kf56@",
324 "kf57@",
325 "kf58@",
326 "kf59@",
327 "kf60@",
328 "kf61@",
329 "kf62@",
330 "kf63@",
331 NULL
333 static const struct tty_feature tty_feature_ignorefkeys = {
334 "ignorefkeys",
335 tty_feature_ignorefkeys_capabilities,
339 /* Terminal has sixel capability. */
340 static const char *const tty_feature_sixel_capabilities[] = {
341 "Sxl",
342 NULL
344 static const struct tty_feature tty_feature_sixel = {
345 "sixel",
346 tty_feature_sixel_capabilities,
347 TERM_SIXEL
350 /* Available terminal features. */
351 static const struct tty_feature *const tty_features[] = {
352 &tty_feature_256,
353 &tty_feature_bpaste,
354 &tty_feature_ccolour,
355 &tty_feature_clipboard,
356 &tty_feature_hyperlinks,
357 &tty_feature_cstyle,
358 &tty_feature_extkeys,
359 &tty_feature_focus,
360 &tty_feature_ignorefkeys,
361 &tty_feature_margins,
362 &tty_feature_mouse,
363 &tty_feature_osc7,
364 &tty_feature_overline,
365 &tty_feature_rectfill,
366 &tty_feature_rgb,
367 &tty_feature_sixel,
368 &tty_feature_strikethrough,
369 &tty_feature_sync,
370 &tty_feature_title,
371 &tty_feature_usstyle
374 void
375 tty_add_features(int *feat, const char *s, const char *separators)
377 const struct tty_feature *tf;
378 char *next, *loop, *copy;
379 u_int i;
381 log_debug("adding terminal features %s", s);
383 loop = copy = xstrdup(s);
384 while ((next = strsep(&loop, separators)) != NULL) {
385 for (i = 0; i < nitems(tty_features); i++) {
386 tf = tty_features[i];
387 if (strcasecmp(tf->name, next) == 0)
388 break;
390 if (i == nitems(tty_features)) {
391 log_debug("unknown terminal feature: %s", next);
392 break;
394 if (~(*feat) & (1 << i)) {
395 log_debug("adding terminal feature: %s", tf->name);
396 (*feat) |= (1 << i);
399 free(copy);
402 const char *
403 tty_get_features(int feat)
405 const struct tty_feature *tf;
406 static char s[512];
407 u_int i;
409 *s = '\0';
410 for (i = 0; i < nitems(tty_features); i++) {
411 if (~feat & (1 << i))
412 continue;
413 tf = tty_features[i];
415 strlcat(s, tf->name, sizeof s);
416 strlcat(s, ",", sizeof s);
418 if (*s != '\0')
419 s[strlen(s) - 1] = '\0';
420 return (s);
424 tty_apply_features(struct tty_term *term, int feat)
426 const struct tty_feature *tf;
427 const char *const *capability;
428 u_int i;
430 if (feat == 0)
431 return (0);
432 log_debug("applying terminal features: %s", tty_get_features(feat));
434 for (i = 0; i < nitems(tty_features); i++) {
435 if ((term->features & (1 << i)) || (~feat & (1 << i)))
436 continue;
437 tf = tty_features[i];
439 log_debug("applying terminal feature: %s", tf->name);
440 if (tf->capabilities != NULL) {
441 capability = tf->capabilities;
442 while (*capability != NULL) {
443 log_debug("adding capability: %s", *capability);
444 tty_term_apply(term, *capability, 1);
445 capability++;
448 term->flags |= tf->flags;
450 if ((term->features | feat) == term->features)
451 return (0);
452 term->features |= feat;
453 return (1);
456 void
457 tty_default_features(int *feat, const char *name, u_int version)
459 static const struct {
460 const char *name;
461 u_int version;
462 const char *features;
463 } table[] = {
464 #define TTY_FEATURES_BASE_MODERN_XTERM \
465 "256,RGB,bpaste,clipboard,mouse,strikethrough,title"
466 { .name = "mintty",
467 .features = TTY_FEATURES_BASE_MODERN_XTERM
468 ",ccolour,cstyle,extkeys,margins,overline,usstyle"
470 { .name = "tmux",
471 .features = TTY_FEATURES_BASE_MODERN_XTERM
472 ",ccolour,cstyle,focus,overline,usstyle,hyperlinks"
474 { .name = "rxvt-unicode",
475 .features = "256,bpaste,ccolour,cstyle,mouse,title,ignorefkeys"
477 { .name = "iTerm2",
478 .features = TTY_FEATURES_BASE_MODERN_XTERM
479 ",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
481 { .name = "XTerm",
483 * xterm also supports DECSLRM and DECFRA, but they can be
484 * disabled so not set it here - they will be added if
485 * secondary DA shows VT420.
487 .features = TTY_FEATURES_BASE_MODERN_XTERM
488 ",ccolour,cstyle,extkeys,focus"
491 u_int i;
493 for (i = 0; i < nitems(table); i++) {
494 if (strcmp(table[i].name, name) != 0)
495 continue;
496 if (version != 0 && version < table[i].version)
497 continue;
498 tty_add_features(feat, table[i].features, ",");