summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCollin Williams <96917990+bluedragon1221@users.noreply.github.com>2026-07-15 06:54:33 -0500
committerCollin Williams <96917990+bluedragon1221@users.noreply.github.com>2026-07-15 06:54:33 -0500
commit8b990276c5e9abccd772694b1f7232d8b49b634c (patch)
tree23f4c3713c538f435354270de2005475c50955d0 /modules
initial commit
Diffstat (limited to 'modules')
-rw-r--r--modules/common/bar.nix69
-rw-r--r--modules/common/defaultGlobalKeys.nix66
-rw-r--r--modules/common/defaultLeaderMenu.nix51
-rw-r--r--modules/common/findFile.nix66
-rw-r--r--modules/common/fzfExec.nix55
-rw-r--r--modules/common/keys.nix66
-rw-r--r--modules/common/main.nix23
-rw-r--r--modules/common/sessionizer.nix92
-rw-r--r--modules/common/sessionizer2.nix50
-rw-r--r--modules/hjem.nix58
-rw-r--r--modules/installer.nix38
11 files changed, 634 insertions, 0 deletions
diff --git a/modules/common/bar.nix b/modules/common/bar.nix
new file mode 100644
index 0000000..cbb162a
--- /dev/null
+++ b/modules/common/bar.nix
@@ -0,0 +1,69 @@
+{
+ config,
+ lib,
+ tsunamiLib,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath;
+in {
+ options = let
+ hexColor = lib.types.strMatching "^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$";
+ in {
+ tsunami.theme = {
+ bg = lib.mkOption {
+ type = hexColor;
+ default = "#fff";
+ };
+ bg_dark = lib.mkOption {
+ type = hexColor;
+ default = "#000";
+ };
+ };
+ };
+ config = {
+ tsunami = {
+ scripts = {
+ "battery" = ''
+ energy_now=$(cat /sys/class/power_supply/BAT0/energy_now)
+ energy_full=$(cat /sys/class/power_supply/BAT0/energy_full)
+ percentage=$((energy_now * 100 / energy_full))
+ printf "%.0f%%" "$percentage"
+ '';
+
+ "bar" = ''
+ tmux set -g status on
+
+ tmux set -g status-position bottom
+ tmux set -g status-justify absolute-centre
+ tmux set -g status-bg "${config.tsunami.theme.bg}"
+
+ tmux set -g status-left-style fg=green,bold
+ tmux set -g status-left " #{client_session}"
+
+ tmux set -g window-status-style fg=color243
+ tmux set -g window-status-format " #I "
+ tmux set -g window-status-current-style fg=color12,bold
+ tmux set -g window-status-current-format " #I "
+ tmux set -g window-status-separator ""
+
+ tmux set -g status-right "#[fg=color243]%l:%M #[fg=red]#(${scriptPath "battery"}) "
+
+ ## pane borders
+ tmux set -g pane-border-style fg=${config.tsunami.theme.bg_dark},bg=${config.tsunami.theme.bg_dark}
+ tmux set -g pane-active-border-style fg=${config.tsunami.theme.bg_dark},bg=${config.tsunami.theme.bg_dark}
+
+ ## pane backgrounds
+ # Set the foreground/background color for the active window
+ tmux set -g window-active-style bg=${config.tsunami.theme.bg}
+
+ # Set the foreground/background color for all other windows
+ tmux set -g window-style bg=${config.tsunami.theme.bg_dark}
+ '';
+ };
+
+ confs."bar" = ''
+ run-shell ${scriptPath "bar"}
+ '';
+ };
+ };
+}
diff --git a/modules/common/defaultGlobalKeys.nix b/modules/common/defaultGlobalKeys.nix
new file mode 100644
index 0000000..fc3c669
--- /dev/null
+++ b/modules/common/defaultGlobalKeys.nix
@@ -0,0 +1,66 @@
+{
+ pkgs,
+ tsunamiLib,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath;
+in {
+ tsunami.scripts."split" = ''
+ width=$(tmux display -p "#{pane_width}")
+ height=$(tmux display -p "#{pane_height}")
+
+ if (( $(echo "$width / $height > 2.5" | ${pkgs.bc}/bin/bc -l) )); then
+ tmux split-window -h "$@"
+ else
+ tmux split-window -v "$@"
+ fi
+ '';
+
+ tsunami.scripts."clean-sessions" = ''
+ current="$(tmux display -p '#{session_name}')"
+
+ tmux list-sessions -F '#{session_name}' | while read -r line; do
+ if [[ "$line" != "$current" && "$line" =~ ^[[:digit:]]+$ ]]; then
+ tmux kill-session -t "$line"
+ fi
+ done
+ '';
+
+ tsunami.keys.global = [
+ {
+ key = "C-w";
+ exec = "kill-pane";
+ }
+ {
+ key = "M-z";
+ exec = "resize-pane -Z";
+ }
+ {
+ key = "C-Enter";
+ exec = ''run-shell "${scriptPath "split"} -c '#{?@default-path,#{@default-path},#{pane_current_path}}'"'';
+ }
+ {
+ key = "C-t";
+ exec = "new-window -c '#{?@default-path,#{@default-path},#{pane_current_path}}'";
+ }
+ {
+ key = "C-Tab";
+ exec = "next-window";
+ }
+ {
+ key = "C-S-Tab";
+ exec = "previous-window";
+ }
+ ];
+
+ tsunami.confs."windows" = ''
+ unbind -n MouseDown3Pane
+ set -g allow-rename on
+ set -g automatic-rename off
+ set -g renumber-windows on
+ set -g base-index 1
+
+ set-hook -ag client-detached 'run-shell ${scriptPath "clean-sessions"}'
+ set-hook -ag client-session-changed 'run-shell ${scriptPath "clean-sessions"}'
+ '';
+}
diff --git a/modules/common/defaultLeaderMenu.nix b/modules/common/defaultLeaderMenu.nix
new file mode 100644
index 0000000..71489e7
--- /dev/null
+++ b/modules/common/defaultLeaderMenu.nix
@@ -0,0 +1,51 @@
+{tsunamiLib, ...}: let
+ inherit (tsunamiLib) scriptPath;
+in {
+ tsunami.scripts = {
+ "find-pane" = ''
+ display_format="#{window_name} #{pane_title} #{pane_current_path} #{pane_current_command}"
+ hidden_format="#{session_name}:#{window_id}:#{pane_id}"
+
+ # select pane
+ selected=$(tmux list-panes -a -F "$hidden_format:$display_format" | fzf --delimiter=: --with-nth 4 --color=hl:2)
+ [ -z "$selected" ] || exit
+
+ # switch to selected
+ args=(''\${selected//:/ })
+ tmux select-pane -t ''\${args[2]} && tmux select-window -t ''\${args[1]} && tmux switch-client -t ''\${args[0]}
+ '';
+
+ "search-pane" = ''
+ trap 'rm -f -- "''\${scrollback:-}"' EXIT
+ scrollback="$(mktemp)"
+
+ tmux capture-pane -e -p -S - > "$scrollback"
+ cat "$scrollback" | fzf --ansi
+
+ exit 0
+ '';
+ };
+
+ tsunami.keys.leader = [
+ {
+ name = "Find Pane";
+ key = "C-w";
+ exec = ''run-shell "${scriptPath "minibuffer"} '${scriptPath "find-pane"}'"'';
+ }
+ {
+ name = "Search Pane";
+ key = "C-/";
+ exec = ''run-shell "${scriptPath "minibuffer"} '${scriptPath "search-pane"}'"'';
+ }
+ {
+ name = "Detach";
+ key = "C-d";
+ exec = "detach";
+ }
+ {
+ name = "Reload";
+ key = "C-r";
+ exec = "source-file ~/.config/tmux/tmux.conf";
+ }
+ ];
+}
diff --git a/modules/common/findFile.nix b/modules/common/findFile.nix
new file mode 100644
index 0000000..3d08603
--- /dev/null
+++ b/modules/common/findFile.nix
@@ -0,0 +1,66 @@
+{
+ pkgs,
+ config,
+ lib,
+ tsunamiLib,
+ std,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath filePath;
+ cfg = config.tsunami.findFile;
+in {
+ options = {
+ tsunami.findFile = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ tsunami.keys.leader = [
+ {
+ name = "Find File";
+ key = "C-f";
+ exec = ''run-shell "${scriptPath "minibuffer"} -d '#{?@default-path,#{@default-path},#{pane_current_path}}' '${scriptPath "find-file"}'"'';
+ }
+ ];
+ tsunami.scripts = {
+ "minibuffer" = ''
+ window_height="$(tmux display -p '#{window_height}')"
+ tmux display-popup -EB \
+ -w 100% -h 16 \
+ -x 0 -y "$(($window_height + 1))" \
+ "$@"
+ '';
+
+ "find-file" = ''${pkgs.broot}/bin/broot --conf ${filePath "broot_find_file.toml"}'';
+ };
+
+ tsunami.files."broot_find_file.toml" = std.serde.toTOML {
+ imports = ["~/.config/broot/conf.hjson"];
+ quit_on_last_cancel = true;
+ verbs = [
+ {
+ invocation = "tmux-split";
+ external = ["bash" "-c" ''${scriptPath "split"} -c "#{?@default-path,#{@default-path},#{pane_current_path}}" "$EDITOR '{file}'"''];
+ key = "ctrl-s";
+ apply_to = "file";
+ leave_broot = true;
+ }
+ {
+ invocation = "tmux-window";
+ external = ["tmux" "new-window" "-c" "#{?@default-path,#{@default-path},#{pane_current_path}}" "$EDITOR '{file}'"];
+ key = "ctrl-w";
+ apply_to = "file";
+ leave_broot = true;
+ }
+ {
+ key = "enter";
+ cmd = ":tmux-window";
+ }
+ ];
+ };
+ };
+}
diff --git a/modules/common/fzfExec.nix b/modules/common/fzfExec.nix
new file mode 100644
index 0000000..2de3741
--- /dev/null
+++ b/modules/common/fzfExec.nix
@@ -0,0 +1,55 @@
+{
+ tsunamiLib,
+ lib,
+ pkgs,
+ config,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath;
+ cfg = config.tsunami.fzfExec;
+in {
+ options = {
+ tsunami.fzfExec = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = true;
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ tsunami.scripts = {
+ # this is buggy af; it only works half the time.
+ # But it's the only way I know of to get docs on a specific tmux command
+ "tmux-doc" = ''
+ usage=$(tmux list-commands -F "#{command_list_name} #{command_list_usage}" "$1")
+
+ man tmux | ${pkgs.gawk}/bin/awk -v usage="$usage" '
+ index($0, usage) > 0 { found=1 }
+ found {
+ print
+ if ($0 == "") exit
+ }
+ '
+ '';
+
+ "fzf-exec" = ''
+ all_cmds() {
+ tmux list-commands -F $'#{command_list_name}#{?command_list_alias,\n#{command_list_alias},}'
+ }
+
+ selected_cmd=$(all_cmds | ${pkgs.fzf}/bin/fzf --bind 'enter:accept-or-print-query,tab:replace-query,alt-backspace:clear-query' --prompt : --preview "~/.config/tmux/scripts/tmux-doc.sh $(printf '{}' | cut -d' ' -f1)")
+ test -z "$selected_cmd" && exit
+
+ tmux $(echo "$selected_cmd" | sed "s@~@$HOME@g")
+ '';
+ };
+
+ tsunami.keys.global = [
+ {
+ key = "M-x";
+ exec = "run-shell '${scriptPath "minibuffer"} -h 10 ${scriptPath "fzf-exec"}'";
+ }
+ ];
+ };
+}
diff --git a/modules/common/keys.nix b/modules/common/keys.nix
new file mode 100644
index 0000000..9e3c1a2
--- /dev/null
+++ b/modules/common/keys.nix
@@ -0,0 +1,66 @@
+{
+ lib,
+ config,
+ tsunamiLib,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath;
+ inherit (lib.strings) escapeShellArg;
+ cfg = config.tsunami.keys;
+in {
+ options = let
+ tmuxKey = lib.types.strMatching "^((C|M|S)-)*(.|Enter|Escape|Tab|Up|Down|Left|Right)$";
+ inherit (lib) mkOption;
+ in {
+ tsunami.keys = {
+ leader = mkOption {
+ type = with lib.types;
+ listOf (submodule {
+ options = {
+ name = mkOption {type = str;};
+ key = mkOption {type = tmuxKey;};
+ exec = mkOption {type = str;};
+ };
+ });
+ };
+
+ global = mkOption {
+ type = with lib.types;
+ listOf (submodule {
+ options = {
+ key = mkOption {type = tmuxKey;};
+ exec = mkOption {type = str;};
+ };
+ });
+ };
+ };
+ };
+
+ config = {
+ tsunami.scripts = {
+ "menu" = ''
+ tmux display-menu \
+ -x "#{window_width}" -y S \
+ -b none \
+ -s "bg=#313244,fg=#9399b2" \
+ -S "bg=#313244" \
+ -H "bg=#45475a fg=#b4befe" \
+ "$@"
+ '';
+
+ "leader-menu" = let
+ args = lib.concatStringsSep " " (builtins.map (f: "${escapeShellArg f.name} ${f.key} ${escapeShellArg f.exec}") cfg.leader);
+ in ''
+ ${scriptPath "menu"} ${args}
+ '';
+ };
+ tsunami.keys.global = [
+ {
+ key = "C-x";
+ exec = "run-shell ${scriptPath "leader-menu"}";
+ }
+ ];
+
+ tsunami.confs."global-keys" = cfg.global |> builtins.map (f: "bind-key -n ${f.key} ${escapeShellArg f.exec}") |> lib.concatStringsSep "\n";
+ };
+}
diff --git a/modules/common/main.nix b/modules/common/main.nix
new file mode 100644
index 0000000..25366d9
--- /dev/null
+++ b/modules/common/main.nix
@@ -0,0 +1,23 @@
+{lib, ...}: let
+ inherit (lib) mkOption mkEnableOption;
+in {
+ options = {
+ tsunami = {
+ enable = mkEnableOption "tsunami tmux distro";
+ scripts = mkOption {
+ type = lib.types.attrsOf (lib.types.str);
+ default = [];
+ };
+
+ files = mkOption {
+ type = lib.types.attrsOf (lib.types.str);
+ default = [];
+ };
+
+ confs = mkOption {
+ type = lib.types.attrsOf (lib.types.str);
+ default = [];
+ };
+ };
+ };
+}
diff --git a/modules/common/sessionizer.nix b/modules/common/sessionizer.nix
new file mode 100644
index 0000000..09aa65a
--- /dev/null
+++ b/modules/common/sessionizer.nix
@@ -0,0 +1,92 @@
+{
+ pkgs,
+ config,
+ lib,
+ tsunamiLib,
+ std,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath filePath;
+ cfg = config.tsunami.sessionizer;
+in {
+ options = {
+ tsunami.sessionizer = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ tsunami.keys.leader = [
+ {
+ name = "Sessions+";
+ key = "C-s";
+ exec = "run-shell ${scriptPath "sessions-menu"}";
+ }
+ ];
+
+ tsunami.scripts = {
+ "sessionizer" =
+ # bash
+ ''
+ [ -z "$1" ] && exit
+
+ selected="$1"
+ session_name="$(basename "$selected" | tr '.' '_')"
+
+ # if the session doesn't exist, create it
+ if ! tmux has-session -t "$session_name"; then
+ tmux new-session -ds "$session_name" -c "$selected"
+ tmux set-option -t "$session_name" @default-path "$selected"
+ fi
+
+ # switch to it
+ tmux switch -t "$session_name"
+ '';
+ "launch-sessionizer" = ''${pkgs.broot}/bin/broot --only-folders --conf ${filePath "broot_sessionizer.toml"}'';
+ "new-session" = ''tmux switch-client -t "$(tmux new-session -dP)"'';
+ "sessions-menu" =
+ # bash
+ ''
+ menu_items=(
+ "Switch Session" s "run-shell '${scriptPath "minibuffer"} -d $HOME ${scriptPath "launch-sessionizer"}'"
+ "New Unnamed Session" n "run-shell ${scriptPath "new-session"}"
+ )
+
+ # put tmux session names into a list
+ mapfile -t sessions < <(tmux list-sessions -F "#{session_name}")
+
+ # ...but limit at 9 sessions
+ for i in "''\${!sessions[@]}"; do
+ (( i >= 9 )) && break # Stop after 9 sessions
+
+ session="''\${sessions[$i]}"
+ key=$((i + 1)) # 1-based key
+
+ # and put those 9 in the list of menu items
+ menu_items+=("$session" "$key" "switch-client -t $session")
+ done
+
+ # Display the menu
+ ${scriptPath "menu"} -T "#[align=centre]Sessions" "''\${menu_items[@]}"
+ '';
+ };
+ tsunami.files = {
+ "broot_sessionizer.toml" = std.serde.toTOML {
+ imports = ["~/.config/broot/conf.hjson"]; # inherit from user's config
+ quit_on_cancel = true;
+ verbs = [
+ {
+ invocation = "session";
+ external = ''bash -c -- "${scriptPath "sessionizer"} '{file}'"'';
+ key = "enter";
+ apply_to = "directory";
+ leave_broot = true;
+ }
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/common/sessionizer2.nix b/modules/common/sessionizer2.nix
new file mode 100644
index 0000000..5f159df
--- /dev/null
+++ b/modules/common/sessionizer2.nix
@@ -0,0 +1,50 @@
+{
+ pkgs,
+ config,
+ lib,
+ tsunamiLib,
+ std,
+ ...
+}: let
+ inherit (tsunamiLib) scriptPath filePath;
+ cfg = config.tsunami.sessionizer2;
+in {
+ options.tsunami.sessionizer2 = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = true;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ tsunami.keys.leader = [
+ {
+ name = "New Session";
+ key = "C-n";
+ exec = "run-shell ${scriptPath "sessions-menu"}";
+ }
+ ];
+
+ tsunami.files = {
+ "broot_sessionizer2_launcher" = std.serde.toTOML {
+ imports = ["~/.config/broot/conf.hjson"]; # inherit from user's config
+ verbs = [
+ {
+ invocation = "tmux-window";
+ external = ["tmux" "new-window" "-c" "#{?@default-path,#{@default-path},#{pane_current_path}}" "$EDITOR '{file}'"];
+ key = "enter";
+ apply_to = "file";
+ leave_broot = false;
+ }
+ {
+ invocation = "tmux-window";
+ external = ["tmux" "new-window" "-c" "#{?@default-path,#{@default-path},#{pane_current_path}}" "$EDITOR '{file}'"];
+ key = "enter";
+ apply_to = "file";
+ leave_broot = false;
+ }
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/hjem.nix b/modules/hjem.nix
new file mode 100644
index 0000000..019eada
--- /dev/null
+++ b/modules/hjem.nix
@@ -0,0 +1,58 @@
+{std, ...}: {
+ pkgs,
+ lib,
+ config,
+ ...
+}: let
+ cfg = config.tsunami;
+in {
+ imports = lib.filesystem.listFilesRecursive ./common;
+
+ _module.args = {
+ inherit std;
+ tsunamiLib = {
+ scriptPath = f: "~/.config/tmux/scripts/${f}.sh";
+ filePath = f: "~/.config/tmux/files/${f}";
+ };
+ };
+
+ files = lib.mkIf cfg.enable (lib.mkMerge [
+ (
+ cfg.scripts
+ |> builtins.mapAttrs (name: value: {
+ name = ".config/tmux/scripts/${name}.sh";
+ value = {
+ text = value;
+ executable = true;
+ };
+ })
+ |> lib.attrValues
+ |> builtins.listToAttrs
+ )
+ (
+ cfg.files
+ |> builtins.mapAttrs (name: value: {
+ name = ".config/tmux/files/${name}";
+ value.text = value;
+ })
+ |> lib.attrValues
+ |> builtins.listToAttrs
+ )
+ (
+ cfg.confs
+ |> builtins.mapAttrs (name: value: {
+ name = ".config/tmux/conf.d/${name}.conf";
+ value.text = value;
+ })
+ |> lib.attrValues
+ |> builtins.listToAttrs
+ )
+ {
+ ".config/tmux/tmux.conf".text = ''
+ run-shell "find ~/.config/tmux/conf.d -print0 | xargs -0 -n1 tmux source-file"
+ '';
+ }
+ ]);
+
+ packages = lib.optional cfg.enable pkgs.tmux;
+}
diff --git a/modules/installer.nix b/modules/installer.nix
new file mode 100644
index 0000000..9cff811
--- /dev/null
+++ b/modules/installer.nix
@@ -0,0 +1,38 @@
+{pkgs, ...}: let
+ tsunamiLib = {
+ scriptPath = f: "$HOME/.config/tmux/scripts/${f}.sh";
+ filePath = f: "$HOME/.config/tmux/files/${f}";
+ };
+ config = pkgs.lib.evalModules {
+ modules =
+ [
+ {_module.args = {inherit pkgs tsunamiLib;};}
+ ]
+ ++ (pkgs.lib.filesystem.listFilesRecursive ./common);
+ };
+
+ moduleConfig = pkgs.writeText "tsunami-installer-config.json" (builtins.toJSON {
+ inherit (config.config.tsunami) scripts files confs;
+ });
+in {
+ mkInstaller =
+ pkgs.runCommand "tsunami-installer" {
+ buildInputs = [pkgs.jq];
+ } ''
+ mkdir -p $out
+ {
+ cat ${moduleConfig} | jq -r '
+ (.scripts | to_entries[] | "cat <<\"EOF\" > $HOME/.config/tmux/scripts/\(.key).sh\n\(.value)\nEOF\n"),
+ (.files | to_entries[] | "cat <<\"EOF\" > $HOME/.config/tmux/files/\(.key)\n\(.value)\nEOF\n"),
+ (.confs | to_entries[] | "cat <<\"EOF\" > $HOME/.config/tmux/conf.d/\(.key).conf\n\(.value)\nEOF\n")
+ '
+ printf '
+ cat <<EOF > $HOME/.config/tmux/tmux.conf
+ run-shell "find $out/conf.d -print0 | xargs -0 -n1 tmux source-file"
+ EOF
+ '
+ } > $out/tsunami-installer
+
+ chmod +x $out/tsunami-installer
+ '';
+}