{ config, lib, pkgs, ... }: # fish for the primary user, configured through home-manager. let cfg = config.modules.fish; user = config.user.name; shortcuts = config.registry.shell-shortcut.${config.networking.hostName}; commandsOf = shortcuts: lib.mapAttrs (_name: shortcut: shortcut.command) shortcuts; in { options.modules.fish = { enable = lib.mkEnableOption "fish as the user's shell, configured via home-manager"; defaultShell = lib.mkOption { type = lib.types.bool; default = false; description = "Set fish as the user's default login shell."; }; }; config = lib.mkIf cfg.enable { # System-level fish registers it in /etc/shells and installs vendor completions. programs.fish.enable = true; users.users.${user}.shell = lib.mkIf cfg.defaultShell pkgs.fish; home-manager.users.${user} = { home.packages = with pkgs; [ bat # backs the manpager fastfetch # the shell greeting ]; programs.fish = { enable = true; preferAbbrs = true; plugins = [ # Notify when a long command finishes. { name = "done"; src = pkgs.fishPlugins.done.src; } # Restore the !! and !$ history bindings. { name = "bang-bang"; src = pkgs.fishPlugins.bang-bang.src; } ]; shellAliases = commandsOf (lib.filterAttrs (_name: shortcut: !shortcut.abbreviation) shortcuts); shellAbbrs = commandsOf (lib.filterAttrs (_name: shortcut: shortcut.abbreviation) shortcuts); functions = { # Pick the logo that fits the terminal so the greeting never wraps. # The full logo needs about 118 columns beside the info block, the # compact one about 89, the info block alone about 71. fish_greeting = '' if test "$COLUMNS" -ge 118 fastfetch else if test "$COLUMNS" -ge 89 fastfetch --logo NixOS_small else fastfetch --logo none end ''; # vi insert mode omits the emacs ctrl-f and ctrl-r bindings, so restore both. # ctrl-f accepts an autosuggestion and ctrl-r opens the history pager. # vi normal mode keeps its ctrl-r redo, since only insert mode is bound. fish_user_key_bindings = '' bind -M insert ctrl-f forward-char bind -M insert ctrl-r history-pager ''; history = { description = "Show command history with timestamps"; body = "builtin history --show-time='%F %T '"; }; backup = { description = "Copy to .bak"; argumentNames = "filename"; body = "cp $filename $filename.bak"; }; copy = { description = "Copy a file, or recursively copy a source directory into a destination"; body = builtins.readFile ./functions/copy.fish; }; deploy-to = { description = "Deploy the current dotfiles branch to a host through target-local nixos-rebuild"; body = builtins.readFile ./functions/deploy-to.fish; }; }; # Rendered by home-manager into ~/.config/fish/config.fish. interactiveShellInit = builtins.readFile ./config.fish; }; }; }; }