nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

commit 687efd210ced98d13b477f6c4544d39828b32632
parent b7539ea9853cd3cdab5c4d3453ac3b3afe26d49b
Author: Benno Schulenberg <bensberg@telfort.nl>
Date:   Tue, 10 Nov 2020 18:27:52 +0100

moving: skip combining characters and other zero-width characters

This makes the cursor move smoothly left and right -- instead of
"stuttering" when passing over a zero-width character.

Pressing <Delete> on a normal (spacing) character also deletes
any zero-width characters after it.  But pressing <Backspace>
while the cursor is placed after a zero-width character, just
deletes that zero-width character.  The latter behavior allows
deleting and retyping just the combining diacritic of a character
instead of the whole character.

This addresses https://savannah.gnu.org/bugs/?50773.
Requested-by: Mike Frysinger <vapier@gentoo.org>

Diffstat:
Msrc/chars.c | 6++++++
Msrc/cut.c | 12+++++++++++-
Msrc/move.c | 29+++++++++++++++++++++++++++++
Msrc/prototypes.h | 1+
4 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/chars.c b/src/chars.c @@ -197,6 +197,12 @@ int mbwidth(const char *c) return 1; } +/* Return TRUE when the given character occupies zero cells. */ +bool is_zerowidth(const char *ch) +{ + return (use_utf8 && mbwidth(ch) == 0); +} + /* Convert the given Unicode value to a multibyte character, if possible. * If the conversion succeeds, return the (dynamically allocated) multibyte * character and its length. Otherwise, return a length of zero. */ diff --git a/src/cut.c b/src/cut.c @@ -121,7 +121,14 @@ void do_delete(void) zap_text(); else #endif + { do_deletion(DEL); +#ifdef ENABLE_UTF8 + while (openfile->current->data[openfile->current_x] != '\0' && + is_zerowidth(openfile->current->data + openfile->current_x)) + do_deletion(DEL); +#endif + } } /* Backspace over one character. That is, move the cursor left one @@ -133,7 +140,10 @@ void do_backspace(void) zap_text(); else #endif - if (openfile->current_x > 0 || openfile->current != openfile->filetop) { + if (openfile->current_x > 0) { + openfile->current_x = step_left(openfile->current->data, openfile->current_x); + do_deletion(BACK); + } else if (openfile->current != openfile->filetop) { do_left(); do_deletion(BACK); } diff --git a/src/move.c b/src/move.c @@ -291,6 +291,10 @@ void do_prev_word(bool allow_punct) /* If at the head of a line now, this surely is a word start. */ if (openfile->current_x == 0) break; +#ifdef ENABLE_UTF8 + } else if (is_zerowidth(openfile->current->data + openfile->current_x)) { + ; /* skip */ +#endif } else if (seen_a_word) { /* This is space now: we've overshot the start of the word. */ step_forward = TRUE; @@ -339,11 +343,20 @@ bool do_next_word(bool after_ends, bool allow_punct) if (is_word_char(openfile->current->data + openfile->current_x, allow_punct)) seen_word = TRUE; +#ifdef ENABLE_UTF8 + else if (is_zerowidth(openfile->current->data + openfile->current_x)) + ; /* skip */ +#endif else if (seen_word) break; } else #endif { +#ifdef ENABLE_UTF8 + if (is_zerowidth(openfile->current->data + openfile->current_x)) + ; /* skip */ + else +#endif /* If this is not a word character, then it's a separator; else * if we've already seen a separator, then it's a word start. */ if (!is_word_char(openfile->current->data + openfile->current_x, @@ -582,8 +595,16 @@ void do_left(void) linestruct *was_current = openfile->current; if (openfile->current_x > 0) + { openfile->current_x = step_left(openfile->current->data, openfile->current_x); +#ifdef ENABLE_UTF8 + while (openfile->current_x > 0 && + is_zerowidth(openfile->current->data + openfile->current_x)) + openfile->current_x = step_left(openfile->current->data, + openfile->current_x); +#endif + } else if (openfile->current != openfile->filetop) { openfile->current = openfile->current->prev; openfile->current_x = strlen(openfile->current->data); @@ -598,8 +619,16 @@ void do_right(void) linestruct *was_current = openfile->current; if (openfile->current->data[openfile->current_x] != '\0') + { openfile->current_x = step_right(openfile->current->data, openfile->current_x); +#ifdef ENABLE_UTF8 + while (openfile->current->data[openfile->current_x] != '\0' && + is_zerowidth(openfile->current->data + openfile->current_x)) + openfile->current_x = step_right(openfile->current->data, + openfile->current_x); +#endif + } else if (openfile->current != openfile->filebot) { openfile->current = openfile->current->next; openfile->current_x = 0; diff --git a/src/prototypes.h b/src/prototypes.h @@ -204,6 +204,7 @@ bool is_word_char(const char *c, bool allow_punct); char control_mbrep(const char *c, bool isdata); #ifdef ENABLE_UTF8 int mbwidth(const char *c); +bool is_zerowidth(const char *ch); char *make_mbchar(long code, int *length); #endif int char_length(const char *pointer);