mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-10 01:29:05 -04:00
op/fgop/bgop into escape block #1525
This commit is contained in:
parent
6767a36996
commit
1207765cc8
@ -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){
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user