Commit 4bf071a

HPCesia <me@hpcesia.com>
2026-10-20 05:13:42
shell: init bash hjem module
1 parent ec3c82d
Changed files (7)
modules/core/shell/_module.nix
@@ -0,0 +1,167 @@
+{
+  lib,
+  config,
+  ...
+}: {
+  options.programs.bash = {
+    enable = lib.mkOption {
+      type = lib.types.bool;
+      description = ''
+        Whenever to configure Bash as an interactive shell.
+      '';
+      default = true;
+    };
+    shellInit = lib.mkOption {
+      type = lib.types.lines;
+      description = ''
+        Shell script code called during bash shell initialisation.
+      '';
+      default = "";
+    };
+    interactiveShellInit = lib.mkOption {
+      type = lib.types.lines;
+      description = ''
+        Shell script code called during interactive bash shell initialisation.
+      '';
+      default = "";
+    };
+    shellAliases = lib.mkOption {
+      type = with lib.types; attrsOf (nullOr (either str path));
+      description = ''
+        Set of aliases for bash shell
+      '';
+      example = {
+        ll = "ls -l";
+        ".." = "cd ..";
+      };
+      default = {};
+    };
+    shellOptions = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      default = [
+        # Append to history file rather than replacing it.
+        "histappend"
+
+        # Extended globbing.
+        "extglob"
+        "globstar"
+
+        # Warn if closing shell with running jobs.
+        "checkjobs"
+      ];
+      example = [
+        "extglob"
+        "-cdspell"
+      ];
+      description = ''
+        Shell options to set. Prefix an option with
+        "`-`" to unset.
+      '';
+    };
+    history = {
+      options = lib.mkOption {
+        type = lib.types.listOf (
+          lib.types.enum [
+            "erasedups"
+            "ignoredups"
+            "ignorespace"
+            "ignoreboth"
+          ]
+        );
+        default = [];
+        description = "Controlling how commands are saved on the history list.";
+      };
+      size = lib.mkOption {
+        type = lib.types.nullOr lib.types.int;
+        default = 100000;
+        description = "Number of history lines to keep on memory.";
+      };
+      ignore = lib.mkOption {
+        type = lib.types.listOf lib.types.str;
+        default = [];
+        example = [
+          "ls"
+          "cd"
+          "exit"
+        ];
+        description = "List of commands that should not be saved to the history list.";
+      };
+      file = {
+        path = lib.mkOption {
+          type = lib.types.nullOr lib.types.str;
+          default = null;
+          description = "Location of the bash history file.";
+        };
+        size = lib.mkOption {
+          type = lib.types.nullOr lib.types.int;
+          default = 100000;
+          description = "Number of history lines to keep on file.";
+        };
+      };
+    };
+  };
+
+  config = let
+    cfg = config.programs.bash;
+
+    historyLines = (
+      lib.concatStringsSep "\n" (
+        lib.mapAttrsToList (n: v: "${n}=${v}") (
+          lib.optionalAttrs (cfg.history.file.size != null) {
+            HISTFILESIZE = toString cfg.history.file.size;
+          }
+          // lib.optionalAttrs (cfg.history.size != null) {
+            HISTSIZE = toString cfg.history.size;
+          }
+          // lib.optionalAttrs (cfg.history.file.path != null) {
+            HISTFILE = ''"${cfg.history.file.path}"'';
+          }
+          // lib.optionalAttrs (cfg.history.options != []) {
+            HISTCONTROL = lib.concatStringsSep ":" cfg.history.options;
+          }
+          // lib.optionalAttrs (cfg.history.ignore != []) {
+            HISTIGNORE = lib.escapeShellArg (lib.concatStringsSep ":" cfg.history.ignore);
+          }
+        )
+        ++ lib.optional (cfg.history.file.path != null) ''mkdir -p "$(dirname "$HISTFILE")"''
+      )
+    );
+
+    shoptsLines = let
+      switch = v:
+        if lib.hasPrefix "-" v
+        then "-u"
+        else "-s";
+    in
+      lib.concatStringsSep "\n" (map (v: "shopt ${switch v} ${lib.removePrefix "-" v}") cfg.shellOptions);
+
+    aliasesLines = builtins.concatStringsSep "\n" (
+      lib.mapAttrsToList (k: v: "alias -- ${k}=${lib.escapeShellArg v}") (
+        lib.filterAttrs (k: v: v != null) cfg.shellAliases
+      )
+    );
+  in {
+    files.".bash_profile".text = ''
+      # load session variables
+      . ${config.environment.loadEnv}
+
+      ${cfg.shellInit}
+
+      # include .bashrc if it exists
+      [[ -f ~/.bashrc ]] && . ~/.bashrc
+    '';
+
+    files.".bashrc".text = ''
+      # Commands that should be applied only for interactive shells.
+      [[ $- == *i* ]] || return
+
+      ${historyLines}
+
+      ${shoptsLines}
+
+      ${aliasesLines}
+
+      ${cfg.interactiveShellInit}
+    '';
+  };
+}
modules/core/shell/default.nix
@@ -64,45 +64,47 @@
         lib,
         ...
       }: {
+        imports = [./_module.nix];
+
         packages = [pkgs.nur.repos.hpcesia.stinkpot];
 
-        files.".bashrc".text = lib.mkOrder 2000 ''
-          eval "$(${lib.getExe pkgs.nur.repos.hpcesia.stinkpot} init)"
-          flyline key bind Ctrl+r 'always=runBashCommand(__stinkpot_search)'
+        programs.bash = {
+          interactiveShellInit = ''
+            eval "$(${lib.getExe pkgs.nur.repos.hpcesia.stinkpot} init)"
+            flyline key bind Ctrl+r 'always=runBashCommand(__stinkpot_search)'
 
-          # Make bash history save immediately
-          shopt -s histappend
-          __ix_history_flush() {
-            history -a
-          }
-          if [[ ";''${PROMPT_COMMAND[*]:-};" != *";__ix_history_flush;"* ]]; then
-            if [[ "$(declare -p PROMPT_COMMAND 2>&1)" == "declare -a"* ]]; then
-              PROMPT_COMMAND=("''${PROMPT_COMMAND[@]}" __ix_history_flush)
-            else
-              PROMPT_COMMAND="''${PROMPT_COMMAND:+$PROMPT_COMMAND;}__ix_history_flush"
+            __ix_history_flush() {
+              history -a
+            }
+            if [[ ";''${PROMPT_COMMAND[*]:-};" != *";__ix_history_flush;"* ]]; then
+              if [[ "$(declare -p PROMPT_COMMAND 2>&1)" == "declare -a"* ]]; then
+                PROMPT_COMMAND=("''${PROMPT_COMMAND[@]}" __ix_history_flush)
+              else
+                PROMPT_COMMAND="''${PROMPT_COMMAND:+$PROMPT_COMMAND;}__ix_history_flush"
+              fi
             fi
-          fi
 
-          # Fix Flyline panic in Zellij
-          __ix_fix_term_size() {
-            local rows cols
-            IFS=' ' read -r rows cols < <(stty size 2>/dev/null)
-            if [ "''${cols:-0}" -gt 0 ] && [ "''${rows:-0}" -gt 0 ]; then
-              export COLUMNS="$cols" LINES="$rows"
-            else
-              [ "''${COLUMNS:-0}" -gt 0 ] || COLUMNS=80
-              [ "''${LINES:-0}" -gt 0 ] || LINES=24
-              export COLUMNS LINES
-            fi
-          }
-          if [[ ";''${PROMPT_COMMAND[*]:-};" != *";__ix_fix_term_size;"* ]]; then
-            if [[ "$(declare -p PROMPT_COMMAND 2>&1)" == "declare -a"* ]]; then
-              PROMPT_COMMAND=("''${PROMPT_COMMAND[@]}" __ix_fix_term_size)
-            else
-              PROMPT_COMMAND="''${PROMPT_COMMAND:+$PROMPT_COMMAND;}__ix_fix_term_size"
+            # Fix Flyline panic in Zellij
+            __ix_fix_term_size() {
+              local rows cols
+              IFS=' ' read -r rows cols < <(stty size 2>/dev/null)
+              if [ "''${cols:-0}" -gt 0 ] && [ "''${rows:-0}" -gt 0 ]; then
+                export COLUMNS="$cols" LINES="$rows"
+              else
+                [ "''${COLUMNS:-0}" -gt 0 ] || COLUMNS=80
+                [ "''${LINES:-0}" -gt 0 ] || LINES=24
+                export COLUMNS LINES
+              fi
+            }
+            if [[ ";''${PROMPT_COMMAND[*]:-};" != *";__ix_fix_term_size;"* ]]; then
+              if [[ "$(declare -p PROMPT_COMMAND 2>&1)" == "declare -a"* ]]; then
+                PROMPT_COMMAND=("''${PROMPT_COMMAND[@]}" __ix_fix_term_size)
+              else
+                PROMPT_COMMAND="''${PROMPT_COMMAND:+$PROMPT_COMMAND;}__ix_fix_term_size"
+              fi
             fi
-          fi
-        '';
+          '';
+        };
       };
     };
   };
