{ lib, pkgs, config, ... }: let inherit (lib) types; cfg = config.programs.fish; toFishFunc = body: funcName: if (types.typeOf body) == "string" then pkgs.writeFish "${funcName}.fish" '' function ${funcName}; ${lib.concatMapStringsSep "\n" (line: "\t${line}") (lib.splitString "\n" body)} end '' else if lib.isDerivation body then body else throw "Input is of invalid type ${types.typeOf body}, expected `path` or `string`."; isVendored = plugin: types.any (p: lib.pathExists "${plugin}/share/fish/${p}") [ "vendor_conf.d" "vendor_completions.d" "vendor_functions.d" ]; in { options.programs.fish = { enable = lib.mkEnableOption "fish"; config = lib.mkOption { default = ""; type = types.lines; }; functions = lib.mkOption { default = { }; type = with types; attrsOf (oneOf [ lines path ]); }; earlyConfigFiles = lib.mkOption { default = { }; type = types.attrsOf types.lines; }; abbrs = lib.mkOption { default = { }; type = types.attrsOf types.lines; }; aliases = lib.mkOption { default = { }; type = types.attrsOf types.lines; }; plugins = lib.mkOption { type = types.attrsOf types.path; default = { }; }; }; config = lib.mkIf cfg.enable { programs.fish.earlyConfigFiles = lib.mapAttrs' ( name: source: lib.nameValuePair "plugin-${name}" # fish '' # Plugin ${name} -- ${source} set -l src "${source}" if test -d "$src/functions" set fish_function_path $fish_function_path[1] "$src/functions" $fish_function_path[2..] end if test -d "$src/completions" set fish_complete_path $fish_complete_path[1] "$src/completions" $fish_complete_path[2..] end for f in "$src/conf.d/"* source "$f" end if test -f "$src/key_bindings.fish" source "$src/key_bindings.fish" end if test -f "$src/init.fish" source "$src/init.fish" end '' ) (lib.filterAttrs (n: v: !(isVendored v)) cfg.plugins); file.xdg_config = { "fish/config.fish" = lib.mkIf (cfg.config != "") { source = pkgs.writers.writeFish "config.fish" cfg.config; }; "fish/conf.d/session-variables.fish" = lib.mkIf (config.environment.sessionVariables != { }) { text = lib.concatMapAttrsStringSep "\n" ( name: value: "set --global --export ${lib.escapeShellArg name} ${lib.escapeShellArg (toString value)}" ) config.environment.sessionVariables; }; "fish/conf.d/abbreviations.fish" = lib.mkIf (cfg.abbrs != { }) { text = lib.concatMapAttrsStringSep "\n" ( name: value: "abbr --add -- ${lib.escapeShellArg name} ${lib.escapeShellArg (toString value)}" ) cfg.abbrs; }; "fish/conf.d/aliases.fish".text = lib.concatMapAttrsStringSep "\n" ( name: value: "alias -- ${lib.escapeShellArg name} ${lib.escapeShellArg (toString value)}" ) cfg.aliases; } // (lib.mapAttrs' ( name: val: lib.nameValuePair "fish/functions/${name}.fish" { source = toFishFunc val name; } ) cfg.functions) // (lib.mapAttrs' ( name: val: lib.nameValuePair "fish/conf.d/${name}.fish" { source = pkgs.writers.writeFish "${name}.fish" val; } ) cfg.earlyConfigFiles); }; }