[BACK]Return to tty-features.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/tty-features.c, Revision 1.30

1.30    ! nicm        1: /* $OpenBSD: tty-features.c,v 1.29 2023/09/02 09:17:23 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:  * - default colours (under AX or op capabilities);
                     29:  * - AIX colours (under colors >= 16);
1.13      nicm       30:  * - alternate escape (if terminal is VT100-like).
1.1       nicm       31:  *
                     32:  * Also:
1.7       nicm       33:  * - DECFRA uses a flag instead of capabilities;
1.1       nicm       34:  * - UTF-8 is a separate flag on the client; needed for unattached clients.
                     35:  */
                     36:
                     37: /* A named terminal feature. */
                     38: struct tty_feature {
1.26      nicm       39:        const char              *name;
                     40:        const char *const       *capabilities;
                     41:        int                      flags;
1.1       nicm       42: };
                     43:
                     44: /* Terminal has xterm(1) title setting. */
1.26      nicm       45: static const char *const tty_feature_title_capabilities[] = {
1.1       nicm       46:        "tsl=\\E]0;", /* should be using TS really */
                     47:        "fsl=\\a",
                     48:        NULL
                     49: };
1.12      nicm       50: static const struct tty_feature tty_feature_title = {
1.1       nicm       51:        "title",
                     52:        tty_feature_title_capabilities,
                     53:        0
                     54: };
                     55:
1.22      nicm       56: /* Terminal has OSC 7 working directory. */
1.26      nicm       57: static const char *const tty_feature_osc7_capabilities[] = {
1.22      nicm       58:        "Swd=\\E]7;",
                     59:        "fsl=\\a",
                     60:        NULL
                     61: };
                     62: static const struct tty_feature tty_feature_osc7 = {
                     63:        "osc7",
                     64:        tty_feature_osc7_capabilities,
                     65:        0
                     66: };
                     67:
1.20      nicm       68: /* Terminal has mouse support. */
1.26      nicm       69: static const char *const tty_feature_mouse_capabilities[] = {
1.20      nicm       70:        "kmous=\\E[M",
                     71:        NULL
                     72: };
                     73: static const struct tty_feature tty_feature_mouse = {
                     74:        "mouse",
                     75:        tty_feature_mouse_capabilities,
                     76:        0
                     77: };
                     78:
1.1       nicm       79: /* Terminal can set the clipboard with OSC 52. */
1.26      nicm       80: static const char *const tty_feature_clipboard_capabilities[] = {
1.1       nicm       81:        "Ms=\\E]52;%p1%s;%p2%s\\a",
                     82:        NULL
                     83: };
1.12      nicm       84: static const struct tty_feature tty_feature_clipboard = {
1.1       nicm       85:        "clipboard",
                     86:        tty_feature_clipboard_capabilities,
                     87:        0
                     88: };
                     89:
1.25      nicm       90: /* Terminal supports OSC 8 hyperlinks. */
1.26      nicm       91: static const char *const tty_feature_hyperlinks_capabilities[] = {
1.25      nicm       92:        "*:Hls=\\E]8;%?%p1%l%tid=%p1%s%;;%p2%s\\E\\\\",
                     93:        NULL
                     94: };
                     95: static const struct tty_feature tty_feature_hyperlinks = {
                     96:        "hyperlinks",
                     97:        tty_feature_hyperlinks_capabilities,
                     98:        0
                     99: };
                    100:
1.1       nicm      101: /*
                    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.
                    105:  */
1.26      nicm      106: static const char *const tty_feature_rgb_capabilities[] = {
1.4       nicm      107:        "AX",
1.1       nicm      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
                    113: };
1.12      nicm      114: static const struct tty_feature tty_feature_rgb = {
1.1       nicm      115:        "RGB",
                    116:        tty_feature_rgb_capabilities,
1.7       nicm      117:        TERM_256COLOURS|TERM_RGBCOLOURS
1.1       nicm      118: };
                    119:
                    120: /* Terminal supports 256 colours. */
1.26      nicm      121: static const char *const tty_feature_256_capabilities[] = {
1.4       nicm      122:        "AX",
1.1       nicm      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
                    126: };
