]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cli: improve fuzzy matching to work on all remaining words at once
authorWilly Tarreau <w@1wt.eu>
Mon, 15 Mar 2021 09:00:29 +0000 (10:00 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 15 Mar 2021 09:33:45 +0000 (10:33 +0100)
Till now the fuzzy matching would only work on the same number of words,
but this doesn't account for commands like "show servers conn" which
involve 3 words and were not proposed when entering only "show conn".
Let's improve the situation by building the two fingerprints separately
for the correct keyword sequence and the entered one, then compare them.
This can result in slightly larger variations due to the different string
lengths but is easily compensated for. Thanks to this, we can now see
"show servers conn" when entering "show conn", and the following choices
are relevant to correct typos:

- "show foo"
   show sess [id] : report the list of current sessions or dump this session
   show info      : report information about the running process [desc|json|typed]*
   show env [var] : dump environment variables known to the process
   show fd [num] : dump list of file descriptors in use
   show pools     : report information about the memory pools usage

- "show stuff"
   show sess [id] : report the list of current sessions or dump this session
   show info      : report information about the running process [desc|json|typed]*
   show stat      : report counters for each proxy and server [desc|json|no-maint|typed|up]*
   show fd [num] : dump list of file descriptors in use
   show tasks     : show running tasks

- "show stafe"
   show sess [id] : report the list of current sessions or dump this session
   show stat      : report counters for each proxy and server [desc|json|no-maint|typed|up]*
   show fd [num] : dump list of file descriptors in use
   show table [id]: report table usage stats or dump this table's contents
   show tasks     : show running tasks

- "show state"
   show stat      : report counters for each proxy and server [desc|json|no-maint|typed|up]*
   show servers state [id]: dump volatile server information (for backend <id>)

It's still visible that the shorter ones continue to easily match, such
as "show sess" not having much in common with "show foo" but what matters
is that the best candidates are definitely relevant. Probably that listing
them in match order would further help.

src/cli.c

index cfe14d6852ed81f889e0981c23c60bf6ec4f34e2..010655ac67ed54573f0e86e19d05f7333b02a14c 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -164,26 +164,32 @@ static char *cli_gen_usage_msg(struct appctx *appctx, char * const *args)
                                        uint8_t list_sig[1024];
                                        int dist = 0;
                                        int totlen = 0;
+                                       int i;
 
                                        /* this one matches, let's compute the distance between the two
-                                        * on the remaining words
+                                        * on the remaining words. For this we're computing the signature
+                                        * of everything that remains and the cumulated length of the
+                                        * strings.
                                         */
                                        memset(word_sig, 0, sizeof(word_sig));
-                                       memset(list_sig, 0, sizeof(list_sig));
+                                       for (i = idx; i < CLI_PREFIX_KW_NB && args[i] && *args[i]; i++) {
+                                               update_word_fingerprint(word_sig, args[i]);
+                                               totlen += strlen(args[i]);
+                                       }
 
-                                       while (idx < CLI_PREFIX_KW_NB && kw->str_kw[idx] && args[idx] && *args[idx]) {
-                                               update_word_fingerprint(word_sig, args[idx]);
-                                               update_word_fingerprint(list_sig, kw->str_kw[idx]);
-                                               totlen += strlen(args[idx]) + strlen(kw->str_kw[idx]);
-                                               idx++;
+                                       memset(list_sig, 0, sizeof(list_sig));
+                                       for (i = idx; i < CLI_PREFIX_KW_NB && kw->str_kw[i]; i++) {
+                                               update_word_fingerprint(list_sig, kw->str_kw[i]);
+                                               totlen += strlen(kw->str_kw[i]);
                                        }
+
                                        dist = word_fingerprint_distance(word_sig, list_sig);
 
                                        /* insert this one at its place if relevant, in order to keep only
                                         * the best matches.
                                         */
                                        swp.kw = kw; swp.dist = dist;
-                                       if (dist < totlen && dist < matches[CLI_MAX_MATCHES-1].dist) {
+                                       if (dist < 5*totlen/2 && dist < matches[CLI_MAX_MATCHES-1].dist) {
                                                matches[CLI_MAX_MATCHES-1] = swp;
                                                for (idx = CLI_MAX_MATCHES - 1; --idx >= 0;) {
                                                        if (matches[idx+1].dist >= matches[idx].dist)
@@ -229,7 +235,7 @@ static char *cli_gen_usage_msg(struct appctx *appctx, char * const *args)
                                 * idx will be CLI_MAX_MATCHES, indicating "not found".
                                 */
                                for (idx = 0; matches[0].kw && idx < CLI_MAX_MATCHES; idx++)
-                                       if (kw == matches[idx].kw && matches[idx].dist <= 2*matches[0].dist)
+                                       if (kw == matches[idx].kw && matches[idx].dist <= 5*matches[0].dist/2)
                                                break;
 
                                if (idx < CLI_MAX_MATCHES)