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>
This commit is contained in:
		
				
					committed by
					
						 Denys Vlasenko
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							852ffbee34
						
					
				
				
					commit
					acd3079fd1
				
			
							
								
								
									
										126
									
								
								editors/vi.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user