This commit is contained in:
atagen 2026-05-19 23:32:51 +10:00
parent da4bc139eb
commit 7567f202e8
49 changed files with 8338 additions and 5483 deletions

View file

@ -1,150 +1,28 @@
# 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.
inshellah indexes completions for the commands in your `$PATH` and
serves them to nushell's external completer. indexed data is stored as
`.json` and `.nu` files that the `complete` command reads at
tab-completion time.
## quick start
index completions from a system prefix:
```sh
# index from a prefix containing bin/ and share/man/
# from a prefix containing bin/ and share/man/
inshellah index /usr
# index from multiple prefixes
# multiple prefixes
inshellah index /usr /usr/local
# store in a custom directory
# custom directory
inshellah index /usr --dir ~/my-completions
```
parse a single manpage:
```sh
inshellah manpage /usr/share/man/man1/git.1.gz
```
batch-process all manpages under a directory (man1 and man8):
```sh
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[:PATH...]]
nushell custom completer. outputs json completion candidates.
falls back to --help resolution if command is not indexed.
--dir takes colon-separated paths. the first path is the writable
user cache; additional paths are read-only system directories.
manpages are found via sibling share/man of system dir paths.
inshellah query CMD [--dir PATH[:PATH...]]
print stored completion data for CMD.
inshellah dump [--dir PATH[: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.
when a `--help` invocation produces rendered manpage output (some
commands like `git stash` delegate `--help` to `man`), inshellah
detects this and locates the raw manpage source to parse with the
groff parser instead. this yields richer results (subcommands,
structured flag sections) than parsing the rendered text.
### 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 directories specified via `--dir`
(colon-separated), performs fuzzy matching, and outputs json completion
candidates. the first path is the writable user cache; additional paths
are read-only system directories.
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
then wire up the completer in `~/.config/nushell/config.nu`:
```nu
# ~/.config/nushell/config.nu
$env.config.completions.external = {
enable: true
completer: {|spans|
@ -154,27 +32,62 @@ $env.config.completions.external = {
}
```
with the nixos module, use the provided `snippet` option value (see
[nixos.md](nixos.md)) which points at the system index automatically.
that's it. tab-completion now works for every command indexed.
## nixos module
## commands
enable automatic completion indexing at system build time:
```
inshellah index PREFIX... [--dir PATH] [--ignore FILE] [--help-only FILE]
[--workers N] [--timeout-ms N]
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
--workers N worker-thread count
--timeout-ms N per-subprocess timeout in ms (default: 200)
```nix
{
imports = [ ./path/to/inshellah/nix/module.nix ];
programs.inshellah.enable = true;
}
inshellah complete CMD [ARGS...] [--dir PATH[:PATH...]] [--timeout-ms N]
nushell custom completer. outputs JSON completion candidates.
falls back to on-the-fly --help resolution if a command isn't
indexed yet — the result is cached and subsequent presses are
instant.
--dir takes colon-separated paths. the first path is the writable
user cache; additional paths are read-only system directories.
inshellah query CMD [--dir PATH[:PATH...]]
print stored completion data for CMD.
inshellah dump [--dir PATH[:PATH...]]
list indexed commands.
inshellah manpage FILE
parse a manpage and emit a nushell extern block.
inshellah manpage-dir DIR
batch-process manpages under DIR (man1 and man8 sections).
```
this runs `inshellah index` during the system profile build. see
[nixos.md](nixos.md) for full details.
## what gets handled
## what gets generated
- **sources**: native nushell completion generators (clap/cobra tools
that can emit completions themselves), manpages in section 1 and 8,
`--help` and `-h` output.
- **groff styles**: gnu `.TP` (coreutils, help2man), `.IP` (curl,
hand-written), `.PP`+`.RS`/`.RE` (git, docbook), nix3 bullet
(`nix run`, `nix build`), mdoc (BSD), plus a deroff fallback.
- **subcommand naming**: `git-commit.1` produces `git commit`, not
`git-commit`. clap-style per-subcommand manpages get one file each.
- **synopsis-only flags**: flags declared in a manpage SYNOPSIS but
missing from the body (e.g. nix-env's `--profile`, most of sed's
interface) are picked up too.
- **elevation wrappers**: `sudo`, `doas`, `pkexec`, `su`, `run0` are
stripped before lookup, including when the real target is given as
an absolute path.
- **exclusions**: nushell built-ins (ls, cd, mv, etc.) are skipped —
nushell serves its own completions for those.
the `manpage` and `manpage-dir` commands emit nushell `extern` blocks
with flags, parameter types, and descriptions:
## extern blocks (manpage / manpage-dir)
```nu
export extern "rg" [
@ -186,9 +99,12 @@ export extern "rg" [
]
```
subcommand manpages (e.g. `git-commit.1`) are detected via synopsis
parsing and generate the correct nushell name (`git commit` not
`git-commit`).
these are produced by `inshellah manpage` / `inshellah manpage-dir` and
can be source'd directly in your nushell config if you prefer that to
the json completer flow.
nushell built-in commands (ls, cd, mv, etc.) are excluded since nushell
provides its own completions for these.
## nixos
`programs.inshellah.enable = true` will index at system build time and
ship a richer completer with runtime fallbacks (live cluster queries,
git/ssh/docker/k8s lookups, etc.). see [nixos.md](nixos.md).