1.12      nicm      127: static const struct tty_feature tty_feature_256 = {
1.1       nicm      128:        "256",
                    129:        tty_feature_256_capabilities,
                    130:        TERM_256COLOURS
                    131: };
                    132:
                    133: /* Terminal supports overline. */
1.26      nicm      134: static const char *const tty_feature_overline_capabilities[] = {
1.1       nicm      135:        "Smol=\\E[53m",
                    136:        NULL
                    137: };
1.12      nicm      138: static const struct tty_feature tty_feature_overline = {
1.1       nicm      139:        "overline",
                    140:        tty_feature_overline_capabilities,
                    141:        0
                    142: };
                    143:
                    144: /* Terminal supports underscore styles. */
1.26      nicm      145: static const char *const tty_feature_usstyle_capabilities[] = {
1.17      daniel    146:        "Smulx=\\E[4::%p1%dm",
                    147:        "Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
1.29      nicm      148:        "Setulc1=\\E[58::5::%p1%dm",
1.18      nicm      149:        "ol=\\E[59m",
1.1       nicm      150:        NULL
                    151: };
1.12      nicm      152: static const struct tty_feature tty_feature_usstyle = {
1.1       nicm      153:        "usstyle",
                    154:        tty_feature_usstyle_capabilities,
                    155:        0
                    156: };
                    157:
1.12      nicm      158: /* Terminal supports bracketed paste. */
1.26      nicm      159: static const char *const tty_feature_bpaste_capabilities[] = {
1.12      nicm      160:        "Enbp=\\E[?2004h",
1.11      nicm      161:        "Dsbp=\\E[?2004l",
                    162:        NULL
                    163: };
1.12      nicm      164: static const struct tty_feature tty_feature_bpaste = {
1.11      nicm      165:        "bpaste",
                    166:        tty_feature_bpaste_capabilities,
                    167:        0
                    168: };
                    169:
1.12      nicm      170: /* Terminal supports focus reporting. */
1.26      nicm      171: static const char *const tty_feature_focus_capabilities[] = {
1.12      nicm      172:        "Enfcs=\\E[?1004h",
                    173:        "Dsfcs=\\E[?1004l",
                    174:        NULL
                    175: };
                    176: static const struct tty_feature tty_feature_focus = {
                    177:        "focus",
                    178:        tty_feature_focus_capabilities,
                    179:        0
                    180: };
                    181:
1.1       nicm      182: /* Terminal supports cursor styles. */
1.26      nicm      183: static const char *const tty_feature_cstyle_capabilities[] = {
1.1       nicm      184:        "Ss=\\E[%p1%d q",
                    185:        "Se=\\E[2 q",
                    186:        NULL
                    187: };
1.12      nicm      188: static const struct tty_feature tty_feature_cstyle = {
1.1       nicm      189:        "cstyle",
                    190:        tty_feature_cstyle_capabilities,
                    191:        0
                    192: };
                    193:
                    194: /* Terminal supports cursor colours. */
1.26      nicm      195: static const char *const tty_feature_ccolour_capabilities[] = {
1.1       nicm      196:        "Cs=\\E]12;%p1%s\\a",
                    197:        "Cr=\\E]112\\a",
                    198:        NULL
                    199: };
1.12      nicm      200: static const struct tty_feature tty_feature_ccolour = {
1.1       nicm      201:        "ccolour",
                    202:        tty_feature_ccolour_capabilities,
                    203:        0
                    204: };
                    205:
1.10      nicm      206: /* Terminal supports strikethrough. */
1.26      nicm      207: static const char *const tty_feature_strikethrough_capabilities[] = {
1.10      nicm      208:        "smxx=\\E[9m",
                    209:        NULL
                    210: };
1.12      nicm      211: static const struct tty_feature tty_feature_strikethrough = {
1.10      nicm      212:        "strikethrough",
                    213:        tty_feature_strikethrough_capabilities,
                    214:        0
                    215: };
                    216:
1.1       nicm      217: /* Terminal supports synchronized updates. */
1.26      nicm      218: static const char *const tty_feature_sync_capabilities[] = {
1.30    ! nicm      219:        "Sync=\\E[?2026%?%p1%{1}%-%tl%eh%;",
1.1       nicm      220:        NULL
                    221: };