modules/core/misc.nix
@@ -23,15 +23,8 @@
       };
     };
 
-    hjem = {config, ...}: {
+    hjem = {
       clobberFiles = true;
-      files.".bash_profile".text = ''
-        # load session variables
-        . ${config.environment.loadEnv}
-
-        # include .bashrc if it exists
-        [[ -f ~/.bashrc ]] && . ~/.bashrc
-      '';
     };
   };
 }
modules/dev/zellij/default.nix
@@ -89,9 +89,9 @@
             + builtins.readFile ./keybinds.kdl;
         };
 
-        files.".bashrc".text = lib.mkOrder 3000 ''
-          alias -- zj=zellij
-        '';
+        programs.bash.shellAliases = {
+          zj = "zellij";
+        };
       };
     };
   };
modules/dev/direnv.nix
@@ -14,7 +14,7 @@
       }: {
         packages = [pkgs.direnv];
 
-        files.".bashrc".text = lib.mkAfter ''
+        programs.bash.interactiveShellInit = ''
           eval "$(${lib.getExe pkgs.direnv} hook bash)"
         '';
 
modules/dev/yazi.nix
@@ -19,7 +19,7 @@
     in {
       packages = [pkgs.yazi];
 
-      files.".bashrc".text = ''
+      programs.bash.interactiveShellInit = ''
         function yy() {
           local tmp="$(mktemp -t "yazi-cwd.XXXXX")"
           command yazi "$@" --cwd-file="$tmp"
modules/dev/zoxide.nix
@@ -13,7 +13,7 @@
     }: {
       packages = [pkgs.zoxide];
 
-      files.".bashrc".text = lib.mkOrder 2000 ''
+      programs.bash.interactiveShellInit = ''
         eval "$(${lib.getExe pkgs.zoxide} init bash)"
       '';
     };