ncreader: implement reamining shortcuts #983

This commit is contained in:
nick black 2020-11-07 05:52:12 -05:00
parent 1b1d727169
commit 8a81d06b4b
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
2 changed files with 63 additions and 41 deletions

View File

@ -9,9 +9,10 @@ rearrangements of Notcurses.
callable by the user, this ought not lead to any user-visible changes.
* Added (k)eller demo to `notcurses-demo`.
* `ncreader` now supports Alt+'b' to move one word back, Alt+'f' to move one
word forward, Ctrl+'A' to move to the beginning of the line, and Ctrl+'E'
to move to the end of the line (when `NCREADER_OPTION_NOCMDKEYS` is not
used).
word forward, Ctrl+'A' to move to the beginning of the line, Ctrl+'E' to
move to the end of the line, Ctrl+'U' to clear the line before the cursor,
and Ctrl+'W' to clear the word before the cursor (when
`NCREADER_OPTION_NOCMDKEYS` has not been specified).
* 2.0.2 (2020-10-25)
* Add `ncvisual_decode_loop()`, which returns to the first frame upon

View File

@ -214,13 +214,48 @@ int ncreader_write_egc(ncreader* n, const char* egc){
return 0;
}
static bool
do_backspace(ncreader* n){
int x = n->textarea->x;
int y = n->textarea->y;
if(n->textarea->x == 0){
if(n->textarea->y){
y = n->textarea->y - 1;
x = n->textarea->lenx - 1;
}
}else{
--x;
}
ncplane_putegc_yx(n->textarea, y, x, "", NULL);
ncplane_cursor_move_yx(n->textarea, y, x);
ncplane_cursor_move_yx(n->ncp, n->ncp->y, n->ncp->x - 1);
ncreader_redraw(n);
return true;
}
static bool
is_egc_wordbreak(ncplane* textarea){
char* egc = ncplane_at_yx(textarea, textarea->y, textarea->x, NULL, NULL);
fprintf(stderr, "TAKING A LOKO AT [%s]\n", egc);
if(egc == NULL){
return true;
}
wchar_t w;
mbstate_t mbstate = {0};
size_t s = mbrtowc(&w, egc, MB_CUR_MAX, &mbstate);
free(egc);
if(s == (size_t)-1 || s == (size_t)-2){
return true;
}
if(iswordbreak(w)){
return true;
}
return false;
}
static bool
ncreader_ctrl_input(ncreader* n, const ncinput* ni){
switch(ni->id){
case 'U':
ncplane_erase(n->ncp); // homes the cursor
ncplane_erase(n->textarea);
break;
case 'B':
ncreader_move_left(n);
break;
@ -241,31 +276,31 @@ ncreader_ctrl_input(ncreader* n, const ncinput* ni){
}
}
break;
case 'U': // clear line before cursor
while(n->textarea->x){
do_backspace(n);
}
break;
case 'W': // clear word before cursor
while(n->textarea->x){
if(ncreader_move_left(n)){
break;
}
if(is_egc_wordbreak(n->textarea)){
break;
}
if(ncreader_move_right(n)){
break;
}
do_backspace(n);
}
break;
default:
return false; // pass on all other ctrls
}
return true;
}
static bool
is_egc_wordbreak(ncplane* textarea){
char* egc = ncplane_at_yx(textarea, textarea->y, textarea->x, NULL, NULL);
if(egc == NULL){
return true;
}
wchar_t w;
mbstate_t mbstate = {0};
size_t s = mbrtowc(&w, egc, MB_CUR_MAX, &mbstate);
free(egc);
if(s == (size_t)-1 || s == (size_t)-2){
return true;
}
if(iswordbreak(w)){
return true;
}
return false;
}
static bool
ncreader_alt_input(ncreader* n, const ncinput* ni){
switch(ni->id){
@ -300,8 +335,6 @@ ncreader_alt_input(ncreader* n, const ncinput* ni){
// * anything with Ctrl, except 'U' (which clears all input)
// * anything synthesized, save arrow keys and backspace
bool ncreader_offer_input(ncreader* n, const ncinput* ni){
int x = n->textarea->x;
int y = n->textarea->y;
if(ni->ctrl && !n->no_cmd_keys){
return ncreader_ctrl_input(n, ni);
}else if(ni->alt && !n->no_cmd_keys){
@ -311,19 +344,7 @@ bool ncreader_offer_input(ncreader* n, const ncinput* ni){
return false;
}
if(ni->id == NCKEY_BACKSPACE){
if(n->textarea->x == 0){
if(n->textarea->y){
y = n->textarea->y - 1;
x = n->textarea->lenx - 1;
}
}else{
--x;
}
ncplane_putegc_yx(n->textarea, y, x, "", NULL);
ncplane_cursor_move_yx(n->textarea, y, x);
ncplane_cursor_move_yx(n->ncp, n->ncp->y, n->ncp->x - 1);
ncreader_redraw(n);
return true;
return do_backspace(n);
}
// FIXME deal with multicolumn EGCs -- probably extract these and make them
// general ncplane_cursor_{left, right, up, down}()