diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 1492296e..2c08a156 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1207,6 +1207,13 @@ in A new module is available: 'programs.yazi'. ''; } + + { + time = "2023-09-05T06:38:05+00:00"; + message = '' + A new module is available: 'programs.carapace'. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index 4e0f5635..f00540c3 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -67,6 +67,7 @@ let ./programs/broot.nix ./programs/browserpass.nix ./programs/btop.nix + ./programs/carapace.nix ./programs/chromium.nix ./programs/command-not-found/command-not-found.nix ./programs/comodoro.nix diff --git a/modules/programs/carapace.nix b/modules/programs/carapace.nix new file mode 100644 index 00000000..fd592935 --- /dev/null +++ b/modules/programs/carapace.nix @@ -0,0 +1,98 @@ +{ config, pkgs, lib, ... }: + +let + + inherit (lib) + mkEnableOption mkPackageOption mkIf pipe fileContents splitString; + cfg = config.programs.carapace; + bin = cfg.package + "/bin/carapace"; + +in { + meta.maintainers = with lib.maintainers; [ weathercold bobvanderlinden ]; + + options.programs.carapace = { + enable = + mkEnableOption "carapace, a multi-shell multi-command argument completer"; + + package = mkPackageOption pkgs "carapace" { }; + + enableBashIntegration = mkEnableOption "Bash integration" // { + default = true; + }; + + enableZshIntegration = mkEnableOption "Zsh integration" // { + default = true; + }; + + enableFishIntegration = mkEnableOption "Fish integration" // { + default = true; + }; + + enableNushellIntegration = mkEnableOption "Nushell integration" // { + default = true; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + + programs = { + bash.initExtra = mkIf cfg.enableBashIntegration '' + source <(${bin} _carapace bash) + ''; + + zsh.initExtra = mkIf cfg.enableZshIntegration '' + source <(${bin} _carapace zsh) + ''; + + fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' + ${bin} _carapace fish | source + ''; + + nushell = mkIf cfg.enableNushellIntegration { + extraEnv = '' + let carapace_cache = "${config.xdg.cacheHome}/carapace" + if not ($carapace_cache | path exists) { + mkdir $carapace_cache + } + ${bin} _carapace nushell | save -f $"($carapace_cache)/init.nu" + ''; + extraConfig = '' + source ${config.xdg.cacheHome}/carapace/init.nu + ''; + }; + }; + + xdg.configFile = + mkIf (config.programs.fish.enable && cfg.enableFishIntegration) ( + # Convert the entries from `carapace --list` to empty + # xdg.configFile."fish/completions/NAME.fish" entries. + # + # This is to disable fish builtin completion for each of the + # carapace-supported completions It is in line with the instructions from + # carapace-bin: + # + # carapace --list | awk '{print $1}' | xargs -I{} touch ~/.config/fish/completions/{}.fish + # + # See https://github.com/rsteube/carapace-bin#getting-started + let + carapaceListFile = pkgs.runCommandLocal "carapace-list" { + buildInputs = [ cfg.package ]; + } '' + ${bin} --list > $out + ''; + in pipe carapaceListFile [ + fileContents + (splitString "\n") + (map (builtins.match "^([a-z0-9-]+) .*")) + (builtins.filter + (match: match != null && (builtins.length match) > 0)) + (map (match: builtins.head match)) + (map (name: { + name = "fish/completions/${name}.fish"; + value = { text = ""; }; + })) + builtins.listToAttrs + ]); + }; +} diff --git a/tests/default.nix b/tests/default.nix index 0aca7a3c..178bee05 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -68,6 +68,7 @@ import nmt { ./modules/programs/broot ./modules/programs/browserpass ./modules/programs/btop + ./modules/programs/carapace ./modules/programs/comodoro ./modules/programs/darcs ./modules/programs/dircolors diff --git a/tests/modules/programs/carapace/bash.nix b/tests/modules/programs/carapace/bash.nix new file mode 100644 index 00000000..7377df3c --- /dev/null +++ b/tests/modules/programs/carapace/bash.nix @@ -0,0 +1,14 @@ +{ ... }: + +{ + programs = { + carapace.enable = true; + bash.enable = true; + }; + + nmt.script = '' + assertFileExists home-files/.bashrc + assertFileRegex home-files/.bashrc \ + 'source <(/nix/store/.*carapace.*/bin/carapace _carapace bash)' + ''; +} diff --git a/tests/modules/programs/carapace/default.nix b/tests/modules/programs/carapace/default.nix new file mode 100644 index 00000000..acdf02cf --- /dev/null +++ b/tests/modules/programs/carapace/default.nix @@ -0,0 +1,6 @@ +{ + carapace-bash = ./bash.nix; + carapace-zsh = ./zsh.nix; + carapace-fish = ./fish.nix; + carapace-nushell = ./nushell.nix; +} diff --git a/tests/modules/programs/carapace/fish.nix b/tests/modules/programs/carapace/fish.nix new file mode 100644 index 00000000..6b71cef5 --- /dev/null +++ b/tests/modules/programs/carapace/fish.nix @@ -0,0 +1,18 @@ +{ ... }: + +{ + programs = { + carapace.enable = true; + fish.enable = true; + }; + + nmt.script = '' + assertFileExists home-files/.config/fish/config.fish + assertFileRegex home-files/.config/fish/config.fish \ + '/nix/store/.*carapace.*/bin/carapace _carapace fish \| source' + + # Check whether completions are overridden. + assertFileExists home-files/.config/fish/completions/git.fish + assertFileContent home-files/.config/fish/completions/git.fish /dev/null + ''; +} diff --git a/tests/modules/programs/carapace/nushell.nix b/tests/modules/programs/carapace/nushell.nix new file mode 100644 index 00000000..a025da18 --- /dev/null +++ b/tests/modules/programs/carapace/nushell.nix @@ -0,0 +1,22 @@ +{ pkgs, ... }: + +{ + programs = { + carapace.enable = true; + nushell.enable = true; + }; + + nmt.script = let + configDir = if pkgs.stdenv.isDarwin then + "home-files/Library/Application Support/nushell" + else + "home-files/.config/nushell"; + in '' + assertFileExists "${configDir}/env.nu" + assertFileRegex "${configDir}/env.nu" \ + '/nix/store/.*carapace.*/bin/carapace _carapace nushell \| save -f \$"(\$carapace_cache)/init\.nu"' + assertFileExists "${configDir}/config.nu" + assertFileRegex "${configDir}/config.nu" \ + 'source /.*/\.cache/carapace/init\.nu' + ''; +} diff --git a/tests/modules/programs/carapace/zsh.nix b/tests/modules/programs/carapace/zsh.nix new file mode 100644 index 00000000..5ab4fe8a --- /dev/null +++ b/tests/modules/programs/carapace/zsh.nix @@ -0,0 +1,14 @@ +{ ... }: + +{ + programs = { + carapace.enable = true; + zsh.enable = true; + }; + + nmt.script = '' + assertFileExists home-files/.zshrc + assertFileRegex home-files/.zshrc \ + 'source <(/nix/store/.*carapace.*/bin/carapace _carapace zsh)' + ''; +}