aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-04-06 13:44:05 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-11 00:18:56 +0200
commitf4a9908b4c21e5e8f544ab9d2bc3770b35942a6b (patch)
tree672a0715fd51c2523d8db3894dc53b640f885220
parent99fb5f2144fc30337ec2ece3d1f59ba92ebed5fb (diff)
downloadbusybox-w32-f4a9908b4c21e5e8f544ab9d2bc3770b35942a6b.tar.gz
busybox-w32-f4a9908b4c21e5e8f544ab9d2bc3770b35942a6b.tar.bz2
busybox-w32-f4a9908b4c21e5e8f544ab9d2bc3770b35942a6b.zip
vi: improvements to reporting of changes
Traditional vi is mostly silent about the results of yank, delete, change, undo or substitution commands. Vim reports some details about undo and substitution. BusyBox vi is positively verbose in comparison. Make some improvements to BusyBox vi: - Add vim-like reporting of changes caused by substitutions, of the form '64 substitutions on 53 lines'. This replaces a fairly useless report of the result of the last change made. - Ensure that the report about put operations correctly reflects the newly introduced repetition count. - Commit 25d2592640 tried to limit status updates for delete and yank operations by detecting whether the register had changed. This didn't always work because the previously allocated memory could be reused for the new register contents. Fix this by delaying freeing the old register until after the new one has been allocated. - Add a configuration option to control verbose status reporting. This is on by default. Turning it off make BusyBox vi as taciturn as traditional vi and saves 435 bytes. function old new delta colon 3212 3292 +80 yank_status - 74 +74 static.text_yank 99 86 -13 string_insert 130 76 -54 do_cmd 4842 4776 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/3 up/down: 154/-133) Total: 21 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/vi.c90
1 files changed, 59 insertions, 31 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 96e6af318..fb46dc381 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -159,6 +159,14 @@
159//config: and will generally malloc() larger objects and less frequently. 159//config: and will generally malloc() larger objects and less frequently.
160//config: Unless you want more (or less) frequent "undo points" while typing, 160//config: Unless you want more (or less) frequent "undo points" while typing,
161//config: you should probably leave this unchanged. 161//config: you should probably leave this unchanged.
162//config:
163//config:config FEATURE_VI_VERBOSE_STATUS
164//config: bool "Enable verbose status reporting"
165//config: default y
166//config: depends on VI
167//config: help
168//config: Enable more verbose reporting of the results of yank, change,
169//config: delete, undo and substitution commands.
162 170
163//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) 171//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP))
164 172
@@ -1357,14 +1365,17 @@ static void not_implemented(const char *s)
1357// copy text into a register 1365// copy text into a register
1358static char *text_yank(char *p, char *q, int dest, int buftype) 1366static char *text_yank(char *p, char *q, int dest, int buftype)
1359{ 1367{
1368 char *oldreg = reg[dest];
1360 int cnt = q - p; 1369 int cnt = q - p;
1361 if (cnt < 0) { // they are backwards- reverse them 1370 if (cnt < 0) { // they are backwards- reverse them
1362 p = q; 1371 p = q;
1363 cnt = -cnt; 1372 cnt = -cnt;
1364 } 1373 }
1365 free(reg[dest]); // if already a yank register, free it 1374 // Don't free register yet. This prevents the memory allocator
1375 // from reusing the free block so we can detect if it's changed.
1366 reg[dest] = xstrndup(p, cnt + 1); 1376 reg[dest] = xstrndup(p, cnt + 1);
1367 regtype[dest] = buftype; 1377 regtype[dest] = buftype;
1378 free(oldreg);
1368 return p; 1379 return p;
1369} 1380}
1370 1381
@@ -1415,6 +1426,22 @@ static char *swap_context(char *p) // goto new context for '' command make this
1415 } 1426 }
1416 return p; 1427 return p;
1417} 1428}
1429
1430# if ENABLE_FEATURE_VI_VERBOSE_STATUS
1431static void yank_status(const char *op, const char *p, int cnt)
1432{
1433 int lines, chars;
1434
1435 lines = chars = 0;
1436 while (*p) {
1437 ++chars;
1438 if (*p++ == '\n')
1439 ++lines;
1440 }
1441 status_line("%s %d lines (%d chars) from [%c]",
1442 op, lines * cnt, chars * cnt, what_reg());
1443}
1444# endif
1418#endif /* FEATURE_VI_YANKMARK */ 1445#endif /* FEATURE_VI_YANKMARK */
1419 1446
1420#if ENABLE_FEATURE_VI_UNDO 1447#if ENABLE_FEATURE_VI_UNDO
@@ -1687,10 +1714,12 @@ static void undo_pop(void)
1687 u_start = text + undo_entry->start; 1714 u_start = text + undo_entry->start;
1688 text_hole_make(u_start, undo_entry->length); 1715 text_hole_make(u_start, undo_entry->length);
1689 memcpy(u_start, undo_entry->undo_text, undo_entry->length); 1716 memcpy(u_start, undo_entry->undo_text, undo_entry->length);
1717# if ENABLE_FEATURE_VI_VERBOSE_STATUS
1690 status_line("Undo [%d] %s %d chars at position %d", 1718 status_line("Undo [%d] %s %d chars at position %d",
1691 modified_count, "restored", 1719 modified_count, "restored",
1692 undo_entry->length, undo_entry->start 1720 undo_entry->length, undo_entry->start
1693 ); 1721 );
1722# endif
1694 break; 1723 break;
1695 case UNDO_INS: 1724 case UNDO_INS:
1696 case UNDO_INS_CHAIN: 1725 case UNDO_INS_CHAIN:
@@ -1698,10 +1727,12 @@ static void undo_pop(void)
1698 u_start = undo_entry->start + text; 1727 u_start = undo_entry->start + text;
1699 u_end = u_start - 1 + undo_entry->length; 1728 u_end = u_start - 1 + undo_entry->length;
1700 text_hole_delete(u_start, u_end, NO_UNDO); 1729 text_hole_delete(u_start, u_end, NO_UNDO);
1730# if ENABLE_FEATURE_VI_VERBOSE_STATUS
1701 status_line("Undo [%d] %s %d chars at position %d", 1731 status_line("Undo [%d] %s %d chars at position %d",
1702 modified_count, "deleted", 1732 modified_count, "deleted",
1703 undo_entry->length, undo_entry->start 1733 undo_entry->length, undo_entry->start
1704 ); 1734 );
1735# endif
1705 break; 1736 break;
1706 } 1737 }
1707 repeat = 0; 1738 repeat = 0;
@@ -2150,16 +2181,6 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s
2150 bias = text_hole_make(p, i); 2181 bias = text_hole_make(p, i);
2151 p += bias; 2182 p += bias;
2152 memcpy(p, s, i); 2183 memcpy(p, s, i);
2153#if ENABLE_FEATURE_VI_YANKMARK
2154 {
2155 int cnt;
2156 for (cnt = 0; *s != '\0'; s++) {
2157 if (*s == '\n')
2158 cnt++;
2159 }
2160 status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
2161 }
2162#endif
2163 return bias; 2184 return bias;
2164} 2185}
2165#endif 2186#endif
@@ -2821,6 +2842,9 @@ static void colon(char *buf)
2821 size_t len_F, len_R; 2842 size_t len_F, len_R;
2822 int gflag = 0; // global replace flag 2843 int gflag = 0; // global replace flag
2823 int subs = 0; // number of substitutions 2844 int subs = 0; // number of substitutions
2845# if ENABLE_FEATURE_VI_VERBOSE_STATUS
2846 int last_line = 0, lines = 0;
2847# endif
2824 2848
2825 // F points to the "find" pattern 2849 // F points to the "find" pattern
2826 // R points to the "replace" pattern 2850 // R points to the "replace" pattern
@@ -2860,6 +2884,12 @@ static void colon(char *buf)
2860 subs ? ALLOW_UNDO_CHAIN: ALLOW_UNDO); 2884 subs ? ALLOW_UNDO_CHAIN: ALLOW_UNDO);
2861 // can't do this above, no undo => no third argument 2885 // can't do this above, no undo => no third argument
2862 subs++; 2886 subs++;
2887# if ENABLE_FEATURE_VI_VERBOSE_STATUS
2888 if (last_line != i) {
2889 last_line = i;
2890 ++lines;
2891 }
2892# endif
2863 // insert the "replace" patern 2893 // insert the "replace" patern
2864 bias = string_insert(found, R, ALLOW_UNDO_CHAIN); 2894 bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
2865 found += bias; 2895 found += bias;
@@ -2880,6 +2910,10 @@ static void colon(char *buf)
2880 status_line_bold("No match"); 2910 status_line_bold("No match");
2881 } else { 2911 } else {
2882 dot_skip_over_ws(); 2912 dot_skip_over_ws();
2913# if ENABLE_FEATURE_VI_VERBOSE_STATUS
2914 if (subs > 1)
2915 status_line("%d substitutions on %d lines", subs, lines);
2916# endif
2883 } 2917 }
2884# endif /* FEATURE_VI_SEARCH */ 2918# endif /* FEATURE_VI_SEARCH */
2885 } else if (strncmp(cmd, "version", i) == 0) { // show software version 2919 } else if (strncmp(cmd, "version", i) == 0) { // show software version
@@ -3434,8 +3468,9 @@ static void do_cmd(int c)
3434 status_line_bold("Nothing in register %c", what_reg()); 3468 status_line_bold("Nothing in register %c", what_reg());
3435 break; 3469 break;
3436 } 3470 }
3437 // are we putting whole lines or strings
3438 cnt = 0; 3471 cnt = 0;
3472 i = cmdcnt ?: 1;
3473 // are we putting whole lines or strings
3439 if (regtype[YDreg] == WHOLE) { 3474 if (regtype[YDreg] == WHOLE) {
3440 if (c == 'P') { 3475 if (c == 'P') {
3441 dot_begin(); // putting lines- Put above 3476 dot_begin(); // putting lines- Put above
@@ -3453,7 +3488,7 @@ static void do_cmd(int c)
3453 dot_right(); // move to right, can move to NL 3488 dot_right(); // move to right, can move to NL
3454 // how far to move cursor if register doesn't have a NL 3489 // how far to move cursor if register doesn't have a NL
3455 if (strchr(p, '\n') == NULL) 3490 if (strchr(p, '\n') == NULL)
3456 cnt = (cmdcnt ?: 1) * strlen(p) - 1; 3491 cnt = i * strlen(p) - 1;
3457 } 3492 }
3458 do { 3493 do {
3459 // dot is adjusted if text[] is reallocated so we don't have to 3494 // dot is adjusted if text[] is reallocated so we don't have to
@@ -3463,6 +3498,9 @@ static void do_cmd(int c)
3463# endif 3498# endif
3464 } while (--cmdcnt > 0); 3499 } while (--cmdcnt > 0);
3465 dot += cnt; 3500 dot += cnt;
3501# if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS
3502 yank_status("Put", p, i);
3503# endif
3466 end_cmd_q(); // stop adding to q 3504 end_cmd_q(); // stop adding to q
3467 break; 3505 break;
3468 case 'U': // U- Undo; replace current line with original version 3506 case 'U': // U- Undo; replace current line with original version
@@ -3473,6 +3511,9 @@ static void do_cmd(int c)
3473 p += string_insert(p, reg[Ureg], ALLOW_UNDO_CHAIN); // insert orig line 3511 p += string_insert(p, reg[Ureg], ALLOW_UNDO_CHAIN); // insert orig line
3474 dot = p; 3512 dot = p;
3475 dot_skip_over_ws(); 3513 dot_skip_over_ws();
3514# if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS
3515 yank_status("Undo", reg[Ureg], 1);
3516# endif
3476 } 3517 }
3477 break; 3518 break;
3478#endif /* FEATURE_VI_YANKMARK */ 3519#endif /* FEATURE_VI_YANKMARK */
@@ -3878,7 +3919,9 @@ static void do_cmd(int c)
3878 int yf = YANKDEL; // assume either "c" or "d" 3919 int yf = YANKDEL; // assume either "c" or "d"
3879 int buftype; 3920 int buftype;
3880#if ENABLE_FEATURE_VI_YANKMARK 3921#if ENABLE_FEATURE_VI_YANKMARK
3922# if ENABLE_FEATURE_VI_VERBOSE_STATUS
3881 char *savereg = reg[YDreg]; 3923 char *savereg = reg[YDreg];
3924# endif
3882 if (c == 'y' || c == 'Y') 3925 if (c == 'y' || c == 'Y')
3883 yf = YANKONLY; 3926 yf = YANKONLY;
3884#endif 3927#endif
@@ -3901,27 +3944,12 @@ static void do_cmd(int c)
3901 } 3944 }
3902 // if CHANGING, not deleting, start inserting after the delete 3945 // if CHANGING, not deleting, start inserting after the delete
3903 if (c == 'c') { 3946 if (c == 'c') {
3904 //strcpy(buf, "Change");
3905 goto dc_i; // start inserting 3947 goto dc_i; // start inserting
3906 } 3948 }
3907#if ENABLE_FEATURE_VI_YANKMARK 3949#if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS
3908 // only update status if a yank has actually happened 3950 // only update status if a yank has actually happened
3909 if (reg[YDreg] != savereg) { 3951 if (reg[YDreg] != savereg)
3910 if (c == 'd') { 3952 yank_status(c == 'd' ? "Delete" : "Yank", reg[YDreg], 1);
3911 strcpy(buf, "Delete");
3912 }
3913 if (c == 'y' || c == 'Y') {
3914 strcpy(buf, "Yank");
3915 }
3916 p = reg[YDreg];
3917 q = p + strlen(p);
3918 for (cnt = 0; p <= q; p++) {
3919 if (*p == '\n')
3920 cnt++;
3921 }
3922 status_line("%s %u lines (%u chars) using [%c]",
3923 buf, cnt, (unsigned)strlen(reg[YDreg]), what_reg());
3924 }
3925#endif 3953#endif
3926 dc6: 3954 dc6:
3927 end_cmd_q(); // stop adding to q 3955 end_cmd_q(); // stop adding to q