1.12      nicm      222: static const struct tty_feature tty_feature_sync = {
1.1       nicm      223:        "sync",
                    224:        tty_feature_sync_capabilities,
                    225:        0
                    226: };
                    227:
1.14      nicm      228: /* Terminal supports extended keys. */
1.26      nicm      229: static const char *const tty_feature_extkeys_capabilities[] = {
1.14      nicm      230:        "Eneks=\\E[>4;1m",
                    231:        "Dseks=\\E[>4m",
                    232:        NULL
                    233: };
                    234: static const struct tty_feature tty_feature_extkeys = {
                    235:        "extkeys",
                    236:        tty_feature_extkeys_capabilities,
                    237:        0
                    238: };
                    239:
1.1       nicm      240: /* Terminal supports DECSLRM margins. */
1.26      nicm      241: static const char *const tty_feature_margins_capabilities[] = {
1.7       nicm      242:        "Enmg=\\E[?69h",
                    243:        "Dsmg=\\E[?69l",
                    244:        "Clmg=\\E[s",
                    245:        "Cmg=\\E[%i%p1%d;%p2%ds",
                    246:        NULL
                    247: };
1.12      nicm      248: static const struct tty_feature tty_feature_margins = {
1.1       nicm      249:        "margins",
1.7       nicm      250:        tty_feature_margins_capabilities,
1.1       nicm      251:        TERM_DECSLRM
                    252: };
                    253:
                    254: /* Terminal supports DECFRA rectangle fill. */
1.26      nicm      255: static const char *const tty_feature_rectfill_capabilities[] = {
1.19      nicm      256:        "Rect",
                    257:        NULL
                    258: };
1.12      nicm      259: static const struct tty_feature tty_feature_rectfill = {
1.1       nicm      260:        "rectfill",
1.19      nicm      261:        tty_feature_rectfill_capabilities,
1.1       nicm      262:        TERM_DECFRA
                    263: };
                    264:
1.24      nicm      265: /* Use builtin function keys only. */
1.26      nicm      266: static const char *const tty_feature_ignorefkeys_capabilities[] = {
1.24      nicm      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
                    332: };
                    333: static const struct tty_feature tty_feature_ignorefkeys = {
                    334:        "ignorefkeys",
                    335:        tty_feature_ignorefkeys_capabilities,
                    336:        0
                    337: };
                    338:
1.27      nicm      339: /* Terminal has sixel capability. */
                    340: static const char *const tty_feature_sixel_capabilities[] = {
                    341:        "Sxl",
                    342:        NULL
                    343: };
                    344: static const struct tty_feature tty_feature_sixel = {
                    345:        "sixel",
                    346:        tty_feature_sixel_capabilities,
1.28      nicm      347:        TERM_SIXEL
1.27      nicm      348: };
                    349:
