The left shift operator ('<') didn't support undo at all; right
shift ('>') required changes to be undone separately for each line.
Allow both types of shift to be undone as a single operation.

Also, neither traditional vi nor vim yank the lines being shifted by
the '<' and '>' commands, so remove that call to yank_delete();

When a repetition count was specified for the '~', 'x', 'X' or 's'
commands the changes had to be undone one character at a time.
Allow undo as a single operation (though the delete and change
parts of the 's' command still have to be undone separately).

function                                             old     new   delta
undo_push_insert                                      37      40      +3
do_cmd                                              4695    4663     -32
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 3/-32)             Total: -29 bytes

v2: Don't break build when FEATURE_VI_UNDO is  disabled.  Don't reset
    'undo_del' too early in '~' handling code.  Code shrink '~'.

Signed-off-by: Ron Yorston <[email protected]>
---
 editors/vi.c | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 7ede8f2ff..da3e8aeb3 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3190,6 +3190,10 @@ static void do_cmd(int c)
        int dir;
        int cnt, i, j;
        int c1;
+#if ENABLE_FEATURE_VI_UNDO
+       int allow_undo = ALLOW_UNDO;
+       int undo_del = UNDO_DEL;
+#endif
 
 //     c1 = c; // quiet the compiler
 //     cnt = yf = 0; // quiet the compiler
@@ -3591,24 +3595,29 @@ static void do_cmd(int c)
                cnt = count_lines(text, dot);   // remember what line we are on
                if (find_range(&p, &q, c) == -1)
                        goto dc6;
-               yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO);    // save copy 
before change
                i = count_lines(p, q);  // # of lines we are shifting
                for ( ; i > 0; i--, p = next_line(p)) {
                        if (c == '<') {
                                // shift left- remove tab or 8 spaces
                                if (*p == '\t') {
                                        // shrink buffer 1 char
-                                       text_hole_delete(p, p, NO_UNDO);
+                                       text_hole_delete(p, p, allow_undo);
                                } else if (*p == ' ') {
                                        // we should be calculating columns, 
not just SPACE
                                        for (j = 0; *p == ' ' && j < tabstop; 
j++) {
-                                               text_hole_delete(p, p, NO_UNDO);
+                                               text_hole_delete(p, p, 
allow_undo);
+#if ENABLE_FEATURE_VI_UNDO
+                                               allow_undo = ALLOW_UNDO_CHAIN;
+#endif
                                        }
                                }
-                       } else if (c == '>') {
+                       } else /* if (c == '>') */ {
                                // shift right -- add tab or 8 spaces
-                               char_insert(p, '\t', ALLOW_UNDO);
+                               char_insert(p, '\t', allow_undo);
                        }
+#if ENABLE_FEATURE_VI_UNDO
+                       allow_undo = ALLOW_UNDO_CHAIN;
+#endif
                }
                dot = find_line(cnt);   // what line were we on
                dot_skip_over_ws();
@@ -3762,7 +3771,10 @@ static void do_cmd(int c)
                        if (dot[dir] != '\n') {
                                if (c == 'X')
                                        dot--;  // delete prev char
-                               dot = yank_delete(dot, dot, PARTIAL, YANKDEL, 
ALLOW_UNDO);      // delete char
+                               dot = yank_delete(dot, dot, PARTIAL, YANKDEL, 
allow_undo);      // delete char
+#if ENABLE_FEATURE_VI_UNDO
+                               allow_undo = ALLOW_UNDO_CHAIN;
+#endif
                        }
                } while (--cmdcnt > 0);
                end_cmd_q();    // stop adding to q
@@ -3922,14 +3934,11 @@ static void do_cmd(int c)
        case '~':                       // ~- flip the case of letters   a-z -> 
A-Z
                do {
 #if ENABLE_FEATURE_VI_UNDO
-                       if (islower(*dot)) {
-                               undo_push(dot, 1, UNDO_DEL);
-                               *dot = toupper(*dot);
-                               undo_push(dot, 1, UNDO_INS_CHAIN);
-                       } else if (isupper(*dot)) {
-                               undo_push(dot, 1, UNDO_DEL);
-                               *dot = tolower(*dot);
+                       if (isalpha(*dot)) {
+                               undo_push(dot, 1, undo_del);
+                               *dot = islower(*dot) ? toupper(*dot) : 
tolower(*dot);
                                undo_push(dot, 1, UNDO_INS_CHAIN);
+                               undo_del = UNDO_DEL_CHAIN;
                        }
 #else
                        if (islower(*dot)) {
-- 
2.30.2

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to