Merge branch 'master' of github.com:dankamongmen/notcurses

pull/1867/head
nick black 3 years ago
commit 70b8bba715
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -49,70 +49,6 @@ int ncdirect_putstr(ncdirect* nc, uint64_t channels, const char* utf8){
return fprintf(nc->ttyfp, "%s", utf8); return fprintf(nc->ttyfp, "%s", utf8);
} }
static int
cursor_yx_get(int ttyfd, const char* u7, int* y, int* x){
if(tty_emit(u7, ttyfd)){
return -1;
}
bool done = false;
enum { // what we expect now
CURSOR_ESC, // 27 (0x1b)
CURSOR_LSQUARE,
CURSOR_ROW, // delimited by a semicolon
CURSOR_COLUMN,
CURSOR_R,
} state = CURSOR_ESC;
int row = 0, column = 0;
char in;
while(read(ttyfd, &in, 1) == 1){
bool valid = false;
switch(state){
case CURSOR_ESC: valid = (in == NCKEY_ESC); state = CURSOR_LSQUARE; break;
case CURSOR_LSQUARE: valid = (in == '['); state = CURSOR_ROW; break;
case CURSOR_ROW:
if(isdigit(in)){
row *= 10;
row += in - '0';
valid = true;
}else if(in == ';'){
state = CURSOR_COLUMN;
valid = true;
}
break;
case CURSOR_COLUMN:
if(isdigit(in)){
column *= 10;
column += in - '0';
valid = true;
}else if(in == 'R'){
state = CURSOR_R;
valid = true;
}
break;
case CURSOR_R: default: // logical error, whoops
break;
}
if(!valid){
fprintf(stderr, "Unexpected result from terminal: %d\n", in);
break;
}
if(state == CURSOR_R){
done = true;
break;
}
}
if(!done){
return -1;
}
if(y){
*y = row;
}
if(x){
*x = column;
}
return 0;
}
int ncdirect_cursor_up(ncdirect* nc, int num){ int ncdirect_cursor_up(ncdirect* nc, int num){
if(num < 0){ if(num < 0){
return -1; return -1;
@ -343,22 +279,22 @@ detect_cursor_inversion(ncdirect* n, const char* u7, int rows, int cols, int* y,
// we only changed one, supposedly the number of rows. if we were on the // we only changed one, supposedly the number of rows. if we were on the
// top row before, the reply is inverted. // top row before, the reply is inverted.
if(*y == 0){ if(*y == 0){
n->inverted_cursor = true; n->tcache.inverted_cursor = true;
} }
}else if(*y == newy){ }else if(*y == newy){
// we only changed one, supposedly the number of columns. if we were on the // we only changed one, supposedly the number of columns. if we were on the
// rightmost column before, the reply is inverted. // rightmost column before, the reply is inverted.
if(*x == cols){ if(*x == cols){
n->inverted_cursor = true; n->tcache.inverted_cursor = true;
} }
}else{ }else{
// the row ought have decreased, and the column ought have increased. if it // the row ought have decreased, and the column ought have increased. if it
// went the other way, the reply is inverted. // went the other way, the reply is inverted.
if(newy > *y && newx < *x){ if(newy > *y && newx < *x){
n->inverted_cursor = true; n->tcache.inverted_cursor = true;
} }
} }
n->detected_cursor_inversion = true; n->tcache.detected_cursor_inversion = true;
return 0; return 0;
} }
@ -412,13 +348,13 @@ int ncdirect_cursor_yx(ncdirect* n, int* y, int* x){
if(!x){ if(!x){
x = &xval; x = &xval;
} }
if(!n->detected_cursor_inversion){ if(!n->tcache.detected_cursor_inversion){
ret = detect_cursor_inversion_wrapper(n, u7, y, x); ret = detect_cursor_inversion_wrapper(n, u7, y, x);
}else{ }else{
ret = cursor_yx_get(n->ctermfd, u7, y, x); ret = cursor_yx_get(n->ctermfd, u7, y, x);
} }
if(ret == 0){ if(ret == 0){
if(n->inverted_cursor){ if(n->tcache.inverted_cursor){
int tmp = *y; int tmp = *y;
*y = *x; *y = *x;
*x = tmp; *x = tmp;

@ -406,10 +406,6 @@ typedef struct ncdirect {
tinfo tcache; // terminfo cache tinfo tcache; // terminfo cache
uint64_t channels; // current channels uint64_t channels; // current channels
uint16_t stylemask; // current styles uint16_t stylemask; // current styles
// some terminals (e.g. kmscon) return cursor coordinates inverted from the
// typical order. we detect it the first time ncdirect_cursor_yx() is called.
bool detected_cursor_inversion; // have we performed inversion testing?
bool inverted_cursor; // does the terminal return inverted coordinates?
bool initialized_readline; // have we initialized Readline? bool initialized_readline; // have we initialized Readline?
uint64_t flags; // copied in ncdirect_init() from param uint64_t flags; // copied in ncdirect_init() from param
} ncdirect; } ncdirect;

@ -887,11 +887,9 @@ init_banner_warnings(const notcurses* nc, FILE* out){
// returns the number of lines printed. // returns the number of lines printed.
static int static int
init_banner(const notcurses* nc){ init_banner(const notcurses* nc){
int liness = 0;
if(!nc->suppress_banner){ if(!nc->suppress_banner){
char prefixbuf[BPREFIXSTRLEN + 1]; char prefixbuf[BPREFIXSTRLEN + 1];
term_fg_palindex(nc, stdout, 50 % nc->tcache.caps.colors); term_fg_palindex(nc, stdout, 50 % nc->tcache.caps.colors);
++liness;
fprintf(nc->ttyfp, "notcurses %s on %s %s\n", notcurses_version(), fprintf(nc->ttyfp, "notcurses %s on %s %s\n", notcurses_version(),
nc->tcache.termname ? nc->tcache.termname : "?", nc->tcache.termname ? nc->tcache.termname : "?",
nc->tcache.termversion ? nc->tcache.termversion : ""); nc->tcache.termversion ? nc->tcache.termversion : "");
@ -911,7 +909,6 @@ init_banner(const notcurses* nc){
sizeof(struct crender), nc->tcache.caps.colors); sizeof(struct crender), nc->tcache.caps.colors);
} }
const char* setaf; const char* setaf;
liness += 3;
if(nc->tcache.caps.rgb && (setaf = get_escape(&nc->tcache, ESCAPE_SETAF))){ if(nc->tcache.caps.rgb && (setaf = get_escape(&nc->tcache, ESCAPE_SETAF))){
ncfputc('+', nc->ttyfp); ncfputc('+', nc->ttyfp);
term_fg_rgb8(&nc->tcache, stdout, 0xe0, 0x60, 0x60); term_fg_rgb8(&nc->tcache, stdout, 0xe0, 0x60, 0x60);
@ -938,17 +935,14 @@ init_banner(const notcurses* nc){
#endif #endif
, curses_version()); , curses_version());
ncvisual_printbanner(nc); ncvisual_printbanner(nc);
++liness; init_banner_warnings(nc, nc->ttyfp);
// don't go sending these to stderr; it would fuck up our line count, for
// one, and we don't know if we can meaningfully send escapes there.
liness += init_banner_warnings(nc, nc->ttyfp);
const char* esc; const char* esc;
if( (esc = get_escape(&nc->tcache, ESCAPE_SGR0)) || if( (esc = get_escape(&nc->tcache, ESCAPE_SGR0)) ||
(esc = get_escape(&nc->tcache, ESCAPE_OP))){ (esc = get_escape(&nc->tcache, ESCAPE_OP))){
term_emit(esc, nc->ttyfp, false); term_emit(esc, nc->ttyfp, false);
} }
} }
return liness; return 0;
} }
// it's critical that we're using UTF-8 encoding if at all possible. since the // it's critical that we're using UTF-8 encoding if at all possible. since the
@ -1160,15 +1154,15 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
goto err; goto err;
} }
ret->rstate.x = ret->rstate.y = -1; ret->rstate.x = ret->rstate.y = -1;
int bannerlines = init_banner(ret); init_banner(ret);
if(ncflush(ret->ttyfp)){ if(ncflush(ret->ttyfp)){
free_plane(ret->stdplane); free_plane(ret->stdplane);
goto err; goto err;
} }
if(cursor_y >= 0 && cursor_x >= 0){ if(cursor_y >= 0 && cursor_x >= 0){
cursor_y += bannerlines; if(!ret->suppress_banner && locate_cursor_early(ret, &cursor_y, &cursor_x)){
if(cursor_y >= ncplane_dim_y(ret->stdplane)){ free_plane(ret->stdplane);
cursor_y = ncplane_dim_y(ret->stdplane) - 1; goto err;
} }
ncplane_cursor_move_yx(ret->stdplane, cursor_y, cursor_x); ncplane_cursor_move_yx(ret->stdplane, cursor_y, cursor_x);
} }

@ -881,7 +881,7 @@ static int
rasterize_scrolls(ncpile* p, FILE* out){ rasterize_scrolls(ncpile* p, FILE* out){
//fprintf(stderr, "%d tardies to work off, by far the most in the class\n", p->scrolls); //fprintf(stderr, "%d tardies to work off, by far the most in the class\n", p->scrolls);
while(p->scrolls){ while(p->scrolls){
if(fprintf(out, "\n") < 0){ if(fprintf(out, "\v") < 0){
return -1; return -1;
} }
--p->scrolls; --p->scrolls;

@ -726,3 +726,86 @@ char* termdesc_longterm(const tinfo* ti){
} }
return ret; return ret;
} }
int cursor_yx_get(int ttyfd, const char* u7, int* y, int* x){
if(tty_emit(u7, ttyfd)){
return -1;
}
bool done = false;
enum { // what we expect now
CURSOR_ESC, // 27 (0x1b)
CURSOR_LSQUARE,
CURSOR_ROW, // delimited by a semicolon
CURSOR_COLUMN,
CURSOR_R,
} state = CURSOR_ESC;
int row = 0, column = 0;
int r;
char in;
do{
while((r = read(ttyfd, &in, 1)) == 1){
bool valid = false;
switch(state){
case CURSOR_ESC: valid = (in == NCKEY_ESC); state = CURSOR_LSQUARE; break;
case CURSOR_LSQUARE: valid = (in == '['); state = CURSOR_ROW; break;
case CURSOR_ROW:
if(isdigit(in)){
row *= 10;
row += in - '0';
valid = true;
}else if(in == ';'){
state = CURSOR_COLUMN;
valid = true;
}
break;
case CURSOR_COLUMN:
if(isdigit(in)){
column *= 10;
column += in - '0';
valid = true;
}else if(in == 'R'){
state = CURSOR_R;
valid = true;
}
break;
case CURSOR_R: default: // logical error, whoops
break;
}
if(!valid){
fprintf(stderr, "Unexpected result from terminal: %d\n", in);
break;
}
if(state == CURSOR_R){
done = true;
break;
}
}
}while(!done && (r == 1 || (errno == EINTR || errno == EAGAIN || errno == EBUSY)));
if(!done){
return -1;
}
if(y){
*y = row;
}
if(x){
*x = column;
}
return 0;
}
int locate_cursor_early(struct notcurses* nc, int* cursor_y, int* cursor_x){
const char* u7 = get_escape(&nc->tcache, ESCAPE_DSRCPR);
// FIXME ought check for cursor inversion!
int ret = cursor_yx_get(nc->ttyfd, u7, cursor_y, cursor_x);
if(ret == 0){
if(nc->tcache.inverted_cursor){
int tmp = *cursor_y;
*cursor_y = *cursor_x;
*cursor_x = tmp;
}
// we use 0-based coordinates, but known terminals use 1-based coordinates
--*cursor_y;
--*cursor_x;
}
return ret;
}

@ -161,6 +161,11 @@ typedef struct tinfo {
int default_cols; // COLUMNS environment var / cols terminfo / 80 int default_cols; // COLUMNS environment var / cols terminfo / 80
int linux_fb_fd; // linux framebuffer device fd int linux_fb_fd; // linux framebuffer device fd
// some terminals (e.g. kmscon) return cursor coordinates inverted from the
// typical order. we detect it the first time ncdirect_cursor_yx() is called.
bool detected_cursor_inversion; // have we performed inversion testing?
bool inverted_cursor; // does the terminal return inverted coordinates?
} tinfo; } tinfo;
// retrieve the terminfo(5)-style escape 'e' from tdesc (NULL if undefined). // retrieve the terminfo(5)-style escape 'e' from tdesc (NULL if undefined).
@ -194,6 +199,12 @@ void free_terminfo_cache(tinfo* ti);
// return a heap-allocated copy of termname + termversion // return a heap-allocated copy of termname + termversion
char* termdesc_longterm(const tinfo* ti); char* termdesc_longterm(const tinfo* ti);
// get the cursor location early (after interrogate_terminfo(), but before
// handing control back to the user). blocking call. FIXME this should go away
// once we have proper input handling that separates out control sequences.
int locate_cursor_early(struct notcurses* nc, int* cursor_y, int* cursor_x);
int cursor_yx_get(int ttyfd, const char* u7, int* y, int* x);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

Loading…
Cancel
Save