Skip to content

[Nexthop][fboss2-dev] bash completion for leaf attribute tokens - #1689

Open
benoit-nexthop wants to merge 1 commit into
meta:mainfrom
nexthop-ai:fboss2-bash-completion
Open

benoit-nexthop wants to merge 1 commit into
meta:mainfrom
nexthop-ai:fboss2-bash-completion

Conversation

@benoit-nexthop

@benoit-nexthop benoit-nexthop commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

FBOSS tab completion (fboss2 __completion) only walks the CLI11
sub-command tree, so it stops at config arp and cannot offer timeout,
max-probes, ...: the config/delete commands keep the last level of
tokens in a list inside one handler rather than as one .cpp/.h per leaf,
to avoid code bloat.

This gives commands a uniform way to complete those tokens:

  • A Traits may declare
    static std::vector<std::string> completeArgs(const std::vector<std::string>& typed)
    returning the tokens that may follow the positionals typed so far.
    argRegistrar<Traits> (now a struct carrying both addCliArg and the
    optional completer) picks it up, and CmdSubcommands remembers it per
    CLI11 command. No command-tree entries change; a Traits without
    completeArgs simply gets no leaf completion.
  • utils/ArgCompletion.h holds the three grammars that recur across the
    tree so nearly every command is a one-liner: completeAttrGrammar for
    [<object>...] <attr> <value> ... (per-attr enum values, valueless
    attrs, multi-word attrs such as timers hold-time, used attrs not
    offered again), completeAttrList for the delete-side <attr> [<attr>...]
    and completePositions for fixed positional grammars.
  • CmdCompletion.cpp walks the CLI11 tree along the typed words (skipping
    options and their values), then offers sub-commands, the completer's
    candidates, or option names when the word starts with '-'. Sub-commands
    are not offered while an attribute's value is being completed, and
    nothing is offered while an option's value is under the cursor.
  • completeArgs added to every config/delete command with a static
    vocabulary (arp, interface and its sub-commands, load-balancing, copp,
    traffic-policy, acl, tunnel, qos, bgp, static routes, l2, ptp, vlan
    tagging, dhcp, srv6). Free-form-only commands (names, ids, prefixes)
    opt out by not declaring it.
  • The bash script now passes the word under the cursor, completes
    fboss2-dev as well as fboss2, and asks the binary being completed.
    package.py ships it under share/bash-completion and setup_fboss_env
    sources it in interactive shells (before its idempotency guard, since
    completion specs are not inherited by child shells; bash-completion's
    lazy loader would not look under /opt/fboss anyway). The image now also
    bundles the bash-completion package.

Test Plan

Unit tests: ArgCompletionTest covers the three grammars; CmdCompletionTest
completes against the real fboss2-dev command trees (it lives in cmd_test,
which links the config command tree).

fboss2_framework_test
[  PASSED  ] 42 tests.
fboss2_cmd_test --gtest_filter='CmdCompletionTest.*:CmdListConfigTest.*'
[  PASSED  ] 9 tests.
fboss2_cmd_config_test
[  PASSED  ] 1162 tests.

On an NH-4010-F test switch, installed the new fboss2-dev, the completion
script under /opt/fboss/share/bash-completion/completions/fboss2 and the
new setup_fboss_env, then checked that a login shell registers the
completions:

$ bash -lic 'complete -p fboss2-dev fboss2'
complete -F _fboss2_complete fboss2-dev
complete -F _fboss2_complete fboss2

and pressed TAB in an interactive shell for a range of command lines.

Sample outputs

Captured from an interactive bash login shell on the
switch (80 columns, <TAB> marks where TAB was pressed). Leaf attributes,
attribute values, two-word BGP attributes and options all complete; a
single match is filled in directly:

$ fboss2-dev config arp <TAB>
age-interval    max-probes      stale-interval  timeout

$ fboss2-dev config arp ti<TAB>
$ fboss2-dev config arp timeout

$ fboss2-dev config arp timeout 30 <TAB>
age-interval    max-probes      stale-interval

$ fboss2-dev config interface eth1/1/1 <TAB>
description                lookup-class
dhcp                       loopback-mode
flow-control-rx            mtu
flow-control-tx            name
ip-address                 no-shutdown
ipv6                       pfc-config
ipv6-address               profile
lldp-expected-chassis      queue-config
lldp-expected-port-desc    sflow
lldp-expected-system-desc  shutdown
lldp-expected-system-name  switchport
lldp-expected-ttl          type
lldp-expected-value

$ fboss2-dev config interface eth1/1/1 loopback-mode <TAB>
MAC   NIF   none  PHY

$ fboss2-dev config interface eth1/1/1 sflow sample-dest <TAB>
cpu     mirror

$ fboss2-dev config copp reason <TAB>
arp                 eapol               mpls-unknown-label
arp-response        host-miss           ndp
bgp                 l3-dest-miss        port-mtu-error
bgpv6               l3-mtu-error        samplepacket
bpdu                l3-slow-path        ttl-0
cpu-is-nhop         lacp                ttl-1
dhcp                lldp                unmatched
dhcpv6              mpls-ttl-1

$ fboss2-dev config copp queue 1 scheduling <TAB>
DEFICIT_ROUND_ROBIN   SP                    WRR
DRR                   STRICT_PRIORITY
INTERNAL              WEIGHTED_ROUND_ROBIN

$ fboss2-dev config protocol bgp neighbor 1.2.3.4 timers <TAB>
hold-time              out-delay
keepalive              withdraw-unprog-delay

$ fboss2-dev show interface --<TAB>
--agent-port       --detail           --fsdb-port        --qsfp-port
--aggregate        --file             --help
--aggregate-hosts  --filter           --host
--color            --fmt              --loglevel

