xref: /openbsd-src/usr.bin/tmux/tty-features.c (revision a65ab485132062e96ebf64b5454dea20deeb9c2d)
1*a65ab485Snicm /* $OpenBSD: tty-features.c,v 1.32 2024/11/28 08:49:14 nicm Exp $ */
25a160f88Snicm 
35a160f88Snicm /*
45a160f88Snicm  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
55a160f88Snicm  *
65a160f88Snicm  * Permission to use, copy, modify, and distribute this software for any
75a160f88Snicm  * purpose with or without fee is hereby granted, provided that the above
85a160f88Snicm  * copyright notice and this permission notice appear in all copies.
95a160f88Snicm  *
105a160f88Snicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115a160f88Snicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125a160f88Snicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135a160f88Snicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145a160f88Snicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
155a160f88Snicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
165a160f88Snicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175a160f88Snicm  */
185a160f88Snicm 
195a160f88Snicm #include <sys/types.h>
205a160f88Snicm 
215a160f88Snicm #include <stdlib.h>
225a160f88Snicm #include <string.h>
235a160f88Snicm 
245a160f88Snicm #include "tmux.h"
255a160f88Snicm 
265a160f88Snicm /*
275a160f88Snicm  * Still hardcoded:
285a160f88Snicm  * - default colours (under AX or op capabilities);
295a160f88Snicm  * - AIX colours (under colors >= 16);
309884925cSnicm  * - alternate escape (if terminal is VT100-like).
315a160f88Snicm  *
325a160f88Snicm  * Also:
336763df04Snicm  * - DECFRA uses a flag instead of capabilities;
345a160f88Snicm  * - UTF-8 is a separate flag on the client; needed for unattached clients.
355a160f88Snicm  */
365a160f88Snicm 
375a160f88Snicm /* A named terminal feature. */
385a160f88Snicm struct tty_feature {
395a160f88Snicm 	const char		*name;
40ac937780Snicm 	const char *const	*capabilities;
415a160f88Snicm 	int			 flags;
425a160f88Snicm };
435a160f88Snicm 
445a160f88Snicm /* Terminal has xterm(1) title setting. */
45ac937780Snicm static const char *const tty_feature_title_capabilities[] = {
465a160f88Snicm 	"tsl=\\E]0;", /* should be using TS really */
475a160f88Snicm 	"fsl=\\a",
485a160f88Snicm 	NULL
495a160f88Snicm };
50ed2e005dSnicm static const struct tty_feature tty_feature_title = {
515a160f88Snicm 	"title",
525a160f88Snicm 	tty_feature_title_capabilities,
535a160f88Snicm 	0
545a160f88Snicm };
555a160f88Snicm 
56989dfa67Snicm /* Terminal has OSC 7 working directory. */
57ac937780Snicm static const char *const tty_feature_osc7_capabilities[] = {
58989dfa67Snicm 	"Swd=\\E]7;",
59989dfa67Snicm 	"fsl=\\a",
60989dfa67Snicm 	NULL
61989dfa67Snicm };
62989dfa67Snicm static const struct tty_feature tty_feature_osc7 = {
63989dfa67Snicm 	"osc7",
64989dfa67Snicm 	tty_feature_osc7_capabilities,
65989dfa67Snicm 	0
66989dfa67Snicm };
67989dfa67Snicm 
683893e820Snicm /* Terminal has mouse support. */
69ac937780Snicm static const char *const tty_feature_mouse_capabilities[] = {
703893e820Snicm 	"kmous=\\E[M",
713893e820Snicm 	NULL
723893e820Snicm };
733893e820Snicm static const struct tty_feature tty_feature_mouse = {
743893e820Snicm 	"mouse",
753893e820Snicm 	tty_feature_mouse_capabilities,
763893e820Snicm 	0
773893e820Snicm };
783893e820Snicm 
795a160f88Snicm /* Terminal can set the clipboard with OSC 52. */
80ac937780Snicm static const char *const tty_feature_clipboard_capabilities[] = {
815a160f88Snicm 	"Ms=\\E]52;%p1%s;%p2%s\\a",
825a160f88Snicm 	NULL
835a160f88Snicm };
84ed2e005dSnicm static const struct tty_feature tty_feature_clipboard = {
855a160f88Snicm 	"clipboard",
865a160f88Snicm 	tty_feature_clipboard_capabilities,
875a160f88Snicm 	0
885a160f88Snicm };
895a160f88Snicm 
902df6775cSnicm /* Terminal supports OSC 8 hyperlinks. */
91ac937780Snicm static const char *const tty_feature_hyperlinks_capabilities[] = {
922df6775cSnicm 	"*:Hls=\\E]8;%?%p1%l%tid=%p1%s%;;%p2%s\\E\\\\",
932df6775cSnicm 	NULL
942df6775cSnicm };
952df6775cSnicm static const struct tty_feature tty_feature_hyperlinks = {
962df6775cSnicm 	"hyperlinks",
972df6775cSnicm 	tty_feature_hyperlinks_capabilities,
982df6775cSnicm 	0
992df6775cSnicm };
1002df6775cSnicm 
1015a160f88Snicm /*
1025a160f88Snicm  * Terminal supports RGB colour. This replaces setab and setaf also since
1035a160f88Snicm  * terminals with RGB have versions that do not allow setting colours from the
1045a160f88Snicm  * 256 palette.
1055a160f88Snicm  */
106ac937780Snicm static const char *const tty_feature_rgb_capabilities[] = {
107ab658049Snicm 	"AX",
1085a160f88Snicm 	"setrgbf=\\E[38;2;%p1%d;%p2%d;%p3%dm",
1095a160f88Snicm 	"setrgbb=\\E[48;2;%p1%d;%p2%d;%p3%dm",
1105a160f88Snicm 	"setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
1115a160f88Snicm 	"setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
1125a160f88Snicm 	NULL
1135a160f88Snicm };
114ed2e005dSnicm static const struct tty_feature tty_feature_rgb = {
1155a160f88Snicm 	"RGB",
1165a160f88Snicm 	tty_feature_rgb_capabilities,
1176763df04Snicm 	TERM_256COLOURS|TERM_RGBCOLOURS
1185a160f88Snicm };
1195a160f88Snicm 
1205a160f88Snicm /* Terminal supports 256 colours. */
121ac937780Snicm static const char *const tty_feature_256_capabilities[] = {
122ab658049Snicm 	"AX",
1235a160f88Snicm 	"setab=\\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
1245a160f88Snicm 	"setaf=\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
1255a160f88Snicm 	NULL
1265a160f88Snicm };
127ed2e005dSnicm static const struct tty_feature tty_feature_256 = {
1285a160f88Snicm 	"256",
1295a160f88Snicm 	tty_feature_256_capabilities,
1305a160f88Snicm 	TERM_256COLOURS
1315a160f88Snicm };
1325a160f88Snicm 
1335a160f88Snicm /* Terminal supports overline. */
134ac937780Snicm static const char *const tty_feature_overline_capabilities[] = {
1355a160f88Snicm 	"Smol=\\E[53m",
1365a160f88Snicm 	NULL
1375a160f88Snicm };
138ed2e005dSnicm static const struct tty_feature tty_feature_overline = {
1395a160f88Snicm 	"overline",
1405a160f88Snicm 	tty_feature_overline_capabilities,
1415a160f88Snicm 	0
1425a160f88Snicm };
1435a160f88Snicm 
1445a160f88Snicm /* Terminal supports underscore styles. */
145ac937780Snicm static const char *const tty_feature_usstyle_capabilities[] = {
146efa5b6a3Sdaniel 	"Smulx=\\E[4::%p1%dm",
147efa5b6a3Sdaniel 	"Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
1484620f414Snicm 	"Setulc1=\\E[58::5::%p1%dm",
149e9a14db2Snicm 	"ol=\\E[59m",
1505a160f88Snicm 	NULL
1515a160f88Snicm };
152ed2e005dSnicm static const struct tty_feature tty_feature_usstyle = {
1535a160f88Snicm 	"usstyle",
1545a160f88Snicm 	tty_feature_usstyle_capabilities,
1555a160f88Snicm 	0
1565a160f88Snicm };
1575a160f88Snicm 
158ed2e005dSnicm /* Terminal supports bracketed paste. */
159ac937780Snicm static const char *const tty_feature_bpaste_capabilities[] = {
160ed2e005dSnicm 	"Enbp=\\E[?2004h",
16180bd3d52Snicm 	"Dsbp=\\E[?2004l",
16280bd3d52Snicm 	NULL
16380bd3d52Snicm };
164ed2e005dSnicm static const struct tty_feature tty_feature_bpaste = {
16580bd3d52Snicm 	"bpaste",
16680bd3d52Snicm 	tty_feature_bpaste_capabilities,
16780bd3d52Snicm 	0
16880bd3d52Snicm };
16980bd3d52Snicm 
170ed2e005dSnicm /* Terminal supports focus reporting. */
171ac937780Snicm static const char *const tty_feature_focus_capabilities[] = {
172ed2e005dSnicm 	"Enfcs=\\E[?1004h",
173ed2e005dSnicm 	"Dsfcs=\\E[?1004l",
174ed2e005dSnicm 	NULL
175ed2e005dSnicm };
176ed2e005dSnicm static const struct tty_feature tty_feature_focus = {
177ed2e005dSnicm 	"focus",
178ed2e005dSnicm 	tty_feature_focus_capabilities,
179ed2e005dSnicm 	0
180ed2e005dSnicm };
181ed2e005dSnicm 
1825a160f88Snicm /* Terminal supports cursor styles. */
183ac937780Snicm static const char *const tty_feature_cstyle_capabilities[] = {
1845a160f88Snicm 	"Ss=\\E[%p1%d q",
1855a160f88Snicm 	"Se=\\E[2 q",
1865a160f88Snicm 	NULL
1875a160f88Snicm };
188ed2e005dSnicm static const struct tty_feature tty_feature_cstyle = {
1895a160f88Snicm 	"cstyle",
1905a160f88Snicm 	tty_feature_cstyle_capabilities,
1915a160f88Snicm 	0
1925a160f88Snicm };
1935a160f88Snicm 
1945a160f88Snicm /* Terminal supports cursor colours. */
195ac937780Snicm static const char *const tty_feature_ccolour_capabilities[] = {
1965a160f88Snicm 	"Cs=\\E]12;%p1%s\\a",
1975a160f88Snicm 	"Cr=\\E]112\\a",
1985a160f88Snicm 	NULL
1995a160f88Snicm };
200ed2e005dSnicm static const struct tty_feature tty_feature_ccolour = {
2015a160f88Snicm 	"ccolour",
2025a160f88Snicm 	tty_feature_ccolour_capabilities,
2035a160f88Snicm 	0
2045a160f88Snicm };
2055a160f88Snicm 
206dfff4af3Snicm /* Terminal supports strikethrough. */
207ac937780Snicm static const char *const tty_feature_strikethrough_capabilities[] = {
208dfff4af3Snicm 	"smxx=\\E[9m",
209dfff4af3Snicm 	NULL
210dfff4af3Snicm };
211ed2e005dSnicm static const struct tty_feature tty_feature_strikethrough = {
212dfff4af3Snicm 	"strikethrough",
213dfff4af3Snicm 	tty_feature_strikethrough_capabilities,
214dfff4af3Snicm 	0
215dfff4af3Snicm };
216dfff4af3Snicm 
2175a160f88Snicm /* Terminal supports synchronized updates. */
218ac937780Snicm static const char *const tty_feature_sync_capabilities[] = {
219c101cdd2Snicm 	"Sync=\\E[?2026%?%p1%{1}%-%tl%eh%;",
2205a160f88Snicm 	NULL
2215a160f88Snicm };
222ed2e005dSnicm static const struct tty_feature tty_feature_sync = {
2235a160f88Snicm 	"sync",
2245a160f88Snicm 	tty_feature_sync_capabilities,
2255a160f88Snicm 	0
2265a160f88Snicm };
2275a160f88Snicm 
228dcf80b09Snicm /* Terminal supports extended keys. */
229ac937780Snicm static const char *const tty_feature_extkeys_capabilities[] = {
230719f5715Snicm 	"Eneks=\\E[>4;2m",
231dcf80b09Snicm 	"Dseks=\\E[>4m",
232dcf80b09Snicm 	NULL
233dcf80b09Snicm };
234dcf80b09Snicm static const struct tty_feature tty_feature_extkeys = {
235dcf80b09Snicm 	"extkeys",
236dcf80b09Snicm 	tty_feature_extkeys_capabilities,
237dcf80b09Snicm 	0
238dcf80b09Snicm };
239dcf80b09Snicm 
2405a160f88Snicm /* Terminal supports DECSLRM margins. */
241ac937780Snicm static const char *const tty_feature_margins_capabilities[] = {
2426763df04Snicm 	"Enmg=\\E[?69h",
2436763df04Snicm 	"Dsmg=\\E[?69l",
2446763df04Snicm 	"Clmg=\\E[s",
2456763df04Snicm 	"Cmg=\\E[%i%p1%d;%p2%ds",
2466763df04Snicm 	NULL
2476763df04Snicm };
248ed2e005dSnicm static const struct tty_feature tty_feature_margins = {
2495a160f88Snicm 	"margins",
2506763df04Snicm 	tty_feature_margins_capabilities,
2515a160f88Snicm 	TERM_DECSLRM
2525a160f88Snicm };
2535a160f88Snicm 
2545a160f88Snicm /* Terminal supports DECFRA rectangle fill. */
255ac937780Snicm static const char *const tty_feature_rectfill_capabilities[] = {
256dd3a9cf8Snicm 	"Rect",
257dd3a9cf8Snicm 	NULL
258dd3a9cf8Snicm };
259ed2e005dSnicm static const struct tty_feature tty_feature_rectfill = {
2605a160f88Snicm 	"rectfill",
261dd3a9cf8Snicm 	tty_feature_rectfill_capabilities,
2625a160f88Snicm 	TERM_DECFRA
2635a160f88Snicm };
2645a160f88Snicm 
265c620fc9fSnicm /* Use builtin function keys only. */
266ac937780Snicm static const char *const tty_feature_ignorefkeys_capabilities[] = {
267c620fc9fSnicm 	"kf0@",
268c620fc9fSnicm 	"kf1@",
269c620fc9fSnicm 	"kf2@",
270c620fc9fSnicm 	"kf3@",
271c620fc9fSnicm 	"kf4@",
272c620fc9fSnicm 	"kf5@",
273c620fc9fSnicm 	"kf6@",
274c620fc9fSnicm 	"kf7@",
275c620fc9fSnicm 	"kf8@",
276c620fc9fSnicm 	"kf9@",
277c620fc9fSnicm 	"kf10@",
278c620fc9fSnicm 	"kf11@",
279c620fc9fSnicm 	"kf12@",
280c620fc9fSnicm 	"kf13@",
281c620fc9fSnicm 	"kf14@",
282c620fc9fSnicm 	"kf15@",
283c620fc9fSnicm 	"kf16@",
284c620fc9fSnicm 	"kf17@",
285c620fc9fSnicm 	"kf18@",
286c620fc9fSnicm 	"kf19@",
287c620fc9fSnicm 	"kf20@",
288c620fc9fSnicm 	"kf21@",
289c620fc9fSnicm 	"kf22@",
290c620fc9fSnicm 	"kf23@",
291c620fc9fSnicm 	"kf24@",
292c620fc9fSnicm 	"kf25@",
293c620fc9fSnicm 	"kf26@",
294c620fc9fSnicm 	"kf27@",
295c620fc9fSnicm 	"kf28@",
296c620fc9fSnicm 	"kf29@",
297c620fc9fSnicm 	"kf30@",
298c620fc9fSnicm 	"kf31@",
299c620fc9fSnicm 	"kf32@",
300c620fc9fSnicm 	"kf33@",
301c620fc9fSnicm 	"kf34@",
302c620fc9fSnicm 	"kf35@",
303c620fc9fSnicm 	"kf36@",
304c620fc9fSnicm 	"kf37@",
305c620fc9fSnicm 	"kf38@",
306c620fc9fSnicm 	"kf39@",
307c620fc9fSnicm 	"kf40@",
308c620fc9fSnicm 	"kf41@",
309c620fc9fSnicm 	"kf42@",
310c620fc9fSnicm 	"kf43@",
311c620fc9fSnicm 	"kf44@",
312c620fc9fSnicm 	"kf45@",
313c620fc9fSnicm 	"kf46@",
314c620fc9fSnicm 	"kf47@",
315c620fc9fSnicm 	"kf48@",
316c620fc9fSnicm 	"kf49@",
317c620fc9fSnicm 	"kf50@",
318c620fc9fSnicm 	"kf51@",
319c620fc9fSnicm 	"kf52@",
320c620fc9fSnicm 	"kf53@",
321c620fc9fSnicm 	"kf54@",
322c620fc9fSnicm 	"kf55@",
323c620fc9fSnicm 	"kf56@",
324c620fc9fSnicm 	"kf57@",
325c620fc9fSnicm 	"kf58@",
326c620fc9fSnicm 	"kf59@",
327c620fc9fSnicm 	"kf60@",
328c620fc9fSnicm 	"kf61@",
329c620fc9fSnicm 	"kf62@",
330c620fc9fSnicm 	"kf63@",
331c620fc9fSnicm 	NULL
332c620fc9fSnicm };
333c620fc9fSnicm static const struct tty_feature tty_feature_ignorefkeys = {
334c620fc9fSnicm 	"ignorefkeys",
335c620fc9fSnicm 	tty_feature_ignorefkeys_capabilities,
336c620fc9fSnicm 	0
337c620fc9fSnicm };
338c620fc9fSnicm 
339e0697ebcSnicm /* Terminal has sixel capability. */
340e0697ebcSnicm static const char *const tty_feature_sixel_capabilities[] = {
341e0697ebcSnicm 	"Sxl",
342e0697ebcSnicm 	NULL
343e0697ebcSnicm };
344e0697ebcSnicm static const struct tty_feature tty_feature_sixel = {
345e0697ebcSnicm 	"sixel",
346e0697ebcSnicm 	tty_feature_sixel_capabilities,
347f4ec6bcaSnicm 	TERM_SIXEL
348e0697ebcSnicm };
349e0697ebcSnicm 
3505a160f88Snicm /* Available terminal features. */
351ac937780Snicm static const struct tty_feature *const tty_features[] = {
3525a160f88Snicm 	&tty_feature_256,
35380bd3d52Snicm 	&tty_feature_bpaste,
3545a160f88Snicm 	&tty_feature_ccolour,
355ed2e005dSnicm 	&tty_feature_clipboard,
3562df6775cSnicm 	&tty_feature_hyperlinks,
3575a160f88Snicm 	&tty_feature_cstyle,
358dcf80b09Snicm 	&tty_feature_extkeys,
359ed2e005dSnicm 	&tty_feature_focus,
360c620fc9fSnicm 	&tty_feature_ignorefkeys,
3615a160f88Snicm 	&tty_feature_margins,
3623893e820Snicm 	&tty_feature_mouse,
363989dfa67Snicm 	&tty_feature_osc7,
3645a160f88Snicm 	&tty_feature_overline,
3655a160f88Snicm 	&tty_feature_rectfill,
3665a160f88Snicm 	&tty_feature_rgb,
367e0697ebcSnicm 	&tty_feature_sixel,
368dfff4af3Snicm 	&tty_feature_strikethrough,
3695a160f88Snicm 	&tty_feature_sync,
3705a160f88Snicm 	&tty_feature_title,
3715a160f88Snicm 	&tty_feature_usstyle
3725a160f88Snicm };
3735a160f88Snicm 
3745a160f88Snicm void
3755a160f88Snicm tty_add_features(int *feat, const char *s, const char *separators)
3765a160f88Snicm {
3775a160f88Snicm 	const struct tty_feature	 *tf;
3785a160f88Snicm 	char				 *next, *loop, *copy;
3795a160f88Snicm 	u_int				  i;
3805a160f88Snicm 
3818942cc58Snicm 	log_debug("adding terminal features %s", s);
3826763df04Snicm 
3835a160f88Snicm 	loop = copy = xstrdup(s);
3845a160f88Snicm 	while ((next = strsep(&loop, separators)) != NULL) {
3855a160f88Snicm 		for (i = 0; i < nitems(tty_features); i++) {
3865a160f88Snicm 			tf = tty_features[i];
3875a160f88Snicm 			if (strcasecmp(tf->name, next) == 0)
3885a160f88Snicm 				break;
3895a160f88Snicm 		}
3905a160f88Snicm 		if (i == nitems(tty_features)) {
3915a160f88Snicm 			log_debug("unknown terminal feature: %s", next);
3925a160f88Snicm 			break;
3935a160f88Snicm 		}
3945a160f88Snicm 		if (~(*feat) & (1 << i)) {
3955a160f88Snicm 			log_debug("adding terminal feature: %s", tf->name);
3965a160f88Snicm 			(*feat) |= (1 << i);
3975a160f88Snicm 		}
3985a160f88Snicm 	}
3995a160f88Snicm 	free(copy);
4005a160f88Snicm }
4015a160f88Snicm 
4025a160f88Snicm const char *
4035a160f88Snicm tty_get_features(int feat)
4045a160f88Snicm {
4055a160f88Snicm 	const struct tty_feature	*tf;
4065a160f88Snicm 	static char			 s[512];
4075a160f88Snicm 	u_int				 i;
4085a160f88Snicm 
4095a160f88Snicm 	*s = '\0';
4105a160f88Snicm 	for (i = 0; i < nitems(tty_features); i++) {
4115a160f88Snicm 		if (~feat & (1 << i))
4125a160f88Snicm 			continue;
4135a160f88Snicm 		tf = tty_features[i];
4145a160f88Snicm 
4155a160f88Snicm 		strlcat(s, tf->name, sizeof s);
4165a160f88Snicm 		strlcat(s, ",", sizeof s);
4175a160f88Snicm 	}
4185a160f88Snicm 	if (*s != '\0')
4195a160f88Snicm 		s[strlen(s) - 1] = '\0';
4205a160f88Snicm 	return (s);
4215a160f88Snicm }
4225a160f88Snicm 
4239c34abedSnicm int
4245a160f88Snicm tty_apply_features(struct tty_term *term, int feat)
4255a160f88Snicm {
4265a160f88Snicm 	const struct tty_feature	*tf;
427ac937780Snicm 	const char *const		*capability;
4285a160f88Snicm 	u_int				 i;
4295a160f88Snicm 
4305a160f88Snicm 	if (feat == 0)
4319c34abedSnicm 		return (0);
4325a160f88Snicm 	log_debug("applying terminal features: %s", tty_get_features(feat));
4335a160f88Snicm 
4345a160f88Snicm 	for (i = 0; i < nitems(tty_features); i++) {
4355a160f88Snicm 		if ((term->features & (1 << i)) || (~feat & (1 << i)))
4365a160f88Snicm 			continue;
4375a160f88Snicm 		tf = tty_features[i];
4385a160f88Snicm 
4395a160f88Snicm 		log_debug("applying terminal feature: %s", tf->name);
4405a160f88Snicm 		if (tf->capabilities != NULL) {
4415a160f88Snicm 			capability = tf->capabilities;
4425a160f88Snicm 			while (*capability != NULL) {
4435a160f88Snicm 				log_debug("adding capability: %s", *capability);
4445a160f88Snicm 				tty_term_apply(term, *capability, 1);
4455a160f88Snicm 				capability++;
4465a160f88Snicm 			}
4475a160f88Snicm 		}
4485a160f88Snicm 		term->flags |= tf->flags;
4495a160f88Snicm 	}
4509c34abedSnicm 	if ((term->features | feat) == term->features)
4519c34abedSnicm 		return (0);
4525a160f88Snicm 	term->features |= feat;
4539c34abedSnicm 	return (1);
4545a160f88Snicm }
4558942cc58Snicm 
4568942cc58Snicm void
4578942cc58Snicm tty_default_features(int *feat, const char *name, u_int version)
4588942cc58Snicm {
459ac937780Snicm 	static const struct {
4608942cc58Snicm 		const char	*name;
4618942cc58Snicm 		u_int		 version;
4628942cc58Snicm 		const char	*features;
4638942cc58Snicm 	} table[] = {
46425373524Snicm #define TTY_FEATURES_BASE_MODERN_XTERM \
4653893e820Snicm 	"256,RGB,bpaste,clipboard,mouse,strikethrough,title"
4668942cc58Snicm 		{ .name = "mintty",
46725373524Snicm 		  .features = TTY_FEATURES_BASE_MODERN_XTERM
468e9a14db2Snicm 			      ",ccolour,cstyle,extkeys,margins,overline,usstyle"
4698942cc58Snicm 		},
4708942cc58Snicm 		{ .name = "tmux",
47125373524Snicm 		  .features = TTY_FEATURES_BASE_MODERN_XTERM
4722df6775cSnicm 			      ",ccolour,cstyle,focus,overline,usstyle,hyperlinks"
4738942cc58Snicm 		},
4748942cc58Snicm 		{ .name = "rxvt-unicode",
475c620fc9fSnicm 		  .features = "256,bpaste,ccolour,cstyle,mouse,title,ignorefkeys"
4768942cc58Snicm 		},
4778942cc58Snicm 		{ .name = "iTerm2",
47825373524Snicm 		  .features = TTY_FEATURES_BASE_MODERN_XTERM
4792df6775cSnicm 			      ",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
4808942cc58Snicm 		},
481*a65ab485Snicm 		{ .name = "foot",
482*a65ab485Snicm 		  .features = TTY_FEATURES_BASE_MODERN_XTERM
483*a65ab485Snicm 		              ",cstyle,extkeys"
484*a65ab485Snicm 		},
4858942cc58Snicm 		{ .name = "XTerm",
486dd3a9cf8Snicm 		  /*
487dd3a9cf8Snicm 		   * xterm also supports DECSLRM and DECFRA, but they can be
488dd3a9cf8Snicm 		   * disabled so not set it here - they will be added if
489dd3a9cf8Snicm 		   * secondary DA shows VT420.
490dd3a9cf8Snicm 		   */
49125373524Snicm 		  .features = TTY_FEATURES_BASE_MODERN_XTERM
492dd3a9cf8Snicm 			      ",ccolour,cstyle,extkeys,focus"
4938942cc58Snicm 		}
4948942cc58Snicm 	};
4958942cc58Snicm 	u_int	i;
4968942cc58Snicm 
4978942cc58Snicm 	for (i = 0; i < nitems(table); i++) {
4988942cc58Snicm 		if (strcmp(table[i].name, name) != 0)
4998942cc58Snicm 			continue;
5008942cc58Snicm 		if (version != 0 && version < table[i].version)
5018942cc58Snicm 			continue;
5028942cc58Snicm 		tty_add_features(feat, table[i].features, ",");
5038942cc58Snicm 	}
5048942cc58Snicm }
505