diff options
| author | Jilles Tjoelker <jilles@FreeBSD.org> | 2010-06-15 21:34:57 +0000 | 
|---|---|---|
| committer | Jilles Tjoelker <jilles@FreeBSD.org> | 2010-06-15 21:34:57 +0000 | 
| commit | 3d0f8bcd307dfefacba6d1ec6875b235d08ea16b (patch) | |
| tree | a84dac06f08aa076cd8d1ae683ae34e3228efa78 /lib/libedit/filecomplete.c | |
| parent | 0dee704f01aa2190b429ee039c680391f8ffe061 (diff) | |
Notes
Diffstat (limited to 'lib/libedit/filecomplete.c')
| -rw-r--r-- | lib/libedit/filecomplete.c | 143 | 
1 files changed, 133 insertions, 10 deletions
diff --git a/lib/libedit/filecomplete.c b/lib/libedit/filecomplete.c index ce0db10004c9..97ba2d0c02cb 100644 --- a/lib/libedit/filecomplete.c +++ b/lib/libedit/filecomplete.c @@ -52,6 +52,8 @@ __FBSDID("$FreeBSD$");  static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@',      '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; +/* Tilde is deliberately omitted here, we treat it specially. */ +static char extra_quote_chars[] = { ')', '}', '\0' };  /********************************/ @@ -380,10 +382,14 @@ fn_complete(EditLine *el,  	char **(*attempted_completion_function)(const char *, int, int),  	const char *word_break, const char *special_prefixes,  	const char *(*app_func)(const char *), size_t query_items, -	int *completion_type, int *over, int *point, int *end) +	int *completion_type, int *over, int *point, int *end, +	const char *(*find_word_start_func)(const char *, const char *), +	char *(*dequoting_func)(const char *), +	char *(*quoting_func)(const char *))  {  	const LineInfo *li;  	char *temp; +	char *dequoted_temp;  	char **matches;  	const char *ctemp;  	size_t len; @@ -404,11 +410,15 @@ fn_complete(EditLine *el,  	/* We now look backwards for the start of a filename/variable word */  	li = el_line(el); -	ctemp = li->cursor; -	while (ctemp > li->buffer -	    && !strchr(word_break, ctemp[-1]) -	    && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) -		ctemp--; +	if (find_word_start_func) +		ctemp = find_word_start_func(li->buffer, li->cursor); +	else { +		ctemp = li->cursor; +		while (ctemp > li->buffer +		    && !strchr(word_break, ctemp[-1]) +		    && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) +			ctemp--; +	}  	len = li->cursor - ctemp;  #if defined(__SSP__) || defined(__SSP_ALL__) @@ -421,6 +431,13 @@ fn_complete(EditLine *el,  	(void)strncpy(temp, ctemp, len);  	temp[len] = '\0'; +	if (dequoting_func) { +		dequoted_temp = dequoting_func(temp); +		if (dequoted_temp == NULL) +			return retval; +	} else +		dequoted_temp = NULL; +  	/* these can be used by function called in completion_matches() */  	/* or (*attempted_completion_function)() */  	if (point != 0) @@ -430,13 +447,13 @@ fn_complete(EditLine *el,  	if (attempted_completion_function) {  		int cur_off = (int)(li->cursor - li->buffer); -		matches = (*attempted_completion_function) (temp, +		matches = (*attempted_completion_function) (dequoted_temp ? dequoted_temp : temp,  		    (int)(cur_off - len), cur_off);  	} else  		matches = 0;  	if (!attempted_completion_function ||   	    (over != NULL && !*over && !matches)) -		matches = completion_matches(temp, complet_func); +		matches = completion_matches(dequoted_temp ? dequoted_temp : temp, complet_func);  	if (over != NULL)  		*over = 0; @@ -451,8 +468,18 @@ fn_complete(EditLine *el,  		 * possible matches if there is possible completion.  		 */  		if (matches[0][0] != '\0') { +			char *quoted_match; +			if (quoting_func) { +				quoted_match = quoting_func(matches[0]); +				if (quoted_match == NULL) +					goto free_matches; +			} else +				quoted_match = NULL; +  			el_deletestr(el, (int) len); -			el_insertstr(el, matches[0]); +			el_insertstr(el, quoted_match ? quoted_match : matches[0]); + +			free(quoted_match);  		}  		if (what_to_do == '?') @@ -514,12 +541,14 @@ fn_complete(EditLine *el,  			retval = CC_NORM;  		} +free_matches:  		/* free elements of array and the array itself */  		for (i = 0; matches[i]; i++)  			free(matches[i]);  		free(matches);  		matches = NULL;  	} +	free(dequoted_temp);  #if defined(__SSP__) || defined(__SSP_ALL__)  	free(temp);  #endif @@ -536,5 +565,99 @@ _el_fn_complete(EditLine *el, int ch __attribute__((__unused__)))  {  	return (unsigned char)fn_complete(el, NULL, NULL,  	    break_chars, NULL, NULL, 100, -	    NULL, NULL, NULL, NULL); +	    NULL, NULL, NULL, NULL, +	    NULL, NULL, NULL); +} + + +static const char * +sh_find_word_start(const char *buffer, const char *cursor) +{ +	const char *word_start = buffer; + +	while (buffer < cursor) { +		if (*buffer == '\\') +			buffer++; +		else if (strchr(break_chars, *buffer)) +			word_start = buffer + 1; + +		buffer++; +	} + +	return word_start; +} + + +static char * +sh_quote(const char *str) +{ +	const char *src; +	int extra_len = 0; +	char *quoted_str, *dst; + +	for (src = str; *src != '\0'; src++) +		if (strchr(break_chars, *src) || +		    strchr(extra_quote_chars, *src)) +			extra_len++; + +	quoted_str = malloc(sizeof(*quoted_str) * +	    (strlen(str) + extra_len + 1)); +	if (quoted_str == NULL) +		return NULL; + +	dst = quoted_str; +	for (src = str; *src != '\0'; src++) { +		if (strchr(break_chars, *src) || +		    strchr(extra_quote_chars, *src)) +			*dst++ = '\\'; +		*dst++ = *src; +	} +	*dst = '\0'; + +	return quoted_str; +} + + +static char * +sh_dequote(const char *str) +{ +	char *dequoted_str, *dst; + +	/* save extra space to replace \~ with ./~ */ +	dequoted_str = malloc(sizeof(*dequoted_str) * (strlen(str) + 1 + 1)); +	if (dequoted_str == NULL) +		return NULL; + +	dst = dequoted_str; + +	/* dequote \~ at start as ./~ */ +	if (*str == '\\' && str[1] == '~') { +		str++; +		*dst++ = '.'; +		*dst++ = '/'; +	} + +	while (*str) { +		if (*str == '\\') +			str++; +		if (*str) +			*dst++ = *str++; +	} +	*dst = '\0'; + +	return dequoted_str; +} + + +/* + * completion function using sh quoting rules; for key binding + */ +/* ARGSUSED */ +unsigned char +_el_fn_sh_complete(EditLine *el, int ch __attribute__((__unused__))) +{ +	return (unsigned char)fn_complete(el, NULL, NULL, +	    break_chars, NULL, NULL, 100, +	    NULL, NULL, NULL, NULL, +	    sh_find_word_start, sh_dequote, sh_quote);  }  | 