@benoit-nexthop

Copy link
Copy Markdown
Contributor Author

/autorebase

Summary:

FBOSS tab completion (`fboss2 __completion`) only walks the CLI11
sub-command tree, so it stops at `config arp` and cannot offer `timeout`,
`max-probes`, ...: the config/delete commands keep the last level of
tokens in a list inside one handler rather than as one .cpp/.h per leaf,
to avoid code bloat.

This gives commands a uniform way to complete those tokens:

- A Traits may declare
  `static std::vector<std::string> completeArgs(const std::vector<std::string>& typed)`
  returning the tokens that may follow the positionals typed so far.
  `argRegistrar<Traits>` (now a struct carrying both addCliArg and the
  optional completer) picks it up, and CmdSubcommands remembers it per
  CLI11 command. No command-tree entries change; a Traits without
  completeArgs simply gets no leaf completion.
- utils/ArgCompletion.h holds the three grammars that recur across the
  tree so nearly every command is a one-liner: completeAttrGrammar for
  `[<object>...] <attr> <value> ...` (per-attr enum values, valueless
  attrs, multi-word attrs such as `timers hold-time`, used attrs not
  offered again), completeAttrList for the delete-side `<attr> [<attr>...]`
  and completePositions for fixed positional grammars.
- CmdCompletion.cpp walks the CLI11 tree along the typed words (skipping
  options and their values), then offers sub-commands, the completer's
  candidates, or option names when the word starts with '-'. Sub-commands
  are not offered while an attribute's value is being completed, and
  nothing is offered while an option's value is under the cursor.
- completeArgs added to every config/delete command with a static
  vocabulary (arp, interface and its sub-commands, load-balancing, copp,
  traffic-policy, acl, tunnel, qos, bgp, static routes, l2, ptp, vlan
  tagging, dhcp, srv6). Free-form-only commands (names, ids, prefixes)
  opt out by not declaring it.
- The bash script now passes the word under the cursor, completes
  fboss2-dev as well as fboss2, and asks the binary being completed.
  package.py ships it under share/bash-completion and setup_fboss_env
  sources it in interactive shells (before its idempotency guard, since
  completion specs are not inherited by child shells; bash-completion's
  lazy loader would not look under /opt/fboss anyway). The image now also
  bundles the bash-completion package.

Test Plan:

Unit tests: ArgCompletionTest covers the three grammars; CmdCompletionTest
completes against the real fboss2-dev command trees (it lives in cmd_test,
which links the config command tree).

    fboss2_framework_test
    [  PASSED  ] 42 tests.
    fboss2_cmd_test --gtest_filter='CmdCompletionTest.*:CmdListConfigTest.*'
    [  PASSED  ] 9 tests.
    fboss2_cmd_config_test
    [  PASSED  ] 1162 tests.

On an NH-4010-F test switch, installed the new fboss2-dev, the completion
script under /opt/fboss/share/bash-completion/completions/fboss2 and the
new setup_fboss_env, then checked that a login shell registers the
completions:

    $ bash -lic 'complete -p fboss2-dev fboss2'
    complete -F _fboss2_complete fboss2-dev
    complete -F _fboss2_complete fboss2

and pressed TAB in an interactive shell for a range of command lines.

Sample outputs, captured from an interactive bash login shell on the
switch (80 columns, `<TAB>` marks where TAB was pressed). Leaf attributes,
attribute values, two-word BGP attributes and options all complete; a
single match is filled in directly:

    $ fboss2-dev config arp <TAB>
    age-interval    max-probes      stale-interval  timeout

    $ fboss2-dev config arp ti<TAB>
    $ fboss2-dev config arp timeout

    $ fboss2-dev config arp timeout 30 <TAB>
    age-interval    max-probes      stale-interval

    $ fboss2-dev config interface eth1/1/1 <TAB>
    description                lookup-class
    dhcp                       loopback-mode
    flow-control-rx            mtu
    flow-control-tx            name
    ip-address                 no-shutdown
    ipv6                       pfc-config
    ipv6-address               profile
    lldp-expected-chassis      queue-config
    lldp-expected-port-desc    sflow
    lldp-expected-system-desc  shutdown
    lldp-expected-system-name  switchport
    lldp-expected-ttl          type
    lldp-expected-value

    $ fboss2-dev config interface eth1/1/1 loopback-mode <TAB>
    MAC   NIF   none  PHY

    $ fboss2-dev config interface eth1/1/1 sflow sample-dest <TAB>
    cpu     mirror

    $ fboss2-dev config copp reason <TAB>
    arp                 eapol               mpls-unknown-label
    arp-response        host-miss           ndp
    bgp                 l3-dest-miss        port-mtu-error
    bgpv6               l3-mtu-error        samplepacket
    bpdu                l3-slow-path        ttl-0
    cpu-is-nhop         lacp                ttl-1
    dhcp                lldp                unmatched
    dhcpv6              mpls-ttl-1

    $ fboss2-dev config copp queue 1 scheduling <TAB>
    DEFICIT_ROUND_ROBIN   SP                    WRR
    DRR                   STRICT_PRIORITY
    INTERNAL              WEIGHTED_ROUND_ROBIN

    $ fboss2-dev config protocol bgp neighbor 1.2.3.4 timers <TAB>
    hold-time              out-delay
    keepalive              withdraw-unprog-delay

    $ fboss2-dev show interface --<TAB>
    --agent-port       --detail           --fsdb-port        --qsfp-port
    --aggregate        --file             --help
    --aggregate-hosts  --filter           --host
    --color            --fmt              --loglevel

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant