Change:
This is a feature request. May you please make shell easily configurable as a default shell. With , for example, I can simply enable it like so and set . cc
I'm not sure that actually closes this. See
How not? He only asked for being able to put fish in current-system/sw so that he could use it as shell like it's done with zsh. With the PR merged he can perfectly do so.
Setting the default shell to fish with the new module would result in a shell that doesn't inherit any environment from , as bash and zsh do.
It's really so incompatible to not being able to set a couple of variables? In which case I can revert.
And even it if it were compatible, the module doesn't even correctly set up an initialization file from which to source .
Impressive. Reverting, thanks.
The syntax for fish is different, so instead of using , you use . I've been poking around and will try and come up with a reasonable fish script to set up the environment.
Could we get away with a wrapper that sets up the environment and then invokes fish?
For anyone else who gets here from Google, I rewrote a version of in as a stopgap.
do you think this can this be integrated to nixpkgs to provide a somewhat seamless experience for those who want to use fish as their default shell?
I'll look into how gets written and such after work today. I wouldn't expect it to be too labor-intensive.
FWIW trying to set fish as the default shell (though it works when manually running) leads to all sorts of trouble: !
One way to do this is with 'fenv', a fish function defined in the plugin-foreign-env package for Oh My Fish: The fenv function takes a bash command or a path to a bash script, runs it under bash, and then modifies the fish environment appropriately to match any environment variables that were set in the bash environment. Fish also automatically escapes the output of subcommands in the appropriate way, so if we want to use the output of a command, as we would with ssh-agent, for example, without modifying anything to get fish code, we can do or or ssh-agent`` and so on. I think leveraging this function would be a good idea, but what's the best way to go about it? Should we arrange things so that " = true;" also installs oh-my-fish as well as the plugin for omf in a nixy way? Should we rip out the code from the package? Or maybe, should we just write a nix expression that installs the files for the functions, ripping them directly from git but arranging them in a different location (maybe globally)? Edit: oh-my-fish also has a plugin which implements a function called 'export' that acts like bash's export, so you can just make those export calls and all is well.
Using the function would make it accessible to the user, which she may not want. Plus, if the script one day uses a bash-specific feature, it would raise an error difficult to pin down. IMHO, we should just replicate fenv as a compatibility hook.
Do you have any preference as to how it's done? I'm willing to do it, but idk what I'm doing, really. If you want to gesture in some direction I'd be happy to iterate through a few attempts. On Sun, Dec 6, 2015, 08:11 gpyh wrote:
I'd love to see this fixed, but I'm kinda in the same boat, don't really know how to approach this.
Would appreciate some feedback for the above PR.
Does it work in your system? As I instected the viability some time ago, I found some nixpkgs modules explicitly build array environment variables by concatenating with s, I think does it that way. afaik automatically converts only some few explicit envvars to fish-arrays, e.g. . I suspect those explicit string concatenations need to be abstracted for POSIX-like shells and fish-like shells first.
Of course it works on my system. I've been using it for the last two weeks without any issues (other than . but that was an issue in the package). Just look at the source, it completely bypasses any compatibility issues by importing the environment using fish-foreign-env. Making NixOS fish-compatible is just not possible because we have things like :
That’s nice! I will try to use it.
Thanks for taking care of this, . I'm glad to see this closed. :-)
Can anyone who got this working update the wiki? Currently says Is this still true? What do I do in my config file if I want to use fish as my shell?
Never mind, I figured it out and I will update the wiki myself :+1:
Just saw this: Anyway the answer is: Easy!
It might make sense to document changing the default shell in the nixos manual, with examples for fish & zsh. Do you want to do that?

Discussion:
./programs/dconf.nix ./programs/environment.nix ./programs/freetds.nix <ins> ./programs/fish.nix </ins> ./programs/ibus.nix ./programs/kbdlight.nix ./programs/light.nix

