From 8e563fec515b81649ecf98491d24264b7f2e76f5 Mon Sep 17 00:00:00 2001 From: Jens Luedicke Date: Mon, 22 Sep 2025 15:26:42 +0200 Subject: [PATCH] Add session manager for tmux. This will open a tmux session for each monitor. Add helper script for tmux actions. --- alacritty/alacritty.toml | 8 +- i3/config | 34 ++++-- i3/simple-terminal.sh | 13 +++ i3/smart-terminal.sh | 97 ++++++++++++++++ i3/tmux-session-manager.sh | 229 +++++++++++++++++++++++++++++++++++++ tmux/move-window.sh | 42 +++++++ tmux/tmux-fzf-menu.sh | 193 +++++++++++++++++++++++++++++++ tmux/tmux.conf | 17 ++- 8 files changed, 622 insertions(+), 11 deletions(-) create mode 100755 i3/simple-terminal.sh create mode 100755 i3/smart-terminal.sh create mode 100755 i3/tmux-session-manager.sh create mode 100755 tmux/move-window.sh create mode 100755 tmux/tmux-fzf-menu.sh diff --git a/alacritty/alacritty.toml b/alacritty/alacritty.toml index de2f08a..34bf2b8 100644 --- a/alacritty/alacritty.toml +++ b/alacritty/alacritty.toml @@ -8,7 +8,7 @@ dimensions = { columns = 140, lines = 45 } option_as_alt = "Both" [font] -size = 16.0 +size = 12.0 [font.normal] family = "0xProto Nerd Font" @@ -115,9 +115,11 @@ bindings = [ [terminal] osc52 = "CopyPaste" # Enable OSC 52 for clipboard support +# Shell configuration - tmux sessions are now handled by smart-terminal.sh +# which creates monitor/workspace-specific sessions automatically [terminal.shell] -program = "/usr/bin/tmux" -args = ["new-session", "-A", "-s", "main"] +program = "/bin/bash" +args = ["-l"] [scrolling] history = 10000 diff --git a/i3/config b/i3/config index b43d484..3de7fa9 100644 --- a/i3/config +++ b/i3/config @@ -34,10 +34,6 @@ exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock -f --nofork # and nm-applet is a desktop environment-independent system tray GUI for it. exec --no-startup-id nm-applet -# Wallpaper rotation script -exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --once -exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --daemon 1800 - # Use pactl to adjust volume in PulseAudio. set $refresh_i3status killall -SIGUSR1 i3status bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status @@ -48,8 +44,15 @@ bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOU # Use Mouse+$mod to drag floating windows to their wanted position floating_modifier $mod -# start a terminal -bindsym $mod+Return exec alacritty +# start a terminal with smart monitor/workspace-aware tmux sessions +bindsym $mod+Return exec --no-startup-id /home/jens/.config/i3/smart-terminal.sh + +# fallback simple terminal (without smart sessions) +bindsym $mod+Shift+Return exec --no-startup-id /home/jens/.config/i3/simple-terminal.sh + +# tmux session management keybindings +bindsym $mod+Shift+t exec --no-startup-id /home/jens/.cargo/bin/alacritty -e /home/jens/.config/i3/tmux-session-manager.sh +bindsym $mod+Control+t exec --no-startup-id /home/jens/.config/i3/tmux-session-manager.sh list | rofi -dmenu -p "Tmux Sessions" -width 60 # kill focused window bindsym $mod+Shift+q kill @@ -63,6 +66,23 @@ bindsym $mod+Shift+q kill # bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop bindsym $mod+d exec rofi -show run +# Screenshot bindings +bindsym Print exec --no-startup-id ~/.local/bin/screenshot.sh full +bindsym Shift+Print exec --no-startup-id ~/.local/bin/screenshot.sh selection +bindsym $mod+Print exec --no-startup-id ~/.local/bin/screenshot.sh window +bindsym Control+Print exec --no-startup-id ~/.local/bin/screenshot.sh clipboard +bindsym Control+Shift+Print exec --no-startup-id ~/.local/bin/screenshot.sh clipboard-selection + +# Alternative screenshot bindings for keyboards that send different codes +bindsym XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh full +bindsym Shift+XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh selection +bindsym $mod+XF86ScreenSaver exec --no-startup-id ~/.local/bin/screenshot.sh window + +# Additional screenshot bindings with mod+s combinations +bindsym $mod+Shift+s exec --no-startup-id ~/.local/bin/screenshot.sh selection +bindsym $mod+Control+s exec --no-startup-id ~/.local/bin/screenshot.sh window +bindsym $mod+Control+Shift+s exec --no-startup-id ~/.local/bin/screenshot.sh full + # change focus bindsym $mod+j focus left bindsym $mod+k focus down @@ -116,7 +136,7 @@ bindsym $mod+a focus parent # Wallpaper controls bindsym $mod+Shift+w exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --once bindsym $mod+Shift+n exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category nature -bindsym $mod+Control+s exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category space +# bindsym $mod+Control+s exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category space # Disabled - conflicts with screenshot binding bindsym $mod+Control+c exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --category cityscape # Define names for default workspaces for which we configure key bindings later on. diff --git a/i3/simple-terminal.sh b/i3/simple-terminal.sh new file mode 100755 index 0000000..44fa692 --- /dev/null +++ b/i3/simple-terminal.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Simple fallback terminal launcher +# Uses alacritty directly without complex session detection + +ALACRITTY="/home/jens/.cargo/bin/alacritty" + +if [ -x "$ALACRITTY" ]; then + exec "$ALACRITTY" +else + # Fallback to xterm + exec xterm +fi \ No newline at end of file diff --git a/i3/smart-terminal.sh b/i3/smart-terminal.sh new file mode 100755 index 0000000..7fcf200 --- /dev/null +++ b/i3/smart-terminal.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Smart terminal launcher with monitor-aware tmux sessions +# This script detects the current monitor and workspace to create/attach to appropriate tmux sessions + +# Get the focused monitor using i3-msg +get_current_monitor() { + if command -v i3-msg &> /dev/null && i3-msg -t get_workspaces &>/dev/null; then + i3-msg -t get_workspaces 2>/dev/null | jq -r '.[] | select(.focused==true) | .output' 2>/dev/null + else + echo "default" + fi +} + +# Get the current workspace number +get_current_workspace() { + if command -v i3-msg &> /dev/null && i3-msg -t get_workspaces &>/dev/null; then + i3-msg -t get_workspaces 2>/dev/null | jq -r '.[] | select(.focused==true) | .num' 2>/dev/null + else + echo "1" + fi +} + +# Determine session name based on monitor and workspace +get_session_name() { + local monitor=$(get_current_monitor) + local workspace=$(get_current_workspace) + + # Fallback if we can't get monitor/workspace info + if [ -z "$monitor" ] || [ "$monitor" = "null" ]; then + monitor="default" + fi + if [ -z "$workspace" ] || [ "$workspace" = "null" ]; then + workspace="1" + fi + + # Clean monitor name (remove special characters) + monitor_clean=$(echo "$monitor" | sed 's/[^a-zA-Z0-9-]/_/g') + + # Map monitors to logical screen names + case "$monitor_clean" in + "eDP_1"|"eDP1") + screen="laptop" + ;; + "DVI_I_2_2"|"HDMI_1"|"HDMI1"|"DP_1"|"DP1") + screen="external1" + ;; + "DVI_I_1_1"|"HDMI_2"|"HDMI2"|"DP_2"|"DP2") + screen="external2" + ;; + "default") + screen="main" + ;; + *) + screen="${monitor_clean}" + ;; + esac + + # Create session name: screen-workspace (e.g., laptop-1, external1-5) + if [ "$screen" = "main" ]; then + echo "main" + else + echo "${screen}-ws${workspace}" + fi +} + +# Launch alacritty with tmux +launch_terminal() { + local session_name=$(get_session_name) + + # Debug logging (remove after testing) + echo "Launching terminal with session: $session_name" >> /tmp/smart-terminal.log + + # Check if alacritty exists + ALACRITTY_PATH="/home/jens/.cargo/bin/alacritty" + if [ ! -x "$ALACRITTY_PATH" ]; then + ALACRITTY_PATH=$(which alacritty 2>/dev/null) + if [ -z "$ALACRITTY_PATH" ]; then + # Fallback to xterm or another terminal + echo "Alacritty not found, falling back to xterm" >> /tmp/smart-terminal.log + xterm -e tmux new-session -A -s "$session_name" & + exit 0 + fi + fi + + # Check if tmux session exists + if tmux has-session -t "$session_name" 2>/dev/null; then + # Session exists, attach to it + "$ALACRITTY_PATH" --title "Terminal [$session_name]" -e tmux attach-session -t "$session_name" & + else + # Create new session with meaningful name + "$ALACRITTY_PATH" --title "Terminal [$session_name]" -e tmux new-session -s "$session_name" & + fi +} + +# Main execution +launch_terminal \ No newline at end of file diff --git a/i3/tmux-session-manager.sh b/i3/tmux-session-manager.sh new file mode 100755 index 0000000..8606c9b --- /dev/null +++ b/i3/tmux-session-manager.sh @@ -0,0 +1,229 @@ +#!/bin/bash + +# Advanced tmux session management for multi-monitor setup +# Provides utilities for managing monitor-specific tmux sessions + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# List all tmux sessions with their status +list_sessions() { + echo -e "${BLUE}=== Tmux Sessions by Screen ===${NC}" + + # Group sessions by screen + for screen in laptop external1 external2; do + sessions=$(tmux list-sessions 2>/dev/null | grep "^${screen}-" | cut -d: -f1) + if [ ! -z "$sessions" ]; then + echo -e "\n${GREEN}${screen}:${NC}" + while IFS= read -r session; do + workspace=$(echo "$session" | cut -d- -f2) + attached="" + if tmux list-sessions 2>/dev/null | grep "^${session}:" | grep -q "(attached)"; then + attached=" ${YELLOW}[attached]${NC}" + fi + echo -e " • ${session}${attached}" + done <<< "$sessions" + fi + done + + # Show other sessions + other_sessions=$(tmux list-sessions 2>/dev/null | grep -v -E "^(laptop|external1|external2)-" | cut -d: -f1) + if [ ! -z "$other_sessions" ]; then + echo -e "\n${BLUE}Other sessions:${NC}" + while IFS= read -r session; do + attached="" + if tmux list-sessions 2>/dev/null | grep "^${session}:" | grep -q "(attached)"; then + attached=" ${YELLOW}[attached]${NC}" + fi + echo -e " • ${session}${attached}" + done <<< "$other_sessions" + fi +} + +# Kill all sessions for a specific screen +kill_screen_sessions() { + local screen=$1 + if [ -z "$screen" ]; then + echo -e "${RED}Error: Please specify a screen (laptop, external1, external2)${NC}" + return 1 + fi + + sessions=$(tmux list-sessions 2>/dev/null | grep "^${screen}-" | cut -d: -f1) + if [ -z "$sessions" ]; then + echo -e "${YELLOW}No sessions found for screen: ${screen}${NC}" + return 0 + fi + + echo -e "${YELLOW}Killing all sessions for ${screen}...${NC}" + while IFS= read -r session; do + tmux kill-session -t "$session" 2>/dev/null + echo -e " ${RED}✗${NC} Killed: $session" + done <<< "$sessions" +} + +# Rename a session +rename_session() { + local old_name=$1 + local new_name=$2 + + if [ -z "$old_name" ] || [ -z "$new_name" ]; then + echo -e "${RED}Error: Usage: rename_session ${NC}" + return 1 + fi + + if tmux has-session -t "$old_name" 2>/dev/null; then + tmux rename-session -t "$old_name" "$new_name" + echo -e "${GREEN}✓${NC} Renamed: $old_name → $new_name" + else + echo -e "${RED}Error: Session '$old_name' not found${NC}" + return 1 + fi +} + +# Switch to a different session +switch_session() { + local session_name=$1 + + if [ -z "$session_name" ]; then + # Interactive session picker using fzf if available + if command -v fzf &> /dev/null; then + session_name=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --prompt="Select session: ") + else + echo -e "${RED}Error: Please specify a session name${NC}" + list_sessions + return 1 + fi + fi + + if [ ! -z "$session_name" ] && tmux has-session -t "$session_name" 2>/dev/null; then + if [ -n "$TMUX" ]; then + tmux switch-client -t "$session_name" + else + tmux attach-session -t "$session_name" + fi + else + echo -e "${RED}Error: Session '$session_name' not found${NC}" + return 1 + fi +} + +# Create a new session for current monitor/workspace +new_session_here() { + # Source the functions from smart-terminal.sh + source /home/jens/.config/i3/smart-terminal.sh + local session_name=$(get_session_name) + + if tmux has-session -t "$session_name" 2>/dev/null; then + echo -e "${YELLOW}Session '$session_name' already exists${NC}" + return 1 + fi + + tmux new-session -d -s "$session_name" + echo -e "${GREEN}✓${NC} Created new session: $session_name" +} + +# Clean up detached sessions +cleanup_detached() { + local detached=$(tmux list-sessions 2>/dev/null | grep -v "(attached)" | cut -d: -f1) + + if [ -z "$detached" ]; then + echo -e "${GREEN}No detached sessions to clean up${NC}" + return 0 + fi + + echo -e "${YELLOW}Found detached sessions:${NC}" + echo "$detached" + echo -e "\n${YELLOW}Kill all detached sessions? (y/N)${NC}" + read -r response + + if [[ "$response" =~ ^[Yy]$ ]]; then + while IFS= read -r session; do + tmux kill-session -t "$session" 2>/dev/null + echo -e " ${RED}✗${NC} Killed: $session" + done <<< "$detached" + fi +} + +# Main menu +show_menu() { + echo -e "${BLUE}=== Tmux Session Manager ===${NC}" + echo "1. List all sessions" + echo "2. Switch to session" + echo "3. Kill screen sessions" + echo "4. Rename session" + echo "5. Create session for current workspace" + echo "6. Cleanup detached sessions" + echo "7. Exit" + echo -n "Select option: " +} + +# Main execution +case "$1" in + list) + list_sessions + ;; + kill-screen) + kill_screen_sessions "$2" + ;; + rename) + rename_session "$2" "$3" + ;; + switch) + switch_session "$2" + ;; + new) + new_session_here + ;; + cleanup) + cleanup_detached + ;; + *) + if [ -z "$1" ]; then + # Interactive mode + while true; do + show_menu + read -r option + case $option in + 1) list_sessions ;; + 2) + echo -n "Session name: " + read -r session + switch_session "$session" + ;; + 3) + echo -n "Screen (laptop/external1/external2): " + read -r screen + kill_screen_sessions "$screen" + ;; + 4) + echo -n "Old name: " + read -r old + echo -n "New name: " + read -r new + rename_session "$old" "$new" + ;; + 5) new_session_here ;; + 6) cleanup_detached ;; + 7) exit 0 ;; + *) echo -e "${RED}Invalid option${NC}" ;; + esac + echo + done + else + echo "Usage: $0 [command] [args]" + echo "Commands:" + echo " list - List all sessions" + echo " kill-screen - Kill all sessions for a screen" + echo " rename - Rename a session" + echo " switch - Switch to a session" + echo " new - Create session for current workspace" + echo " cleanup - Cleanup detached sessions" + echo "" + echo "Run without arguments for interactive mode" + fi + ;; +esac \ No newline at end of file diff --git a/tmux/move-window.sh b/tmux/move-window.sh new file mode 100755 index 0000000..6fe157c --- /dev/null +++ b/tmux/move-window.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Tmux window mover with fzf +# Allows moving current window to another session + +# Get current session and window +current_session=$(tmux display-message -p '#S') +current_window=$(tmux display-message -p '#I') +current_window_name=$(tmux display-message -p '#W') + +# Get list of all sessions with window count +sessions=$(tmux list-sessions -F '#{session_name}: #{session_windows} windows' | grep -v "^${current_session}:") + +# If no other sessions, offer to create one +if [ -z "$sessions" ]; then + echo "No other sessions available. Create a new session? (y/n)" + read -r response + if [[ "$response" =~ ^[Yy]$ ]]; then + echo "Enter new session name:" + read -r new_session + if [ ! -z "$new_session" ]; then + tmux new-session -d -s "$new_session" + tmux move-window -t "${new_session}:" + tmux switch-client -t "$new_session" + fi + fi + exit 0 +fi + +# Select target session with fzf +target_session=$(echo "$sessions" | fzf --header="Move window '${current_window_name}' to session:" --preview='tmux list-windows -t {1} -F "#{window_index}: #{window_name} [#{window_panes} panes]"' | cut -d: -f1) + +# If a session was selected, move the window +if [ ! -z "$target_session" ]; then + # Move window to target session + tmux move-window -t "${target_session}:" + + # Switch to the target session + tmux switch-client -t "$target_session" + + echo "Moved window '${current_window_name}' to session '${target_session}'" +fi \ No newline at end of file diff --git a/tmux/tmux-fzf-menu.sh b/tmux/tmux-fzf-menu.sh new file mode 100755 index 0000000..09550cd --- /dev/null +++ b/tmux/tmux-fzf-menu.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +# Advanced tmux operations menu using fzf +# Provides a unified interface for various tmux operations + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Main menu options +show_menu() { + echo "Session: Switch to session" + echo "Window: Switch to window" + echo "Move Window: Move current window to another session" + echo "Move Pane: Move current pane to another window" + echo "Swap Window: Swap current window with another" + echo "Rename Window: Rename current window" + echo "Rename Session: Rename current session" + echo "Kill Window: Kill a window" + echo "Kill Session: Kill a session" + echo "New Session: Create new session" + echo "Link Window: Link window from another session" + echo "Unlink Window: Unlink current window" +} + +# Function to switch session +switch_session() { + tmux list-sessions -F '#{session_name}: #{session_windows} windows#{?session_attached, (attached),}' | \ + fzf --header='Switch to session:' \ + --preview='tmux list-windows -t {1} -F "#{window_index}: #{window_name} [#{window_panes} panes]"' | \ + cut -d: -f1 | \ + xargs -I {} tmux switch-client -t {} +} + +# Function to switch window +switch_window() { + tmux list-windows -a -F '#{session_name}:#{window_index}: #{window_name}' | \ + fzf --header='Switch to window:' \ + --preview='tmux list-panes -t {1} -F "Pane #{pane_index}: #{pane_current_command}"' | \ + cut -d: -f1,2 | \ + xargs -I {} tmux switch-client -t {} +} + +# Function to move current window +move_window() { + current_window=$(tmux display-message -p '#W') + target=$(tmux list-sessions -F '#{session_name}' | \ + fzf --header="Move window '${current_window}' to session:" \ + --preview='tmux list-windows -t {} -F "#{window_index}: #{window_name}"') + + if [ ! -z "$target" ]; then + tmux move-window -t "${target}:" + tmux switch-client -t "$target" + fi +} + +# Function to move current pane +move_pane() { + target=$(tmux list-windows -a -F '#{session_name}:#{window_index}: #{window_name}' | \ + fzf --header='Move pane to window:' \ + --preview='tmux list-panes -t {1} -F "Pane #{pane_index}: #{pane_current_command}"') + + if [ ! -z "$target" ]; then + window_target=$(echo "$target" | cut -d: -f1,2) + tmux join-pane -t "$window_target" + fi +} + +# Function to swap windows +swap_window() { + target=$(tmux list-windows -F '#{window_index}: #{window_name}' | \ + fzf --header='Swap current window with:') + + if [ ! -z "$target" ]; then + window_idx=$(echo "$target" | cut -d: -f1) + tmux swap-window -t "$window_idx" + fi +} + +# Function to rename window +rename_window() { + echo -n "New window name: " + read -r new_name + if [ ! -z "$new_name" ]; then + tmux rename-window "$new_name" + fi +} + +# Function to rename session +rename_session() { + echo -n "New session name: " + read -r new_name + if [ ! -z "$new_name" ]; then + tmux rename-session "$new_name" + fi +} + +# Function to kill window +kill_window() { + target=$(tmux list-windows -a -F '#{session_name}:#{window_index}: #{window_name}' | \ + fzf --header='Kill window:' --multi \ + --preview='tmux list-panes -t {1} -F "Pane #{pane_index}: #{pane_current_command}"') + + if [ ! -z "$target" ]; then + echo "$target" | while IFS= read -r window; do + window_target=$(echo "$window" | cut -d: -f1,2) + tmux kill-window -t "$window_target" + done + fi +} + +# Function to kill session +kill_session() { + target=$(tmux list-sessions -F '#{session_name}: #{session_windows} windows#{?session_attached, (attached),}' | \ + fzf --header='Kill session:' --multi \ + --preview='tmux list-windows -t {1} -F "#{window_index}: #{window_name}"') + + if [ ! -z "$target" ]; then + echo "$target" | while IFS= read -r session; do + session_name=$(echo "$session" | cut -d: -f1) + tmux kill-session -t "$session_name" + done + fi +} + +# Function to create new session +new_session() { + echo -n "New session name: " + read -r session_name + if [ ! -z "$session_name" ]; then + tmux new-session -d -s "$session_name" + tmux switch-client -t "$session_name" + fi +} + +# Function to link window from another session +link_window() { + target=$(tmux list-windows -a -F '#{session_name}:#{window_index}: #{window_name}' | \ + fzf --header='Link window:' \ + --preview='tmux list-panes -t {1} -F "Pane #{pane_index}: #{pane_current_command}"') + + if [ ! -z "$target" ]; then + source_window=$(echo "$target" | cut -d' ' -f1) + tmux link-window -s "$source_window" + fi +} + +# Function to unlink current window +unlink_window() { + tmux unlink-window + echo "Current window unlinked" +} + +# Main execution +if [ "$1" == "--menu" ] || [ -z "$1" ]; then + # Show interactive menu + selection=$(show_menu | fzf --header='Tmux Operations:' | cut -d: -f1) + + case "$selection" in + "Session") switch_session ;; + "Window") switch_window ;; + "Move Window") move_window ;; + "Move Pane") move_pane ;; + "Swap Window") swap_window ;; + "Rename Window") rename_window ;; + "Rename Session") rename_session ;; + "Kill Window") kill_window ;; + "Kill Session") kill_session ;; + "New Session") new_session ;; + "Link Window") link_window ;; + "Unlink Window") unlink_window ;; + esac +else + # Direct command execution + case "$1" in + session) switch_session ;; + window) switch_window ;; + move-window) move_window ;; + move-pane) move_pane ;; + swap-window) swap_window ;; + rename-window) rename_window ;; + rename-session) rename_session ;; + kill-window) kill_window ;; + kill-session) kill_session ;; + new-session) new_session ;; + link-window) link_window ;; + unlink-window) unlink_window ;; + *) echo "Unknown command: $1" ;; + esac +fi \ No newline at end of file diff --git a/tmux/tmux.conf b/tmux/tmux.conf index 7a87d19..ad6f611 100644 --- a/tmux/tmux.conf +++ b/tmux/tmux.conf @@ -108,4 +108,19 @@ bind w display-popup -E "tmux list-windows -F '#{window_index}: #{window_name}' bind f display-popup -E "fd --type f --hidden --follow --exclude .git | fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}' | xargs -I {} tmux new-window 'vim {}'" # Quick directory navigation -bind g display-popup -E "fd --type d --hidden --follow --exclude .git | fzf --preview 'tree -C {} | head -200' | xargs -I {} tmux send-keys 'cd {}' Enter" \ No newline at end of file +bind g display-popup -E "fd --type d --hidden --follow --exclude .git | fzf --preview 'tree -C {} | head -200' | xargs -I {} tmux send-keys 'cd {}' Enter" + +# Move window to another session with fzf +bind m display-popup -E "bash ~/.config/tmux/move-window.sh" + +# Swap windows with fzf +bind M display-popup -E "tmux list-windows -F '#{window_index}: #{window_name}' | fzf --header='Swap current window with:' | cut -d: -f1 | xargs -I {} tmux swap-window -t {}" + +# Move pane to another window with fzf +bind p display-popup -E "tmux list-windows -F '#{window_index}: #{window_name}' | fzf --header='Move pane to window:' | cut -d: -f1 | xargs -I {} tmux join-pane -t :{}" + +# Break pane into new window +bind B break-pane -d + +# Comprehensive tmux operations menu with fzf +bind Space display-popup -E -w 80% -h 80% "bash ~/.config/tmux/tmux-fzf-menu.sh --menu" \ No newline at end of file