diff --git a/config/tmuxinator/default.nix b/config/tmuxinator/default.nix index 3a046b9ed..0380669b5 100644 --- a/config/tmuxinator/default.nix +++ b/config/tmuxinator/default.nix @@ -1,4 +1,7 @@ { ... }: { - xdg.configFile."tmuxinator".source = ./tmuxinator; + xdg.configFile."tmuxinator/primary.yml".source = ./primary.yml; + xdg.configFile."tmuxinator/mobile.yml".source = ./mobile.yml; + xdg.configFile."tmuxinator/work.yml".source = ./work.yml; + xdg.configFile."tmuxinator/desktop.yml".source = ./desktop.yml; } diff --git a/config/tmuxinator/tmuxinator/desktop.yml b/config/tmuxinator/desktop.yml similarity index 100% rename from config/tmuxinator/tmuxinator/desktop.yml rename to config/tmuxinator/desktop.yml diff --git a/config/tmuxinator/tmuxinator/mobile.yml b/config/tmuxinator/mobile.yml similarity index 100% rename from config/tmuxinator/tmuxinator/mobile.yml rename to config/tmuxinator/mobile.yml diff --git a/config/tmuxinator/tmuxinator/primary.yml b/config/tmuxinator/primary.yml similarity index 100% rename from config/tmuxinator/tmuxinator/primary.yml rename to config/tmuxinator/primary.yml diff --git a/config/tmuxinator/tmuxinator/work.yml b/config/tmuxinator/work.yml similarity index 100% rename from config/tmuxinator/tmuxinator/work.yml rename to config/tmuxinator/work.yml diff --git a/home-manager/programs/fish/default.nix b/home-manager/programs/fish/default.nix index 149fb7e8f..2bcef9422 100644 --- a/home-manager/programs/fish/default.nix +++ b/home-manager/programs/fish/default.nix @@ -119,6 +119,7 @@ tmo = "_tmo_function"; tpo = "_tpo_function"; tsh = "_tsh_function"; + tsk = "_tsk_function"; tss = "_tss_function"; tsw = "_tsw_function"; two = "_two_function"; @@ -211,6 +212,7 @@ "_tmo_function" "_tpo_function" "_tsh_function" + "_tsk_function" "_tss_function" "_tsw_function" "_two_function" diff --git a/home-manager/programs/fish/functions/_tsh_function.fish b/home-manager/programs/fish/functions/_tsh_function.fish index 297b0ce66..413853371 100644 --- a/home-manager/programs/fish/functions/_tsh_function.fish +++ b/home-manager/programs/fish/functions/_tsh_function.fish @@ -1,72 +1,35 @@ -function _tsh_function --description "Search tmux session history log or pane contents" - set -l log ~/.local/share/tmux/session-history.log +function _tsh_function --description "Search tmux pane contents (live + archived)" set -l pane_dir ~/.local/share/tmux/panes set -l archive_dir ~/.local/share/tmux/archive - # With argument(s): search stored pane content files (live + archived) - if test (count $argv) -gt 0 - if not test -d "$pane_dir" - echo "No pane content store found at $pane_dir" - return - end - - set -l query (string join ' ' $argv) - set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \ - | fzf --prompt="pane-search> " \ - --height=40% \ - --preview="rg -n -- '$query' {} 2>/dev/null | head -80" \ - --preview-window=right:60%) - - if test -z "$selected" - return - end - - # work--0--0.txt or work--0--0--20260226-103000.txt → sess=work, widx=0 - set -l fname (string replace -r '.*/' '' "$selected" \ - | string replace -r '--\d{8}-\d{6}\.txt$' '' \ - | string replace '.txt' '') - set -l parts (string split -- '--' $fname) - set -l sess $parts[1] - set -l widx $parts[2] - - if not tmux has-session -t "$sess" 2>/dev/null - echo "Session '$sess' no longer exists (archived pane — content shown above in preview)" - return - end - - if test -n "$TMUX" - tmux switch-client -t "$sess" - tmux select-window -t "$sess:$widx" 2>/dev/null - else - tmux attach-session -t "$sess" \; select-window -t "$sess:$widx" - end - return - end - - # No argument: fzf over the history log (session/window/path metadata) - if not test -f "$log" - echo "No session history found at $log" + # Default: fzf over pane content files, optional query pre-fills search + if not test -d "$pane_dir" + echo "No pane content store found at $pane_dir" return end - set -l selected (cat "$log" | fzf \ - --prompt="session-history> " \ - --height=40% \ - --tac \ - --no-sort \ - --preview='echo {}') + set -l query (string join ' ' $argv) + set -l selected (rg -l -- "$query" "$pane_dir" "$archive_dir" 2>/dev/null \ + | fzf --prompt="pane-search> " \ + --height=40% \ + --query="$query" \ + --preview="rg -n -- '$query' {} 2>/dev/null | head -80" \ + --preview-window=right:60%) if test -z "$selected" return end - set -l target (string split ' ' $selected)[2] - set -l parts (string split ':' $target) + # work--0--0.txt or work--0--0--20260226-103000.txt → sess=work, widx=0 + set -l fname (string replace -r '.*/' '' "$selected" \ + | string replace -r '--\d{8}-\d{6}\.txt$' '' \ + | string replace '.txt' '') + set -l parts (string split -- '--' $fname) set -l sess $parts[1] set -l widx $parts[2] if not tmux has-session -t "$sess" 2>/dev/null - echo "Session '$sess' no longer exists" + bat --style=plain "$selected" 2>/dev/null; or less "$selected" return end diff --git a/home-manager/programs/fish/functions/_tsk_function.fish b/home-manager/programs/fish/functions/_tsk_function.fish new file mode 100644 index 000000000..36b5c7717 --- /dev/null +++ b/home-manager/programs/fish/functions/_tsk_function.fish @@ -0,0 +1,34 @@ +function _tsk_function --description "Kill tmux sessions or windows via fzf" + # Build list: sessions and windows + set -l items (begin + tmux list-sessions -F 'session #{session_name}' 2>/dev/null + tmux list-windows -a -F 'window #{session_name}:#{window_index} #{window_name}' 2>/dev/null + end) + + set -l selected (printf '%s\n' $items \ + | fzf --prompt="kill> " \ + --height=40% \ + --multi \ + --preview=' + set kind (string split " " {})[1] + set target (string split " " {})[2] + if test "$kind" = session + tmux list-windows -F "#I: #W #{pane_current_path}" -t $target 2>/dev/null + else + tmux list-panes -F "#P: #{pane_current_command} #{pane_current_path}" -t $target 2>/dev/null + end') + + if test -z "$selected" + return + end + + for line in $selected + set -l kind (string split ' ' $line)[1] + set -l target (string split ' ' $line)[2] + if test "$kind" = session + tmux kill-session -t "$target" 2>/dev/null + else + tmux kill-window -t "$target" 2>/dev/null + end + end +end diff --git a/home-manager/programs/fish/functions/_tss_function.fish b/home-manager/programs/fish/functions/_tss_function.fish index 95c3edaea..528e15a12 100644 --- a/home-manager/programs/fish/functions/_tss_function.fish +++ b/home-manager/programs/fish/functions/_tss_function.fish @@ -1,4 +1,43 @@ function _tss_function --description "Fuzzy-pick or create a tmux session" + set -l log ~/.local/share/tmux/session-history.log + + # --log: browse session/window metadata log + if test (count $argv) -gt 0 -a "$argv[1]" = --log + if not test -f "$log" + echo "No session history found at $log" + return + end + + set -l selected (cat "$log" | fzf \ + --prompt="session-history> " \ + --height=40% \ + --tac \ + --no-sort \ + --preview='echo {}') + + if test -z "$selected" + return + end + + set -l target (string split ' ' $selected)[2] + set -l parts (string split ':' $target) + set -l sess $parts[1] + set -l widx $parts[2] + + if not tmux has-session -t "$sess" 2>/dev/null + echo "Session '$sess' no longer exists" + return + end + + if test -n "$TMUX" + tmux switch-client -t "$sess" + tmux select-window -t "$sess:$widx" 2>/dev/null + else + tmux attach-session -t "$sess" \; select-window -t "$sess:$widx" + end + return + end + set -l default_sessions primary mobile desktop work # Build candidate list: default sessions first, then any extra existing sessions diff --git a/home-manager/programs/fish/functions/_tsw_function.fish b/home-manager/programs/fish/functions/_tsw_function.fish index c57f3bae4..c46bdb0df 100644 --- a/home-manager/programs/fish/functions/_tsw_function.fish +++ b/home-manager/programs/fish/functions/_tsw_function.fish @@ -1,4 +1,43 @@ function _tsw_function --description "Fuzzy-pick any window across all sessions" + set -l log ~/.local/share/tmux/session-history.log + + # --log: browse session/window metadata log + if test (count $argv) -gt 0 -a "$argv[1]" = --log + if not test -f "$log" + echo "No session history found at $log" + return + end + + set -l selected (cat "$log" | fzf \ + --prompt="session-history> " \ + --height=40% \ + --tac \ + --no-sort \ + --preview='echo {}') + + if test -z "$selected" + return + end + + set -l target (string split ' ' $selected)[2] + set -l parts (string split ':' $target) + set -l sess $parts[1] + set -l widx $parts[2] + + if not tmux has-session -t "$sess" 2>/dev/null + echo "Session '$sess' no longer exists" + return + end + + if test -n "$TMUX" + tmux switch-client -t "$sess" + tmux select-window -t "$sess:$widx" 2>/dev/null + else + tmux attach-session -t "$sess" \; select-window -t "$sess:$widx" + end + return + end + set -l selected (tmux list-windows -a -F '#{session_name}:#{window_index} #{window_name}' 2>/dev/null \ | fzf --prompt="window> " --height=40% \ --preview='set t (string split " " {})[1]; tmux list-panes -t $t -F "#P: #{pane_current_command} #{pane_current_path}" 2>/dev/null') diff --git a/home-manager/programs/tmux/tmux.conf b/home-manager/programs/tmux/tmux.conf index b7531aaf5..c552922de 100644 --- a/home-manager/programs/tmux/tmux.conf +++ b/home-manager/programs/tmux/tmux.conf @@ -145,6 +145,12 @@ bind Tab switch-client -l # Cross-session window picker bind W run-shell "tmux new-window 'fish -c _tsw_function'" +# Pane content search (live + archived) +bind H run-shell "tmux new-window 'fish -c _tsh_function'" + +# Kill sessions/windows via fzf +bind K run-shell "tmux new-window 'fish -c _tsk_function'" + # Extrakto (text extraction) set -g @extrakto_key 'tab'