From 381263e9fe6793e2eb7a183bcab6be4f3e2003b5 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 19 May 2020 07:32:26 -0400 Subject: [PATCH] Unify interrogate_terminfo() #614 --- src/input/input.cpp | 13 ++- src/lib/internal.h | 3 + src/lib/notcurses.c | 208 +++++--------------------------------------- src/lib/terminfo.c | 129 +++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 194 deletions(-) create mode 100644 src/lib/terminfo.c diff --git a/src/input/input.cpp b/src/input/input.cpp index 5a295fab7..06f2ecb17 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -225,8 +225,8 @@ int main(void){ if(!plot){ return EXIT_FAILURE; } - n->set_fg(0); - n->set_bg(0xbb64bb); + n->set_fg_rgb(0x00, 0x00, 0x00); + n->set_bg_rgb(0xbb, 0x64, 0xbb); n->styles_on(CellStyle::Underline); if(n->putstr(0, NCAlign::Center, "mash keys, yo. give that mouse some waggle! ctrl+d exits.") <= 0){ return EXIT_FAILURE; @@ -234,7 +234,7 @@ int main(void){ n->styles_set(CellStyle::None); n->set_bg_default(); if(!nc.render()){ - throw std::runtime_error("error rendering"); + return EXIT_FAILURE; } int y = 2; std::deque cells; @@ -247,7 +247,6 @@ int main(void){ if(r == 0){ // interrupted by signal continue; } - if((r == 'D' || r == 'd') && ni.ctrl){ done = true; tid.join(); @@ -276,13 +275,11 @@ int main(void){ }else{ if(nckey_supppuab_p(r)){ n->set_fg_rgb(250, 64, 128); - if(n->printf("Special: [0x%02x (%02d)] '%s'", - r, r, nckeystr(r)) < 0){ + if(n->printf("Special: [0x%02x (%02d)] '%s'", r, r, nckeystr(r)) < 0){ break; } if(NCKey::IsMouse(r)){ - if(n->printf(-1, NCAlign::Right, " x: %d y: %d", - ni.x, ni.y) < 0){ + if(n->printf(-1, NCAlign::Right, " x: %d y: %d", ni.x, ni.y) < 0){ break; } } diff --git a/src/lib/internal.h b/src/lib/internal.h index 90bfb10bd..ad4b58262 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -320,6 +320,9 @@ typedef struct notcurses { void sigwinch_handler(int signo); +int term_verify_seq(char** gseq, const char* name); +int interrogate_terminfo(tinfo* ti); + // Search the provided multibyte (UTF8) string 's' for the provided unicode // codepoint 'cp'. If found, return the column offset of the EGC in which the // codepoint appears in 'col', and the byte offset as the return value. If not diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 37dd72c03..4f45feabb 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -238,19 +238,6 @@ int update_term_dimensions(int fd, int* rows, int* cols){ return 0; } -static int -term_verify_seq(char** gseq, const char* name){ - char* seq; - if(gseq == NULL){ - gseq = &seq; - } - *gseq = tigetstr(name); - if(*gseq == NULL || *gseq == (char*)-1){ - return -1; - } - return 0; -} - static void free_plane(ncplane* p){ if(p){ @@ -525,141 +512,6 @@ int ncplane_destroy(ncplane* ncp){ return 0; } -static bool -query_rgb(void){ - bool rgb = tigetflag("RGB") == 1; - if(!rgb){ - // RGB terminfo capability being a new thing (as of ncurses 6.1), it's not commonly found in - // terminal entries today. COLORTERM, however, is a de-facto (if imperfect/kludgy) standard way - // of indicating TrueColor support for a terminal. The variable takes one of two case-sensitive - // values: - // - // truecolor - // 24bit - // - // https://gist.github.com/XVilka/8346728#true-color-detection gives some more information about - // the topic - // - const char* cterm = getenv("COLORTERM"); - rgb = cterm && (strcmp(cterm, "truecolor") == 0 || strcmp(cterm, "24bit") == 0); - } - return rgb; -} - -static int -interrogate_terminfo(notcurses* nc, const notcurses_options* opts, int* dimy, int* dimx){ - *dimy = *dimx = 0; - update_term_dimensions(nc->ttyfd, dimy, dimx); - nc->truecols = *dimx; - char* shortname_term = termname(); - char* longname_term = longname(); - if(!opts->suppress_banner){ - fprintf(stderr, "Term: %dx%d %s (%s)\n", *dimx, *dimy, - shortname_term ? shortname_term : "?", - longname_term ? longname_term : "?"); - } - nc->tcache.RGBflag = query_rgb(); - if((nc->tcache.colors = tigetnum("colors")) <= 0){ - if(!opts->suppress_banner){ - fprintf(stderr, "This terminal doesn't appear to support colors\n"); - } - nc->tcache.colors = 1; - nc->tcache.CCCflag = false; - nc->tcache.RGBflag = false; - nc->tcache.initc = NULL; - }else{ - term_verify_seq(&nc->tcache.initc, "initc"); - if(nc->tcache.initc){ - nc->tcache.CCCflag = tigetflag("ccc") == 1; - }else{ - nc->tcache.CCCflag = false; - } - } - term_verify_seq(&nc->tcache.cup, "cup"); - if(nc->tcache.cup == NULL){ - fprintf(stderr, "Required terminfo capability 'cup' not defined\n"); - return -1; - } - nc->tcache.AMflag = tigetflag("am") == 1; - if(!nc->tcache.AMflag){ - fprintf(stderr, "Required terminfo capability 'am' not defined\n"); - return -1; - } - term_verify_seq(&nc->tcache.civis, "civis"); - term_verify_seq(&nc->tcache.cnorm, "cnorm"); - term_verify_seq(&nc->tcache.standout, "smso"); // smso / rmso - term_verify_seq(&nc->tcache.uline, "smul"); - term_verify_seq(&nc->tcache.reverse, "reverse"); - term_verify_seq(&nc->tcache.blink, "blink"); - term_verify_seq(&nc->tcache.dim, "dim"); - term_verify_seq(&nc->tcache.bold, "bold"); - term_verify_seq(&nc->tcache.italics, "sitm"); - term_verify_seq(&nc->tcache.italoff, "ritm"); - term_verify_seq(&nc->tcache.sgr, "sgr"); - term_verify_seq(&nc->tcache.sgr0, "sgr0"); - term_verify_seq(&nc->tcache.op, "op"); - term_verify_seq(&nc->tcache.oc, "oc"); - term_verify_seq(&nc->tcache.home, "home"); - term_verify_seq(&nc->tcache.clearscr, "clear"); - term_verify_seq(&nc->tcache.cleareol, "el"); - term_verify_seq(&nc->tcache.clearbol, "el1"); - term_verify_seq(&nc->tcache.cuf, "cuf"); // n non-destructive spaces - term_verify_seq(&nc->tcache.cub, "cub"); // n non-destructive backspaces - term_verify_seq(&nc->tcache.cuf1, "cuf1"); // non-destructive space - term_verify_seq(&nc->tcache.cub1, "cub1"); // non-destructive backspace - term_verify_seq(&nc->tcache.smkx, "smkx"); // set application mode - if(nc->tcache.smkx){ - if(putp(tiparm(nc->tcache.smkx)) != OK){ - fprintf(stderr, "Error entering application mode\n"); - return -1; - } - } - if(prep_special_keys(nc)){ - return -1; - } - // Some terminals cannot combine certain styles with colors. Don't advertise - // support for the style in that case. - int nocolor_stylemask = tigetnum("ncv"); - if(nocolor_stylemask > 0){ - if(nocolor_stylemask & WA_STANDOUT){ // ncv is composed of terminfo bits, not ours - nc->tcache.standout = NULL; - } - if(nocolor_stylemask & WA_UNDERLINE){ - nc->tcache.uline = NULL; - } - if(nocolor_stylemask & WA_REVERSE){ - nc->tcache.reverse = NULL; - } - if(nocolor_stylemask & WA_BLINK){ - nc->tcache.blink = NULL; - } - if(nocolor_stylemask & WA_DIM){ - nc->tcache.dim = NULL; - } - if(nocolor_stylemask & WA_BOLD){ - nc->tcache.bold = NULL; - } - if(nocolor_stylemask & WA_ITALIC){ - nc->tcache.italics = NULL; - } - } - term_verify_seq(&nc->tcache.getm, "getm"); // get mouse events - // Not all terminals support setting the fore/background independently - term_verify_seq(&nc->tcache.setaf, "setaf"); - term_verify_seq(&nc->tcache.setab, "setab"); - term_verify_seq(&nc->tcache.smkx, "smkx"); - term_verify_seq(&nc->tcache.rmkx, "rmkx"); - // Neither of these is supported on e.g. the "linux" virtual console. - if(!opts->inhibit_alternate_screen){ - term_verify_seq(&nc->tcache.smcup, "smcup"); - term_verify_seq(&nc->tcache.rmcup, "rmcup"); - }else{ - nc->tcache.smcup = nc->tcache.rmcup = NULL; - } - nc->top = nc->stdscr = NULL; - return 0; -} - static int make_nonblocking(FILE* fp){ int fd = fileno(fp); @@ -769,43 +621,9 @@ ncdirect* ncdirect_init(const char* termtype, FILE* outfp){ free(ret); return NULL; } - term_verify_seq(&ret->tcache.standout, "smso"); // smso / rmso - term_verify_seq(&ret->tcache.uline, "smul"); - term_verify_seq(&ret->tcache.reverse, "reverse"); - term_verify_seq(&ret->tcache.blink, "blink"); - term_verify_seq(&ret->tcache.dim, "dim"); - term_verify_seq(&ret->tcache.bold, "bold"); - term_verify_seq(&ret->tcache.italics, "sitm"); - term_verify_seq(&ret->tcache.italoff, "ritm"); - term_verify_seq(&ret->tcache.sgr, "sgr"); - term_verify_seq(&ret->tcache.sgr0, "sgr0"); - term_verify_seq(&ret->tcache.op, "op"); - term_verify_seq(&ret->tcache.oc, "oc"); - term_verify_seq(&ret->tcache.setaf, "setaf"); - term_verify_seq(&ret->tcache.setab, "setab"); - term_verify_seq(&ret->tcache.clear, "clear"); - term_verify_seq(&ret->tcache.cup, "cup"); - term_verify_seq(&ret->tcache.cuu, "cuu"); // move N up - term_verify_seq(&ret->tcache.cuf, "cuf"); // move N right - term_verify_seq(&ret->tcache.cud, "cud"); // move N down - term_verify_seq(&ret->tcache.cub, "cub"); // move N left - term_verify_seq(&ret->tcache.hpa, "hpa"); - term_verify_seq(&ret->tcache.vpa, "vpa"); - term_verify_seq(&ret->tcache.civis, "civis"); - term_verify_seq(&ret->tcache.cnorm, "cnorm"); - ret->tcache.RGBflag = query_rgb(); - if((ret->tcache.colors = tigetnum("colors")) <= 0){ - ret->tcache.colors = 1; - ret->tcache.CCCflag = false; - ret->tcache.RGBflag = false; - ret->tcache.initc = NULL; - }else{ - term_verify_seq(&ret->tcache.initc, "initc"); - if(ret->tcache.initc){ - ret->tcache.CCCflag = tigetflag("ccc") == 1; - }else{ - ret->tcache.CCCflag = false; - } + if(interrogate_terminfo(&ret->tcache)){ + free(ret); + return NULL; } ret->fgdefault = ret->bgdefault = true; ret->fgrgb = ret->bgrgb = 0; @@ -988,9 +806,27 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){ goto err; } int dimy, dimx; - if(interrogate_terminfo(ret, opts, &dimy, &dimx)){ + update_term_dimensions(ret->ttyfd, &dimy, &dimx); + char* shortname_term = termname(); + char* longname_term = longname(); + if(!opts->suppress_banner){ + fprintf(stderr, "Term: %dx%d %s (%s)\n", dimx, dimy, + shortname_term ? shortname_term : "?", + longname_term ? longname_term : "?"); + } + ret->truecols = dimx; + if(interrogate_terminfo(&ret->tcache)){ + goto err; + } + if(prep_special_keys(ret)){ goto err; } + // Neither of these is supported on e.g. the "linux" virtual console. + if(!opts->inhibit_alternate_screen){ + term_verify_seq(&ret->tcache.smcup, "smcup"); + term_verify_seq(&ret->tcache.rmcup, "rmcup"); + } + ret->top = ret->stdscr = NULL; if(ncvisual_init(ffmpeg_log_level(opts->loglevel))){ goto err; } diff --git a/src/lib/terminfo.c b/src/lib/terminfo.c new file mode 100644 index 000000000..fd1d18569 --- /dev/null +++ b/src/lib/terminfo.c @@ -0,0 +1,129 @@ +#include // needed for some definitions, see terminfo(3ncurses) +#include "internal.h" + +static bool +query_rgb(void){ + bool rgb = tigetflag("RGB") == 1; + if(!rgb){ + // RGB terminfo capability being a new thing (as of ncurses 6.1), it's not commonly found in + // terminal entries today. COLORTERM, however, is a de-facto (if imperfect/kludgy) standard way + // of indicating TrueColor support for a terminal. The variable takes one of two case-sensitive + // values: + // + // truecolor + // 24bit + // + // https://gist.github.com/XVilka/8346728#true-color-detection gives some more information about + // the topic + // + const char* cterm = getenv("COLORTERM"); + rgb = cterm && (strcmp(cterm, "truecolor") == 0 || strcmp(cterm, "24bit") == 0); + } + return rgb; +} + +int term_verify_seq(char** gseq, const char* name){ + char* seq; + if(gseq == NULL){ + gseq = &seq; + } + *gseq = tigetstr(name); + if(*gseq == NULL || *gseq == (char*)-1){ + return -1; + } + return 0; +} + +int interrogate_terminfo(tinfo* ti){ + memset(ti, 0, sizeof(*ti)); + ti->RGBflag = query_rgb(); + if((ti->colors = tigetnum("colors")) <= 0){ + ti->colors = 1; + ti->CCCflag = false; + ti->RGBflag = false; + ti->initc = NULL; + }else{ + term_verify_seq(&ti->initc, "initc"); + if(ti->initc){ + ti->CCCflag = tigetflag("ccc") == 1; + }else{ + ti->CCCflag = false; + } + } + term_verify_seq(&ti->cup, "cup"); + if(ti->cup == NULL){ + fprintf(stderr, "Required terminfo capability 'cup' not defined\n"); + return -1; + } + ti->AMflag = tigetflag("am") == 1; + if(!ti->AMflag){ + fprintf(stderr, "Required terminfo capability 'am' not defined\n"); + return -1; + } + term_verify_seq(&ti->civis, "civis"); + term_verify_seq(&ti->cnorm, "cnorm"); + term_verify_seq(&ti->standout, "smso"); // smso / rmso + term_verify_seq(&ti->uline, "smul"); + term_verify_seq(&ti->reverse, "reverse"); + term_verify_seq(&ti->blink, "blink"); + term_verify_seq(&ti->dim, "dim"); + term_verify_seq(&ti->bold, "bold"); + term_verify_seq(&ti->italics, "sitm"); + term_verify_seq(&ti->italoff, "ritm"); + term_verify_seq(&ti->sgr, "sgr"); + term_verify_seq(&ti->sgr0, "sgr0"); + term_verify_seq(&ti->op, "op"); + term_verify_seq(&ti->oc, "oc"); + term_verify_seq(&ti->home, "home"); + term_verify_seq(&ti->clearscr, "clear"); + term_verify_seq(&ti->cleareol, "el"); + term_verify_seq(&ti->clearbol, "el1"); + term_verify_seq(&ti->cuu, "cuu"); // move N up + term_verify_seq(&ti->cud, "cud"); // move N down + term_verify_seq(&ti->hpa, "hpa"); + term_verify_seq(&ti->vpa, "vpa"); + term_verify_seq(&ti->cuf, "cuf"); // n non-destructive spaces + term_verify_seq(&ti->cub, "cub"); // n non-destructive backspaces + term_verify_seq(&ti->cuf1, "cuf1"); // non-destructive space + term_verify_seq(&ti->cub1, "cub1"); // non-destructive backspace + term_verify_seq(&ti->smkx, "smkx"); // set application mode + if(ti->smkx){ + if(putp(tiparm(ti->smkx)) != OK){ + fprintf(stderr, "Error entering application mode\n"); + return -1; + } + } + // Some terminals cannot combine certain styles with colors. Don't advertise + // support for the style in that case. + int nocolor_stylemask = tigetnum("ncv"); + if(nocolor_stylemask > 0){ + if(nocolor_stylemask & WA_STANDOUT){ // ncv is composed of terminfo bits, not ours + ti->standout = NULL; + } + if(nocolor_stylemask & WA_UNDERLINE){ + ti->uline = NULL; + } + if(nocolor_stylemask & WA_REVERSE){ + ti->reverse = NULL; + } + if(nocolor_stylemask & WA_BLINK){ + ti->blink = NULL; + } + if(nocolor_stylemask & WA_DIM){ + ti->dim = NULL; + } + if(nocolor_stylemask & WA_BOLD){ + ti->bold = NULL; + } + if(nocolor_stylemask & WA_ITALIC){ + ti->italics = NULL; + } + } + term_verify_seq(&ti->getm, "getm"); // get mouse events + // Not all terminals support setting the fore/background independently + term_verify_seq(&ti->setaf, "setaf"); + term_verify_seq(&ti->setab, "setab"); + term_verify_seq(&ti->smkx, "smkx"); + term_verify_seq(&ti->rmkx, "rmkx"); + return 0; +}