lineedit: fix tab-completion of filenames with spaces
Using ash in busybox git version dea28e1e, tab completion doesn't seem to work properly for filenames that have special characters (such as spaces) in them. For example, with filenames "foo bar" and "foo zap", typing "ls fo<TAB>" correctly expands to "ls foo\ ", but then continuing to type "b<TAB>" will produce "ls foo\ bbar", which is not correct (the 'b' is duplicated). Signed-off-by: Mike Shal <marfey@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
7c6ed78aaa
commit
f3763033e4
@ -584,6 +584,12 @@ static void input_forward(void)
|
||||
|
||||
#if ENABLE_FEATURE_TAB_COMPLETION
|
||||
|
||||
//FIXME:
|
||||
//needs to be more clever: currently it thinks that "foo\ b<TAB>
|
||||
//matches the file named "foo bar", which is untrue.
|
||||
//Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>,
|
||||
//not "foo bar <cursor>...
|
||||
|
||||
static void free_tab_completion_data(void)
|
||||
{
|
||||
if (matches) {
|
||||
@ -1015,13 +1021,18 @@ static void showfiles(void)
|
||||
}
|
||||
}
|
||||
|
||||
static char *add_quote_for_spec_chars(char *found)
|
||||
static const char *is_special_char(char c)
|
||||
{
|
||||
return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c);
|
||||
}
|
||||
|
||||
static char *quote_special_chars(char *found)
|
||||
{
|
||||
int l = 0;
|
||||
char *s = xzalloc((strlen(found) + 1) * 2);
|
||||
|
||||
while (*found) {
|
||||
if (strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", *found))
|
||||
if (is_special_char(*found))
|
||||
s[l++] = '\\';
|
||||
s[l++] = *found++;
|
||||
}
|
||||
@ -1085,19 +1096,30 @@ static NOINLINE void input_tab(smallint *lastWasTab)
|
||||
free_tab_completion_data();
|
||||
|
||||
# if ENABLE_FEATURE_USERNAME_COMPLETION
|
||||
/* If the word starts with `~' and there is no slash in the word,
|
||||
/* If the word starts with ~ and there is no slash in the word,
|
||||
* then try completing this word as a username. */
|
||||
if (state->flags & USERNAME_COMPLETION)
|
||||
if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL)
|
||||
match_pfx_len = complete_username(match_buf);
|
||||
# endif
|
||||
/* Try to match a command in $PATH, or a directory, or a file */
|
||||
/* If complete_username() did not match,
|
||||
* try to match a command in $PATH, or a directory, or a file */
|
||||
if (!matches)
|
||||
match_pfx_len = complete_cmd_dir_file(match_buf, find_type);
|
||||
|
||||
/* Account for backslashes which will be inserted
|
||||
* by quote_special_chars() later */
|
||||
{
|
||||
const char *e = match_buf + strlen(match_buf);
|
||||
const char *s = e - match_pfx_len;
|
||||
while (s < e)
|
||||
if (is_special_char(*s++))
|
||||
match_pfx_len++;
|
||||
}
|
||||
|
||||
/* Remove duplicates */
|
||||
if (matches) {
|
||||
unsigned i;
|
||||
unsigned n = 0;
|
||||
unsigned i, n = 0;
|
||||
qsort_string_vector(matches, num_matches);
|
||||
for (i = 0; i < num_matches - 1; ++i) {
|
||||
//if (matches[i] && matches[i+1]) { /* paranoia */
|
||||
@ -1112,6 +1134,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
|
||||
matches[n++] = matches[i];
|
||||
num_matches = n;
|
||||
}
|
||||
|
||||
/* Did we find exactly one match? */
|
||||
if (num_matches != 1) { /* no */
|
||||
char *cp;
|
||||
@ -1133,7 +1156,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
|
||||
goto ret; /* no */
|
||||
}
|
||||
*cp = '\0';
|
||||
cp = add_quote_for_spec_chars(chosen_match);
|
||||
cp = quote_special_chars(chosen_match);
|
||||
free(chosen_match);
|
||||
chosen_match = cp;
|
||||
len_found = strlen(chosen_match);
|
||||
@ -1141,7 +1164,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
|
||||
/* Next <tab> is not a double-tab */
|
||||
*lastWasTab = 0;
|
||||
|
||||
chosen_match = add_quote_for_spec_chars(matches[0]);
|
||||
chosen_match = quote_special_chars(matches[0]);
|
||||
len_found = strlen(chosen_match);
|
||||
if (chosen_match[len_found-1] != '/') {
|
||||
chosen_match[len_found] = ' ';
|
||||
|
Loading…
x
Reference in New Issue
Block a user