inshellah/doc/nushell-integration.md
2026-03-24 22:57:18 +11:00

5.7 KiB

using inshellah completions in nushell

inshellah indexes completions from three sources (in priority order):

  1. native generators — programs that can emit nushell completions directly
  2. manpages — groff/troff/mdoc manpage parsing
  3. --help output — parsing help text as a fallback

indexed data is stored as .json and .nu files in a directory that the complete command reads from at tab-completion time.

quick start

index completions from a system prefix:

# index from a prefix containing bin/ and share/man/
inshellah index /usr

# index from multiple prefixes
inshellah index /usr /usr/local

# store in a custom directory
inshellah index /usr --dir ~/my-completions

parse a single manpage:

inshellah manpage /usr/share/man/man1/git.1.gz

batch-process all manpages under a directory (man1 and man8):

inshellah manpage-dir /usr/share/man

commands

inshellah index PREFIX... [--dir PATH] [--ignore FILE] [--help-only FILE]
    index completions into a directory of json/nu files.
    PREFIX is a directory containing bin/ and share/man/.
    default dir: $XDG_CACHE_HOME/inshellah
    --ignore FILE     skip listed commands entirely
    --help-only FILE  skip manpages for listed commands, use --help instead

inshellah complete CMD [ARGS...] [--dir PATH] [--system-dir PATH]
    nushell custom completer. outputs json completion candidates.
    falls back to --help resolution if command is not indexed.

inshellah query CMD [--dir PATH] [--system-dir PATH]
    print stored completion data for CMD.

inshellah dump [--dir PATH] [--system-dir PATH]
    list indexed commands.

inshellah manpage FILE
    parse a manpage and emit nushell extern block.

inshellah manpage-dir DIR
    batch-process manpages under DIR (man1 and man8 sections).

the index pipeline

the index command runs a three-phase pipeline over all executables in each PREFIX/bin:

phase 1: native completion detection (parallel)

for each executable, inshellah scans the elf binary for the string completion. if found, it probes common patterns like CMD completions nushell to see if the program can generate its own nushell completions. native output is used verbatim — these are always higher quality than parsed completions.

programs like niri, and any clap/cobra tool with nushell support, are handled this way.

phase 2: manpage parsing (sequential)

for commands not covered by phase 1, inshellah parses manpages from man1 (user commands) and man8 (sysadmin commands). it handles:

  • gnu .TP style (coreutils, help2man)
  • .IP style (curl, hand-written)
  • .PP+.RS/.RE style (git, docbook)
  • nix3 bullet+hyperlink style (nix run, nix build, etc.)
  • mdoc (bsd) format
  • deroff fallback for unusual formats

synopsis sections are parsed to detect subcommands: git-commit.1 generates export extern "git commit", not export extern "git-commit".

phase 3: --help fallback (parallel)

remaining executables without manpages get --help (or -h) called with a 200ms timeout. elf binaries are pre-scanned for the -h string to skip those that don't support help flags. shell scripts are run directly (they're fast). execution is parallelized to available cores.

subcommands are recursively resolved — if --help output lists subcommands, inshellah runs CMD SUBCMD --help for each.

output

each command gets its own file in the index directory. native generators produce .nu files; parsed results produce .json files. the complete command reads both formats.

nushell built-in commands (ls, cd, cp, mv, etc.) are excluded since nushell provides its own completions.

performance

on a typical nixos system (~950 executables, ~1600 manpages):

  • total time: ~4-10 seconds
  • native gzip decompression (camlzip, no process spawning)
  • parallel --help with core-scaled forking
  • elf string scanning to skip ~15% of binaries

the completer

the complete command is designed to be wired into nushell as an external completer. it reads from the index directory (--dir) and optional system directories (--system-dir), performs fuzzy matching, and outputs json completion candidates.

if a command is not indexed, complete falls back to on-the-fly --help resolution — it runs the command's help, caches the result in the user directory, and returns completions immediately.

setting up the completer

# ~/.config/nushell/config.nu
$env.config.completions.external = {
    enable: true
    completer: {|spans|
        inshellah complete ...$spans
        | from json
    }
}

with the nixos module, use the provided snippet option value (see nixos.md) which points at the system index automatically.

nixos module

enable automatic completion indexing at system build time:

{
  imports = [ ./path/to/inshellah/nix/module.nix ];
  programs.inshellah.enable = true;
}

this runs inshellah index during the system profile build. see nixos.md for full details.

what gets generated

the manpage and manpage-dir commands emit nushell extern blocks with flags, parameter types, and descriptions:

export extern "rg" [
    --regexp(-e): string            # a pattern to search for
    --file(-f): path                # search for patterns from the given file
    --count(-c)                     # only show the count of matching lines
    --color: string                 # controls when to use color
    --max-depth: int                # limit the depth of directory traversal
]

subcommand manpages (e.g. git-commit.1) are detected via synopsis parsing and generate the correct nushell name (git commit not git-commit).

nushell built-in commands (ls, cd, mv, etc.) are excluded since nushell provides its own completions for these.