From a54450248b063afd96530821020872bfc9ec9997 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Apr 2021 16:48:07 +0100 Subject: [PATCH] vi: allow the '.' command to have a repetition count The '.' command repeats the last text change. When it has a repetition count replay the change the number of times requested. Update the stored count if it changes. For example, 3dw deletes 3 words . deletes another 3 words 2. deletes 2 words and changes the stored count . deletes 2 words function old new delta do_cmd 4746 4781 +35 .rodata 105133 105138 +5 edit_file 887 849 -38 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 40/-38) Total: 2 bytes v2: Change implementation to include repetition count in string. Otherwise repeating 'r' doesn't work properly. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index fad53174e..9a2d7b0d9 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -338,6 +338,7 @@ struct globals { smallint adding2q; // are we currently adding user input to q int lmc_len; // length of last_modifying_cmd char *ioq, *ioq_start; // pointer to string for get_one_char to "read" + int dotcnt; // number of times to repeat '.' command #endif #if ENABLE_FEATURE_VI_SEARCH char *last_search_pattern; // last pattern from a '/' or '?' search @@ -460,6 +461,7 @@ struct globals { #define lmc_len (G.lmc_len ) #define ioq (G.ioq ) #define ioq_start (G.ioq_start ) +#define dotcnt (G.dotcnt ) #define last_search_pattern (G.last_search_pattern) #define edit_file__cur_line (G.edit_file__cur_line) @@ -1094,8 +1096,8 @@ static int get_one_char(void) } // we are adding STDIN chars to q. c = readit(); - if (lmc_len >= ARRAY_SIZE(last_modifying_cmd) - 1) { - // last_modifying_cmd[] is too small, can't remeber the cmd + if (lmc_len >= ARRAY_SIZE(last_modifying_cmd) - 2) { + // last_modifying_cmd[] is too small, can't remember the cmd // - drop it adding2q = 0; lmc_len = 0; @@ -1863,13 +1865,9 @@ static char *bound_dot(char *p) // make sure text[0] <= P < "end" static void start_new_cmd_q(char c) { // get buffer for new cmd - // if there is a current cmd count put it in the buffer first - if (cmdcnt > 0) { - lmc_len = sprintf(last_modifying_cmd, "%u%c", cmdcnt, c); - } else { // just save char c onto queue - last_modifying_cmd[0] = c; - lmc_len = 1; - } + dotcnt = cmdcnt ?: 1; + last_modifying_cmd[0] = c; + lmc_len = 1; adding2q = 1; } static void end_cmd_q(void) @@ -3515,7 +3513,10 @@ static void do_cmd(int c) // Stuff the last_modifying_cmd back into stdin // and let it be re-executed. if (lmc_len != 0) { - ioq = ioq_start = xstrndup(last_modifying_cmd, lmc_len); + if (cmdcnt) // update saved count if current count is non-zero + dotcnt = cmdcnt; + last_modifying_cmd[lmc_len] = '\0'; + ioq = ioq_start = xasprintf("%u%s", dotcnt, last_modifying_cmd); } break; #endif