diff options
author | Ron Yorston | 2021-04-25 11:55:42 +0100 |
---|---|---|
committer | Denys Vlasenko | 2021-04-28 11:29:33 +0200 |
commit | acd3079fd1be1b350ab3f75338de67ad1e933024 (patch) | |
tree | c8f9c6f4ab15b8f3a702b0ff42dca98a224925f6 | |
parent | 852ffbee341ccbcdb6400ad5cb4688b410e236b5 (diff) | |
download | busybox-acd3079fd1be1b350ab3f75338de67ad1e933024.zip busybox-acd3079fd1be1b350ab3f75338de67ad1e933024.tar.gz |
vi: expand '%' and '#' in colon commands
Track the current and alternate filenames. The placeholders '%'
and '#' can be used in arguments to colon commands to represent
the current and alternate filenames respectively. Backslash can
be used to allow literal '%' and '#' characters to be entered.
This feature is controlled by the configuration option
FEATURE_VI_COLON_EXPAND.
function old new delta
expand_args - 198 +198
colon 3751 3927 +176
update_filename - 70 +70
init_filename - 48 +48
.rodata 105218 105239 +21
get_one_char 115 124 +9
edit_file 835 838 +3
do_cmd 4724 4727 +3
init_text_buffer 190 172 -18
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 5/1 up/down: 528/-18) Total: 510 bytes
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/vi.c | 126 |
1 files changed, 112 insertions, 14 deletions
diff --git a/editors/vi.c b/editors/vi.c index 7159610..6a879fa 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -53,6 +53,14 @@ //config: Enable a limited set of colon commands. This does not //config: provide an "ex" mode. //config: +//config:config FEATURE_VI_COLON_EXPAND +//config: bool "Expand \"%\" and \"#\" in colon commands" +//config: default y +//config: depends on FEATURE_VI_COLON +//config: help +//config: Expand the special characters \"%\" (current filename) +//config: and \"#\" (alternate filename) in colon commands. +//config: //config:config FEATURE_VI_YANKMARK //config: bool "Enable yank/put commands and mark cmds" //config: default y @@ -347,6 +355,9 @@ struct globals { // [don't make smallint!] int last_status_cksum; // hash of current status line char *current_filename; +#if ENABLE_FEATURE_VI_COLON_EXPAND + char *alt_filename; +#endif char *screenbegin; // index into text[], of top line on the screen char *screen; // pointer to the virtual screen buffer int screensize; // and its size @@ -471,6 +482,7 @@ struct globals { #define have_status_msg (G.have_status_msg ) #define last_status_cksum (G.last_status_cksum ) #define current_filename (G.current_filename ) +#define alt_filename (G.alt_filename ) #define screen (G.screen ) #define screensize (G.screensize ) #define screenbegin (G.screenbegin ) @@ -2198,6 +2210,41 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' return p; } +#if ENABLE_FEATURE_VI_COLON_EXPAND +static void init_filename(char *fn) +{ + char *copy = xstrdup(fn); + + if (current_filename == NULL) { + current_filename = copy; + } else { + free(alt_filename); + alt_filename = copy; + } +} +#else +# define init_filename(f) ((void)(0)) +#endif + +static void update_filename(char *fn) +{ +#if ENABLE_FEATURE_VI_COLON_EXPAND + if (fn == NULL) + return; + + if (current_filename == NULL || strcmp(fn, current_filename) != 0) { + free(alt_filename); + alt_filename = current_filename; + current_filename = xstrdup(fn); + } +#else + if (fn != current_filename) { + free(current_filename); + current_filename = xstrdup(fn); + } +#endif +} + // read text from file or create an empty buf // will also update current_filename static int init_text_buffer(char *fn) @@ -2209,10 +2256,7 @@ static int init_text_buffer(char *fn) text_size = 10240; screenbegin = dot = end = text = xzalloc(text_size); - if (fn != current_filename) { - free(current_filename); - current_filename = xstrdup(fn); - } + update_filename(fn); rc = file_insert(fn, text, 1); if (rc < 0) { // file doesnt exist. Start empty buf with dummy line @@ -2556,6 +2600,43 @@ static void setops(char *args, int flg_no) } # endif +# if ENABLE_FEATURE_VI_COLON_EXPAND +static char *expand_args(char *args) +{ + char *s, *t; + const char *replace; + + args = xstrdup(args); + for (s = args; *s; s++) { + if (*s == '%') { + replace = current_filename; + } else if (*s == '#') { + replace = alt_filename; + } else { + if (*s == '\\' && s[1] != '\0') { + for (t = s++; *t; t++) + *t = t[1]; + } + continue; + } + + if (replace == NULL) { + free(args); + status_line_bold("No previous filename"); + return NULL; + } + + *s = '\0'; + t = xasprintf("%s%s%s", args, replace, s+1); + s = t + (s - args) + strlen(replace); + free(args); + args = t; + } + return args; +} +# else +# define expand_args(a) (a) +# endif #endif /* FEATURE_VI_COLON */ // buf must be no longer than MAX_INPUT_LEN! @@ -2620,7 +2701,7 @@ static void colon(char *buf) #else char c, *buf1, *q, *r; - char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args; + char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; int i, l, li, b, e; int useforce; @@ -2708,9 +2789,12 @@ static void colon(char *buf) else if (cmd[0] == '!') { // run a cmd int retcode; // :!ls run the <cmd> + exp = expand_args(buf + 1); + if (exp == NULL) + goto ret; go_bottom_and_clear_to_eol(); cookmode(); - retcode = system(buf + 1); // run the cmd + retcode = system(exp); // run the cmd if (retcode) printf("\nshell returned %i\n\n", retcode); rawmode(); @@ -2739,7 +2823,9 @@ static void colon(char *buf) } if (args[0]) { // the user supplied a file name - fn = args; + fn = exp = expand_args(args); + if (exp == NULL) + goto ret; } else if (current_filename == NULL) { // no user file name, no current name- punt status_line_bold("No current filename"); @@ -2763,7 +2849,7 @@ static void colon(char *buf) status_line("'%s'%s" IF_FEATURE_VI_READONLY("%s") " %uL, %uC", - current_filename, + fn, (size < 0 ? " [New file]" : ""), IF_FEATURE_VI_READONLY( ((readonly_mode) ? " [Readonly]" : ""), @@ -2777,8 +2863,10 @@ static void colon(char *buf) } if (args[0]) { // user wants a new filename - free(current_filename); - current_filename = xstrdup(args); + exp = expand_args(args); + if (exp == NULL) + goto ret; + update_filename(exp); } else { // user wants file status info last_status_cksum = 0; // force status update @@ -2862,7 +2950,10 @@ static void colon(char *buf) if (args[0]) { // the user supplied a file name - fn = args; + fn = exp = expand_args(args); + if (exp == NULL) + goto ret; + init_filename(fn); } else if (current_filename == NULL) { // no user file name, no current name- punt status_line_bold("No current filename"); @@ -3042,12 +3133,16 @@ static void colon(char *buf) if (args[0]) { struct stat statbuf; - if (!useforce && (fn == NULL || strcmp(fn, args) != 0) && - stat(args, &statbuf) == 0) { + exp = expand_args(args); + if (exp == NULL) + goto ret; + if (!useforce && (fn == NULL || strcmp(fn, exp) != 0) && + stat(exp, &statbuf) == 0) { status_line_bold("File exists (:w! overrides)"); goto ret; } - fn = args; + fn = exp; + init_filename(fn); } # if ENABLE_FEATURE_VI_READONLY else if (readonly_mode && !useforce && fn) { @@ -3109,6 +3204,9 @@ static void colon(char *buf) not_implemented(cmd); } ret: +# if ENABLE_FEATURE_VI_COLON_EXPAND + free(exp); +# endif dot = bound_dot(dot); // make sure "dot" is valid return; # if ENABLE_FEATURE_VI_SEARCH |