Add session manager for tmux.
This will open a tmux session for each monitor. Add helper script for tmux actions.
This commit is contained in:
@@ -8,7 +8,7 @@ dimensions = { columns = 140, lines = 45 }
|
|||||||
option_as_alt = "Both"
|
option_as_alt = "Both"
|
||||||
|
|
||||||
[font]
|
[font]
|
||||||
size = 16.0
|
size = 12.0
|
||||||
|
|
||||||
[font.normal]
|
[font.normal]
|
||||||
family = "0xProto Nerd Font"
|
family = "0xProto Nerd Font"
|
||||||
@@ -115,9 +115,11 @@ bindings = [
|
|||||||
[terminal]
|
[terminal]
|
||||||
osc52 = "CopyPaste" # Enable OSC 52 for clipboard support
|
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]
|
[terminal.shell]
|
||||||
program = "/usr/bin/tmux"
|
program = "/bin/bash"
|
||||||
args = ["new-session", "-A", "-s", "main"]
|
args = ["-l"]
|
||||||
|
|
||||||
[scrolling]
|
[scrolling]
|
||||||
history = 10000
|
history = 10000
|
||||||
|
|||||||
34
i3/config
34
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.
|
# and nm-applet is a desktop environment-independent system tray GUI for it.
|
||||||
exec --no-startup-id nm-applet
|
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.
|
# Use pactl to adjust volume in PulseAudio.
|
||||||
set $refresh_i3status killall -SIGUSR1 i3status
|
set $refresh_i3status killall -SIGUSR1 i3status
|
||||||
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_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
|
# Use Mouse+$mod to drag floating windows to their wanted position
|
||||||
floating_modifier $mod
|
floating_modifier $mod
|
||||||
|
|
||||||
# start a terminal
|
# start a terminal with smart monitor/workspace-aware tmux sessions
|
||||||
bindsym $mod+Return exec alacritty
|
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
|
# kill focused window
|
||||||
bindsym $mod+Shift+q kill
|
bindsym $mod+Shift+q kill
|
||||||
@@ -63,6 +66,23 @@ bindsym $mod+Shift+q kill
|
|||||||
# bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop
|
# bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop
|
||||||
bindsym $mod+d exec rofi -show run
|
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
|
# change focus
|
||||||
bindsym $mod+j focus left
|
bindsym $mod+j focus left
|
||||||
bindsym $mod+k focus down
|
bindsym $mod+k focus down
|
||||||
@@ -116,7 +136,7 @@ bindsym $mod+a focus parent
|
|||||||
# Wallpaper controls
|
# Wallpaper controls
|
||||||
bindsym $mod+Shift+w exec --no-startup-id ~/.config/i3/wallpaper-rotate.sh --once
|
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+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
|
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.
|
# Define names for default workspaces for which we configure key bindings later on.
|
||||||
|
|||||||
13
i3/simple-terminal.sh
Executable file
13
i3/simple-terminal.sh
Executable file
@@ -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
|
||||||
97
i3/smart-terminal.sh
Executable file
97
i3/smart-terminal.sh
Executable file
@@ -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
|
||||||
229
i3/tmux-session-manager.sh
Executable file
229
i3/tmux-session-manager.sh
Executable file
@@ -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 <old_name> <new_name>${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 <screen> - Kill all sessions for a screen"
|
||||||
|
echo " rename <old> <new> - Rename a session"
|
||||||
|
echo " switch <session> - 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
|
||||||
42
tmux/move-window.sh
Executable file
42
tmux/move-window.sh
Executable file
@@ -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
|
||||||
193
tmux/tmux-fzf-menu.sh
Executable file
193
tmux/tmux-fzf-menu.sh
Executable file
@@ -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
|
||||||
@@ -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 {}'"
|
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
|
# 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"
|
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"
|
||||||
Reference in New Issue
Block a user