Client: Add support for completion of command options

We can easily extend command completion to handle also keywords for
command options. Help for command options is not yet supported.
This commit is contained in:
Ondrej Zajicek 2024-03-05 19:04:10 +01:00
parent 114be2af28
commit 1b064355f7
7 changed files with 78 additions and 9 deletions

View File

@ -20,6 +20,7 @@ struct cmd_info {
char *args;
char *help;
int is_real_cmd;
int is_option;
};
static struct cmd_info command_table[] = {
@ -30,7 +31,8 @@ struct cmd_node {
struct cmd_node *sibling, *son, **plastson;
struct cmd_info *cmd, *help;
int len;
signed char prio;
u8 final;
s8 prio;
char token[1];
};
@ -51,12 +53,13 @@ cmd_build_tree(void)
struct cmd_node *old, *new;
char *c = cmd->command;
old = &cmd_root;
new = &cmd_root;
while (*c)
{
char *d = c;
while (*c && !isspace_(*c))
c++;
old = new;
for(new=old->son; new; new=new->sibling)
if (new->len == c-d && !memcmp(new->token, d, c-d))
break;
@ -72,14 +75,17 @@ cmd_build_tree(void)
memcpy(new->token, d, c-d);
new->prio = (new->len == 3 && (!memcmp(new->token, "roa", 3) || !memcmp(new->token, "rip", 3))) ? 0 : 1; /* Hack */
}
old = new;
while (isspace_(*c))
c++;
}
if (cmd->is_real_cmd)
old->cmd = cmd;
new->cmd = cmd;
else
old->help = cmd;
new->help = cmd;
if (cmd->is_option)
old->final = 1;
}
}
@ -147,7 +153,7 @@ cmd_help(char *cmd, int len)
int ambig;
n = &cmd_root;
while (cmd < end)
while (cmd < end && !n->final)
{
if (isspace_(*cmd))
{
@ -168,6 +174,11 @@ cmd_help(char *cmd, int len)
n = m;
}
cmd_display_help(n->cmd, NULL);
/* Currently no help for options */
if (n->final)
return;
for (m=n->son; m; m=m->sibling)
cmd_display_help(m->help, m->cmd);
}
@ -229,7 +240,7 @@ cmd_complete(char *cmd, int len, char *buf, int again)
/* Find the context */
n = &cmd_root;
while (cmd < fin && n->son)
while (cmd < fin && n->son && !n->final)
{
if (isspace_(*cmd))
{
@ -290,7 +301,7 @@ cmd_expand(char *cmd)
args = c = cmd;
n = &cmd_root;
while (*c)
while (*c && !n->final)
{
if (isspace_(*c))
{

View File

@ -13,6 +13,9 @@ m4_divert(-1)')
m4_define(CF_CLI_CMD, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1 },
m4_divert(-1)')
m4_define(CF_CLI_OPT, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1, .is_option = 1 },
m4_divert(-1)')
m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
m4_divert(-1)')

View File

@ -48,6 +48,7 @@ m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
m4_divert(3)cli_cmd: CF_cmd
CF_cmd: $1 $2 END')
m4_define(CF_CLI_CMD, `')
m4_define(CF_CLI_OPT, `')
m4_define(CF_CLI_HELP, `')
# ENUM declarations are ignored

View File

@ -650,6 +650,23 @@ CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]])
CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>|in <prefix>] [table <t>] [(import|export) table <p>.<c>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport|noexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]])
{ rt_show($3); } ;
CF_CLI_OPT(SHOW ROUTE FOR, <ip>|<prefix>)
CF_CLI_OPT(SHOW ROUTE IN, <prefix>)
CF_CLI_OPT(SHOW ROUTE TABLE, <t>)
CF_CLI_OPT(SHOW ROUTE FILTER, <f>)
CF_CLI_OPT(SHOW ROUTE WHERE, <cond>)
CF_CLI_OPT(SHOW ROUTE ALL)
CF_CLI_OPT(SHOW ROUTE PRIMARY)
CF_CLI_OPT(SHOW ROUTE FILTERED)
CF_CLI_OPT(SHOW ROUTE IMPORT, <p>[.<c>])
CF_CLI_OPT(SHOW ROUTE EXPORT, <p>[.<c>])
CF_CLI_OPT(SHOW ROUTE EXPORTED, <p>[.<c>])
CF_CLI_OPT(SHOW ROUTE PREEXPORT, <p>[.<c>])
CF_CLI_OPT(SHOW ROUTE NOEXPORT, <p>[.<c>])
CF_CLI_OPT(SHOW ROUTE PROTOCOL, <p>)
CF_CLI_OPT(SHOW ROUTE STATS)
CF_CLI_OPT(SHOW ROUTE COUNT)
r_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct rt_show_data));
@ -841,13 +858,19 @@ CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
{ cmd_show_symbols($3); } ;
CF_CLI_OPT(SHOW SYMBOLS TABLE)
CF_CLI_OPT(SHOW SYMBOLS FILTER)
CF_CLI_OPT(SHOW SYMBOLS FUNCTION)
CF_CLI_OPT(SHOW SYMBOLS PROTOCOL)
CF_CLI_OPT(SHOW SYMBOLS TEMPLATE)
sym_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct sym_show_data));
}
| sym_args TABLE { $$ = $1; $$->type = SYM_TABLE; }
| sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
| sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
| sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
| sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
| sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
| sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; }
@ -914,6 +937,15 @@ CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
CF_CLI(DEBUG, debug_args, (<protocol> | <channel> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
{ /* Done in debug_args */ };
CF_CLI_OPT(DEBUG ALL)
CF_CLI_OPT(DEBUG OFF)
CF_CLI_OPT(DEBUG STATES)
CF_CLI_OPT(DEBUG ROUTES)
CF_CLI_OPT(DEBUG FILTERS)
CF_CLI_OPT(DEBUG INTERFACES)
CF_CLI_OPT(DEBUG EVENTS)
CF_CLI_OPT(DEBUG PACKETS)
debug_args:
proto_patt debug_mask { proto_apply_cmd($1, proto_cmd_debug, 1, $2); }
| channel_arg debug_mask { channel_cmd_debug($1, $2); }

View File

@ -189,6 +189,15 @@ CF_CLI_HELP(SHOW BFD SESSIONS, ..., [[Show information about BFD sessions]]);
CF_CLI(SHOW BFD SESSIONS, bfd_show_sessions_args, [<name>] [address <ip|prefix>] [(interface|dev) \"<name>\"] [ipv4|ipv6] [direct|multihop] [all], [[Show information about BFD sessions]])
{ PROTO_WALK_CMD($4->name, &proto_bfd, p) bfd_show_sessions(p, $4); };
CF_CLI_OPT(SHOW BFD SESSIONS ADDRESS, <ip>|<prefix>)
CF_CLI_OPT(SHOW BFD SESSIONS INTERFACE, \"<name>\")
CF_CLI_OPT(SHOW BFD SESSIONS DEV, \"<name>\")
CF_CLI_OPT(SHOW BFD SESSIONS ALL)
CF_CLI_OPT(SHOW BFD SESSIONS IPV4)
CF_CLI_OPT(SHOW BFD SESSIONS IPV6)
CF_CLI_OPT(SHOW BFD SESSIONS DIRECT)
CF_CLI_OPT(SHOW BFD SESSIONS MULTIHOP)
bfd_show_sessions_args:
/* empty */ { $$ = cfg_allocz(sizeof(struct bfd_show_sessions_cmd)); }
| bfd_show_sessions_args CF_SYM_KNOWN { cf_assert_symbol($2, SYM_PROTO); $$->name = $2; }

View File

@ -53,6 +53,11 @@ CF_CLI_HELP(MRT DUMP, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filt
CF_CLI(MRT DUMP, mrt_dump_args, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>], [[Save mrt table dump v2 of table name <t> right now]])
{ mrt_dump_cmd($3); } ;
CF_CLI_OPT(MRT DUMP TABLE, <name>|\"<pattern>\")
CF_CLI_OPT(MRT DUMP TO, \"<file>\")
CF_CLI_OPT(MRT DUMP FILTER, <filter>)
CF_CLI_OPT(MRT DUMP WHERE, <where filter>)
mrt_dump_args:
/* empty */ { $$ = cfg_allocz(sizeof(struct mrt_dump_data)); }
| mrt_dump_args TABLE rtable { $$ = $1; $$->table_ptr = $3->table; }

View File

@ -546,6 +546,14 @@ CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [ls
ospf_sh_lsadb($4);
};
CF_CLI_OPT(SHOW OSPF LSADB GLOBAL)
CF_CLI_OPT(SHOW OSPF LSADB AREA, <id>)
CF_CLI_OPT(SHOW OSPF LSADB LINK)
CF_CLI_OPT(SHOW OSPF LSADB TYPE, <num>)
CF_CLI_OPT(SHOW OSPF LSADB LSID, <id>)
CF_CLI_OPT(SHOW OSPF LSADB SELF)
CF_CLI_OPT(SHOW OSPF LSADB ROUTER, <id>)
lsadb_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct lsadb_show_data));