1.1       nicm      350: /* Available terminal features. */
1.26      nicm      351: static const struct tty_feature *const tty_features[] = {
1.1       nicm      352:        &tty_feature_256,
1.11      nicm      353:        &tty_feature_bpaste,
1.12      nicm      354:        &tty_feature_ccolour,
1.1       nicm      355:        &tty_feature_clipboard,
1.25      nicm      356:        &tty_feature_hyperlinks,
1.1       nicm      357:        &tty_feature_cstyle,
1.14      nicm      358:        &tty_feature_extkeys,
1.12      nicm      359:        &tty_feature_focus,
1.24      nicm      360:        &tty_feature_ignorefkeys,
1.1       nicm      361:        &tty_feature_margins,
1.20      nicm      362:        &tty_feature_mouse,
1.22      nicm      363:        &tty_feature_osc7,
1.1       nicm      364:        &tty_feature_overline,
                    365:        &tty_feature_rectfill,
                    366:        &tty_feature_rgb,
1.27      nicm      367:        &tty_feature_sixel,
1.10      nicm      368:        &tty_feature_strikethrough,
1.1       nicm      369:        &tty_feature_sync,
                    370:        &tty_feature_title,
                    371:        &tty_feature_usstyle
                    372: };
                    373:
                    374: void
                    375: tty_add_features(int *feat, const char *s, const char *separators)
                    376: {
                    377:        const struct tty_feature         *tf;
                    378:        char                             *next, *loop, *copy;
                    379:        u_int                             i;
1.7       nicm      380:
1.9       nicm      381:        log_debug("adding terminal features %s", s);
1.1       nicm      382:
                    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;
                    389:                }
                    390:                if (i == nitems(tty_features)) {
                    391:                        log_debug("unknown terminal feature: %s", next);
                    392:                        break;
                    393:                }
                    394:                if (~(*feat) & (1 << i)) {
                    395:                        log_debug("adding terminal feature: %s", tf->name);
                    396:                        (*feat) |= (1 << i);
                    397:                }
                    398:        }
                    399:        free(copy);
                    400: }
                    401:
                    402: const char *
                    403: tty_get_features(int feat)
                    404: {
                    405:        const struct tty_feature        *tf;
                    406:        static char                      s[512];
                    407:        u_int                            i;
                    408:
                    409:        *s = '\0';
                    410:        for (i = 0; i < nitems(tty_features); i++) {
                    411:                if (~feat & (1 << i))
                    412:                        continue;
                    413:                tf = tty_features[i];
                    414:
                    415:                strlcat(s, tf->name, sizeof s);
                    416:                strlcat(s, ",", sizeof s);
                    417:        }
                    418:        if (*s != '\0')
                    419:                s[strlen(s) - 1] = '\0';
                    420:        return (s);
                    421: }
                    422:
1.3       nicm      423: int
1.1       nicm      424: tty_apply_features(struct tty_term *term, int feat)
                    425: {
1.26      nicm      426:        const struct tty_feature        *tf;
                    427:        const char *const               *capability;
                    428:        u_int                            i;
1.1       nicm      429:
                    430:        if (feat == 0)
1.3       nicm      431:                return (0);
1.1       nicm      432:        log_debug("applying terminal features: %s", tty_get_features(feat));
                    433:
                    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];
                    438:
                    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++;
                    446:                        }
                    447:                }
                    448:                term->flags |= tf->flags;
                    449:        }
1.3       nicm      450:        if ((term->features | feat) == term->features)
                    451:                return (0);
1.1       nicm      452:        term->features |= feat;
1.3       nicm      453:        return (1);
1.9       nicm      454: }
                    455:
                    456: void
                    457: tty_default_features(int *feat, const char *name, u_int version)
                    458: {
1.26      nicm      459:        static const struct {
1.9       nicm      460:                const char      *name;
                    461:                u_int            version;
                    462:                const char      *features;
                    463:        } table[] = {
1.16      nicm      464: #define TTY_FEATURES_BASE_MODERN_XTERM \
1.20      nicm      465:        "256,RGB,bpaste,clipboard,mouse,strikethrough,title"
1.9       nicm      466:                { .name = "mintty",
1.16      nicm      467:                  .features = TTY_FEATURES_BASE_MODERN_XTERM
1.18      nicm      468:                              ",ccolour,cstyle,extkeys,margins,overline,usstyle"
1.9       nicm      469:                },
                    470:                { .name = "tmux",
1.16      nicm      471:                  .features = TTY_FEATURES_BASE_MODERN_XTERM
1.25      nicm      472:                              ",ccolour,cstyle,focus,overline,usstyle,hyperlinks"
1.9       nicm      473:                },
                    474:                { .name = "rxvt-unicode",
1.24      nicm      475:                  .features = "256,bpaste,ccolour,cstyle,mouse,title,ignorefkeys"
1.9       nicm      476:                },
                    477:                { .name = "iTerm2",
1.16      nicm      478:                  .features = TTY_FEATURES_BASE_MODERN_XTERM
1.25      nicm      479:                              ",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
1.9       nicm      480:                },
                    481:                { .name = "XTerm",
1.19      nicm      482:                  /*
                    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.
                    486:                   */
1.16      nicm      487:                  .features = TTY_FEATURES_BASE_MODERN_XTERM
1.19      nicm      488:                              ",ccolour,cstyle,extkeys,focus"
1.9       nicm      489:                }
                    490:        };
                    491:        u_int   i;
                    492:
                    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, ",");
                    499:        }
1.1       nicm      500: }