Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 176 additions & 121 deletions nixos/modules/programs/fish.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ let
(filterAttrs (k: v: v != null) cfg.shellAliases)
);

envShellInit = pkgs.writeText "shellInit" cfge.shellInit;

envLoginShellInit = pkgs.writeText "loginShellInit" cfge.loginShellInit;

envInteractiveShellInit = pkgs.writeText "interactiveShellInit" cfge.interactiveShellInit;

sourceEnv = file:
if cfg.useBabelfish then
"source /etc/fish/${file}.fish"
else
''
set fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish-foreign-env/functions $fish_function_path
fenv source /etc/fish/foreign-env/${file} > /dev/null
set -e fish_function_path[1]
'';

babelfishTranslate = path: name:
pkgs.runCommand "${name}.fish" {
nativeBuildInputs = [ pkgs.babelfish ];
} "${pkgs.babelfish}/bin/babelfish < ${path} > $out;";

in

{
Expand All @@ -29,6 +50,15 @@ in
type = types.bool;
};

useBabelfish = mkOption {
type = types.bool;
default = false;
description = ''
If enabled, the configured environment will be translated to native fish using <link xlink:href="https://github.com/bouk/babelfish">babelfish</link>.
Otherwise, <link xlink:href="https://github.com/oh-my-fish/plugin-foreign-env">foreign-env</link> will be used.
'';
};

vendor.config.enable = mkOption {
type = types.bool;
default = true;
Expand Down Expand Up @@ -105,72 +135,152 @@ in
# Required for man completions
documentation.man.generateCaches = lib.mkDefault true;

environment.etc."fish/foreign-env/shellInit".text = cfge.shellInit;
environment.etc."fish/foreign-env/loginShellInit".text = cfge.loginShellInit;
environment.etc."fish/foreign-env/interactiveShellInit".text = cfge.interactiveShellInit;

environment.etc."fish/nixos-env-preinit.fish".text = ''
# This happens before $__fish_datadir/config.fish sets fish_function_path, so it is currently
# unset. We set it and then completely erase it, leaving its configuration to $__fish_datadir/config.fish
set fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish/vendor_functions.d $__fish_datadir/functions

# source the NixOS environment config
if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]
fenv source ${config.system.build.setEnvironment}
end

# clear fish_function_path so that it will be correctly set when we return to $__fish_datadir/config.fish
set -e fish_function_path
'';

environment.etc."fish/config.fish".text = ''
# /etc/fish/config.fish: DO NOT EDIT -- this file has been generated automatically.

# if we haven't sourced the general config, do it
if not set -q __fish_nixos_general_config_sourced
set --prepend fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish/vendor_functions.d
fenv source /etc/fish/foreign-env/shellInit > /dev/null
set -e fish_function_path[1]

${cfg.shellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew)
set -g __fish_nixos_general_config_sourced 1
end

# if we haven't sourced the login config, do it
status --is-login; and not set -q __fish_nixos_login_config_sourced
and begin
set --prepend fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish/vendor_functions.d
fenv source /etc/fish/foreign-env/loginShellInit > /dev/null
set -e fish_function_path[1]

${cfg.loginShellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew)
set -g __fish_nixos_login_config_sourced 1
end

# if we haven't sourced the interactive config, do it
status --is-interactive; and not set -q __fish_nixos_interactive_config_sourced
and begin
${fishAliases}

set --prepend fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish/vendor_functions.d
fenv source /etc/fish/foreign-env/interactiveShellInit > /dev/null
set -e fish_function_path[1]
Comment thread
cole-h marked this conversation as resolved.
Outdated

${cfg.promptInit}
${cfg.interactiveShellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew,
# allowing configuration changes in, e.g, aliases, to propagate)
set -g __fish_nixos_interactive_config_sourced 1
end
'';
environment = mkMerge [
(mkIf cfg.useBabelfish
{
etc."fish/setEnvironment.fish".source = babelfishTranslate config.system.build.setEnvironment "setEnvironment";
etc."fish/shellInit.fish".source = babelfishTranslate envShellInit "shellInit";
etc."fish/loginShellInit.fish".source = babelfishTranslate envLoginShellInit "loginShellInit";
etc."fish/interactiveShellInit.fish".source = babelfishTranslate envInteractiveShellInit "interactiveShellInit";
})

(mkIf (!cfg.useBabelfish)
{
etc."fish/foreign-env/shellInit".source = envShellInit;
etc."fish/foreign-env/loginShellInit".source = envLoginShellInit;
etc."fish/foreign-env/interactiveShellInit".source = envInteractiveShellInit;
})

{
etc."fish/nixos-env-preinit.fish".text =
if cfg.useBabelfish
then ''
# source the NixOS environment config
if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]
source /etc/fish/setEnvironment.fish
end
''
else ''
# This happens before $__fish_datadir/config.fish sets fish_function_path, so it is currently
# unset. We set it and then completely erase it, leaving its configuration to $__fish_datadir/config.fish
set fish_function_path ${pkgs.fishPlugins.foreign-env}/share/fish/vendor_functions.d $__fish_datadir/functions

# source the NixOS environment config
if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]
fenv source ${config.system.build.setEnvironment}
end

# clear fish_function_path so that it will be correctly set when we return to $__fish_datadir/config.fish
set -e fish_function_path
'';
}

