[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.14

1.14    ! nicm        1: /* $OpenBSD: tty-features.c,v 1.13 2020/05/16 14:46:14 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[] = {
                    113:        "Smulx=\E[4::%p1%dm",
                    114:        "Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
                    115:        NULL
                    116: };
1.12      nicm      117: static const struct tty_feature tty_feature_usstyle = {
1.1       nicm      118:        "usstyle",
                    119:        tty_feature_usstyle_capabilities,
                    120:        0
                    121: };
                    122:
1.12      nicm      123: /* Terminal supports bracketed paste. */
1.11      nicm      124: static const char *tty_feature_bpaste_capabilities[] = {
1.12      nicm      125:        "Enbp=\\E[?2004h",
1.11      nicm      126:        "Dsbp=\\E[?2004l",
                    127:        NULL
                    128: };
1.12      nicm      129: static const struct tty_feature tty_feature_bpaste = {
1.11      nicm      130:        "bpaste",
                    131:        tty_feature_bpaste_capabilities,
                    132:        0
                    133: };
                    134:
1.12      nicm      135: /* Terminal supports focus reporting. */
                    136: static const char *tty_feature_focus_capabilities[] = {
                    137:        "Enfcs=\\E[?1004h",
                    138:        "Dsfcs=\\E[?1004l",
                    139:        NULL
                    140: };
                    141: static const struct tty_feature tty_feature_focus = {
                    142:        "focus",
                    143:        tty_feature_focus_capabilities,
                    144:        0
                    145: };
                    146:
1.1       nicm      147: /* Terminal supports cursor styles. */
                    148: static const char *tty_feature_cstyle_capabilities[] = {
                    149:        "Ss=\\E[%p1%d q",
                    150:        "Se=\\E[2 q",
                    151:        NULL
                    152: };
1.12      nicm      153: static const struct tty_feature tty_feature_cstyle = {
1.1       nicm      154:        "cstyle",
                    155:        tty_feature_cstyle_capabilities,
                    156:        0
                    157: };
                    158:
                    159: /* Terminal supports cursor colours. */
                    160: static const char *tty_feature_ccolour_capabilities[] = {
                    161:        "Cs=\\E]12;%p1%s\\a",
                    162:        "Cr=\\E]112\\a",
                    163:        NULL
                    164: };
1.12      nicm      165: static const struct tty_feature tty_feature_ccolour = {
1.1       nicm      166:        "ccolour",
                    167:        tty_feature_ccolour_capabilities,
                    168:        0
                    169: };
                    170:
1.10      nicm      171: /* Terminal supports strikethrough. */
                    172: static const char *tty_feature_strikethrough_capabilities[] = {
                    173:        "smxx=\\E[9m",
                    174:        NULL
                    175: };
1.12      nicm      176: static const struct tty_feature tty_feature_strikethrough = {
1.10      nicm      177:        "strikethrough",
                    178:        tty_feature_strikethrough_capabilities,
                    179:        0
                    180: };
                    181:
1.1       nicm      182: /* Terminal supports synchronized updates. */
                    183: static const char *tty_feature_sync_capabilities[] = {
1.2       nicm      184:        "Sync=\\EP=%p1%ds\\E\\\\",
1.1       nicm      185:        NULL
                    186: };
1.12      nicm      187: static const struct tty_feature tty_feature_sync = {
1.1       nicm      188:        "sync",
                    189:        tty_feature_sync_capabilities,
                    190:        0
                    191: };
                    192:
1.14    ! nicm      193: /* Terminal supports extended keys. */
        !           194: static const char *tty_feature_extkeys_capabilities[] = {
        !           195:        "Eneks=\\E[>4;1m",
        !           196:        "Dseks=\\E[>4m",
        !           197:        NULL
        !           198: };
        !           199: static const struct tty_feature tty_feature_extkeys = {
        !           200:        "extkeys",
        !           201:        tty_feature_extkeys_capabilities,
        !           202:        0
        !           203: };
        !           204:
1.1       nicm      205: /* Terminal supports DECSLRM margins. */
1.7       nicm      206: static const char *tty_feature_margins_capabilities[] = {
                    207:        "Enmg=\\E[?69h",
                    208:        "Dsmg=\\E[?69l",
                    209:        "Clmg=\\E[s",
                    210:        "Cmg=\\E[%i%p1%d;%p2%ds",
                    211:        NULL
                    212: };
1.12      nicm      213: static const struct tty_feature tty_feature_margins = {
1.1       nicm      214:        "margins",
1.7       nicm      215:        tty_feature_margins_capabilities,
1.1       nicm      216:        TERM_DECSLRM
                    217: };
                    218:
                    219: /* Terminal supports DECFRA rectangle fill. */
1.12      nicm      220: static const struct tty_feature tty_feature_rectfill = {
1.1       nicm      221:        "rectfill",
                    222:        NULL,
                    223:        TERM_DECFRA
                    224: };
                    225:
                    226: /* Available terminal features. */
                    227: static const struct tty_feature *tty_features[] = {
                    228:        &tty_feature_256,
1.11      nicm      229:        &tty_feature_bpaste,
1.12      nicm      230:        &tty_feature_ccolour,
1.1       nicm      231:        &tty_feature_clipboard,
                    232:        &tty_feature_cstyle,
1.14    ! nicm      233:        &tty_feature_extkeys,
1.12      nicm      234:        &tty_feature_focus,
1.1       nicm      235:        &tty_feature_margins,
                    236:        &tty_feature_overline,
                    237:        &tty_feature_rectfill,
                    238:        &tty_feature_rgb,
1.10      nicm      239:        &tty_feature_strikethrough,
1.1       nicm      240:        &tty_feature_sync,
                    241:        &tty_feature_title,
                    242:        &tty_feature_usstyle
                    243: };
                    244:
                    245: void
                    246: tty_add_features(int *feat, const char *s, const char *separators)
                    247: {
                    248:        const struct tty_feature         *tf;
                    249:        char                             *next, *loop, *copy;
                    250:        u_int                             i;
1.7       nicm      251:
1.9       nicm      252:        log_debug("adding terminal features %s", s);
1.1       nicm      253:
                    254:        loop = copy = xstrdup(s);
                    255:        while ((next = strsep(&loop, separators)) != NULL) {
                    256:                for (i = 0; i < nitems(tty_features); i++) {
                    257:                        tf = tty_features[i];
                    258:                        if (strcasecmp(tf->name, next) == 0)
                    259:                                break;
                    260:                }
                    261:                if (i == nitems(tty_features)) {
                    262:                        log_debug("unknown terminal feature: %s", next);
                    263:                        break;
                    264:                }
                    265:                if (~(*feat) & (1 << i)) {
                    266:                        log_debug("adding terminal feature: %s", tf->name);
                    267:                        (*feat) |= (1 << i);
                    268:                }
                    269:        }
                    270:        free(copy);
                    271: }
                    272:
                    273: const char *
                    274: tty_get_features(int feat)
                    275: {
                    276:        const struct tty_feature        *tf;
                    277:        static char                      s[512];
                    278:        u_int                            i;
                    279:
                    280:        *s = '\0';
                    281:        for (i = 0; i < nitems(tty_features); i++) {
                    282:                if (~feat & (1 << i))
                    283:                        continue;
                    284:                tf = tty_features[i];
                    285:
                    286:                strlcat(s, tf->name, sizeof s);
                    287:                strlcat(s, ",", sizeof s);
                    288:        }
                    289:        if (*s != '\0')
                    290:                s[strlen(s) - 1] = '\0';
                    291:        return (s);
                    292: }
                    293:
1.3       nicm      294: int
1.1       nicm      295: tty_apply_features(struct tty_term *term, int feat)
                    296: {
                    297:        const struct tty_feature         *tf;
                    298:        const char                      **capability;
                    299:        u_int                             i;
                    300:
                    301:        if (feat == 0)
1.3       nicm      302:                return (0);
1.1       nicm      303:        log_debug("applying terminal features: %s", tty_get_features(feat));
                    304:
                    305:        for (i = 0; i < nitems(tty_features); i++) {
                    306:                if ((term->features & (1 << i)) || (~feat & (1 << i)))
                    307:                        continue;
                    308:                tf = tty_features[i];
                    309:
                    310:                log_debug("applying terminal feature: %s", tf->name);
                    311:                if (tf->capabilities != NULL) {
                    312:                        capability = tf->capabilities;
                    313:                        while (*capability != NULL) {
                    314:                                log_debug("adding capability: %s", *capability);
                    315:                                tty_term_apply(term, *capability, 1);
                    316:                                capability++;
                    317:                        }
                    318:                }
                    319:                term->flags |= tf->flags;
                    320:        }
1.3       nicm      321:        if ((term->features | feat) == term->features)
                    322:                return (0);
1.1       nicm      323:        term->features |= feat;
1.3       nicm      324:        return (1);
1.9       nicm      325: }
                    326:
                    327: void
                    328: tty_default_features(int *feat, const char *name, u_int version)
                    329: {
                    330:        static struct {
                    331:                const char      *name;
                    332:                u_int            version;
                    333:                const char      *features;
                    334:        } table[] = {
1.12      nicm      335: #define TTY_FEATURES_BASE_MODERN_XTERM "256,RGB,bpaste,clipboard,strikethrough,title"
1.9       nicm      336:                { .name = "mintty",
1.14    ! nicm      337:                  .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,extkeys,margins,overline"
1.9       nicm      338:                },
                    339:                { .name = "tmux",
1.12      nicm      340:                  .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,focus,overline,usstyle"
1.9       nicm      341:                },
                    342:                { .name = "rxvt-unicode",
1.12      nicm      343:                  .features = "256,bpaste,ccolour,cstyle,title"
1.9       nicm      344:                },
                    345:                { .name = "iTerm2",
1.12      nicm      346:                  .features = TTY_FEATURES_BASE_MODERN_XTERM ",cstyle,margins,sync"
1.9       nicm      347:                },
                    348:                { .name = "XTerm",
1.14    ! nicm      349:                  .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,extkeys,focus,margins,rectfill"
1.9       nicm      350:                }
                    351:        };
                    352:        u_int   i;
                    353:
                    354:        for (i = 0; i < nitems(table); i++) {
                    355:                if (strcmp(table[i].name, name) != 0)
                    356:                        continue;
                    357:                if (version != 0 && version < table[i].version)
                    358:                        continue;
                    359:                tty_add_features(feat, table[i].features, ",");
                    360:        }
1.1       nicm      361: }