From cbbc18c3a35457135d500264cc56a8ab26424760 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 4 Dec 2019 23:15:52 -0500 Subject: [PATCH] build and destroy input sequence trie #78 --- src/lib/input.c | 72 +++++++++++++++++++++++++++++++++++++++++++-- src/lib/internal.h | 8 +++++ src/lib/notcurses.c | 2 ++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/lib/input.c b/src/lib/input.c index 30a8bf714..6ed29e8e7 100644 --- a/src/lib/input.c +++ b/src/lib/input.c @@ -8,7 +8,7 @@ sig_atomic_t resize_seen = 0; static inline int pop_input_keypress(notcurses* nc){ int candidate = nc->inputbuf[nc->inputbuf_valid_starts]; -fprintf(stderr, "DEOCCUPY: %u@%u read: %d\n", nc->inputbuf_occupied, nc->inputbuf_valid_starts, nc->inputbuf[nc->inputbuf_valid_starts]); +// fprintf(stderr, "DEOCCUPY: %u@%u read: %d\n", nc->inputbuf_occupied, nc->inputbuf_valid_starts, nc->inputbuf[nc->inputbuf_valid_starts]); if(++nc->inputbuf_valid_starts == sizeof(nc->inputbuf) / sizeof(*nc->inputbuf)){ nc->inputbuf_valid_starts = 0; } @@ -16,17 +16,83 @@ fprintf(stderr, "DEOCCUPY: %u@%u read: %d\n", nc->inputbuf_occupied, nc->inputbu return candidate; } +// we assumed escapes can only be composed of 7-bit chars +typedef struct esctrie { + ncspecial_key special; // escape terminating here + struct esctrie** trie; // if non-NULL, next level of radix-128 trie +} esctrie; + +static esctrie* +create_esctrie_node(ncspecial_key special){ + esctrie* e = malloc(sizeof(*e)); + if(e){ + e->special = special; + e->trie = NULL; + } + return e; +} + +void input_free_esctrie(esctrie** eptr){ + esctrie* e; + if( (e = *eptr) ){ + if(e->trie){ + int z; + for(z = 0 ; z < 0x80 ; ++z){ + if(e->trie[z]){ + input_free_esctrie(&e->trie[z]); + } + } + free(e->trie); + } + free(e); + } +} + +int input_add_escape(notcurses* nc, const char* esc, ncspecial_key special){ + esctrie** cur; + fprintf(stderr, "ADDING: %s for %d\n", esc, special); + if(esc[0] != ESC || strlen(esc) < 2){ // assume ESC prefix + content + return -1; + } + do{ + ++esc; + int validate = *esc; + if(validate < 0 || validate >= 0x80){ + return -1; + } + if(nc->inputescapes == NULL){ + cur = &nc->inputescapes; + }else if(validate){ + if((*cur)->trie == NULL){ + const size_t tsize = sizeof((*cur)->trie) * 0x80; + (*cur)->trie = malloc(tsize); + memset((*cur)->trie, 0, tsize); + } + cur = &(*cur)->trie[validate]; + } + if(*cur == NULL){ + if((*cur = create_esctrie_node(NCKEY_INVALID)) == NULL){ + return -1; + } + } + }while(*esc); + if((*cur)->special){ // already had one here! + return -1; + } + (*cur)->special = special; + return 0; +} + // add the keypress we just read to our input queue (assuming there is room). // if there is a full UTF8 codepoint or keystroke (composed or otherwise), // return it, and pop it from the queue. static int handle_getc(notcurses* nc, cell* c, int kpress, ncspecial_key* special){ -fprintf(stderr, "KEYPRESS: %d\n", kpress); +// fprintf(stderr, "KEYPRESS: %d\n", kpress); if(kpress < 0){ return -1; } if(kpress == ESC){ -fprintf(stderr, "ESCAPE OH SHIT\n"); // FIXME delay a little waiting for more? while(nc->inputbuf_occupied){ int candidate = pop_input_keypress(nc); diff --git a/src/lib/internal.h b/src/lib/internal.h index 03279b75d..6cff13b7b 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -23,6 +23,7 @@ struct AVCodec; struct AVCodecParameters; struct AVPacket; struct SwsContext; +struct esctrie; // A plane is memory for some rectilinear virtual window, plus current cursor // state for that window. A notcurses context describes a single terminal, and @@ -121,10 +122,17 @@ typedef struct notcurses { unsigned inputbuf_occupied; unsigned inputbuf_valid_starts; unsigned inputbuf_write_at; + struct esctrie* inputescapes; // trie of input escapes -> ncspecial_keys } notcurses; extern sig_atomic_t resize_seen; +// add this escape sequence to the trie, resolving to the specified specialkey +int input_add_escape(notcurses* nc, const char* esc, ncspecial_key special); + +// free up the input escapes trie +void input_free_esctrie(struct esctrie** trie); + #ifdef __cplusplus } #endif diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index f258b4dbf..728e14202 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -607,6 +607,7 @@ notcurses* notcurses_init(const notcurses_options* opts){ ret->stats.render_min_bytes = ~0UL; ret->ttyfp = opts->outfp; ret->renderfp = opts->renderfp; + ret->inputescapes = NULL; ret->ttyinfp = stdin; // FIXME if(make_nonblocking(ret->ttyinfp)){ free(ret); @@ -729,6 +730,7 @@ int notcurses_stop(notcurses* nc){ nc->top = p->z; free_plane(p); } + input_free_esctrie(&nc->inputescapes); ret |= pthread_mutex_destroy(&nc->lock); free(nc); }