inshellah/nix/module.nix
2026-03-23 11:01:54 +11:00

92 lines
2.7 KiB
Nix

# NixOS module: automatic nushell completion generation
#
# Generates completions using three strategies in priority order:
# 1. Native completion generators (e.g. CMD completions nushell)
# 2. Manpage parsing
# 3. --help output parsing
#
# Runs as a single pass during the system profile build.
#
# Usage:
# { pkgs, ... }: {
# imports = [ ./path/to/inshellah/nix/module.nix ];
# programs.inshellah.enable = true;
# }
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.inshellah;
in
{
options.programs.inshellah = {
enable = lib.mkEnableOption "nushell completion generation via inshellah";
package = lib.mkOption {
type = lib.types.package;
description = "The inshellah package to use for generating completions.";
};
generatedCompletionsPath = lib.mkOption {
type = lib.types.str;
default = "/share/nushell/vendor/autoload";
description = ''
Subdirectory within the merged environment where completion files
are placed. The default matches nushell's vendor autoload convention
(discovered via XDG_DATA_DIRS).
'';
};
ignoreCommands = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
example = [ "meat" "problematic-tool" ];
description = ''
List of command names to skip during completion generation.
'';
};
};
config = lib.mkIf cfg.enable {
environment.pathsToLink = [ cfg.generatedCompletionsPath ];
environment.extraSetup =
let
inshellah = "${cfg.package}/bin/inshellah";
destDir = "$out${cfg.generatedCompletionsPath}";
segments = lib.filter (s: s != "") (lib.splitString "/" cfg.generatedCompletionsPath);
derefPath = lib.concatMapStringsSep "\n " (seg: ''
_cur="$_cur/${seg}"
if [ -L "$_cur" ]; then
_target=$(readlink "$_cur")
rm "$_cur"
mkdir -p "$_cur"
if [ -d "$_target" ]; then
cp -rT "$_target" "$_cur"
chmod -R u+w "$_cur"
fi
fi'') segments;
ignoreFile = pkgs.writeText "inshellah-ignore" (lib.concatStringsSep "\n" cfg.ignoreCommands);
ignoreFlag = lib.optionalString (cfg.ignoreCommands != []) " --ignore ${ignoreFile}";
in
''
_cur="$out"
${derefPath}
mkdir -p ${destDir}
# Generate all completions in one pass:
# native generators > manpages > --help fallback
if [ -d "$out/bin" ] && [ -d "$out/share/man" ]; then
${inshellah} generate "$out/bin" "$out/share/man" -o ${destDir}${ignoreFlag} \
2>/dev/null || true
fi
find ${destDir} -maxdepth 1 -empty -delete
'';
};
}