aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-18 14:55:21 +0530
committerArpit Chakladar <arpitchakladar+git@gmail.com>2026-07-18 14:55:21 +0530
commit03bd9b6ad5335aff65d9cb6fb1d117b5cb4b7919 (patch)
tree04780c0d23aac335fe60320c181bd3ac6850d5d3 /modules
parentbde84587b2a408970086f4c708ac9a629abfa554 (diff)
downloadhome-manager-config-03bd9b6ad5335aff65d9cb6fb1d117b5cb4b7919.tar.gz
home-manager-config-03bd9b6ad5335aff65d9cb6fb1d117b5cb4b7919.zip
refactor(scripts): split monolithic module into per-script submodules
Extract shared `mkScript` and `mkScriptModule` helpers into `lib.nix` Split each script into `modules/scripts/<name>/` with its own `default.nix`, `script.sh`, and `assertions.nix` Remove `conditions` parameter from `mkScriptModule`; move condition assertions into per-script `assertions.nix` files with inline checks and error messages Simplify `mkScriptModule` to return `{ options, moduleConfig }` instead of a module function, taking `config` as a direct parameter Add `description` field to `mkScript` that inserts the description as a `# <text>` comment between the shebang and env vars Thread `description` through `mkScriptModule` to each `default.nix` Move top comment lines from each `script.sh` into the `description` field and remove from sources to avoid duplication Remove old flat `.sh` files from `modules/scripts/` root
Diffstat (limited to 'modules')
-rw-r--r--modules/scripts/aria2-run/assertions.nix7
-rw-r--r--modules/scripts/aria2-run/default.nix26
-rw-r--r--modules/scripts/aria2-run/script.sh (renamed from modules/scripts/aria2-run.sh)1
-rw-r--r--modules/scripts/deep-clean/default.nix19
-rw-r--r--modules/scripts/deep-clean/script.sh (renamed from modules/scripts/deep-clean.sh)3
-rw-r--r--modules/scripts/default.nix365
-rw-r--r--modules/scripts/file-preview-clean/assertions.nix7
-rw-r--r--modules/scripts/file-preview-clean/default.nix22
-rw-r--r--modules/scripts/file-preview-clean/script.sh (renamed from modules/scripts/file-preview-clean.sh)1
-rw-r--r--modules/scripts/file-preview/assertions.nix19
-rw-r--r--modules/scripts/file-preview/default.nix36
-rw-r--r--modules/scripts/file-preview/script.sh (renamed from modules/scripts/file-preview.sh)1
-rw-r--r--modules/scripts/fzf-launcher/assertions.nix7
-rw-r--r--modules/scripts/fzf-launcher/default.nix26
-rw-r--r--modules/scripts/fzf-launcher/script.sh (renamed from modules/scripts/fzf-launcher.sh)2
-rw-r--r--modules/scripts/i3-keybindings/assertions.nix11
-rw-r--r--modules/scripts/i3-keybindings/default.nix30
-rw-r--r--modules/scripts/i3-keybindings/script.sh (renamed from modules/scripts/i3-keybindings.sh)1
-rw-r--r--modules/scripts/lib.nix94
-rw-r--r--modules/scripts/neomutt-sync/assertions.nix7
-rw-r--r--modules/scripts/neomutt-sync/default.nix30
-rw-r--r--modules/scripts/neomutt-sync/script.sh (renamed from modules/scripts/neomutt-sync.sh)2
-rw-r--r--modules/scripts/screen-recording/assertions.nix11
-rw-r--r--modules/scripts/screen-recording/default.nix29
-rw-r--r--modules/scripts/screen-recording/script.sh (renamed from modules/scripts/screen-recording.sh)4
-rw-r--r--modules/scripts/system-monitor/assertions.nix19
-rw-r--r--modules/scripts/system-monitor/default.nix32
-rw-r--r--modules/scripts/system-monitor/script.sh (renamed from modules/scripts/system-monitor.sh)4
-rw-r--r--modules/scripts/vpn-connect/assertions.nix11
-rw-r--r--modules/scripts/vpn-connect/default.nix32
-rw-r--r--modules/scripts/vpn-connect/script.sh (renamed from modules/scripts/vpn-connect.sh)1
-rw-r--r--modules/scripts/vpn-disconnect/assertions.nix7
-rw-r--r--modules/scripts/vpn-disconnect/default.nix21
-rw-r--r--modules/scripts/vpn-disconnect/script.sh (renamed from modules/scripts/vpn-disconnect.sh)1
34 files changed, 533 insertions, 356 deletions
diff --git a/modules/scripts/aria2-run/assertions.nix b/modules/scripts/aria2-run/assertions.nix
new file mode 100644
index 0000000..8d1e1cd
--- /dev/null
+++ b/modules/scripts/aria2-run/assertions.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.aria2-run.enable || config.web.aria2.enable;
+ message = "scripts.aria2-run is enabled but requires `web.aria2.enable`.";
+ }
+]
diff --git a/modules/scripts/aria2-run/default.nix b/modules/scripts/aria2-run/default.nix
new file mode 100644
index 0000000..0cdc456
--- /dev/null
+++ b/modules/scripts/aria2-run/default.nix
@@ -0,0 +1,26 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "aria2-run";
+ path = ./script.sh;
+ description = "Start aria2 RPC daemon";
+ deps = [ config.web.aria2.package ];
+ desktop = {
+ enable = true;
+ displayName = "Aria2 Download Manager";
+ };
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/aria2-run.sh b/modules/scripts/aria2-run/script.sh
index e151b53..167fc5d 100644
--- a/modules/scripts/aria2-run.sh
+++ b/modules/scripts/aria2-run/script.sh
@@ -1,2 +1 @@
-# Start aria2 RPC daemon
aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port=6800
diff --git a/modules/scripts/deep-clean/default.nix b/modules/scripts/deep-clean/default.nix
new file mode 100644
index 0000000..dc93c2c
--- /dev/null
+++ b/modules/scripts/deep-clean/default.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "deep-clean";
+ path = ./script.sh;
+ description = "Deep clean script for Nix systems\nRemoves old generations, garbage, and optimizes store\nWARNING: Do NOT run with sudo - run as normal user";
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig;
+}
diff --git a/modules/scripts/deep-clean.sh b/modules/scripts/deep-clean/script.sh
index 5d1c87a..dcbd62b 100644
--- a/modules/scripts/deep-clean.sh
+++ b/modules/scripts/deep-clean/script.sh
@@ -1,6 +1,3 @@
-# Deep clean script for Nix systems
-# Removes old generations, garbage, and optimizes store
-# WARNING: Do NOT run with sudo - run as normal user
echo "--- Starting Nix Deep Clean ---"
if [[ $EUID -eq 0 ]]; then
diff --git a/modules/scripts/default.nix b/modules/scripts/default.nix
index 789c32d..abecc38 100644
--- a/modules/scripts/default.nix
+++ b/modules/scripts/default.nix
@@ -1,351 +1,46 @@
-# Scripts - Generates wrapped scripts with environment variables and dependencies
{
config,
lib,
pkgs,
...
}:
-let
- shell = pkgs.runtimeShell;
-
- mkScript =
- name: path: env: deps:
- let
- envVars = lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n}=\"${toString v}\"") env);
- wrappedScript = pkgs.writeTextFile {
- name = name;
- executable = true;
- destination = "/bin/${name}";
- text = ''
- #!${shell}
- ${envVars}
- ${builtins.readFile path}
- '';
- };
- in
- pkgs.runCommand name
- {
- name = name;
- nativeBuildInputs = [ pkgs.makeWrapper ];
- meta.mainProgram = name;
- }
- ''
- mkdir -p $out/bin
- cp ${wrappedScript}/bin/${name} $out/bin/${name}
- chmod +x $out/bin/${name}
-
- wrapProgram $out/bin/${name} \
- --prefix PATH : ${lib.makeBinPath deps}
- '';
-
- # Script definitions: { path, env?, deps?, conditions? }
- # condition: attrset of { option (string path), value (expected value) }
- scriptDefs = {
- aria2-run = {
- path = ./aria2-run.sh;
- deps = [
- config.web.aria2.package
- ];
- conditions = [
- {
- option = "web.aria2.enable";
- value = true;
- }
- ];
- };
- deep-clean = {
- path = ./deep-clean.sh;
- };
- file-preview = {
- path = ./file-preview.sh;
- deps = [
- config.terminal.kitty.package
- config.terminal.bat.package
- config.media.ffmpeg.package
- config.file-management.ouch.package
- pkgs.coreutils
- pkgs.file
- pkgs.findutils
- pkgs.fontconfig
- pkgs.librsvg
- pkgs.antiword
- pkgs.pandoc
- pkgs.poppler-utils
- pkgs.util-linux
- ];
- conditions = [
- {
- option = "terminal.kitty.enable";
- value = true;
- }
- {
- option = "media.ffmpeg.enable";
- value = true;
- }
- {
- option = "file-management.ouch.enable";
- value = true;
- }
- {
- option = "terminal.bat.enable";
- value = true;
- }
- ];
- };
- file-preview-clean = {
- path = ./file-preview-clean.sh;
- deps = [
- config.terminal.kitty.package
- ];
- conditions = [
- {
- option = "scripts.file-preview.enable";
- value = true;
- }
- ];
- };
- fzf-launcher = {
- path = ./fzf-launcher.sh;
- deps = [
- config.terminal.fzf.package
- pkgs.dex
- pkgs.util-linux
- ];
- conditions = [
- {
- option = "terminal.fzf.enable";
- value = true;
- }
- ];
- };
- i3-keybindings = {
- path = ./i3-keybindings.sh;
- deps = [
- pkgs.coreutils
- pkgs.gawk
- pkgs.ncurses
- ];
- conditions = [
- {
- option = "desktop.enable";
- value = true;
- }
- {
- option = "terminal.less.enable";
- value = true;
- }
- ];
- };
- screen-recording = {
- path = ./screen-recording.sh;
- deps = [
- config.media.ffmpeg.package
- config.media.slop.package
- ];
- conditions = [
- {
- option = "media.ffmpeg.enable";
- value = true;
- }
- {
- option = "media.slop.enable";
- value = true;
- }
- ];
- };
- system-monitor = {
- path = ./system-monitor.sh;
- deps = [
- config.system.bottom.package
- config.system.nvtop.package
- config.terminal.tmux.package
- config.terminal.kitty.package
- pkgs.bash
- ];
- conditions = [
- {
- option = "system.bottom.enable";
- value = true;
- }
- {
- option = "system.nvtop.enable";
- value = true;
- }
- {
- option = "terminal.tmux.enable";
- value = true;
- }
- {
- option = "terminal.kitty.enable";
- value = true;
- }
- ];
- };
- vpn-connect = {
- path = ./vpn-connect.sh;
- env = {
- SYSTEMD_RESOLVED_PATH = "${config.security.openvpn.package}/libexec/update-systemd-resolved";
- };
- deps = [
- config.terminal.fzf.package
- config.security.openvpn.package
- pkgs.coreutils
- pkgs.findutils
- pkgs.gnugrep
- pkgs.gnused
- ];
- conditions = [
- {
- option = "security.openvpn.enable";
- value = true;
- }
- {
- option = "terminal.fzf.enable";
- value = true;
- }
- ];
- };
- vpn-disconnect = {
- path = ./vpn-disconnect.sh;
- conditions = [
- {
- option = "scripts.vpn-connect.enable";
- value = true;
- }
- ];
- };
- neomutt-sync = {
- path = ./neomutt-sync.sh;
- deps = [
- pkgs.dialog
- pkgs.coreutils
- pkgs.gawk
- pkgs.gnused
- pkgs.util-linux
- config.programs.mbsync.package
- config.programs.notmuch.package
- ];
- conditions = [
- {
- option = "communication.neomutt.enable";
- value = true;
- }
- ];
- };
- };
-
- # Check whether all conditions for a script are satisfied
- conditionsMet =
- name: def:
- lib.all (cond: lib.attrByPath (lib.splitString "." cond.option) false config == cond.value) (
- def.conditions or [ ]
- );
-
- # Generate a .desktop entry that launches the script in kitty
- mkDesktopItem =
- name: def:
- let
- sc = config.scripts.${name};
- in
- if sc.enable && sc.desktop.enable then
- pkgs.makeDesktopItem {
- name = name;
- desktopName = sc.desktop.displayName;
- exec = "${lib.getExe config.terminal.kitty.package} -e ${lib.getExe sc.package}";
- icon = "kitty";
- categories = [ "Utility" ];
- terminal = false;
- type = "Application";
- }
- else
- null;
-
- desktopItems = lib.mapAttrsToList mkDesktopItem scriptDefs;
-
-in
{
- options.scripts = lib.mapAttrs (name: def: {
- enable = lib.mkOption {
- type = lib.types.bool;
- # Auto-enable if all required tool options are satisfied
- default = conditionsMet name def;
- description = ''
- Whether to enable the ${name} script.
- Defaults to true when all required options are set.
- '';
- };
- package = lib.mkOption {
- type = lib.types.nullOr lib.types.package;
- readOnly = true;
- description = "The derivation for the ${name} script. Set automatically when enabled.";
- };
- desktop = {
- enable = lib.mkOption {
- type = lib.types.bool;
- default = false;
- description = "Whether to create a .desktop entry for this script.";
- };
- displayName = lib.mkOption {
- type = lib.types.str;
- default = name;
- description = "Display name for the .desktop entry.";
- };
- };
- }) scriptDefs;
+ imports = [
+ ./aria2-run
+ ./deep-clean
+ ./file-preview
+ ./file-preview-clean
+ ./fzf-launcher
+ ./i3-keybindings
+ ./neomutt-sync
+ ./screen-recording
+ ./system-monitor
+ ./vpn-connect
+ ./vpn-disconnect
+ ];
config = {
- # Wire up .package for each enabled script, with assertions for unmet conditions
- scripts =
- lib.recursiveUpdate
- (lib.mapAttrs (name: def: {
- package = lib.mkIf config.scripts.${name}.enable (
- mkScript name def.path (def.env or { }) (def.deps or [ ])
- );
- }) scriptDefs)
- {
- aria2-run.desktop = {
- enable = true;
- displayName = "Aria2 Download Manager";
- };
- i3-keybindings.desktop = {
- enable = true;
- displayName = "i3 Keybindings";
- };
- screen-recording.desktop = {
- enable = true;
- displayName = "Screen Recording";
- };
- system-monitor.desktop = {
- enable = true;
- displayName = "System Monitor";
- };
- };
-
- assertions =
- lib.concatLists (
- lib.mapAttrsToList (
- name: def:
- map (cond: {
- assertion =
- !config.scripts.${name}.enable
- || lib.attrByPath (lib.splitString "." cond.option) false config == cond.value;
- message = "scripts.${name} is enabled but requires `${cond.option} = ${builtins.toJSON cond.value}`.";
- }) (def.conditions or [ ])
- ) scriptDefs
- )
- ++ lib.mapAttrsToList (name: _: {
- assertion =
- !config.scripts.${name}.enable
- || !config.scripts.${name}.desktop.enable
- || config.terminal.kitty.enable;
- message = "scripts.${name}.desktop.enable requires terminal.kitty.enable because desktop entries launch scripts in kitty.";
- }) scriptDefs;
-
home.packages = [
pkgs.file
config.terminal.bat.package
]
++ lib.filter (x: x != null) (lib.mapAttrsToList (_: s: s.package) config.scripts)
- ++ lib.filter (x: x != null) desktopItems;
+ ++ lib.filter (x: x != null) (
+ lib.mapAttrsToList (
+ name: sc:
+ if sc.enable && sc.desktop.enable then
+ pkgs.makeDesktopItem {
+ name = name;
+ desktopName = sc.desktop.displayName;
+ exec = "${lib.getExe config.terminal.kitty.package} -e ${lib.getExe sc.package}";
+ icon = "kitty";
+ categories = [ "Utility" ];
+ terminal = false;
+ type = "Application";
+ }
+ else
+ null
+ ) config.scripts
+ );
};
}
diff --git a/modules/scripts/file-preview-clean/assertions.nix b/modules/scripts/file-preview-clean/assertions.nix
new file mode 100644
index 0000000..b801ee3
--- /dev/null
+++ b/modules/scripts/file-preview-clean/assertions.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.file-preview-clean.enable || config.scripts.file-preview.enable;
+ message = "scripts.file-preview-clean is enabled but requires `scripts.file-preview.enable`.";
+ }
+]
diff --git a/modules/scripts/file-preview-clean/default.nix b/modules/scripts/file-preview-clean/default.nix
new file mode 100644
index 0000000..776e042
--- /dev/null
+++ b/modules/scripts/file-preview-clean/default.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "file-preview-clean";
+ path = ./script.sh;
+ description = "Clear kitty icat preview after lf exits";
+ deps = [ config.terminal.kitty.package ];
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/file-preview-clean.sh b/modules/scripts/file-preview-clean/script.sh
index 006f63c..ee8ca73 100644
--- a/modules/scripts/file-preview-clean.sh
+++ b/modules/scripts/file-preview-clean/script.sh
@@ -1,2 +1 @@
-# Clear kitty icat preview after lf exits
exec kitten icat --clear --stdin no --transfer-mode file </dev/null >/dev/tty
diff --git a/modules/scripts/file-preview/assertions.nix b/modules/scripts/file-preview/assertions.nix
new file mode 100644
index 0000000..41fd4d6
--- /dev/null
+++ b/modules/scripts/file-preview/assertions.nix
@@ -0,0 +1,19 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.file-preview.enable || config.terminal.kitty.enable;
+ message = "scripts.file-preview is enabled but requires `terminal.kitty.enable`.";
+ }
+ {
+ assertion = !config.scripts.file-preview.enable || config.media.ffmpeg.enable;
+ message = "scripts.file-preview is enabled but requires `media.ffmpeg.enable`.";
+ }
+ {
+ assertion = !config.scripts.file-preview.enable || config.file-management.ouch.enable;
+ message = "scripts.file-preview is enabled but requires `file-management.ouch.enable`.";
+ }
+ {
+ assertion = !config.scripts.file-preview.enable || config.terminal.bat.enable;
+ message = "scripts.file-preview is enabled but requires `terminal.bat.enable`.";
+ }
+]
diff --git a/modules/scripts/file-preview/default.nix b/modules/scripts/file-preview/default.nix
new file mode 100644
index 0000000..eec5fb2
--- /dev/null
+++ b/modules/scripts/file-preview/default.nix
@@ -0,0 +1,36 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "file-preview";
+ path = ./script.sh;
+ description = "Timeout protection (prevents hanging)";
+ deps = [
+ config.terminal.kitty.package
+ config.terminal.bat.package
+ config.media.ffmpeg.package
+ config.file-management.ouch.package
+ pkgs.coreutils
+ pkgs.file
+ pkgs.findutils
+ pkgs.fontconfig
+ pkgs.librsvg
+ pkgs.antiword
+ pkgs.pandoc
+ pkgs.poppler-utils
+ pkgs.util-linux
+ ];
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/file-preview.sh b/modules/scripts/file-preview/script.sh
index 7712754..748b1ea 100644
--- a/modules/scripts/file-preview.sh
+++ b/modules/scripts/file-preview/script.sh
@@ -1,4 +1,3 @@
-# Timeout protection (prevents hanging)
TIMEOUT=5
if [ -z "$LF_PREVIEW_RUNNING" ]; then
export LF_PREVIEW_RUNNING=1
diff --git a/modules/scripts/fzf-launcher/assertions.nix b/modules/scripts/fzf-launcher/assertions.nix
new file mode 100644
index 0000000..308a818
--- /dev/null
+++ b/modules/scripts/fzf-launcher/assertions.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.fzf-launcher.enable || config.terminal.fzf.enable;
+ message = "scripts.fzf-launcher is enabled but requires `terminal.fzf.enable`.";
+ }
+]
diff --git a/modules/scripts/fzf-launcher/default.nix b/modules/scripts/fzf-launcher/default.nix
new file mode 100644
index 0000000..e9c065d
--- /dev/null
+++ b/modules/scripts/fzf-launcher/default.nix
@@ -0,0 +1,26 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "fzf-launcher";
+ path = ./script.sh;
+ description = "Fzf-launcher - FZF-based application launcher (scans .desktop files)";
+ deps = [
+ config.terminal.fzf.package
+ pkgs.dex
+ pkgs.util-linux
+ ];
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/fzf-launcher.sh b/modules/scripts/fzf-launcher/script.sh
index 0858078..2fce83a 100644
--- a/modules/scripts/fzf-launcher.sh
+++ b/modules/scripts/fzf-launcher/script.sh
@@ -1,5 +1,3 @@
-# Fzf-launcher - FZF-based application launcher (scans .desktop files)
-
DIRS=(
/run/current-system/sw/share/applications
"$HOME/.nix-profile/share/applications"
diff --git a/modules/scripts/i3-keybindings/assertions.nix b/modules/scripts/i3-keybindings/assertions.nix
new file mode 100644
index 0000000..ce1dd6b
--- /dev/null
+++ b/modules/scripts/i3-keybindings/assertions.nix
@@ -0,0 +1,11 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.i3-keybindings.enable || config.desktop.enable;
+ message = "scripts.i3-keybindings is enabled but requires `desktop.enable`.";
+ }
+ {
+ assertion = !config.scripts.i3-keybindings.enable || config.terminal.less.enable;
+ message = "scripts.i3-keybindings is enabled but requires `terminal.less.enable`.";
+ }
+]
diff --git a/modules/scripts/i3-keybindings/default.nix b/modules/scripts/i3-keybindings/default.nix
new file mode 100644
index 0000000..e1be7fe
--- /dev/null
+++ b/modules/scripts/i3-keybindings/default.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "i3-keybindings";
+ path = ./script.sh;
+ description = "Path to your i3 config file";
+ deps = [
+ pkgs.coreutils
+ pkgs.gawk
+ pkgs.ncurses
+ ];
+ desktop = {
+ enable = true;
+ displayName = "i3 Keybindings";
+ };
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/i3-keybindings.sh b/modules/scripts/i3-keybindings/script.sh
index 22ddef4..326e8bd 100644
--- a/modules/scripts/i3-keybindings.sh
+++ b/modules/scripts/i3-keybindings/script.sh
@@ -1,4 +1,3 @@
-# Path to your i3 config file
I3_CONFIG="$HOME/.config/i3/config"
# Function to wrap text
diff --git a/modules/scripts/lib.nix b/modules/scripts/lib.nix
new file mode 100644
index 0000000..8b04b5f
--- /dev/null
+++ b/modules/scripts/lib.nix
@@ -0,0 +1,94 @@
+{ lib, pkgs }:
+let
+ shell = pkgs.runtimeShell;
+
+ mkScript =
+ name: path: description: env: deps:
+ let
+ descLines = lib.filter (s: s != "") (lib.splitString "\n" description);
+ descComment =
+ if descLines == [ ] then "" else lib.concatMapStringsSep "\n" (line: "# ${line}") descLines + "\n";
+ envVars = lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n}=\"${toString v}\"") env);
+ wrappedScript = pkgs.writeTextFile {
+ name = name;
+ executable = true;
+ destination = "/bin/${name}";
+ text = ''
+ #!${shell}
+ ${descComment}${envVars}
+ ${builtins.readFile path}
+ '';
+ };
+ in
+ pkgs.runCommand name
+ {
+ nativeBuildInputs = [ pkgs.makeWrapper ];
+ meta.mainProgram = name;
+ }
+ ''
+ mkdir -p $out/bin
+ cp ${wrappedScript}/bin/${name} $out/bin/${name}
+ chmod +x $out/bin/${name}
+
+ wrapProgram $out/bin/${name} \
+ --prefix PATH : ${lib.makeBinPath deps}
+ '';
+
+ mkScriptModule =
+ {
+ name,
+ path,
+ env ? { },
+ deps ? [ ],
+ desktop ? null,
+ config,
+ description ? "",
+ }:
+ {
+ options.scripts.${name} = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = true;
+ description = "Whether to enable the ${name} script.";
+ };
+ package = lib.mkOption {
+ type = lib.types.nullOr lib.types.package;
+ readOnly = true;
+ description = "The derivation for the ${name} script.";
+ };
+ desktop = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = "Whether to create a .desktop entry for this script.";
+ };
+ displayName = lib.mkOption {
+ type = lib.types.str;
+ default = name;
+ description = "Display name for the .desktop entry.";
+ };
+ };
+ };
+
+ moduleConfig = {
+ scripts.${name} = lib.mkIf config.scripts.${name}.enable (
+ {
+ package = mkScript name path description env deps;
+ }
+ // lib.optionalAttrs (desktop != null) { inherit desktop; }
+ );
+ assertions = [
+ {
+ assertion =
+ !config.scripts.${name}.enable
+ || !config.scripts.${name}.desktop.enable
+ || config.terminal.kitty.enable;
+ message = "scripts.${name}.desktop.enable requires terminal.kitty.enable because desktop entries launch scripts in kitty.";
+ }
+ ];
+ };
+ };
+in
+{
+ inherit mkScript mkScriptModule;
+}
diff --git a/modules/scripts/neomutt-sync/assertions.nix b/modules/scripts/neomutt-sync/assertions.nix
new file mode 100644
index 0000000..38f48e4
--- /dev/null
+++ b/modules/scripts/neomutt-sync/assertions.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.neomutt-sync.enable || config.communication.neomutt.enable;
+ message = "scripts.neomutt-sync is enabled but requires `communication.neomutt.enable`.";
+ }
+]
diff --git a/modules/scripts/neomutt-sync/default.nix b/modules/scripts/neomutt-sync/default.nix
new file mode 100644
index 0000000..816c9f7
--- /dev/null
+++ b/modules/scripts/neomutt-sync/default.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "neomutt-sync";
+ path = ./script.sh;
+ description = "Neomutt-sync - Interactive mail sync with dialog progress bar";
+ deps = [
+ pkgs.dialog
+ pkgs.coreutils
+ pkgs.gawk
+ pkgs.gnused
+ pkgs.util-linux
+ config.programs.mbsync.package
+ config.programs.notmuch.package
+ ];
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/neomutt-sync.sh b/modules/scripts/neomutt-sync/script.sh
index e5aae34..96d866d 100644
--- a/modules/scripts/neomutt-sync.sh
+++ b/modules/scripts/neomutt-sync/script.sh
@@ -1,5 +1,3 @@
-# Neomutt-sync - Interactive mail sync with dialog progress bar
-# 1. Create temporary files for the dark theme and notmuch logs
export DIALOGRC=$(mktemp)
NOTMUCH_LOG=$(mktemp)
TITLE="[SYNCING MAIL]"
diff --git a/modules/scripts/screen-recording/assertions.nix b/modules/scripts/screen-recording/assertions.nix
new file mode 100644
index 0000000..ad4d1eb
--- /dev/null
+++ b/modules/scripts/screen-recording/assertions.nix
@@ -0,0 +1,11 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.screen-recording.enable || config.media.ffmpeg.enable;
+ message = "scripts.screen-recording is enabled but requires `media.ffmpeg.enable`.";
+ }
+ {
+ assertion = !config.scripts.screen-recording.enable || config.media.slop.enable;
+ message = "scripts.screen-recording is enabled but requires `media.slop.enable`.";
+ }
+]
diff --git a/modules/scripts/screen-recording/default.nix b/modules/scripts/screen-recording/default.nix
new file mode 100644
index 0000000..f687d36
--- /dev/null
+++ b/modules/scripts/screen-recording/default.nix
@@ -0,0 +1,29 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "screen-recording";
+ path = ./script.sh;
+ description = "Screen recording script using FFmpeg and slop for region selection\nRecords X11 screen to MP4 with x264 encoding\nUsage: screen-recording.sh [-s|--select]\n -s, --select Launch slop to select recording region";
+ deps = [
+ config.media.ffmpeg.package
+ config.media.slop.package
+ ];
+ desktop = {
+ enable = true;
+ displayName = "Screen Recording";
+ };
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/screen-recording.sh b/modules/scripts/screen-recording/script.sh
index c0e8525..a3bf86a 100644
--- a/modules/scripts/screen-recording.sh
+++ b/modules/scripts/screen-recording/script.sh
@@ -1,7 +1,3 @@
-# Screen recording script using FFmpeg and slop for region selection
-# Records X11 screen to MP4 with x264 encoding
-# Usage: screen-recording.sh [-s|--select]
-# -s, --select Launch slop to select recording region
OUT_DIR="$HOME/Videos/Recordings"
mkdir -p "$OUT_DIR"
diff --git a/modules/scripts/system-monitor/assertions.nix b/modules/scripts/system-monitor/assertions.nix
new file mode 100644
index 0000000..0710fc3
--- /dev/null
+++ b/modules/scripts/system-monitor/assertions.nix
@@ -0,0 +1,19 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.system-monitor.enable || config.system.bottom.enable;
+ message = "scripts.system-monitor is enabled but requires `system.bottom.enable`.";
+ }
+ {
+ assertion = !config.scripts.system-monitor.enable || config.system.nvtop.enable;
+ message = "scripts.system-monitor is enabled but requires `system.nvtop.enable`.";
+ }
+ {
+ assertion = !config.scripts.system-monitor.enable || config.terminal.tmux.enable;
+ message = "scripts.system-monitor is enabled but requires `terminal.tmux.enable`.";
+ }
+ {
+ assertion = !config.scripts.system-monitor.enable || config.terminal.kitty.enable;
+ message = "scripts.system-monitor is enabled but requires `terminal.kitty.enable`.";
+ }
+]
diff --git a/modules/scripts/system-monitor/default.nix b/modules/scripts/system-monitor/default.nix
new file mode 100644
index 0000000..1f4990b
--- /dev/null
+++ b/modules/scripts/system-monitor/default.nix
@@ -0,0 +1,32 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "system-monitor";
+ path = ./script.sh;
+ description = "System monitor script using tmux to run bottom and nvtop side-by-side\nOpens a tmux session with:\n - Left pane: bottom (system/process monitor)\n - Right pane: nvtop (GPU monitor)";
+ deps = [
+ config.system.bottom.package
+ config.system.nvtop.package
+ config.terminal.tmux.package
+ config.terminal.kitty.package
+ pkgs.bash
+ ];
+ desktop = {
+ enable = true;
+ displayName = "System Monitor";
+ };
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/system-monitor.sh b/modules/scripts/system-monitor/script.sh
index cadae3a..951428c 100644
--- a/modules/scripts/system-monitor.sh
+++ b/modules/scripts/system-monitor/script.sh
@@ -1,7 +1,3 @@
-# System monitor script using tmux to run bottom and nvtop side-by-side
-# Opens a tmux session with:
-# - Left pane: bottom (system/process monitor)
-# - Right pane: nvtop (GPU monitor)
SESSION="system-monitor"
kitty @ set-font-size -- -4
diff --git a/modules/scripts/vpn-connect/assertions.nix b/modules/scripts/vpn-connect/assertions.nix
new file mode 100644
index 0000000..252df86
--- /dev/null
+++ b/modules/scripts/vpn-connect/assertions.nix
@@ -0,0 +1,11 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.vpn-connect.enable || config.security.openvpn.enable;
+ message = "scripts.vpn-connect is enabled but requires `security.openvpn.enable`.";
+ }
+ {
+ assertion = !config.scripts.vpn-connect.enable || config.terminal.fzf.enable;
+ message = "scripts.vpn-connect is enabled but requires `terminal.fzf.enable`.";
+ }
+]
diff --git a/modules/scripts/vpn-connect/default.nix b/modules/scripts/vpn-connect/default.nix
new file mode 100644
index 0000000..194513f
--- /dev/null
+++ b/modules/scripts/vpn-connect/default.nix
@@ -0,0 +1,32 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "vpn-connect";
+ path = ./script.sh;
+ description = "VPN-connect - OpenVPN connection script with credential caching and monitoring";
+ env = {
+ SYSTEMD_RESOLVED_PATH = "${config.security.openvpn.package}/libexec/update-systemd-resolved";
+ };
+ deps = [
+ config.terminal.fzf.package
+ config.security.openvpn.package
+ pkgs.coreutils
+ pkgs.findutils
+ pkgs.gnugrep
+ pkgs.gnused
+ ];
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/vpn-connect.sh b/modules/scripts/vpn-connect/script.sh
index 337fa2e..4ba8f3d 100644
--- a/modules/scripts/vpn-connect.sh
+++ b/modules/scripts/vpn-connect/script.sh
@@ -1,4 +1,3 @@
-# VPN-connect - OpenVPN connection script with credential caching and monitoring
CONF_DIR="$HOME/.config/openvpn"
CREDS_DIR="$CONF_DIR/credentials"
SERVERS_DIR="$CONF_DIR/servers"
diff --git a/modules/scripts/vpn-disconnect/assertions.nix b/modules/scripts/vpn-disconnect/assertions.nix
new file mode 100644
index 0000000..60c4e9b
--- /dev/null
+++ b/modules/scripts/vpn-disconnect/assertions.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+[
+ {
+ assertion = !config.scripts.vpn-disconnect.enable || config.scripts.vpn-connect.enable;
+ message = "scripts.vpn-disconnect is enabled but requires `scripts.vpn-connect.enable`.";
+ }
+]
diff --git a/modules/scripts/vpn-disconnect/default.nix b/modules/scripts/vpn-disconnect/default.nix
new file mode 100644
index 0000000..61f4738
--- /dev/null
+++ b/modules/scripts/vpn-disconnect/default.nix
@@ -0,0 +1,21 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit ((import ../lib.nix { inherit lib pkgs; })) mkScriptModule;
+ base = mkScriptModule {
+ name = "vpn-disconnect";
+ path = ./script.sh;
+ description = "VPN-disconnect - Kill VPN process and clean up";
+ inherit config;
+ };
+in
+{
+ options = base.options;
+ config = base.moduleConfig // {
+ assertions = base.moduleConfig.assertions ++ (import ./assertions.nix { inherit config lib; });
+ };
+}
diff --git a/modules/scripts/vpn-disconnect.sh b/modules/scripts/vpn-disconnect/script.sh
index 9a70231..ead912c 100644
--- a/modules/scripts/vpn-disconnect.sh
+++ b/modules/scripts/vpn-disconnect/script.sh
@@ -1,4 +1,3 @@
-# VPN-disconnect - Kill VPN process and clean up
PID_FILE="$HOME/.cache/openvpn/vpn.pid"
if [[ ! -f "$PID_FILE" ]]; then