{
  pkgs,
  config,
  lib,
  labellenixpkgs,
  ...
}:
let
  labellepkgs = import labellenixpkgs { inherit (pkgs) system; };
in
{
  frogeye.hooks.lock = ''
    ${pkgs.coreutils}/bin/rm -rf "/tmp/cached_pass_$UID"
  '';
  programs = {
    home-manager.enable = true;
    bat = {
      enable = true;
      config.style = "full";
    };
    bash.shellAliases = {
      # Replacement commands
      # ls = "lsd"; # lsd is suuuper slow for large directories
      cat = "bat -pp";

      # Completion for existing commands
      mkdir = "mkdir -v";
      # cp = "cp -i"; # Disabled because conflicts with the ZSH/Bash one. This separation is confusing I swear.
      mv = "mv -iv";
      free = "free -h";
      df = "df -h";
      ffmpeg = "ffmpeg -hide_banner";
      ffprobe = "ffprobe -hide_banner";
      ffplay = "ffplay -hide_banner";
      numbat = "numbat --intro-banner off";
      insect = "numbat";

      # Frequent mistakes
      sl = "ls";
      al = "la";
      mdkir = "mkdir";
      systemclt = "systemctl";
      please = "sudo";

      # Shortcuts for commonly used commands
      ll = "lsd -l";
      la = "lsd -la";
      s = "sudo -s -E";

      # Preference
      wol = "wakeonlan"; # TODO Really, isn't wol better? Also wtf Arch aliases to pass because neither is installed anyways x)
      mutt = "neomutt";

      # Bash/Zsh only
      cp = "cp -i --reflink=auto";
      grep = "grep --color=auto";
      dd = "dd status=progress";
      rm = "rm -v --one-file-system";
      # free = "free -m"; # Disabled because... no? Why?
      diff = "diff --color=auto";
      dmesg = "dmesg --ctime";
      wget = "wget --hsts-file ${config.xdg.cacheHome}/wget-hsts";

      # Imported from scripts
      rms = ''${pkgs.findutils}/bin/find . -name "*.sync-conflict-*" -delete''; # Remove syncthing conflict files
      newestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | tail'';
      oldestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | head'';
    };
    thefuck = {
      enable = true;
      enableBashIntegration = true;
      enableZshIntegration = true;
    };
    lsd = {
      enable = true;
      settings = {
        size = "short";
      };
      colors = {
        # Base16 only, so it reuses the current theme.
        date = {
          day-old = 4;
          hour-old = 6;
          older = 5;
        };
        git-status = {
          conflicted = 14;
          default = 13;
          deleted = 1;
          ignored = 13;
          modified = 3;
          new-in-index = 2;
          new-in-workdir = 2;
          renamed = 4;
          typechange = 3;
          unmodified = 13;
        };
        group = 6;
        inode = {
          invalid = 245;
          valid = 13;
        };
        links = {
          invalid = 9;
          valid = 14;
        };
        permission = {
          acl = 6;
          context = 14;
          exec = 1;
          exec-sticky = 5;
          no-access = 245;
          octal = 6;
          read = 2;
          write = 3;
        };
        size = {
          large = 1;
          medium = 9;
          none = 11;
          small = 3;
        };
        tree-edge = 13;
        user = 2;
      };
    };
    dircolors = {
      enable = true;
      enableBashIntegration = true;
      enableZshIntegration = true;
      # UPST This thing put stuff in .dircolors when it actually doesn't have to
    };
    git.enable = true;
    gpg.enable = true;
    fzf = {
      enable = true;
      enableZshIntegration = true;
      defaultOptions = [
        "--height 40%"
        "--layout=default"
      ];
      fileWidgetOptions = [
        "--preview '[[ -d {} ]] && ${pkgs.coreutils}/bin/ls -l --color=always {} || [[ \$(${pkgs.file}/bin/file --mime {}) =~ binary ]] && ${pkgs.file}/bin/file --brief {} || (${pkgs.highlight}/bin/highlight -O ansi -l {} || coderay {} || rougify {} || ${pkgs.coreutils}/bin/cat {}) 2> /dev/null | head -500'"
      ];
      # TODO Above not working... not really used either?
      # file and friends are not in PATH by default... so here we want aboslute paths, which means those won't get reloaded. Meh.
    };
    less.enable = true;
    nixvim.enable = true;
    readline = {
      enable = true;
      variables = {
        "bell-style" = "none";
        "colored-completion-prefix" = true;
        "colored-stats" = true;
        "completion-ignore-case" = true;
        "completion-query-items" = 200;
        "editing-mode" = "vi";
        "history-preserve-point" = true;
        "history-size" = 10000;
        "horizontal-scroll-mode" = false;
        "mark-directories" = true;
        "mark-modified-lines" = false;
        "mark-symlinked-directories" = true;
        "match-hidden-files" = true;
        "menu-complete-display-prefix" = true;
        "page-completions" = true;
        "print-completions-horizontally" = false;
        "revert-all-at-newline" = false;
        "show-all-if-ambiguous" = true;
        "show-all-if-unmodified" = true;
        "show-mode-in-prompt" = true;
        "skip-completed-text" = true;
        "visible-stats" = false;
      };
      extraConfig = builtins.readFile ./inputrc;
    };
    tmux.enable = true;
    translate-shell.enable = true; # TODO Cool config?
  };
  home = {
    activation = {
      # Prevent Virtualbox from creating a "VirtualBox VMs" folder in $HOME
      setVirtualboxSettings = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
        if command -v VBoxManage > /dev/null
        then
            VBoxManage setproperty machinefolder ${config.xdg.dataHome}/virtualbox
        fi
      '';
    };
    stateVersion = "24.05";
    packages = with pkgs; [
      # Terminal utils
      coreutils
      moreutils
      rename
      which
      file
      cached-nix-shell # For scripts

      # Pipe utils
      gnugrep
      gnused
      gawk

      # Extraction
      gnutar
      unzip
      unrar
      p7zip

      # Documentation
      man
      tldr
      neofetch

      # remote
      wget
      curl
      openssl
      openssh
      rsync
      borgbackup
      sshfs

      # cleanup
      ncdu
      jdupes
      duperemove
      compsize
      btdu

      # toolbox
      imagemagick
      numbat

      # hardware
      pciutils
      usbutils
      dmidecode
      lshw
      labellepkgs.labelle # Label printer

      # Locker
      (pkgs.writeShellApplication {
        name = "lock";
        text = ''
          ${config.frogeye.hooks.lock}

          ${pkgs.vlock}/bin/vlock --all
        '';
      })
    ];
    sessionVariables = {
      # Favourite commands

      # Extra config
      # INPUTRC = "${config.xdg.configHome}/inputrc"; # UPST Will use programs.readline, but doesn't allow path setting
      SQLITE_HISTFILE = "${config.xdg.stateHome}/sqlite_history";

      # Bash/ZSH only?
      TIME_STYLE = "+%Y-%m-%d %H:%M:%S";
      # Fzf
      FZF_COMPLETION_OPTS = "${lib.strings.concatStringsSep " " config.programs.fzf.fileWidgetOptions}";
    };
    sessionPath = [
      "${config.home.homeDirectory}/.local/bin"
      "${config.home.homeDirectory}/.config/dotfiles/hm/scripts" # Not Nix path otherwise it gets converted into store,
      # and then every time you want to modify a script you have to rebuild and re-login...
    ];
  };
}