aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiotr Pawel Stefaniak <pstef@FreeBSD.org>2021-09-18 11:26:51 +0000
committerPiotr Pawel Stefaniak <pstef@FreeBSD.org>2021-09-19 11:51:45 +0000
commitb8ff849cbddfee3404d6550cf98f53d6bb617707 (patch)
tree1a9d37bb07c1e03c938666333a722a8dabf2ce43
parente19d93b19dce276bdf178bb6a449728238d1c6f8 (diff)
downloadsrc-b8ff849cbddfee3404d6550cf98f53d6bb617707.tar.gz
src-b8ff849cbddfee3404d6550cf98f53d6bb617707.zip
sh: improve command completion
When multiple matches are found, we keep the provided string on the input line and print unique matches as suggestions. But the multiple matches might be the same command found in different directories, so we should deduplicate the matches first and then decide whether to autocomplete the command or not, based on the number of unique matches.
-rw-r--r--bin/sh/histedit.c40
1 files changed, 19 insertions, 21 deletions
diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c
index b680a99c4ace..1a1e11e6f885 100644
--- a/bin/sh/histedit.c
+++ b/bin/sh/histedit.c
@@ -590,7 +590,7 @@ static char
char *free_path = NULL, *path;
const char *dirname;
char **matches = NULL;
- size_t i = 0, size = 16, j, k;
+ size_t i = 0, size = 16, uniq;
size_t curpos = end - start;
if (start > 0 || memchr("/.~", text[0], 3) != NULL)
@@ -639,6 +639,21 @@ static char
}
out:
free(free_path);
+ if (i == 0) {
+ free(matches);
+ return (NULL);
+ }
+ uniq = 1;
+ if (i > 1) {
+ qsort_s(matches + 1, i, sizeof(matches[0]), comparator,
+ (void *)(intptr_t)curpos);
+ for (size_t k = 2; k <= i; k++)
+ if (strcmp(matches[uniq] + curpos, matches[k] + curpos) == 0)
+ free(matches[k]);
+ else
+ matches[++uniq] = matches[k];
+ }
+ matches[uniq + 1] = NULL;
/*
* matches[0] is special: it's not a real matching file name but a common
* prefix for all matching names. It can't be null, unlike any other
@@ -648,30 +663,13 @@ out:
* string in matches[0] which is the reason to copy the full name of the
* only match.
*/
- if (i == 0) {
- free(matches);
- return (NULL);
- } else if (i == 1) {
- matches[0] = strdup(matches[1]);
- matches[2] = NULL;
- if (matches[0] != NULL)
- return (matches);
- } else
- matches[0] = strdup(text);
+ matches[0] = strdup(uniq == 1 ? matches[1] : text);
if (matches[0] == NULL) {
- for (j = 1; j <= i; j++)
- free(matches[j]);
+ for (size_t k = 1; k <= uniq; k++)
+ free(matches[k]);
free(matches);
return (NULL);
}
- qsort_s(matches + 1, i, sizeof(matches[0]), comparator,
- (void *)(intptr_t)curpos);
- for (j = 1, k = 2; k <= i; k++)
- if (strcmp(matches[j] + curpos, matches[k] + curpos) == 0)
- free(matches[k]);
- else
- matches[++j] = matches[k];
- matches[j + 1] = NULL;
return (matches);
}