Dotfiles update 2025-12-22 12:00

This commit is contained in:
Aaron D. Lee
2025-12-22 12:00:32 -05:00
parent 23ee772ac4
commit 9e916c6c54
13 changed files with 646 additions and 1525 deletions

View File

@@ -2,26 +2,16 @@
# Tmux Workspace Manager - Project Templates & Layouts
# ============================================================================
# Quick project workspace setup with pre-configured tmux layouts
#
# Usage:
# tw-create <name> [template] # Create workspace from template
# tw-attach <name> # Attach to workspace
# tw-list # List all workspaces
# tw-delete <name> # Delete workspace
# tw-save <name> # Save current layout as template
# tw <name> # Quick attach (or create if not exists)
#
# Templates:
# dev - Vim (50%) + terminal (25%) + logs (25%)
# ops - 4 panes: htop, logs, shell, monitoring
# ssh-multi - 4 panes for managing multiple servers
# debug - 2 panes: main (70%) + helper (30%)
# full - Just one full pane
#
# Add to .zshrc:
# source ~/.dotfiles/zsh/functions/tmux-workspaces.zsh
# ============================================================================
# Source shared colors (with fallback)
source "${0:A:h}/../lib/colors.zsh" 2>/dev/null || \
source "$HOME/.dotfiles/zsh/lib/colors.zsh" 2>/dev/null || {
typeset -g DF_GREEN=$'\033[0;32m' DF_BLUE=$'\033[0;34m'
typeset -g DF_YELLOW=$'\033[1;33m' DF_CYAN=$'\033[0;36m'
typeset -g DF_RED=$'\033[0;31m' DF_NC=$'\033[0m'
}
# ============================================================================
# Configuration
# ============================================================================
@@ -30,33 +20,14 @@ typeset -g TW_TEMPLATES_DIR="${TW_TEMPLATES_DIR:-$HOME/.dotfiles/.tmux-templates
typeset -g TW_SESSION_PREFIX="${TW_SESSION_PREFIX:-work}"
typeset -g TW_DEFAULT_TEMPLATE="${TW_DEFAULT_TEMPLATE:-dev}"
# Colors
typeset -g TW_GREEN=$'\033[0;32m'
typeset -g TW_BLUE=$'\033[0;34m'
typeset -g TW_YELLOW=$'\033[1;33m'
typeset -g TW_CYAN=$'\033[0;36m'
typeset -g TW_RED=$'\033[0;31m'
typeset -g TW_NC=$'\033[0m'
# ============================================================================
# Helper Functions
# ============================================================================
_tw_print_step() {
echo -e "${TW_BLUE}==>${TW_NC} $1"
}
_tw_print_success() {
echo -e "${TW_GREEN}${TW_NC} $1"
}
_tw_print_error() {
echo -e "${TW_RED}${TW_NC} $1"
}
_tw_print_info() {
echo -e "${TW_CYAN}${TW_NC} $1"
}
_tw_print_step() { echo -e "${DF_BLUE}==>${DF_NC} $1"; }
_tw_print_success() { echo -e "${DF_GREEN}${DF_NC} $1"; }
_tw_print_error() { echo -e "${DF_RED}${DF_NC} $1"; }
_tw_print_info() { echo -e "${DF_CYAN}${DF_NC} $1"; }
_tw_check_tmux() {
if ! command -v tmux &>/dev/null; then
@@ -68,11 +39,7 @@ _tw_check_tmux() {
_tw_init_templates() {
mkdir -p "$TW_TEMPLATES_DIR"
# Create default templates if they don't exist
if [[ ! -f "$TW_TEMPLATES_DIR/dev.tmux" ]]; then
_tw_create_default_templates
fi
[[ ! -f "$TW_TEMPLATES_DIR/dev.tmux" ]] && _tw_create_default_templates
}
# ============================================================================
@@ -82,89 +49,44 @@ _tw_init_templates() {
_tw_create_default_templates() {
_tw_print_step "Creating default templates..."
# Development template - vim + terminal + logs
cat > "$TW_TEMPLATES_DIR/dev.tmux" << 'EOF'
# Development workspace
# Usage: tw-create myproject dev
# Split vertically (vim on left 50%, rest on right)
split-window -h -p 50
# Split right pane horizontally (terminal top, logs bottom)
split-window -v -p 50
# Select the first pane (vim)
select-pane -t 0
# Optional: Start vim in first pane
# send-keys -t 0 'vim' C-m
# Optional: Set pane titles
# select-pane -t 0 -T "Editor"
# select-pane -t 1 -T "Terminal"
# select-pane -t 2 -T "Logs"
EOF
# Operations template - 4 panes for monitoring
cat > "$TW_TEMPLATES_DIR/ops.tmux" << 'EOF'
# Operations workspace
# 4-pane layout for system monitoring
# Create 2x2 grid
# Operations workspace - 4 panes
split-window -h -p 50
split-window -v -p 50
select-pane -t 0
split-window -v -p 50
# Optional: Auto-start monitoring tools
# send-keys -t 0 'htop' C-m
# send-keys -t 1 'docker ps' C-m
# send-keys -t 2 '' C-m
# send-keys -t 3 'tail -f /var/log/syslog' C-m
select-pane -t 0
EOF
# SSH multi-server template
cat > "$TW_TEMPLATES_DIR/ssh-multi.tmux" << 'EOF'
# Multi-server SSH workspace
# 4 panes for managing multiple servers
# Create 2x2 grid
split-window -h -p 50
split-window -v -p 50
select-pane -t 0
split-window -v -p 50
# Enable pane synchronization (optional - uncomment to enable)
# set-window-option synchronize-panes on
select-pane -t 0
EOF
# Debug template - main + helper pane
cat > "$TW_TEMPLATES_DIR/debug.tmux" << 'EOF'
# Debug workspace
# Main pane (70%) + helper pane (30%)
split-window -h -p 30
select-pane -t 0
EOF
# Full template - single pane
cat > "$TW_TEMPLATES_DIR/full.tmux" << 'EOF'
# Full workspace
# Single full-screen pane (default tmux behavior)
# Full workspace - single pane
EOF
# Code review template - side-by-side comparison
cat > "$TW_TEMPLATES_DIR/review.tmux" << 'EOF'
# Code Review workspace
# Two equal panes side-by-side for comparison
split-window -h -p 50
select-pane -t 0
EOF
@@ -178,42 +100,29 @@ EOF
tw-templates() {
_tw_init_templates
echo -e "${TW_BLUE}╔════════════════════════════════════════════════════════════╗${TW_NC}"
echo -e "${TW_BLUE}${TW_NC} Available Tmux Templates ${TW_BLUE}${TW_NC}"
echo -e "${TW_BLUE}╚════════════════════════════════════════════════════════════╝${TW_NC}"
echo -e "${DF_BLUE}╔════════════════════════════════════════════════════════════╗${DF_NC}"
echo -e "${DF_BLUE}${DF_NC} Available Tmux Templates ${DF_BLUE}${DF_NC}"
echo -e "${DF_BLUE}╚════════════════════════════════════════════════════════════╝${DF_NC}"
echo
for template in "$TW_TEMPLATES_DIR"/*.tmux; do
[[ ! -f "$template" ]] && continue
local name=$(basename "$template" .tmux)
local description=$(grep "^#" "$template" | head -2 | tail -1 | sed 's/^# *//')
echo -e "${TW_GREEN}${TW_NC} ${TW_CYAN}$name${TW_NC}"
echo -e "${DF_GREEN}${DF_NC} ${DF_CYAN}$name${DF_NC}"
[[ -n "$description" ]] && echo " $description"
done
echo
echo "Create workspace: ${TW_CYAN}tw-create myproject dev${TW_NC}"
echo "Quick attach: ${TW_CYAN}tw myproject${TW_NC}"
echo "Create workspace: ${DF_CYAN}tw-create myproject dev${DF_NC}"
echo "Quick attach: ${DF_CYAN}tw myproject${DF_NC}"
}
tw-template-edit() {
local template_name="$1"
if [[ -z "$template_name" ]]; then
echo "Usage: tw-template-edit <template_name>"
echo
tw-templates
return 1
fi
[[ -z "$template_name" ]] && { echo "Usage: tw-template-edit <template_name>"; tw-templates; return 1; }
_tw_init_templates
local template_file="$TW_TEMPLATES_DIR/${template_name}.tmux"
${EDITOR:-vim} "$template_file"
${EDITOR:-vim} "$TW_TEMPLATES_DIR/${template_name}.tmux"
_tw_print_success "Template edited: $template_name"
}
@@ -225,26 +134,19 @@ tw-create() {
local workspace_name="$1"
local template="${2:-$TW_DEFAULT_TEMPLATE}"
if [[ -z "$workspace_name" ]]; then
echo "Usage: tw-create <workspace_name> [template]"
echo
tw-templates
return 1
fi
[[ -z "$workspace_name" ]] && { echo "Usage: tw-create <workspace_name> [template]"; tw-templates; return 1; }
_tw_check_tmux || return 1
_tw_init_templates
local session_name="${TW_SESSION_PREFIX}-${workspace_name}"
# Check if session already exists
if tmux has-session -t "$session_name" 2>/dev/null; then
_tw_print_error "Workspace '$workspace_name' already exists"
echo "Use: ${TW_CYAN}tw $workspace_name${TW_NC} to attach"
echo "Use: ${DF_CYAN}tw $workspace_name${DF_NC} to attach"
return 1
fi
# Check if template exists
local template_file="$TW_TEMPLATES_DIR/${template}.tmux"
if [[ ! -f "$template_file" ]]; then
_tw_print_error "Template '$template' not found"
@@ -254,14 +156,10 @@ tw-create() {
_tw_print_step "Creating workspace: $workspace_name (template: $template)"
# Create new tmux session (detached)
tmux new-session -d -s "$session_name"
# Apply template
_tw_print_step "Applying template: $template"
tmux source-file "$template_file" -t "$session_name"
# Set working directory if we're in a git repo or specific directory
if git rev-parse --git-dir &>/dev/null 2>&1; then
local git_root=$(git rev-parse --show-toplevel)
_tw_print_info "Setting workspace directory to: $git_root"
@@ -270,24 +168,17 @@ tw-create() {
_tw_print_success "Workspace created: $workspace_name"
# Attach if not already in tmux
if [[ -z "$TMUX" ]]; then
_tw_print_step "Attaching to workspace..."
tmux attach-session -t "$session_name"
else
_tw_print_info "Switch with: ${TW_CYAN}tmux switch-client -t $session_name${TW_NC}"
_tw_print_info "Switch with: ${DF_CYAN}tmux switch-client -t $session_name${DF_NC}"
fi
}
tw-attach() {
local workspace_name="$1"
if [[ -z "$workspace_name" ]]; then
echo "Usage: tw-attach <workspace_name>"
echo
tw-list
return 1
fi
[[ -z "$workspace_name" ]] && { echo "Usage: tw-attach <workspace_name>"; tw-list; return 1; }
_tw_check_tmux || return 1
@@ -295,12 +186,10 @@ tw-attach() {
if ! tmux has-session -t "$session_name" 2>/dev/null; then
_tw_print_error "Workspace '$workspace_name' not found"
echo
echo "Create it with: ${TW_CYAN}tw-create $workspace_name${TW_NC}"
echo "Create it with: ${DF_CYAN}tw-create $workspace_name${DF_NC}"
return 1
fi
# Attach or switch
if [[ -z "$TMUX" ]]; then
tmux attach-session -t "$session_name"
else
@@ -311,48 +200,38 @@ tw-attach() {
tw-list() {
_tw_check_tmux || return 1
echo -e "${TW_BLUE}╔════════════════════════════════════════════════════════════╗${TW_NC}"
echo -e "${TW_BLUE}${TW_NC} Active Tmux Workspaces ${TW_BLUE}${TW_NC}"
echo -e "${TW_BLUE}╚════════════════════════════════════════════════════════════╝${TW_NC}"
echo -e "${DF_BLUE}╔════════════════════════════════════════════════════════════╗${DF_NC}"
echo -e "${DF_BLUE}${DF_NC} Active Tmux Workspaces ${DF_BLUE}${DF_NC}"
echo -e "${DF_BLUE}╚════════════════════════════════════════════════════════════╝${DF_NC}"
echo
local has_workspaces=false
# List all tmux sessions
tmux list-sessions 2>/dev/null | while IFS=: read -r session_full rest; do
# Only show sessions with our prefix
if [[ "$session_full" == ${TW_SESSION_PREFIX}-* ]]; then
has_workspaces=true
local workspace_name="${session_full#${TW_SESSION_PREFIX}-}"
local attached=""
# Check if currently attached
if [[ -n "$TMUX" ]]; then
local current_session=$(tmux display-message -p '#S')
[[ "$current_session" == "$session_full" ]] && attached=" ${TW_GREEN}(current)${TW_NC}"
[[ "$current_session" == "$session_full" ]] && attached=" ${DF_GREEN}(current)${DF_NC}"
fi
echo -e "${TW_GREEN}${TW_NC} ${TW_CYAN}$workspace_name${TW_NC}$attached"
echo -e "${DF_GREEN}${DF_NC} ${DF_CYAN}$workspace_name${DF_NC}$attached"
echo " Session: $session_full"
fi
done
if [[ "$has_workspaces" != true ]]; then
_tw_print_info "No active workspaces"
echo
echo "Create one with: ${TW_CYAN}tw-create myproject${TW_NC}"
echo "Create one with: ${DF_CYAN}tw-create myproject${DF_NC}"
fi
}
tw-delete() {
local workspace_name="$1"
if [[ -z "$workspace_name" ]]; then
echo "Usage: tw-delete <workspace_name>"
echo
tw-list
return 1
fi
[[ -z "$workspace_name" ]] && { echo "Usage: tw-delete <workspace_name>"; tw-list; return 1; }
_tw_check_tmux || return 1
@@ -363,75 +242,45 @@ tw-delete() {
return 1
fi
# Kill session
tmux kill-session -t "$session_name"
_tw_print_success "Deleted workspace: $workspace_name"
}
# ============================================================================
# Save Current Layout as Template
# ============================================================================
tw-save() {
local template_name="$1"
if [[ -z "$template_name" ]]; then
echo "Usage: tw-save <template_name>"
echo
echo "Saves the current tmux window layout as a reusable template"
return 1
fi
[[ -z "$template_name" ]] && { echo "Usage: tw-save <template_name>"; return 1; }
_tw_check_tmux || return 1
if [[ -z "$TMUX" ]]; then
_tw_print_error "Must be run from inside tmux"
return 1
fi
[[ -z "$TMUX" ]] && { _tw_print_error "Must be run from inside tmux"; return 1; }
_tw_init_templates
local template_file="$TW_TEMPLATES_DIR/${template_name}.tmux"
if [[ -f "$template_file" ]]; then
[[ -f "$template_file" ]] && {
read -q "REPLY?Template '$template_name' exists. Overwrite? [y/N]: "
echo
[[ ! "$REPLY" =~ ^[Yy]$ ]] && return 1
fi
}
_tw_print_step "Saving current layout as template: $template_name"
# Get current window layout
local layout=$(tmux display-message -p '#{window_layout}')
local pane_count=$(tmux display-message -p '#{window_panes}')
# Create template with layout commands
cat > "$template_file" << EOF
# Custom template: $template_name
# Saved: $(date)
# Panes: $pane_count
# Note: This is a simplified layout recreation
# You may need to adjust split percentages and commands
EOF
# Generate split commands based on pane count
if (( pane_count == 2 )); then
echo "split-window -h -p 50" >> "$template_file"
elif (( pane_count == 3 )); then
cat >> "$template_file" << 'EOF'
split-window -h -p 50
split-window -v -p 50
EOF
echo "split-window -h -p 50" >> "$template_file"
echo "split-window -v -p 50" >> "$template_file"
elif (( pane_count == 4 )); then
cat >> "$template_file" << 'EOF'
split-window -h -p 50
split-window -v -p 50
select-pane -t 0
split-window -v -p 50
EOF
echo "split-window -h -p 50" >> "$template_file"
echo "split-window -v -p 50" >> "$template_file"
echo "select-pane -t 0" >> "$template_file"
echo "split-window -v -p 50" >> "$template_file"
fi
echo "" >> "$template_file"
@@ -439,27 +288,19 @@ EOF
_tw_print_success "Template saved: $template_name"
echo " File: $template_file"
echo " Edit: ${TW_CYAN}tw-template-edit $template_name${TW_NC}"
echo " Edit: ${DF_CYAN}tw-template-edit $template_name${DF_NC}"
}
# ============================================================================
# Quick Workspace (attach or create)
# ============================================================================
tw() {
local workspace_name="$1"
local template="${2:-$TW_DEFAULT_TEMPLATE}"
if [[ -z "$workspace_name" ]]; then
tw-list
return 0
fi
[[ -z "$workspace_name" ]] && { tw-list; return 0; }
_tw_check_tmux || return 1
local session_name="${TW_SESSION_PREFIX}-${workspace_name}"
# If session exists, attach. Otherwise create.
if tmux has-session -t "$session_name" 2>/dev/null; then
tw-attach "$workspace_name"
else
@@ -468,10 +309,6 @@ tw() {
fi
}
# ============================================================================
# Fuzzy Search (requires fzf)
# ============================================================================
twf() {
if ! command -v fzf &>/dev/null; then
_tw_print_error "fzf not installed"
@@ -480,7 +317,6 @@ twf() {
_tw_check_tmux || return 1
# Get list of sessions
local sessions=()
tmux list-sessions 2>/dev/null | while IFS=: read -r session_full rest; do
if [[ "$session_full" == ${TW_SESSION_PREFIX}-* ]]; then
@@ -489,57 +325,33 @@ twf() {
fi
done
if [[ ${#sessions[@]} -eq 0 ]]; then
_tw_print_info "No workspaces found"
return 1
fi
[[ ${#sessions[@]} -eq 0 ]] && { _tw_print_info "No workspaces found"; return 1; }
# Fuzzy select
local selection=$(printf '%s\n' "${sessions[@]}" | \
fzf --height=40% \
--layout=reverse \
--border=rounded \
--prompt='Workspace > ' \
--preview='tmux list-windows -t work-{} 2>/dev/null || echo "No preview"')
fzf --height=40% --layout=reverse --border=rounded --prompt='Workspace > ')
if [[ -n "$selection" ]]; then
tw-attach "$selection"
fi
[[ -n "$selection" ]] && tw-attach "$selection"
}
# ============================================================================
# Pane Synchronization Toggle
# ============================================================================
tw-sync() {
if [[ -z "$TMUX" ]]; then
_tw_print_error "Must be run from inside tmux"
return 1
fi
[[ -z "$TMUX" ]] && { _tw_print_error "Must be run from inside tmux"; return 1; }
local current=$(tmux show-window-option -v synchronize-panes 2>/dev/null)
if [[ "$current" == "on" ]]; then
tmux set-window-option synchronize-panes off
_tw_print_info "Pane synchronization: ${TW_RED}OFF${TW_NC}"
_tw_print_info "Pane synchronization: ${DF_RED}OFF${DF_NC}"
else
tmux set-window-option synchronize-panes on
_tw_print_info "Pane synchronization: ${TW_GREEN}ON${TW_NC}"
_tw_print_info "Pane synchronization: ${DF_GREEN}ON${DF_NC}"
fi
}
# ============================================================================
# Rename Workspace
# ============================================================================
tw-rename() {
local old_name="$1"
local new_name="$2"
if [[ -z "$old_name" || -z "$new_name" ]]; then
echo "Usage: tw-rename <old_name> <new_name>"
return 1
fi
[[ -z "$old_name" || -z "$new_name" ]] && { echo "Usage: tw-rename <old_name> <new_name>"; return 1; }
_tw_check_tmux || return 1
@@ -552,7 +364,6 @@ tw-rename() {
fi
tmux rename-session -t "$old_session" "$new_session"
_tw_print_success "Renamed: $old_name$new_name"
}