{
  lib,
  config,
  namespace,
  pkgs,
  ...
}:
let
  inherit (lib) mkIf;
  inherit (lib.${namespace}) mkEnableModule enabled;

  cfg = config.${namespace}.programs.fish;
  inherit (config.${namespace}) theme;
in
{
  options = mkEnableModule "programs.fish";

  config = mkIf cfg.enable {
    home.packages = with pkgs; [
      # general
      babelfish

      # for extract()
      gnutar
      bzip2
      bzip3
      gzip
      unzip
      pax
      unrar-free
    ];

    programs.fish = {
      enable = true;

      ${theme.colors.name} = enabled;

      preferAbbrs = true;

      plugins = with pkgs.fishPlugins; [
        {
          name = "z";
          src = z;
        }
        {
          name = "Puffer Fish";
          src = puffer;
        }
        {
          name = "Sponge";
          src = sponge;
        }
        {
          name = "autopair.fish";
          src = autopair;
        }
      ];

      shellInit = # fish
        ''
          set -g fish_key_bindings fish_vi_key_bindings
        '';

      shellAbbrs = {
        cp = "cp -iv";
        mkdir = "mkdir -pv";
        mv = "mv -iv";
        rm = "rm -r";
        grep = "grep --color=auto";
      };

      functions = {
        extract = {
          argumentNames = "file";
          body = # fish
            ''
              set --erase argv[1]

              if test -f "$file"
                switch "$file"
                  case "*.tar.bz2"
                    tar -jxvf $argv $file

                  case "*.tar.gz"
                    tar -zxvf $argv $file

                  case "*.bz2"
                    bunzip2 $argv $file

                  case "*.bz3"
                    bunzip3 $argv $file

                  case "*.gz"
                    gunzip $argv $file

                  case "*.tar"
                    tar -xvf $argv $file

                  case "*.tbz2"
                    tar -jxvf $argv $file

                  case "*.tgz"
                    tar -zxvf $argv $file

                  case "*.zip" "*.ZIP"
                    unzip $argv $file

                  case "*pax"
                    cat $file | pax -r $argv

                  case "*.pax.Z"
                    uncompress $file --stdout | pax -r $argv

                  case "*.rar"
                    unrar-free $file

                  case "*.Z"
                    uncompress $argv $file

                  case "*"
                    echo "'$file' cannot be extracted via extract()."
                end
              else
                echo "'$file' is not a valid file."
              end
            '';
        };
      };
    };
  };
}