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