Date: Wed, 22 Sep 2021 20:25:40 GMT From: Piotr Pawel Stefaniak <pstef@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: c866d0c798a2 - main - sh: improve command completion Message-ID: <202109222025.18MKPe1i098592@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by pstef: URL: https://cgit.FreeBSD.org/src/commit/?id=c866d0c798a20b8f0a92df524f4ddd0d81511c88 commit c866d0c798a20b8f0a92df524f4ddd0d81511c88 Author: Piotr Pawel Stefaniak <pstef@FreeBSD.org> AuthorDate: 2021-09-22 16:23:29 +0000 Commit: Piotr Pawel Stefaniak <pstef@FreeBSD.org> CommitDate: 2021-09-22 20:23:32 +0000 sh: improve command completion When there are many matches, find the longest common substring starting from the beginning of each command and use that to replace input. As an example: on my system, llv<tab> will be autocompleted to llvm- and another <tab> will print all matching llvm commands. --- bin/sh/histedit.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c index 37b62cef5746..4e82f7497850 100644 --- a/bin/sh/histedit.c +++ b/bin/sh/histedit.c @@ -596,7 +596,7 @@ static char const char *dirname; char **matches = NULL; size_t i = 0, size = 16, uniq; - size_t curpos = end - start; + size_t curpos = end - start, lcstring = -1; if (start > 0 || memchr("/.~", text[0], 3) != NULL) return (NULL); @@ -652,11 +652,20 @@ out: 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) + for (size_t k = 2; k <= i; k++) { + const char *l = matches[uniq] + curpos; + const char *r = matches[k] + curpos; + size_t common = 0; + + while (*l != '\0' && *r != '\0' && *l == *r) + (void)l++, r++, common++; + if (common < lcstring) + lcstring = common; + if (*l == *r) free(matches[k]); else matches[++uniq] = matches[k]; + } } matches[uniq + 1] = NULL; /* @@ -668,7 +677,12 @@ out: * string in matches[0] which is the reason to copy the full name of the * only match. */ - matches[0] = strdup(uniq == 1 ? matches[1] : text); + if (uniq == 1) + matches[0] = strdup(matches[1]); + else if (lcstring != (size_t)-1) + matches[0] = strndup(matches[1], curpos + lcstring); + else + matches[0] = strdup(text); if (matches[0] == NULL) { for (size_t k = 1; k <= uniq; k++) free(matches[k]);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109222025.18MKPe1i098592>