Fish: Difference between revisions

From NixOS Wiki
imported>Legendofmiracles
m fixed the small mess i created ;-;
 
(21 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{DISPLAYTITLE:fish}}
{{DISPLAYTITLE:fish}}
fish is the [http://fishshell.com/ Friendly Interactive SHell].
fish, the [http://fishshell.com/ Friendly Interactive Shell], is a [[Command Shell|command shell]] designed around user-friendliness.


==Setting fish as the login shell==
== Installation ==
The following <tt>/etc/nixos/configuration.nix</tt> fragment demonstrates how to enable fish and set it as the default shell for user <tt>foo</tt>.
 
A basic user-specific installation with [[Home Manager]] may look like this:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
home-manager.users.myuser = {
  ...
   programs.fish.enable = true;
   programs.fish.enable = true;
};
</syntaxhighlight>
Change <code>myuser</code> to the username of the user you want to configure.
You can enable the fish shell and manage fish configuration and plugins with Home Manager, but to enable vendor fish completions provided by Nixpkgs you will also want to enable the fish shell in <code>/etc/nixos/configuration.nix</code>:
<syntaxhighlight lang="nix">
  programs.fish.enable = true;
</syntaxhighlight>
== Setting fish as your shell ==
Warning! [https://fishshell.com/docs/current/index.html#default-shell As noted in the fish documentation], using fish as your *login* shell (referenced in <code>/etc/passwd</code>) may cause issues because fish is not POSIX compliant. In particular, this author found systemd's emergency mode to be completely broken when fish was set as the login shell.
This issue is discussed extensively on the [https://wiki.gentoo.org/wiki/Fish#Caveats Gentoo] and [https://wiki.archlinux.org/title/Fish#System_integration Arch] wikis. There they present an alternative, keeping bash as the system shell but having it exec fish when run interactively.
Here is one solution, which launches fish unless the parent process is already fish:
<syntaxhighlight lang="nix">
programs.bash = {
  interactiveShellInit = ''
    if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
    then
      shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
      exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
    fi
  '';
};
</syntaxhighlight>
If you still want to set fish as the login shell, see [[Command Shell#Changing default shell]].
=== Running fish interactively with zsh as system shell on darwin ===
Zsh users on darwin will need to use a modified version of the above snippet. As written, it presents two incompatibilities. First, being BSD-derived, MacOS's <code>ps</code> command accepts different options. Second, this is a script intended for bash, not zsh. MacOS uses zsh as its default shell.


  users.users.foo = {
<syntaxhighlight lang="nix">
     shell = pkgs.fish;
programs.zsh = {
  };
  initExtra = ''
   ...
     if [[ $(ps -o command= -p "$PPID" | awk '{print $1}') != 'fish' ]]
}
    then
        exec fish -l
    fi
   ''
};
</syntaxhighlight>
</syntaxhighlight>


== Managing fish plugins with Home Manager ==
== Configuration ==


In order to manage fish with home manager you also have to enable it in your <code>home.nix</code>.
=== System wide ===


Then you can add new ones by adding them to the list of submodules of <code>programs.fish.plugins</code>. So for example for the plugin <code>z</code> from jethrokuan on github.
To enable fish plugins, add your preferred plugins to `environment.systemPackages`:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
   programs.fish.enable = true;
environment.systemPackages = with pkgs; [
   programs.fish.plugins = [{
  fishPlugins.done
    name = "z";
  fishPlugins.fzf-fish
    src = pkgs.fetchFromGitHub {
  fishPlugins.forgit
      owner = "jethrokuan";
  fishPlugins.hydro
      repo = "z";
  fzf
      rev = "e0e1b9dfdba362f8ab1ae8c1afc7ccf62b89f7eb";
  fishPlugins.grc
      sha256 = "0dbnir6jbwjpjalz14snzd3cgdysgcs3raznsijd6savad3qhijc";
   grc
     };
];
  }];
 
programs.fish.enable = true;
</syntaxhighlight>
 
=== Home Manager ===
 
An example configuration in Home Manager for adding plugins and changing options could look like this:
 
<syntaxhighlight lang="nix">
home-manager.users.myuser = {
   programs.fish = {
    enable = true;
    interactiveShellInit = ''
      set fish_greeting # Disable greeting
    '';
    plugins = [
      # Enable a plugin (here grc for colorized command output) from nixpkgs
      { name = "grc"; src = pkgs.fishPlugins.grc.src; }
      # Manually packaging and enable a plugin
      {
        name = "z";
        src = pkgs.fetchFromGitHub {
          owner = "jethrokuan";
          repo = "z";
          rev = "e0e1b9dfdba362f8ab1ae8c1afc7ccf62b89f7eb";
          sha256 = "0dbnir6jbwjpjalz14snzd3cgdysgcs3raznsijd6savad3qhijc";
        };
      }
     ];
  };
};
</syntaxhighlight>
</syntaxhighlight>
Full list of home-manager options for fish can be found  See also [https://github.com/nix-community/home-manager/blob/master/modules/programs/fish.nix here].
See [https://search.nixos.org/packages?channel=unstable&from=0&size=50&buckets=%7B%22package_attr_set%22%3A%5B%22fishPlugins%22%5D%2C%22package_license_set%22%3A%5B%5D%2C%22package_maintainers_set%22%3A%5B%5D%2C%22package_platforms%22%3A%5B%5D%7D&sort=relevance&query=fishPlugins fishPlugins package set] for available plugins in nixpkgs.


== Useful scripts ==
== Useful scripts ==
=== Show that you are in a nix-shell ===
=== Show that you are in a nix-shell ===
Add this to the <code>fish_prompt</code> function (usually placed in <code>~/.config/fish/functions/fish_prompt.fish</code>):
Add this to the <code>fish_prompt</code> function (usually placed in <code>~/.config/fish/functions/fish_prompt.fish</code>):
Line 54: Line 128:
</syntaxhighlight>
</syntaxhighlight>


Now your prompt looks like this
Now your prompt looks like this:


* outside: <code>~></code>
* outside: <code>~></code>
* inside: <code><nix-shell> ~></code>
* inside: <code><nix-shell> ~></code>


btw. you can directly start nix-shell in fish with <code>nix-shell --run fish</code>, but (FIXME) the normal build functions are not available there.
You can directly start nix-shell in fish with <code>nix-shell --run fish</code>.


=== Environments ===
=== Environments ===
Helper functions that put you in a nix-shell with the given packages installed.  
Here are some examples of helper functions that put you in a nix-shell with the given packages installed.  


You can either put these in <code>programs.fish.functions</code> with home-manager or in <code>~/.config/fish/functions/fish_prompt.fish</code> without.
You can either put these in <code>programs.fish.functions</code> with home-manager or in <code>~/.config/fish/functions/fish_prompt.fish</code> without.
Line 94: Line 168:
# or:        pythonEnv 2 ..
# or:        pythonEnv 2 ..
</syntaxhighlight>
</syntaxhighlight>
== See also ==
* [[Command Shell]]
[[Category:Shell]]

Latest revision as of 18:17, 4 July 2024

fish, the Friendly Interactive Shell, is a command shell designed around user-friendliness.

Installation

A basic user-specific installation with Home Manager may look like this:

home-manager.users.myuser = {
  programs.fish.enable = true;
};

Change myuser to the username of the user you want to configure.

You can enable the fish shell and manage fish configuration and plugins with Home Manager, but to enable vendor fish completions provided by Nixpkgs you will also want to enable the fish shell in /etc/nixos/configuration.nix:

  programs.fish.enable = true;

Setting fish as your shell

Warning! As noted in the fish documentation, using fish as your *login* shell (referenced in /etc/passwd) may cause issues because fish is not POSIX compliant. In particular, this author found systemd's emergency mode to be completely broken when fish was set as the login shell.

This issue is discussed extensively on the Gentoo and Arch wikis. There they present an alternative, keeping bash as the system shell but having it exec fish when run interactively.

Here is one solution, which launches fish unless the parent process is already fish:

programs.bash = {
  interactiveShellInit = ''
    if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
    then
      shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
      exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
    fi
  '';
};

If you still want to set fish as the login shell, see Command Shell#Changing default shell.

Running fish interactively with zsh as system shell on darwin

Zsh users on darwin will need to use a modified version of the above snippet. As written, it presents two incompatibilities. First, being BSD-derived, MacOS's ps command accepts different options. Second, this is a script intended for bash, not zsh. MacOS uses zsh as its default shell.

programs.zsh = {
  initExtra = ''
    if [[ $(ps -o command= -p "$PPID" | awk '{print $1}') != 'fish' ]]
    then
        exec fish -l
    fi
  ''
};

Configuration

System wide

To enable fish plugins, add your preferred plugins to `environment.systemPackages`:

environment.systemPackages = with pkgs; [
  fishPlugins.done
  fishPlugins.fzf-fish
  fishPlugins.forgit
  fishPlugins.hydro
  fzf
  fishPlugins.grc
  grc
];

programs.fish.enable = true;

Home Manager

An example configuration in Home Manager for adding plugins and changing options could look like this:

home-manager.users.myuser = {
  programs.fish = {
    enable = true;
    interactiveShellInit = ''
      set fish_greeting # Disable greeting
    '';
    plugins = [
      # Enable a plugin (here grc for colorized command output) from nixpkgs
      { name = "grc"; src = pkgs.fishPlugins.grc.src; }
      # Manually packaging and enable a plugin
      {
        name = "z";
        src = pkgs.fetchFromGitHub {
          owner = "jethrokuan";
          repo = "z";
          rev = "e0e1b9dfdba362f8ab1ae8c1afc7ccf62b89f7eb";
          sha256 = "0dbnir6jbwjpjalz14snzd3cgdysgcs3raznsijd6savad3qhijc";
        };
      }
    ];
  };
};

Full list of home-manager options for fish can be found See also here.

See fishPlugins package set for available plugins in nixpkgs.

Useful scripts

Show that you are in a nix-shell

Add this to the fish_prompt function (usually placed in ~/.config/fish/functions/fish_prompt.fish):

set -l nix_shell_info (
  if test -n "$IN_NIX_SHELL"
    echo -n "<nix-shell> "
  end
)

and $nix_shell_info to the echo in that function, e.g.:

echo -n -s "$nix_shell_info ~>"

Now your prompt looks like this:

  • outside: ~>
  • inside: <nix-shell> ~>

You can directly start nix-shell in fish with nix-shell --run fish.

Environments

Here are some examples of helper functions that put you in a nix-shell with the given packages installed.

You can either put these in programs.fish.functions with home-manager or in ~/.config/fish/functions/fish_prompt.fish without.

haskellEnv

function haskellEnv
  nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ $argv ])"
end
# Invocation: haskellEnv package1 packages2 .. packageN

pythonEnv

function pythonEnv --description 'start a nix-shell with the given python packages' --argument pythonVersion
  if set -q argv[2]
    set argv $argv[2..-1]
  end
 
  for el in $argv
    set ppkgs $ppkgs "python"$pythonVersion"Packages.$el"
  end
 
  nix-shell -p $ppkgs
end

# Invocation: pythonEnv 3 package1 package2 .. packageN
# or:         pythonEnv 2 ..

See also