From bb983f30e7ea69604212793f228270f21e8a5b06 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 3 Feb 2019 10:13:17 +0000 Subject: vi: fix faulty undo after autoinsert Enable autoinsert and enter the following with an indent of three spaces: line 1 line 2 Using 'u' to undo the last insert results in: line1e 2 The insertion of the indent hasn't been properly recorded. Since recording insertions is a common operation add a convenience function, undo_push_insert(), to handle this and use it to record the autoindent correctly. function old new delta undo_push_insert - 36 +36 string_insert 133 129 -4 char_insert 518 473 -45 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 36/-49) Total: -13 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 57 ++++++++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) (limited to 'editors/vi.c') diff --git a/editors/vi.c b/editors/vi.c index 32144abaa..c6adeb311 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -598,6 +598,7 @@ static void check_context(char); // remember context for '' command #if ENABLE_FEATURE_VI_UNDO static void flush_undo_data(void); static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack +static void undo_push_insert(char *, int, int); // convenience function static void undo_pop(void); // Undo the last operation # if ENABLE_FEATURE_VI_UNDO_QUEUE static void undo_queue_commit(void); // Flush any queued objects to the undo stack @@ -2011,19 +2012,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' c = get_one_char(); *p = c; #if ENABLE_FEATURE_VI_UNDO - switch (undo) { - case ALLOW_UNDO: - undo_push(p, 1, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, 1, UNDO_INS_CHAIN); - break; -# if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, 1, UNDO_INS_QUEUED); - break; -# endif - } + undo_push_insert(p, 1, undo); #else modified_count++; #endif /* ENABLE_FEATURE_VI_UNDO */ @@ -2051,19 +2040,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' if (c == '\n') undo_queue_commit(); # endif - switch (undo) { - case ALLOW_UNDO: - undo_push(p, 1, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, 1, UNDO_INS_CHAIN); - break; -# if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, 1, UNDO_INS_QUEUED); - break; -# endif - } + undo_push_insert(p, 1, undo); #else modified_count++; #endif /* ENABLE_FEATURE_VI_UNDO */ @@ -2083,7 +2060,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' p += bias; q += bias; #if ENABLE_FEATURE_VI_UNDO - undo_push(p, len, UNDO_INS); + undo_push_insert(p, len, undo); #endif memcpy(p, q, len); p += len; @@ -2392,6 +2369,23 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to modified_count++; } +static void undo_push_insert(char *p, int len, int undo) +{ + switch (undo) { + case ALLOW_UNDO: + undo_push(p, len, UNDO_INS); + break; + case ALLOW_UNDO_CHAIN: + undo_push(p, len, UNDO_INS_CHAIN); + break; +# if ENABLE_FEATURE_VI_UNDO_QUEUE + case ALLOW_UNDO_QUEUED: + undo_push(p, len, UNDO_INS_QUEUED); + break; +# endif + } +} + static void undo_pop(void) // Undo the last operation { int repeat; @@ -2665,14 +2659,7 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s i = strlen(s); #if ENABLE_FEATURE_VI_UNDO - switch (undo) { - case ALLOW_UNDO: - undo_push(p, i, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, i, UNDO_INS_CHAIN); - break; - } + undo_push_insert(p, i, undo); #endif bias = text_hole_make(p, i); p += bias; -- cgit v1.2.3-55-g6feb From df4e3af9f716e0483bd02fd4ab3ad973ffe5b998 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 3 Feb 2019 14:01:58 +0000 Subject: vi: fix replacement of single character with CR Currently if the 'r' command is followed by a carriage return a literal CR replaces the current character. Fix this so that: - a new line is inserted - the autoindent setting is respected - the cursor is placed at the start of the new line function old new delta do_cmd 5052 5060 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'editors/vi.c') diff --git a/editors/vi.c b/editors/vi.c index c6adeb311..899fcf57e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -4189,14 +4189,9 @@ static void do_cmd(int c) case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char if (*dot != '\n') { -#if ENABLE_FEATURE_VI_UNDO - undo_push(dot, 1, UNDO_DEL); - *dot = c1; - undo_push(dot, 1, UNDO_INS_CHAIN); -#else - *dot = c1; - modified_count++; -#endif + dot = text_hole_delete(dot, dot, ALLOW_UNDO); + dot = char_insert(dot, c1, ALLOW_UNDO_CHAIN); + dot_left(); } end_cmd_q(); // stop adding to q break; -- cgit v1.2.3-55-g6feb From 61052d1bb8fe5da745c4333a8bf7d031d636b76e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 11 Feb 2019 08:29:15 +0000 Subject: vi: further fixes to undo after autoindent Commit bb983f30e (vi: fix faulty undo after autoinsert) has a number of problems: - The commit message refers to 'autoinsert' when it really means 'autoindent'. - The indentation of undo_push_insert() was incorrect. - Most seriously the commit only fixed the problem for cases where the indentation was exactly one character. This is because undo_push() only allows single characters to be queued for UNDO_INS_QUEUED. Lifting this restriction allows the example given in the previous commit message (with a three character indent) to work. function old new delta undo_push 406 435 +29 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 29/0) Total: 29 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'editors/vi.c') diff --git a/editors/vi.c b/editors/vi.c index 899fcf57e..065a1068e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2314,16 +2314,18 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to } break; case UNDO_INS_QUEUED: - if (length != 1) + if (length < 1) return; switch (undo_queue_state) { case UNDO_EMPTY: undo_queue_state = UNDO_INS; undo_queue_spos = src; case UNDO_INS: - undo_q++; // Don't need to save any data for insertions - if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) - undo_queue_commit(); + while (length--) { + undo_q++; // Don't need to save any data for insertions + if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) + undo_queue_commit(); + } return; case UNDO_DEL: // Switch from storing deleted text to inserted text @@ -2372,16 +2374,16 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to static void undo_push_insert(char *p, int len, int undo) { switch (undo) { - case ALLOW_UNDO: - undo_push(p, len, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, len, UNDO_INS_CHAIN); - break; + case ALLOW_UNDO: + undo_push(p, len, UNDO_INS); + break; + case ALLOW_UNDO_CHAIN: + undo_push(p, len, UNDO_INS_CHAIN); + break; # if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, len, UNDO_INS_QUEUED); - break; + case ALLOW_UNDO_QUEUED: + undo_push(p, len, UNDO_INS_QUEUED); + break; # endif } } -- cgit v1.2.3-55-g6feb