From 1207765cc8d881c2de74531dd08da82168ef3875 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 26 May 2021 05:56:45 -0400 Subject: [PATCH] op/fgop/bgop into escape block #1525 --- src/lib/debug.c | 4 +++- src/lib/direct.c | 30 +++++++++++++++--------------- src/lib/internal.h | 2 ++ src/lib/notcurses.c | 17 ++++++++--------- src/lib/render.c | 19 +++++++++++-------- src/lib/termdesc.h | 7 +++---- src/lib/terminfo.c | 27 +++++++++++++++++---------- src/tests/fds.cpp | 2 ++ 8 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/lib/debug.c b/src/lib/debug.c index a412a8262..867acc994 100644 --- a/src/lib/debug.c +++ b/src/lib/debug.c @@ -21,7 +21,9 @@ tinfo_debug_caps(const tinfo* ti, FILE* debugfp, int rows, int cols, fprintf(debugfp, "%ssgr: %c sgr0: %c\n", indent, capyn(ti->sgr), capyn(ti->sgr0)); fprintf(debugfp, "%sop: %c fgop: %c bgop: %c\n", - indent, capyn(ti->op), capyn(ti->fgop), capyn(ti->bgop)); + indent, capyn(get_escape(ti, ESCAPE_OP)), + capyn(get_escape(ti, ESCAPE_FGOP)), + capyn(get_escape(ti, ESCAPE_BGOP))); fprintf(debugfp, "%srows: %u cols: %u rpx: %u cpx: %u (%dx%d)\n", indent, rows, cols, ti->cellpixy, ti->cellpixx, rows * ti->cellpixy, cols * ti->cellpixx); if(!ti->pixel_query_done){ diff --git a/src/lib/direct.c b/src/lib/direct.c index 436a11c2a..51ad6eba6 100644 --- a/src/lib/direct.c +++ b/src/lib/direct.c @@ -702,15 +702,7 @@ ncdirect_stop_minimal(void* vnc){ if(nc->initialized_readline){ rl_deprep_terminal(); } - if(nc->tcache.op && term_emit(nc->tcache.op, nc->ttyfp, true)){ - ret = -1; - } - if(nc->tcache.sgr0 && term_emit(nc->tcache.sgr0, nc->ttyfp, true)){ - ret = -1; - } - if(nc->tcache.oc && term_emit(nc->tcache.oc, nc->ttyfp, true)){ - ret = -1; - } + ret |= reset_term_attributes(&nc->tcache, nc->ttyfp); if(nc->ctermfd >= 0){ if(nc->tcache.pixel_shutdown){ ret |= nc->tcache.pixel_shutdown(nc->ctermfd); @@ -917,11 +909,15 @@ int ncdirect_set_fg_default(ncdirect* nc){ if(ncdirect_fg_default_p(nc)){ return 0; } - if(nc->tcache.fgop){ - if(term_emit(nc->tcache.fgop, nc->ttyfp, false)){ + const char* esc; + if((esc = get_escape(&nc->tcache, ESCAPE_FGOP)) != NULL){ + if(term_emit(esc, nc->ttyfp, false)){ + return -1; + } + }else if((esc = get_escape(&nc->tcache, ESCAPE_OP)) != NULL){ + if(term_emit(esc, nc->ttyfp, false)){ return -1; } - }else if(term_emit(nc->tcache.op, nc->ttyfp, false) == 0){ if(!ncdirect_bg_default_p(nc)){ if(ncdirect_set_bg_rgb(nc, ncchannels_bg_rgb(nc->channels))){ return -1; @@ -936,11 +932,15 @@ int ncdirect_set_bg_default(ncdirect* nc){ if(ncdirect_bg_default_p(nc)){ return 0; } - if(nc->tcache.bgop){ - if(term_emit(nc->tcache.bgop, nc->ttyfp, false)){ + const char* esc; + if((esc = get_escape(&nc->tcache, ESCAPE_BGOP)) != NULL){ + if(term_emit(esc, nc->ttyfp, false)){ + return -1; + } + }else if((esc = get_escape(&nc->tcache, ESCAPE_OP)) != NULL){ + if(term_emit(esc, nc->ttyfp, false)){ return -1; } - }else if(term_emit(nc->tcache.op, nc->ttyfp, false) == 0){ if(!ncdirect_fg_default_p(nc)){ if(ncdirect_set_fg_rgb(nc, ncchannels_fg_rgb(nc->channels))){ return -1; diff --git a/src/lib/internal.h b/src/lib/internal.h index dec996802..9790fd229 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -613,6 +613,8 @@ void init_lang(notcurses* nc); // nc may be NULL, only used for logging int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8, unsigned noaltscreen); +int reset_term_attributes(const tinfo* ti, FILE* fp); + void free_terminfo_cache(tinfo* ti); // perform queries that require writing to the terminal, and reading a diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 4f9e2f8da..5187a9fce 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -36,20 +36,18 @@ void notcurses_version_components(int* major, int* minor, int* patch, int* tweak // reset the current colors, styles, and palette. called on startup (to purge // any preexisting styling) and shutdown (to not affect further programs). -// nc->ttyfd must be valid. -static int -reset_term_attributes(notcurses* nc){ +int reset_term_attributes(const tinfo* ti, FILE* fp){ int ret = 0; - if(nc->tcache.op && tty_emit(nc->tcache.op, nc->ttyfd)){ + const char* esc; + if((esc = get_escape(ti, ESCAPE_OP)) && term_emit(esc, fp, true)){ ret = -1; } - if(nc->tcache.sgr0 && tty_emit(nc->tcache.sgr0, nc->ttyfd)){ + if(ti->sgr0 && term_emit(ti->sgr0, fp, true)){ ret = -1; } - if(nc->tcache.oc && tty_emit(nc->tcache.oc, nc->ttyfd)){ + if(ti->oc && term_emit(ti->oc, fp, true)){ ret = -1; } - ret |= notcurses_mouse_disable(nc); return ret; } @@ -73,7 +71,8 @@ notcurses_stop_minimal(void* vnc){ if(nc->tcache.pixel_shutdown){ ret |= nc->tcache.pixel_shutdown(nc->ttyfd); } - ret |= reset_term_attributes(nc); + ret |= reset_term_attributes(&nc->tcache, nc->ttyfp); + ret |= notcurses_mouse_disable(nc); if(nc->tcache.rmcup && tty_emit(nc->tcache.rmcup, nc->ttyfd)){ ret = -1; } @@ -1081,7 +1080,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){ goto err; } if(ret->ttyfd >= 0){ - reset_term_attributes(ret); + reset_term_attributes(&ret->tcache, ret->ttyfp); if(!(opts->flags & NCOPTION_NO_CLEAR_BITMAPS)){ if(sprite_clear_all(&ret->tcache, ret->ttyfd)){ free_plane(ret->stdplane); diff --git a/src/lib/render.c b/src/lib/render.c index 4466c2967..2e6ac8b89 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -833,16 +833,19 @@ goto_location(notcurses* nc, FILE* out, int y, int x){ // necessary return to default (if one is necessary), and update rstate. static inline int raster_defaults(notcurses* nc, bool fgdef, bool bgdef, FILE* out){ - if(!nc->tcache.op){ // if we don't have op, we don't have fgop/bgop + const char* op = get_escape(&nc->tcache, ESCAPE_OP); + if(op == NULL){ // if we don't have op, we don't have fgop/bgop return 0; } + const char* fgop = get_escape(&nc->tcache, ESCAPE_FGOP); + const char* bgop = get_escape(&nc->tcache, ESCAPE_BGOP); bool mustsetfg = fgdef && !nc->rstate.fgdefelidable; bool mustsetbg = bgdef && !nc->rstate.bgdefelidable; - if(!mustsetfg && !mustsetbg){ // don't need emit anything + if(!mustsetfg && !mustsetbg){ // needn't emit anything ++nc->stats.defaultelisions; return 0; - }else if((mustsetfg && mustsetbg) || !nc->tcache.fgop){ - if(term_emit(nc->tcache.op, out, false)){ + }else if((mustsetfg && mustsetbg) || !fgop || !bgop){ + if(term_emit(op, out, false)){ return -1; } nc->rstate.fgdefelidable = true; @@ -851,15 +854,15 @@ raster_defaults(notcurses* nc, bool fgdef, bool bgdef, FILE* out){ nc->rstate.bgelidable = false; nc->rstate.fgpalelidable = false; nc->rstate.bgpalelidable = false; - }else if(mustsetfg){ - if(term_emit(nc->tcache.fgop, out, false)){ + }else if(mustsetfg){ // if we reach here, we must have fgop + if(term_emit(fgop, out, false)){ return -1; } nc->rstate.fgdefelidable = true; nc->rstate.fgelidable = false; nc->rstate.fgpalelidable = false; - }else{ - if(term_emit(nc->tcache.bgop, out, false)){ + }else{ // mustsetbg and !mustsetfg and bgop != NULL + if(term_emit(bgop, out, false)){ return -1; } nc->rstate.bgdefelidable = true; diff --git a/src/lib/termdesc.h b/src/lib/termdesc.h index 3e192483f..b4b722ec4 100644 --- a/src/lib/termdesc.h +++ b/src/lib/termdesc.h @@ -29,7 +29,9 @@ typedef enum { ESCAPE_VPA, // "vpa" move cursor to absolute vertical position ESCAPE_SETAF, // "setaf" set foreground color ESCAPE_SETAB, // "setab" set background color - ESCAPE_DEFS, // "op" set foreground and background color to defaults + ESCAPE_OP, // "op" set foreground and background color to defaults + ESCAPE_FGOP, // set foreground only to default + ESCAPE_BGOP, // set background only to default ESCAPE_SGR, // "sgr" set graphics rendering (styles) ESCAPE_SGR0, // "sgr0" turn off all styles ESCAPE_CIVIS, // "civis" make the cursor invisiable @@ -45,12 +47,9 @@ typedef enum { typedef struct tinfo { uint16_t escindices[ESCAPE_MAX]; // table of 1-biased indices into esctable char* esctable; // packed table of escape sequences - char* op; // set foreground and background color to default char* sgr; // set many graphics properties at once unsigned colors;// number of colors terminfo reported usable for this screen char* sgr0; // restore default presentation properties - char* fgop; // set foreground to default - char* bgop; // set background to default char* cuu; // move N cells up char* cub; // move N cells left char* cuf; // move N cells right diff --git a/src/lib/terminfo.c b/src/lib/terminfo.c index e1e630821..defe51f9e 100644 --- a/src/lib/terminfo.c +++ b/src/lib/terminfo.c @@ -201,6 +201,7 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, // Not all terminals support setting the fore/background independently { ESCAPE_SETAF, "setaf", }, { ESCAPE_SETAB, "setab", }, + { ESCAPE_OP, "op", }, { ESCAPE_MAX, NULL, }, }; size_t tablelen = 0; @@ -209,8 +210,7 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, char* tstr; if(terminfostr(&tstr, strtdesc->tinfo) == 0){ if(grow_esc_table(ti, tstr, strtdesc->esc, &tablelen, &tableused)){ - free(ti->esctable); - return -1; + goto err; } }else{ ti->escindices[strtdesc->esc] = 0; @@ -218,7 +218,7 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, } if(ti->escindices[ESCAPE_CUP] == 0){ fprintf(stderr, "Required terminfo capability 'cup' not defined\n"); - return -1; + goto err; } // neither of these is supported on e.g. the "linux" virtual console. if(!noaltscreen){ @@ -229,7 +229,7 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, ti->AMflag = tigetflag("am") == 1; if(!ti->AMflag){ fprintf(stderr, "Required terminfo capability 'am' not defined\n"); - return -1; + goto err; } ti->BCEflag = tigetflag("bce") == 1; terminfostr(&ti->civis, "civis"); // cursor invisible @@ -247,7 +247,6 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, terminfostr(&ti->italoff, "ritm"); // end italic mode terminfostr(&ti->sgr, "sgr"); // define video attributes terminfostr(&ti->sgr0, "sgr0"); // turn off all video attributes - terminfostr(&ti->op, "op"); // restore defaults to default pair terminfostr(&ti->oc, "oc"); // restore defaults to all colors terminfostr(&ti->home, "home"); // home the cursor terminfostr(&ti->clearscr, "clear");// clear screen, home cursor @@ -295,23 +294,31 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, if(fd >= 0){ if(tty_emit(tiparm(ti->smkx), fd) < 0){ fprintf(stderr, "Error entering keypad transmit mode\n"); - return -1; + goto err; } } } // if op is defined as ansi 39 + ansi 49, make the split definitions // available. this ought be asserted by extension capability "ax", but // no terminal i've found seems to do so. =[ - if(ti->op && strcmp(ti->op, "\x1b[39;49m") == 0){ - ti->fgop = "\x1b[39m"; - ti->bgop = "\x1b[49m"; + const char* op = get_escape(ti, ESCAPE_OP); + if(op && strcmp(op, "\x1b[39;49m") == 0){ + if(grow_esc_table(ti, "\x1b[39m", ESCAPE_FGOP, &tablelen, &tableused) || + grow_esc_table(ti, "\x1b[49m", ESCAPE_BGOP, &tablelen, &tableused)){ + goto err; + } } pthread_mutex_init(&ti->pixel_query, NULL); ti->pixel_query_done = false; if(apply_term_heuristics(ti, termname, fd)){ - return -1; + pthread_mutex_destroy(&ti->pixel_query); + goto err; } return 0; + +err: + free(ti->esctable); + return -1; } // FIXME need unit tests on this diff --git a/src/tests/fds.cpp b/src/tests/fds.cpp index 9207b1751..e2570b75c 100644 --- a/src/tests/fds.cpp +++ b/src/tests/fds.cpp @@ -133,6 +133,8 @@ TEST_CASE("FdsAndSubprocs" CHECK(0 == notcurses_render(nc_)); } + // assuming the path /dev/nope doesn't exist, cat ought be successfully + // launched (fork() and exec() both succeed), but then immediately fail. SUBCASE("SubprocDestroyCmdFailed") { char * const argv[] = { strdup("/bin/cat"), strdup("/dev/nope"), nullptr, }; bool outofline_cancelled = false;