Skip site navigation (1)Skip section navigation (2)
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>