2015-12-25 00:17:42 +00:00
{ config , lib , pkgs , . . . }:
let
cfge = config . environment ;
cfg = config . programs . fish ;
2024-05-12 23:11:30 +00:00
fishAbbrs = lib . concatStringsSep " \n " (
2024-07-19 08:32:13 +00:00
lib . mapAttrsToList ( k : v : " a b b r - a g ${ k } ${ lib . escapeShellArg v } " )
2021-04-14 21:46:27 +00:00
cfg . shellAbbrs
) ;
2024-05-12 23:11:30 +00:00
fishAliases = lib . concatStringsSep " \n " (
2024-07-19 08:32:13 +00:00
lib . mapAttrsToList ( k : v : " a l i a s ${ k } ${ lib . escapeShellArg v } " )
2024-05-12 23:11:30 +00:00
( lib . filterAttrs ( k : v : v != null ) cfg . shellAliases )
2015-12-25 00:17:42 +00:00
) ;
2021-01-11 07:11:29 +00:00
envShellInit = pkgs . writeText " s h e l l I n i t " cfge . shellInit ;
envLoginShellInit = pkgs . writeText " l o g i n S h e l l I n i t " cfge . loginShellInit ;
envInteractiveShellInit = pkgs . writeText " i n t e r a c t i v e S h e l l I n i t " cfge . interactiveShellInit ;
sourceEnv = file :
if cfg . useBabelfish then
" s o u r c e / e t c / f i s h / ${ file } . f i s h "
else
''
2021-01-24 12:41:37 +00:00
set fish_function_path $ { pkgs . fishPlugins . foreign-env } /share/fish/vendor_functions.d $ fish_function_path
2021-01-11 07:11:29 +00:00
fenv source /etc/fish/foreign-env / $ { file } > /dev/null
set - e fish_function_path [ 1 ]
'' ;
babelfishTranslate = path : name :
2022-11-04 07:08:33 +00:00
pkgs . runCommandLocal " ${ name } . f i s h " {
2021-01-11 07:11:29 +00:00
nativeBuildInputs = [ pkgs . babelfish ] ;
2023-07-31 12:10:04 +00:00
} " b a b e l f i s h < ${ path } > $ o u t ; " ;
2021-01-11 07:11:29 +00:00
2015-12-25 00:17:42 +00:00
in
{
options = {
programs . fish = {
2024-04-17 11:37:58 +00:00
enable = lib . mkOption {
2015-12-25 00:17:42 +00:00
default = false ;
2022-07-20 10:32:04 +00:00
description = ''
2015-12-25 00:17:42 +00:00
Whether to configure fish as an interactive shell .
'' ;
2024-04-17 11:37:58 +00:00
type = lib . types . bool ;
2015-12-25 00:17:42 +00:00
} ;
2018-08-29 16:05:53 +00:00
2024-04-17 11:37:58 +00:00
package = lib . mkPackageOption pkgs " f i s h " { } ;
2024-05-06 10:53:41 +00:00
2024-04-17 11:37:58 +00:00
useBabelfish = lib . mkOption {
type = lib . types . bool ;
2021-01-11 07:11:29 +00:00
default = false ;
2022-07-20 10:32:04 +00:00
description = ''
If enabled , the configured environment will be translated to native fish using [ babelfish ] ( https://github.com/bouk/babelfish ) .
Otherwise , [ foreign-env ] ( https://github.com/oh-my-fish/plugin-foreign-env ) will be used .
2021-01-11 07:11:29 +00:00
'' ;
} ;
2024-04-17 11:37:58 +00:00
vendor . config . enable = lib . mkOption {
type = lib . types . bool ;
2017-03-25 08:37:07 +00:00
default = true ;
2022-07-20 10:32:04 +00:00
description = ''
2017-03-25 08:37:07 +00:00
Whether fish should source configuration snippets provided by other packages .
'' ;
} ;
2024-04-17 11:37:58 +00:00
vendor . completions . enable = lib . mkOption {
type = lib . types . bool ;
2017-03-25 08:37:07 +00:00
default = true ;
2022-07-20 10:32:04 +00:00
description = ''
2017-03-25 08:37:07 +00:00
Whether fish should use completion files provided by other packages .
'' ;
} ;
2018-08-29 16:05:53 +00:00
2024-04-17 11:37:58 +00:00
vendor . functions . enable = lib . mkOption {
type = lib . types . bool ;
2017-03-25 08:37:07 +00:00
default = true ;
2022-07-20 10:32:04 +00:00
description = ''
2017-03-25 08:37:07 +00:00
Whether fish should autoload fish functions provided by other packages .
'' ;
} ;
2015-12-25 00:17:42 +00:00
2024-04-17 11:37:58 +00:00
shellAbbrs = lib . mkOption {
2021-04-14 21:46:27 +00:00
default = { } ;
example = {
gco = " g i t c h e c k o u t " ;
npu = " n i x - p r e f e t c h - u r l " ;
} ;
2022-07-20 10:32:04 +00:00
description = ''
2021-04-14 21:46:27 +00:00
Set of fish abbreviations .
'' ;
2024-04-17 11:37:58 +00:00
type = with lib . types ; attrsOf str ;
2021-04-14 21:46:27 +00:00
} ;
2024-04-17 11:37:58 +00:00
shellAliases = lib . mkOption {
2018-08-04 03:32:30 +00:00
default = { } ;
2022-07-20 10:32:04 +00:00
description = ''
Set of aliases for fish shell , which overrides { option } ` environment . shellAliases ` .
See { option } ` environment . shellAliases ` for an option format description .
2015-12-25 00:17:42 +00:00
'' ;
2024-04-17 11:37:58 +00:00
type = with lib . types ; attrsOf ( nullOr ( either str path ) ) ;
2015-12-25 00:17:42 +00:00
} ;
2024-04-17 11:37:58 +00:00
shellInit = lib . mkOption {
2015-12-25 00:17:42 +00:00
default = " " ;
2022-07-20 10:32:04 +00:00
description = ''
2015-12-25 00:17:42 +00:00
Shell script code called during fish shell initialisation .
'' ;
2024-04-17 11:37:58 +00:00
type = lib . types . lines ;
2015-12-25 00:17:42 +00:00
} ;
2024-04-17 11:37:58 +00:00
loginShellInit = lib . mkOption {
2015-12-25 00:17:42 +00:00
default = " " ;
2022-07-20 10:32:04 +00:00
description = ''
2015-12-25 00:17:42 +00:00
Shell script code called during fish login shell initialisation .
'' ;
2024-04-17 11:37:58 +00:00
type = lib . types . lines ;
2015-12-25 00:17:42 +00:00
} ;
2024-04-17 11:37:58 +00:00
interactiveShellInit = lib . mkOption {
2015-12-25 00:17:42 +00:00
default = " " ;
2022-07-20 10:32:04 +00:00
description = ''
2015-12-25 00:17:42 +00:00
Shell script code called during interactive fish shell initialisation .
'' ;
2024-04-17 11:37:58 +00:00
type = lib . types . lines ;
2015-12-25 00:17:42 +00:00
} ;
2024-04-17 11:37:58 +00:00
promptInit = lib . mkOption {
2015-12-25 00:17:42 +00:00
default = " " ;
2022-07-20 10:32:04 +00:00
description = ''
2015-12-25 00:17:42 +00:00
Shell script code used to initialise fish prompt .
'' ;
2024-04-17 11:37:58 +00:00
type = lib . types . lines ;
2015-12-25 00:17:42 +00:00
} ;
} ;
} ;
2024-04-17 11:37:58 +00:00
config = lib . mkIf cfg . enable {
2015-12-25 00:17:42 +00:00
2024-05-12 23:11:30 +00:00
programs . fish . shellAliases = lib . mapAttrs ( name : lib . mkDefault ) cfge . shellAliases ;
2018-08-04 03:32:30 +00:00
2020-06-29 20:28:32 +00:00
# Required for man completions
2020-12-03 21:00:33 +00:00
documentation . man . generateCaches = lib . mkDefault true ;
2020-06-29 20:28:32 +00:00
2024-04-17 11:37:58 +00:00
environment = lib . mkMerge [
( lib . mkIf cfg . useBabelfish
2021-01-11 07:11:29 +00:00
{
etc . " f i s h / s e t E n v i r o n m e n t . f i s h " . source = babelfishTranslate config . system . build . setEnvironment " s e t E n v i r o n m e n t " ;
etc . " f i s h / s h e l l I n i t . f i s h " . source = babelfishTranslate envShellInit " s h e l l I n i t " ;
etc . " f i s h / l o g i n S h e l l I n i t . f i s h " . source = babelfishTranslate envLoginShellInit " l o g i n S h e l l I n i t " ;
etc . " f i s h / i n t e r a c t i v e S h e l l I n i t . f i s h " . source = babelfishTranslate envInteractiveShellInit " i n t e r a c t i v e S h e l l I n i t " ;
} )
2024-04-17 11:37:58 +00:00
( lib . mkIf ( ! cfg . useBabelfish )
2021-01-11 07:11:29 +00:00
{
etc . " f i s h / f o r e i g n - e n v / s h e l l I n i t " . source = envShellInit ;
etc . " f i s h / f o r e i g n - e n v / l o g i n S h e l l I n i t " . source = envLoginShellInit ;
etc . " f i s h / f o r e i g n - e n v / i n t e r a c t i v e S h e l l I n i t " . source = envInteractiveShellInit ;
} )
{
etc . " f i s h / n i x o s - e n v - p r e i n i t . f i s h " . text =
if cfg . useBabelfish
then ''
# source the NixOS environment config
if [ - z " $ _ _ N I X O S _ S E T _ E N V I R O N M E N T _ D O N E " ]
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 " $ _ _ N I X O S _ S E T _ E N V I R O N M E N T _ D O N E " ]
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 . " f i s h / c o n f i g . f i s h " . 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 " s h e l l I n i t " }
$ { 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
2023-10-19 06:40:56 +00:00
status is-login ; and not set - q __fish_nixos_login_config_sourced
2021-01-11 07:11:29 +00:00
and begin
$ { sourceEnv " l o g i n S h e l l I n i t " }
$ { 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
2023-10-19 06:40:56 +00:00
status is-interactive ; and not set - q __fish_nixos_interactive_config_sourced
2021-01-11 07:11:29 +00:00
and begin
2021-04-14 21:46:27 +00:00
$ { fishAbbrs }
2021-01-11 07:11:29 +00:00
$ { fishAliases }
$ { sourceEnv " i n t e r a c t i v e S h e l l I n i t " }
$ { 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 . " f i s h / g e n e r a t e d _ c o m p l e t i o n s " . source =
let
patchedGenerator = pkgs . stdenv . mkDerivation {
name = " f i s h _ p a t c h e d - c o m p l e t i o n - g e n e r a t o r " ;
srcs = [
2024-05-06 10:53:41 +00:00
" ${ cfg . package } / s h a r e / f i s h / t o o l s / c r e a t e _ m a n p a g e _ c o m p l e t i o n s . p y "
" ${ cfg . package } / s h a r e / f i s h / t o o l s / d e r o f f . p y "
2021-01-11 07:11:29 +00:00
] ;
unpackCmd = " c p $ c u r S r c $ ( b a s e n a m e $ c u r S r c ) " ;
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 ;
} ;
2022-06-08 11:50:36 +00:00
generateCompletions = package : pkgs . runCommandLocal
( with lib . strings ; let
storeLength = stringLength storeDir + 34 ; # Nix' StorePath::HashLen + 2 for the separating slash and dash
pathName = substring storeLength ( stringLength package - storeLength ) package ;
in ( package . name or pathName ) + " _ f i s h - c o m p l e t i o n s " )
( { inherit package ; } //
2024-04-17 11:37:58 +00:00
lib . optionalAttrs ( package ? meta . priority ) { meta . priority = package . meta . priority ; } )
2021-01-11 07:11:29 +00:00
''
mkdir - p $ out
if [ - d $ package/share/man ] ; then
2023-11-06 01:38:24 +00:00
find $ package/share/man - type f | xargs $ { pkgs . python3 . pythonOnBuildForHost . interpreter } $ { patchedGenerator } /create_manpage_completions.py - - directory $ out > /dev/null
2021-01-11 07:11:29 +00:00
fi
'' ;
in
pkgs . buildEnv {
name = " s y s t e m _ f i s h - c o m p l e t i o n s " ;
ignoreCollisions = true ;
2024-04-17 11:37:58 +00:00
paths = builtins . map generateCompletions config . environment . systemPackages ;
2021-01-11 07:11:29 +00:00
} ;
}
# include programs that bring their own completions
{
pathsToLink = [ ]
2024-04-17 11:37:58 +00:00
++ lib . optional cfg . vendor . config . enable " / s h a r e / f i s h / v e n d o r _ c o n f . d "
++ lib . optional cfg . vendor . completions . enable " / s h a r e / f i s h / v e n d o r _ c o m p l e t i o n s . d "
++ lib . optional cfg . vendor . functions . enable " / s h a r e / f i s h / v e n d o r _ f u n c t i o n s . d " ;
2021-01-11 07:11:29 +00:00
}
2024-05-06 10:53:41 +00:00
{ systemPackages = [ cfg . package ] ; }
2021-01-11 07:11:29 +00:00
{
shells = [
" / r u n / c u r r e n t - s y s t e m / s w / b i n / f i s h "
2024-05-06 10:53:41 +00:00
( lib . getExe cfg . package )
2021-01-11 07:11:29 +00:00
] ;
}
] ;
2015-12-25 00:17:42 +00:00
2018-12-17 19:12:09 +00:00
programs . fish . interactiveShellInit = ''
# add completions generated by NixOS to $fish_complete_path
begin
2023-05-20 02:11:38 +00:00
# joins with null byte to accommodate all characters in paths, then respectively gets all paths before (exclusive) / after (inclusive) the first one including "generated_completions",
2018-12-17 19:12:09 +00:00
# splits by null byte, and then removes all empty lines produced by using 'string'
set - l prev ( string join0 $ fish_complete_path | string match - - regex " ^ . * ? ( ? = \x 0 0 [ ^ \x 0 0 ] * g e n e r a t e d _ c o m p l e t i o n s . * ) " | string split0 | string match - er " . " )
set - l post ( string join0 $ fish_complete_path | string match - - regex " [ ^ \x 0 0 ] * g e n e r a t e d _ c o m p l e t i o n s . * " | string split0 | string match - er " . " )
set fish_complete_path $ prev " / e t c / f i s h / g e n e r a t e d _ c o m p l e t i o n s " $ post
end
2020-04-28 12:05:28 +00:00
# prevent fish from generating completions on first run
if not test - d $ __fish_user_data_dir/generated_completions
$ { pkgs . coreutils } /bin/mkdir $ __fish_user_data_dir/generated_completions
end
2018-12-17 19:12:09 +00:00
'' ;
2015-12-25 00:17:42 +00:00
} ;
}