Skip to content

Commit

Permalink
Robustify detect_cursor_inversion()
Browse files Browse the repository at this point in the history
When we're doing cursor querying, whether for detection
of inversion or just straight up localizing ourselves,
we need to talk to a real terminal, or else there's not
much point. When detecting cursor inversion, we need
move the cursor, *and have it reflected in the terminal
feedback*, which means we need write directly to the
terminal (if one exists). This requires ctermfd over
ttyfp, which we now hardcode. Fixes cursor crap when
redirected away from the terminal dankamongmen#1668.
  • Loading branch information
dankamongmen committed May 17, 2021
1 parent a7fe436 commit a903f32
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 22 deletions.
55 changes: 39 additions & 16 deletions src/lib/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ int ncdirect_cursor_right(ncdirect* nc, int num){
}

// if we're on the last line, we need some scrolling action. rather than
// merely using cud, we emit vertical tabs. this has the peculiar property
// (in all terminals tested) of scrolling when necessary but performing no
// carriage return -- a pure line feed.
// merely using cud (which doesn't reliably scroll), we emit vertical tabs.
// this has the peculiar property (in all terminals tested) of scrolling when
// necessary but performing no carriage return -- a pure line feed.
int ncdirect_cursor_down(ncdirect* nc, int num){
if(num < 0){
return -1;
Expand Down Expand Up @@ -266,17 +266,32 @@ detect_cursor_inversion(ncdirect* n, int rows, int cols, int* y, int* x){
if(cursor_yx_get(n->ctermfd, y, x)){
return -1;
}
// do not use normal ncdirect_cursor_*() commands, because those go to ttyfp
// instead of ctermfd. since we always talk directly to the terminal, we need
// to move the cursor directly via the terminal.
if(!n->tcache.cud || !n->tcache.cub || !n->tcache.cuf || !n->tcache.cuu){
return -1;
}
int movex;
int movey;
if(*x == cols && *y == 1){
if(ncdirect_cursor_down(n, 1) || ncdirect_cursor_left(n, 1)){
if(tty_emit(tiparm(n->tcache.cud, 1), n->ctermfd)){
return -1;
}
if(tty_emit(tiparm(n->tcache.cub, 1), n->ctermfd)){
return -1;
}
movex = 1;
movey = -1;
}else{
if(ncdirect_cursor_right(n, 1) || ncdirect_cursor_up(n, 1)){
if(tty_emit(tiparm(n->tcache.cuu, 1), n->ctermfd)){
return -1;
}
}
if(ncdirect_flush(n)){
return -1;
if(tty_emit(tiparm(n->tcache.cuf, 1), n->ctermfd)){
return -1;
}
movex = -1;
movey = 1;
}
int newy, newx;
if(cursor_yx_get(n->ctermfd, &newy, &newx)){
Expand All @@ -288,6 +303,12 @@ detect_cursor_inversion(ncdirect* n, int rows, int cols, int* y, int* x){
*y = newy;
newy = 1;
}
if(tty_emit(tiparm(movex == 1 ? n->tcache.cuf : n->tcache.cub, 1), n->ctermfd)){
return -1;
}
if(tty_emit(tiparm(movey == 1 ? n->tcache.cud : n->tcache.cuu, 1), n->ctermfd)){
return -1;
}
if(*y == newy && *x == newx){
return -1; // hopelessly broken
}else if(*x == newx){
Expand Down Expand Up @@ -315,16 +336,18 @@ detect_cursor_inversion(ncdirect* n, int rows, int cols, int* y, int* x){

static int
detect_cursor_inversion_wrapper(ncdirect* n, int* y, int* x){
// if we're not on a real terminal, there's no point in running this
if(n->ctermfd < 0){
return 0;
}
const int toty = ncdirect_dim_y(n);
const int totx = ncdirect_dim_x(n);
if(ncdirect_cursor_push(n)){
return -1; // FIXME work around lack of sc
}
int ret = detect_cursor_inversion(n, toty, totx, y, x);
if(ncdirect_cursor_pop(n)){
return -1;
}
return ret;
// there's an argument to be made that this ought be wrapped in sc/rc
// (push/pop cursor), rather than undoing itself. problem is, some
// terminals lack sc/rc (they need cursor moves to run the detection
// algorithm in the first place), and our versions go to ttyfp instead
// of ctermfd, as needed by cursor interrogation.
return detect_cursor_inversion(n, toty, totx, y, x);
}

// no terminfo capability for this. dangerous--it involves writing controls to
Expand Down
21 changes: 21 additions & 0 deletions src/poc/cursor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <notcurses/direct.h>

int main(void){
struct ncdirect* n = ncdirect_core_init(NULL, stdout, 0);
if(n == NULL){
return EXIT_FAILURE;
}
int y, x;
if(ncdirect_cursor_yx(n, &y, &x)){
goto err;
}
int dimx = ncdirect_dim_x(n);
int dimy = ncdirect_dim_y(n);
printf("Cursor: column %d/%d row %d/%d\n", x, dimx, y, dimy);
ncdirect_stop(n);
return EXIT_SUCCESS;

err:
ncdirect_stop(n);
return EXIT_FAILURE;
}
12 changes: 6 additions & 6 deletions src/poc/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ int main(void){
y += 2; // we just went down two lines
while(y > 3){
ret = -1;
const int up = y >= 3 ? 3 : y;
if(ncdirect_cursor_up(n, up)){
break;
}
fflush(stdout);
y -= up;
int newy;
if(ncdirect_cursor_yx(n, &newy, NULL)){
break;
Expand All @@ -61,6 +55,12 @@ int main(void){
}
printf("\n\tRead cursor position: y: %d x: %d\n", newy, x);
y += 2;
const int up = 3;
if(ncdirect_cursor_up(n, up)){
break;
}
fflush(stdout);
y -= up;
ret = 0;
}
}else{
Expand Down

0 comments on commit a903f32

Please sign in to comment.