{
etc."fish/config.fish".text = ''
# /etc/fish/config.fish: DO NOT EDIT -- this file has been generated automatically.

# if we haven't sourced the general config, do it
if not set -q __fish_nixos_general_config_sourced
${sourceEnv "shellInit"}

${cfg.shellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew)
set -g __fish_nixos_general_config_sourced 1
end

# if we haven't sourced the login config, do it
status --is-login; and not set -q __fish_nixos_login_config_sourced
and begin
${sourceEnv "loginShellInit"}

${cfg.loginShellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew)
set -g __fish_nixos_login_config_sourced 1
end

# if we haven't sourced the interactive config, do it
status --is-interactive; and not set -q __fish_nixos_interactive_config_sourced
and begin
${fishAliases}

${sourceEnv "interactiveShellInit"}

${cfg.promptInit}
${cfg.interactiveShellInit}

# and leave a note so we don't source this config section again from
# this very shell (children will source the general config anew,
# allowing configuration changes in, e.g, aliases, to propagate)
set -g __fish_nixos_interactive_config_sourced 1
end
'';
}

{
etc."fish/generated_completions".source =
let
patchedGenerator = pkgs.stdenv.mkDerivation {
name = "fish_patched-completion-generator";
srcs = [
"${pkgs.fish}/share/fish/tools/create_manpage_completions.py"
"${pkgs.fish}/share/fish/tools/deroff.py"
];
unpackCmd = "cp $curSrc $(basename $curSrc)";
sourceRoot = ".";
patches = [ ./fish_completion-generator.patch ]; # to prevent collisions of identical completion files
dontBuild = true;
installPhase = ''
mkdir -p $out
cp * $out/
'';
preferLocalBuild = true;
allowSubstitutes = false;
};
generateCompletions = package: pkgs.runCommand
"${package.name}_fish-completions"
(
{
inherit package;
preferLocalBuild = true;
allowSubstitutes = false;
}
// optionalAttrs (package ? meta.priority) { meta.priority = package.meta.priority; }
)
''
mkdir -p $out
if [ -d $package/share/man ]; then
find $package/share/man -type f | xargs ${pkgs.python3.interpreter} ${patchedGenerator}/create_manpage_completions.py --directory $out >/dev/null
fi
'';
in
pkgs.buildEnv {
name = "system_fish-completions";
ignoreCollisions = true;
paths = map generateCompletions config.environment.systemPackages;
};
}

# include programs that bring their own completions
{
pathsToLink = []
++ optional cfg.vendor.config.enable "/share/fish/vendor_conf.d"
++ optional cfg.vendor.completions.enable "/share/fish/vendor_completions.d"
++ optional cfg.vendor.functions.enable "/share/fish/vendor_functions.d";
}

{ systemPackages = [ pkgs.fish ]; }

{
shells = [
"/run/current-system/sw/bin/fish"
"${pkgs.fish}/bin/fish"
];
}
];

programs.fish.interactiveShellInit = ''
# add completions generated by NixOS to $fish_complete_path
Expand All @@ -187,61 +297,6 @@ in
end
'';

environment.etc."fish/generated_completions".source =
let
patchedGenerator = pkgs.stdenv.mkDerivation {
name = "fish_patched-completion-generator";
srcs = [
"${pkgs.fish}/share/fish/tools/create_manpage_completions.py"
"${pkgs.fish}/share/fish/tools/deroff.py"
];
unpackCmd = "cp $curSrc $(basename $curSrc)";
sourceRoot = ".";
patches = [ ./fish_completion-generator.patch ]; # to prevent collisions of identical completion files
dontBuild = true;
installPhase = ''
mkdir -p $out
cp * $out/
'';
preferLocalBuild = true;
allowSubstitutes = false;
};
generateCompletions = package: pkgs.runCommand
"${package.name}_fish-completions"
(
{
inherit package;
preferLocalBuild = true;
allowSubstitutes = false;
}
// optionalAttrs (package ? meta.priority) { meta.priority = package.meta.priority; }
)
''
mkdir -p $out
if [ -d $package/share/man ]; then
find $package/share/man -type f | xargs ${pkgs.python3.interpreter} ${patchedGenerator}/create_manpage_completions.py --directory $out >/dev/null
fi
'';
in
pkgs.buildEnv {
name = "system_fish-completions";
ignoreCollisions = true;
paths = map generateCompletions config.environment.systemPackages;
};

# include programs that bring their own completions
environment.pathsToLink = []
++ optional cfg.vendor.config.enable "/share/fish/vendor_conf.d"
++ optional cfg.vendor.completions.enable "/share/fish/vendor_completions.d"
++ optional cfg.vendor.functions.enable "/share/fish/vendor_functions.d";

environment.systemPackages = [ pkgs.fish ];

environment.shells = [
"/run/current-system/sw/bin/fish"
"${pkgs.fish}/bin/fish"
];

};

}