8.8 KiB
nixos / nix-darwin integration
inshellah provides a module that indexes nushell completions for every installed package at system build time, and a wrapped binary that knows where to find the result. the same module body backs both NixOS and nix-darwin — on Linux it scrapes ELF binaries, on macOS Mach-O ones, selected automatically by the inshellah build's target platform.
enabling (NixOS)
# flake.nix outputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [
inshellah.nixosModules.default
{ programs.inshellah.enable = true; }
];
};
}
or importing directly:
# configuration.nix
{ pkgs, ... }: {
imports = [ ./path/to/inshellah-rs/nix/module.nix ];
programs.inshellah.enable = true;
}
enabling (nix-darwin)
# flake.nix outputs:
{
darwinConfigurations.mymac = nix-darwin.lib.darwinSystem {
modules = [
inshellah.darwinModules.default
{ programs.inshellah.enable = true; }
];
};
}
the options and behaviour are identical to the NixOS module — it reads
the same programs.inshellah.* settings and writes the same completion
index and nushell shim under the system profile (/run/current-system/sw,
which nix-darwin also uses).
on macOS, the tools you reach through /usr/bin (git, clang, …) are
xcrun shims whose real binaries and manpages live under the active
developer dir, outside the nix system profile — so they aren't indexed by
default. rather than probe the host toolchain impurely, list the nix
equivalents you want completed in extraScrapePackages; the module rolls
their store paths into the build-time scrape (inshellah index … --prefix …). this applies on NixOS too, for any package whose completions you want
indexed without putting it on the system path.
after rebuilding, completions are immediately available through the autoloaded nushell shim.
what the module does
- installs the inshellah binary, wrapped so the system completion path is found automatically.
- runs
inshellah index "$out"during the system profile build, producing one file per command under$out/share/inshellah/. - drops the full nushell external-completer shim into
/share/nushell/vendor/autoload/, including sudo/doas overrides so elevated commands still complete through inshellah. - emits lightweight command-name stubs for dynamic-completion backends
that are present in the system profile, so tools like
gitandjjappear in nushell's command list while inshellah still supplies their argument completions lazily. - exposes the same shim as a read-only
snippetoption for users who want to source or inspect it manually.
module options
programs.inshellah = {
enable = true;
# the inshellah package (set automatically by the flake module)
package = pkgs.inshellah;
# subdirectory of the system profile holding the index files
# default: "/share/inshellah"
completionsPath = "/share/inshellah";
# additional read-only completion directories to search
extraDirs = [ "/etc/profiles/per-user/alice/share/inshellah" ];
# commands to skip entirely during indexing
ignoreCommands = [ "problematic-tool" ];
# commands to skip manpage parsing for (uses --help instead)
helpOnlyCommands = [ "nix" ];
# extra packages to scrape alongside the system profile; each store path
# is passed to `inshellah index --prefix`. handy on macOS for the nix
# equivalents of /usr/bin shim tools (git, clang, …)
extraScrapePackages = [ pkgs.git pkgs.clang ];
# per-subprocess timeout in ms during indexing (null = built-in
# default of 200ms)
timeoutMs = null;
# timeout in ms for live dynamic completions at tab-completion time
# set to 0 to disable the runtime timeout
dynamicTimeoutMs = 5000;
# result cap requested from live providers that support native limits
# set to 0 to omit native result-limit flags
dynamicLimit = 200;
# characters that trigger flag completions when a partial token begins
# with one of them. default "-"; e.g. "-+" also triggers on "+"
flagTriggers = "-";
# also surface flags on an empty token (right after a space), mixed in
# with subcommands. default false
flagOnEmpty = false;
# cap on candidates returned and nushell's max_results. 0 = no cap
# (nushell's built-in default of 200 still applies)
maxCompletions = 0;
# per-subprocess timeout (ms) for the completer's on-the-fly --help
# resolution of uncached commands. null = built-in default of 200ms.
# distinct from timeoutMs (indexing) and dynamicTimeoutMs (live shim)
completeTimeoutMs = null;
# worker-thread count for the parallel scrape
workers = null;
};
flag-triggering behaviour
flagTriggers and flagOnEmpty control when option/flag completions are
offered. By default flags appear only after a leading -. Add characters
to flagTriggers (e.g. "-+") to trigger on them as well — for a
non-dash trigger the text after it is matched against the bare flag name,
so +ver completes to --verbose. Set flagOnEmpty = true to list flags
immediately after a space, alongside subcommands. These map to the
INSHELLAH_FLAG_TRIGGERS / INSHELLAH_FLAG_ON_EMPTY environment variables
(see runtime-completions.md).
using the completer
the module installs the completer under nushell's vendor autoload path, so no hand-written nushell config is needed for the normal NixOS case.
the read-only snippet option still holds the complete
external-completer config. to manage sourcing yourself instead of using
autoload, write it to a file:
# generate a config file from the snippet
environment.etc."nushell/inshellah.nu".text = config.programs.inshellah.snippet;
then source that file from your nushell config:
source /etc/nushell/inshellah.nu
or copy the snippet directly into ~/.config/nushell/config.nu:
# (the snippet is many lines — copy it from `nix eval` of the option,
# or use the environment.etc approach above)
$env.config.completions.external = { ... }
the snippet provides both static lookups against the system index and runtime fallbacks for cases the static index can't cover:
runtime fallbacks have a default 5s timeout, controlled by
programs.inshellah.dynamicTimeoutMs or INSHELLAH_DYNAMIC_TIMEOUT_MS
when sourcing the snippet manually. providers with native result caps use
programs.inshellah.dynamicLimit or INSHELLAH_DYNAMIC_LIMIT, defaulting
to 200. set either value to 0 to disable that guard. on timeout the
completer returns null so nushell can fall back to its normal completion
behavior.
| command | dynamic source |
|---|---|
nix |
flake refs via NIX_GET_COMPLETIONS, with optional meta.description |
systemctl / journalctl |
unit names from list-units |
coredumpctl |
units + pids |
loginctl |
users / sessions |
machinectl / networkctl |
machines / links |
ssh / scp / sftp |
hostnames from ssh config + known_hosts |
docker / podman |
containers + image refs by subcommand |
kubectl |
resource names from the live cluster |
git |
refs + worktree paths |
jj |
revisions, operations, bookmarks, remotes, files, and workspaces |
npm / pnpm / yarn |
scripts from package.json |
make / just |
targets / recipes |
cargo |
workspace targets behind --bin / --example / etc. |
kill / pkill |
pid+comm pairs |
home manager and user-level package managers
the system module only indexes packages installed system-wide. for
home-manager or per-user nix profiles, run inshellah index against
those prefixes separately:
# home-manager / per-user profile
inshellah index /etc/profiles/per-user/$USER
# classic nix-env profile
inshellah index ~/.nix-profile
this indexes into $XDG_CACHE_HOME/inshellah, which the completer
searches automatically. to automate via home-manager:
home.activation.inshellah-index = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
${pkgs.inshellah}/bin/inshellah index /etc/profiles/per-user/$USER 2>/dev/null || true
'';
troubleshooting
completions not appearing: check that the system index exists
(ls /run/current-system/sw/share/inshellah/) and that the completer
is configured.
missing completions for a specific command: check if it's a nushell
built-in (help commands | where name == "thecommand") — built-ins
are excluded.
command name missing but arguments complete after typing it: the command may be installed only in a user profile. the system module can only generate command-name stubs for binaries linked into the system profile, though the external completer can still complete arguments once the command word has been typed.
stale completions after update: the index regenerates on every
nixos-rebuild. if a command changed its flags, rebuild.
build-time errors: indexing failures are non-fatal. check
journalctl for the build log if completions are missing for a
specific command.