implement locate_cursor_simple for redirected input case #1942

pull/1946/head
nick black 3 years ago
parent 67c511edba
commit 4398fc223c
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -722,6 +722,7 @@ void ncinputlayer_stop(ncinputlayer* nilayer){
if(nilayer->ttyfd >= 0){
close(nilayer->ttyfd);
}
// do *not* close infd; it's just a fileno extracted from stdin
input_free_esctrie(&nilayer->inputescapes);
}
@ -1372,18 +1373,20 @@ control_read(int ttyfd, query_state* qstate){
return -1;
}
errno = 0;
while((s = read(ttyfd, buf, BUFSIZ)) != -1){
for(ssize_t idx = 0; idx < s ; ++idx){
int r = pump_control_read(qstate, buf[idx]);
if(r == 1){ // success!
free(buf);
//fprintf(stderr, "at end, derived terminal %d\n", inits.qterm);
return 0;
}else if(r < 0){
goto err;
do{
while((s = read(ttyfd, buf, BUFSIZ)) != -1){
for(ssize_t idx = 0; idx < s ; ++idx){
int r = pump_control_read(qstate, buf[idx]);
if(r == 1){ // success!
free(buf);
//fprintf(stderr, "at end, derived terminal %d\n", inits.qterm);
return 0;
}else if(r < 0){
goto err;
}
}
}
}
}while(errno == EINTR || errno == EAGAIN);
err:
fprintf(stderr, "Reading control replies failed on %d (%s)\n", ttyfd, strerror(errno));
free(buf);

@ -1178,7 +1178,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
}
if(ret->rstate.logendy >= 0){ // if either is set, both are
if(!ret->suppress_banner && ret->ttyfd >= 0){
if(locate_cursor(&ret->tcache, ret->ttyfd, &ret->rstate.logendy, &ret->rstate.logendx)){
if(locate_cursor(&ret->tcache, &ret->rstate.logendy, &ret->rstate.logendx)){
free_plane(ret->stdplane);
goto err;
}

@ -792,17 +792,54 @@ char* termdesc_longterm(const tinfo* ti){
return ret;
}
// send a u7 request, and wait until we have a cursor report
int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x){
if(fd < 0){
logwarn("Can't request on fd %d\n", fd);
// when we have input->ttyfd, everything's simple -- we're reading from a
// different source than the user is, so we can just write the query, and block
// on the response, easy peasy.
// FIXME still, we ought reuse buffer, and pass on any excess reads...
static int
locate_cursor_simple(int fd, const char* u7, int* cursor_y, int* cursor_x){
char* buf = malloc(BUFSIZ);
if(buf == NULL){
return -1;
}
if(tty_emit(u7, fd)){
free(buf);
return -1;
}
ssize_t r;
// FIXME rigourize for multiple reads
if((r = read(fd, buf, BUFSIZ - 1)) > 0){
buf[r] = '\0';
if(sscanf(buf, "\e[%d;%dR", cursor_y, cursor_x) != 2){
loginfo("Not a cursor location report: %s\n", buf);
free(buf);
return -1;
}
--*cursor_y;
--*cursor_x;
}
free(buf);
loginfo("Located cursor with %d: %d/%d\n", fd, *cursor_y, *cursor_x);
return 0;
}
// send a u7 request, and wait until we have a cursor report. if input's ttyfd
// is valid, we can just camp there. otherwise, we need dance with potential
// user input looking at infd.
int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x){
const char* u7 = get_escape(ti, ESCAPE_DSRCPR);
if(u7 == NULL){
logwarn("No support in terminfo\n");
return -1;
}
if(ti->input.ttyfd >= 0){
return locate_cursor_simple(ti->input.ttyfd, u7, cursor_y, cursor_x);
}
int fd = ti->input.infd;
if(fd < 0){
logwarn("No valid path for cursor report\n");
return -1;
}
bool emitted_u7 = false; // only want to send one max
cursorreport* clr;
loginfo("Acquiring input lock\n");
@ -822,14 +859,13 @@ int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x){
// return to us holding the input lock.
ncinput_extract_clrs(&ti->input);
if( (clr = ti->input.creport_queue) ){
logdebug("Hustled up a CL report\n");
break;
}
pthread_cond_wait(&ti->input.creport_cond, &ti->input.lock);
}
ti->input.creport_queue = clr->next;
pthread_mutex_unlock(&ti->input.lock);
loginfo("Got a report %d/%d\n", clr->y, clr->x);
loginfo("Got a report from %d %d/%d\n", fd, clr->y, clr->x);
*cursor_y = clr->y;
*cursor_x = clr->x;
if(ti->inverted_cursor){

@ -89,9 +89,12 @@ typedef struct ncinputlayer {
// only allow one reader at a time, whether it's the user trying to do so,
// or our desire for a cursor report competing with the user.
pthread_mutex_t lock;
// must be held to operate on the cursor report queue shared between pure
// input and the control layer.
pthread_cond_t creport_cond;
// ttyfd is only valid if we are connected to a tty, *and* stdin is not
// connected to that tty. in that case, we read control sequences only
// from ttyfd.
// connected to that tty (this usually means stdin was redirected). in that
// case, we read control sequences only from ttyfd.
int ttyfd; // file descriptor for connected tty
int infd; // file descriptor for processing input, from stdin
unsigned char inputbuf[BUFSIZ];
@ -108,7 +111,6 @@ typedef struct ncinputlayer {
uint64_t input_events;
struct esctrie* inputescapes; // trie of input escapes -> ncspecial_keys
cursorreport* creport_queue; // queue of cursor reports
pthread_cond_t creport_cond;
bool user_wants_data; // a user context is active
bool inner_wants_data; // if we're blocking on input
} ncinputlayer;
@ -219,7 +221,7 @@ void free_terminfo_cache(tinfo* ti);
// return a heap-allocated copy of termname + termversion
char* termdesc_longterm(const tinfo* ti);
int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x);
int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x);
#ifdef __cplusplus
}

Loading…
Cancel
Save