From 1e35decffd9b5f9563337dd9b1b17cc0dcd1ebe6 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 2 Dec 2016 21:02:51 +0000 Subject: [PATCH] lib: make CLI completions less surprising * If a token matches exactly at the end of input, it still shows up in completions, e.g. ex# clear clear Reset functions ex(config)# ip route 1.2.3.4 A.B.C.D IP destination prefix A.B.C.D/M IP destination prefix (e.g. 10.0.0.0/8) * If a token in mid-line exactly matches one token and partially matches on one or more additional tokens, the command tree(s) under the partially matching tokens will be ignored in favor of the exact match when compiling completions for the full line, e.g. ex(config)# ip will only show completions for commands under 'ip' and not those under 'ipv6', which the input partially matches. Signed-off-by: Quentin Young --- lib/command_match.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/command_match.c b/lib/command_match.c index 25309654f3..f3f7d3998d 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -125,7 +125,7 @@ command_match (struct graph *cmdgraph, } if (!*el) { - trace_matcher ("No match"); + trace_matcher ("No match\n"); } else { trace_matcher ("Matched command\n->string %s\n->desc %s\n", (*el)->string, (*el)->doc); @@ -343,6 +343,13 @@ command_complete (struct graph *graph, input_token = vector_slot (vline, idx); + int exact_match_exists = 0; + for (ALL_LIST_ELEMENTS_RO (current,node,gn)) + if (!exact_match_exists) + exact_match_exists = (match_token (gn->data, input_token) == exact_match); + else + break; + for (ALL_LIST_ELEMENTS_RO (current,node,gn)) { struct cmd_token *token = gn->data; @@ -351,32 +358,28 @@ command_complete (struct graph *graph, continue; enum match_type minmatch = min_match_level (token->type); - trace_matcher ("\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type); + trace_matcher ("\"%s\" matches \"%s\" (%d) ? ", + input_token, token->text, token->type); + unsigned int last_token = (vector_active (vline) - 1 == idx); switch (match_token (token, input_token)) { + // occurs when last token is whitespace case trivial_match: trace_matcher ("trivial_match\n"); - assert(idx == vector_active (vline) - 1); + assert(last_token); listnode_add (next, gn); break; case partly_match: - trace_matcher ("partly_match\n"); - // last token on line is partial and - // not a space - if (idx == vector_active (vline) - 1) - { - listnode_add (next, gn); - break; - } - if (minmatch <= partly_match) - add_nexthops (next, gn); - - break; + trace_matcher ("trivial_match\n"); + if (exact_match_exists && !last_token) + break; case exact_match: trace_matcher ("exact_match\n"); - add_nexthops (next, gn); - listnode_add (next, gn); + if (last_token) + listnode_add (next, gn); + else + add_nexthops (next, gn); break; default: trace_matcher ("no_match\n"); -- 2.39.5