veks-completion 0.12.0

Dynamic shell completion engine for CLI tools
Documentation

veks-completion

Dynamic shell completion engine for the veks CLI.

Why not clap's built-in completion?

Clap provides clap_complete for generating static shell completion scripts. It works well for simple CLIs with a fixed command tree, but it breaks down for veks for several reasons:

1. Dynamic pipeline commands

Veks has a pipeline command group whose subcommands are registered at runtime from a CommandRegistry, not from clap's derive macros. Commands like compute knn, analyze stats, transform extract etc. are two-level paths (group subcommand) that the registry resolves dynamically. Clap's completion generator only sees the derive-defined tree and misses the entire pipeline command catalog.

2. Shorthand dispatch

Veks supports shorthand commands: veks run is equivalent to veks prepare run, and veks config resolves to veks datasets config. These shorthands are implemented as hidden root-level subcommands cloned from the full tree. Clap's completion engine either hides them (no completions) or shows them alongside the originals (duplicates).

3. One-level-at-a-time completion

Clap's completion eagerly chains subcommands: typing veks com<TAB> might expand to veks compute knn in one step if there's only one match. This is disorienting for a deep command tree. The veks completion engine completes one level at a time — veks com<TAB> expands to veks compute, and a second tab shows the compute subcommands.

4. Context-sensitive value completion

Pipeline commands accept --option value pairs where the valid values depend on context: --dataset should complete to known dataset names, --profile to profile names within the selected dataset, --source to files matching vector formats. Clap's value hints are limited to predefined categories (file paths, directory paths, etc.). This crate supports per-option ValueProvider functions that run arbitrary logic at completion time.

5. Mixed derive + dynamic tree

The veks CLI combines clap derive-based subcommands (datasets, prepare, interact) with dynamically-registered pipeline commands and runtime-generated help trees. The completion engine walks the full augmented clap::Command tree (built by build_augmented_cli()) at completion time, so it always reflects the actual command structure regardless of how commands were registered.

How it works

The crate provides a generic CommandTree with Node variants (Leaf and Group). At startup, dyncomp::build_tree() walks the clap Command tree recursively and builds the CommandTree. When the shell invokes completion (via the _VEKS_COMPLETE=bash env var), the engine:

  1. Parses the current input words
  2. Walks the CommandTree to find the deepest matching node
  3. Returns candidates: child commands (for groups) or --option names (for leaves)
  4. For --option <TAB>, invokes the registered ValueProvider if one exists for that option

The completion script itself is minimal — it sets the env var and re-invokes the veks binary, which does the actual tree walk and prints candidates. This means completions are always current with the installed binary.

Usage

# Add to .bashrc / .zshrc:
eval "$(veks completions)"

This registers a bash completion function that calls veks with _VEKS_COMPLETE=bash on each tab press.

Architecture

veks-completion/        # This crate — generic completion engine
  src/lib.rs            # CommandTree, Node, complete(), print_bash_script()

veks/src/cli/
  dyncomp.rs            # Walks clap::Command -> CommandTree
                        # Registers global ValueProviders (datasets, profiles)
  mod.rs                # Wires eval "$(veks completions)" output

The completion crate has no dependency on clap, veks, or any pipeline code. It is a pure tree-walker that takes a CommandTree and returns string candidates. The clap-to-tree conversion lives in dyncomp.rs inside the veks binary crate.