<ins> { config, lib, pkgs, ... }: with lib; let cfge = config.environment; cfg = config.programs.fish; fishAliases = concatStringsSep "n" ( mapAttrsFlatten (k: v: "alias ${k} '${v}'") cfg.shellAliases ); in { options = { programs.fish = { enable = mkOption { default = false; description = '' Whether to configure fish as an interactive shell. ''; type = types.bool; }; shellAliases = mkOption { default = config.environment.shellAliases; description = '' Set of aliases for fish shell. See <option>environment.shellAliases</option> for an option format description. ''; type = types.attrs; }; shellInit = mkOption { default = ""; description = '' Shell script code called during fish shell initialisation. ''; type = types.lines; }; loginShellInit = mkOption { default = ""; description = '' Shell script code called during fish login shell initialisation. ''; type = types.lines; }; interactiveShellInit = mkOption { default = ""; description = '' Shell script code called during interactive fish shell initialisation. ''; type = types.lines; }; promptInit = mkOption { default = ""; description = '' Shell script code used to initialise fish prompt. ''; type = types.lines; }; }; }; config = mkIf cfg.enable { 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/config.fish".text = '' # /etc/fish/config.fish: DO NOT EDIT -- this file has been generated automatically. set fish_function_path $fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions fenv source ${config.system.build.setEnvironment} 1> /dev/null fenv source /etc/fish/foreign-env/shellInit 1> /dev/null ${cfg.shellInit} if builtin status --is-login fenv source /etc/fish/foreign-env/loginShellInit 1> /dev/null ${cfg.loginShellInit} end if builtin status --is-interactive ${fishAliases} fenv source /etc/fish/foreign-env/interactiveShellInit 1> /dev/null ${cfg.interactiveShellInit} end ''; environment.systemPackages = [ pkgs.fish ]; environment.shells = [ "/run/current-system/sw/bin/fish" "/var/run/current-system/sw/bin/fish" "${pkgs.fish}/bin/fish" ]; }; } </ins>

<ins> { stdenv, fetchFromGitHub, gnused, bash, coreutils }: stdenv.mkDerivation rec { name = "fish-foreign-env-${version}"; version = "git-20151223"; src = fetchFromGitHub { owner = "oh-my-fish"; repo = "plugin-foreign-env"; rev = "2dfe5b73fd2101702c83d1d7b566e2b9332c5ddc"; sha256 = "17jxlbljp7k2azcl1miz5h5xfyazlf9z9lrddcrnm6r7c1w1zdh5"; }; buildCommand = '' mkdir -p $out/share/fish-foreign-env/functions/ cp $src/functions/* $out/share/fish-foreign-env/functions/ sed -e "s|sed|${gnused}/bin/sed|"  -e "s|bash|${bash}/bin/bash|"  -e "s|| tr|| ${coreutils}/bin/tr|"  -i $out/share/fish-foreign-env/functions/* ''; meta = with stdenv.lib; { description = "A foreign environment interface for Fish shell"; license = licenses.mit; maintainers = with maintainers; [ jgillich ]; }; } </ins>

<ins> commit 5145ca56b0ac1e5e284ab6dfa6fdecc5e86e59b8 Author: Jakob Gillich <jakob@gillich.me> Date:   Sat Dec 26 04:57:06 2015 +0100 prefix status command with builtin diff --git a/etc/config.fish b/etc/config.fish index 0683f40..9297a85 100644 --- a/etc/config.fish +++ b/etc/config.fish @@ -6,7 +6,7 @@ # Some things should only be done for login terminals # -if status --is-login +if builtin status --is-login # # Set some value for LANG if nothing was set before, and this is a diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish index 9b27fb9..d1c704b 100644 --- a/share/functions/__fish_config_interactive.fish +++ b/share/functions/__fish_config_interactive.fish @@ -101,7 +101,7 @@ function __fish_config_interactive -d "Initializations that should be performed eval "$__fish_bin_dir/fish -c 'fish_update_completions > /dev/null ^/dev/null' &" end -	if status -i +	if builtin status -i # # Print a greeting # @@ -128,14 +128,14 @@ function __fish_config_interactive -d "Initializations that should be performed # function __fish_repaint --on-variable fish_color_cwd --description "Event handler, repaints the prompt when fish_color_cwd changes" -		if status --is-interactive +		if builtin status --is-interactive set -e __fish_prompt_cwd commandline -f repaint ^/dev/null end end function __fish_repaint_root --on-variable fish_color_cwd_root --description "Event handler, repaints the prompt when fish_color_cwd_root changes" -		if status --is-interactive +		if builtin  status --is-interactive set -e __fish_prompt_cwd commandline -f repaint ^/dev/null end @@ -191,7 +191,7 @@ function __fish_config_interactive -d "Initializations that should be performed # Notify vte-based terminals when $PWD changes (issue #906) if test "$VTE_VERSION" -ge 3405 -o "$TERM_PROGRAM" = "Apple_Terminal" function __update_vte_cwd --on-variable PWD --description 'Notify VTE of change to $PWD' -			status --is-command-substitution; and return +			builtin status --is-command-substitution; and return printf '033]7;file://%s%sa' (hostname) (pwd | __fish_urlencode) end end diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 0117894..4e4b60f 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -728,7 +728,7 @@ for var in repaint describe_style show_informative_status showdirtystate showsta set varargs $varargs --on-variable __fish_git_prompt_$var end function __fish_git_prompt_repaint $varargs --description "Event handler, repaints prompt when functionality changes" -	if status --is-interactive +	if builtin status --is-interactive if test $argv[3] = __fish_git_prompt_show_informative_status # Clear characters that have different defaults with/without informative status for name in cleanstate dirtystate invalidstate stagedstate stateseparator untrackedfiles upstream_ahead upstream_behind @@ -746,7 +746,7 @@ for var in '' _prefix _suffix _bare _merging _cleanstate _invalidstate _upstream end set varargs $varargs --on-variable __fish_git_prompt_showcolorhints function __fish_git_prompt_repaint_color $varargs --description "Event handler, repaints prompt when any color changes" -	if status --is-interactive +	if builtin status --is-interactive set -l var $argv[3] set -e _$var set -e _{$var}_done @@ -766,7 +766,7 @@ for var in cleanstate dirtystate invalidstate stagedstate stashstate statesepara set varargs $varargs --on-variable __fish_git_prompt_char_$var end function __fish_git_prompt_repaint_char $varargs --description "Event handler, repaints prompt when any char changes" -	if status --is-interactive +	if builtin status --is-interactive set -e _$argv[3] commandline -f repaint ^/dev/null end diff --git a/share/functions/cd.fish b/share/functions/cd.fish index 8faa469..10168d7 100644 --- a/share/functions/cd.fish +++ b/share/functions/cd.fish @@ -5,7 +5,7 @@ function cd --description "Change directory" # Skip history in subshells -	if status --is-command-substitution +	if builtin status --is-command-substitution builtin cd $argv return $status end @@ -33,4 +33,3 @@ function cd --description "Change directory" return $cd_status end - diff --git a/share/functions/eval.fish b/share/functions/eval.fish index 052d417..5eeb12a 100644 --- a/share/functions/eval.fish +++ b/share/functions/eval.fish @@ -23,17 +23,17 @@ function eval -S -d "Evaluate parameters as a command" # used interactively, like less, wont work using eval. set -l mode -	if status --is-interactive-job-control +	if builtin status --is-interactive-job-control set mode interactive else -		if status --is-full-job-control +		if builtin status --is-full-job-control set mode full else set mode none end end -	if status --is-interactive -		status --job-control full +	if builtin status --is-interactive +		builtin status --job-control full end __fish_restore_status $status_copy @@ -60,6 +60,6 @@ function eval -S -d "Evaluate parameters as a command" echo "begin; $argv "n" ;end <&3 3<&-" | source 3<&0 set -l res $status -	status --job-control $mode +	builtin status --job-control $mode return $res end diff --git a/share/functions/history.fish b/share/functions/history.fish index fd2b91f..12d28d7 100644 --- a/share/functions/history.fish +++ b/share/functions/history.fish @@ -38,7 +38,7 @@ function history --description "Deletes an item from history" end else #Execute history builtin without any argument -        if status --is-interactive +        if builtin status --is-interactive builtin history | eval $pager else builtin history diff --git a/share/functions/psub.fish b/share/functions/psub.fish index 67863ad..dd0e08b 100644 --- a/share/functions/psub.fish +++ b/share/functions/psub.fish @@ -40,7 +40,7 @@ function psub --description "Read from stdin into a file and output the filename end -	if not status --is-command-substitution +	if not builtin status --is-command-substitution echo psub: Not inside of command substitution >&2 return 1 end diff --git a/share/tools/web_config/sample_prompts/classic_git.fish b/share/tools/web_config/sample_prompts/classic_git.fish index 39f3ab8..601fa19 100644 --- a/share/tools/web_config/sample_prompts/classic_git.fish +++ b/share/tools/web_config/sample_prompts/classic_git.fish @@ -17,25 +17,25 @@ function fish_prompt --description 'Write out the prompt' set -g __fish_classic_git_functions_defined function __fish_repaint_user --on-variable fish_color_user --description "Event handler, repaint when fish_color_user changes" -			if status --is-interactive +			if builtin status --is-interactive commandline -f repaint ^/dev/null end end - + function __fish_repaint_host --on-variable fish_color_host --description "Event handler, repaint when fish_color_host changes" -			if status --is-interactive +			if builtin status --is-interactive commandline -f repaint ^/dev/null end end - + function __fish_repaint_status --on-variable fish_color_status --description "Event handler; repaint when fish_color_status changes" -			if status --is-interactive +			if builtin status --is-interactive commandline -f repaint ^/dev/null end end function __fish_repaint_bind_mode --on-variable fish_key_bindings --description "Event handler; repaint when fish_key_bindings changes" -			if status --is-interactive +			if builtin status --is-interactive commandline -f repaint ^/dev/null end end diff --git a/tests/test_util.fish b/tests/test_util.fish index 22744b3..576dbc4 100644 --- a/tests/test_util.fish +++ b/tests/test_util.fish @@ -4,7 +4,7 @@ if test "$argv[1]" = (status -f) echo 'test_util.fish requires sourcing script as argument to `source`' >&2 echo 'use `source test_util.fish (status -f); or exit`' >&2 -    status --print-stack-trace >&2 +    builtin status --print-stack-trace >&2 exit 1 end </ins>

<del> { stdenv, fetchurl, ncurses, nettools, python, which, groff, gettext, man_db, bc, libiconv, coreutils }: </del> <ins> { stdenv, fetchurl, ncurses, nettools, python, which, groff, gettext, man_db, bc, libiconv, coreutils, gnused, kbd }: </ins> stdenv.mkDerivation rec { name = "fish-${version}";

sha256 = "0ympqz7llmf0hafxwglykplw6j5cz82yhlrw50lw4bnf2kykjqx7"; }; <ins> # builtin_status has been upstreamed https://github.com/fish-shell/fish-shell/pull/2636 patches = [ ./etc_config.patch ./builtin_status.patch ]; </ins> buildInputs = [ ncurses libiconv ]; # Required binaries during execution

++ [ bc coreutils ]; postInstall = '' <ins> sed -e "s|expr|${coreutils}/bin/expr|"  -e "s|if which unicode_start|if true|"  -e "s|unicode_start|${kbd}/bin/unicode_start|"  -i "$out/etc/fish/config.fish" </ins> sed -e "s|bc|${bc}/bin/bc|"  -e "s|/usr/bin/seq|${coreutils}/bin/seq|"  -i "$out/share/fish/functions/seq.fish"  "$out/share/fish/functions/math.fish" sed -i "s|which |${which}/bin/which |" "$out/share/fish/functions/type.fish" <ins> sed -e "s||cut||${coreutils}/bin/cut|" -i "$out/share/fish/functions/fish_prompt.fish" </ins> sed -i "s|nroff |${groff}/bin/nroff |" "$out/share/fish/functions/__fish_print_help.fish" sed -e "s|gettext |${gettext}/bin/gettext |"  -e "s|which |${which}/bin/which |"  -i "$out/share/fish/functions/_.fish" <ins> sed -e "s|uname|${coreutils}/bin/uname|"  -i "$out/share/fish/functions/__fish_pwd.fish"  "$out/share/fish/functions/prompt_pwd.fish" sed -e "s|sed |${gnused}/bin/sed |"  -i "$out/share/fish/functions/alias.fish"  "$out/share/fish/functions/prompt_pwd.fish" </ins> substituteInPlace "$out/share/fish/functions/fish_default_key_bindings.fish"  --replace "clear;" "${ncurses}/bin/clear;" '' + stdenv.lib.optionalString (!stdenv.isDarwin) ''

<ins> commit 0ec07a7018bd69513b0bca6e2f22dbf8575a5b5e Author: Jakob Gillich <jakob@gillich.me> Date:   Fri Dec 25 01:59:29 2015 +0100 load /etc/fish/config.fish if it exists diff --git a/etc/config.fish b/etc/config.fish index 0683f40..33f4da7 100644 --- a/etc/config.fish +++ b/etc/config.fish @@ -37,3 +37,6 @@ if status --is-login end end +if test -f /etc/fish/config.fish +  source /etc/fish/config.fish +end </ins>

python = python27Full; }; <ins> fish-foreign-env = callPackage ../shells/fish-foreign-env { }; </ins> mksh = callPackage ../shells/mksh { }; pash = callPackage ../shells/pash { };