Dotfiles update 2025-12-25 15:11
This commit is contained in:
162
docs/TMUXINATOR.md
Normal file
162
docs/TMUXINATOR.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# Tmuxinator Integration
|
||||||
|
|
||||||
|
The dotfiles now include seamless integration with [tmuxinator](https://github.com/tmuxinator/tmuxinator) for complex project configurations, while maintaining backward compatibility with simple `.tmux` templates.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Arch/CachyOS
|
||||||
|
sudo pacman -S tmuxinator
|
||||||
|
|
||||||
|
# Or via Ruby gems
|
||||||
|
gem install tmuxinator
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a new tmuxinator project
|
||||||
|
txi-new myproject dev
|
||||||
|
|
||||||
|
# Edit the configuration
|
||||||
|
txi-edit myproject
|
||||||
|
|
||||||
|
# Start the project
|
||||||
|
txi myproject
|
||||||
|
|
||||||
|
# Or use the unified tw command (auto-detects tmuxinator)
|
||||||
|
tw myproject
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command Reference
|
||||||
|
|
||||||
|
### Tmuxinator Commands (txi-*)
|
||||||
|
|
||||||
|
| Command | Alias | Description |
|
||||||
|
|---------|-------|-------------|
|
||||||
|
| `txi <name>` | - | Start/attach to tmuxinator project |
|
||||||
|
| `txi-new <name> [template]` | `txin` | Create new project |
|
||||||
|
| `txi-edit <name>` | `txie` | Edit project YAML file |
|
||||||
|
| `txi-list` | `txil` | List all tmuxinator projects |
|
||||||
|
| `txi-delete <name>` | `txid` | Delete project |
|
||||||
|
| `txi-stop <name>` | `txis` | Stop running session |
|
||||||
|
| `txi-templates` | `txit` | Show available templates |
|
||||||
|
| `txi-import <template> [name]` | - | Convert .tmux to tmuxinator |
|
||||||
|
| `txif` | - | Fuzzy search and start |
|
||||||
|
| `txi-help` | `txih` | Show help |
|
||||||
|
|
||||||
|
### Available Templates
|
||||||
|
|
||||||
|
| Template | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `dev` | Development: editor + terminal + server + logs |
|
||||||
|
| `ops` | Operations: monitoring grid + services + SSH |
|
||||||
|
| `web` | Web development: editor + server + frontend + db |
|
||||||
|
| `data` | Data science: jupyter + code + data + terminal |
|
||||||
|
| `minimal` | Single window, single pane |
|
||||||
|
|
||||||
|
### Integration with tw-* Commands
|
||||||
|
|
||||||
|
The existing `tw` commands automatically detect tmuxinator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# If "myproject.yml" exists in ~/.config/tmuxinator/, uses tmuxinator
|
||||||
|
# Otherwise, uses simple .tmux template
|
||||||
|
tw myproject
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority order:**
|
||||||
|
1. Running tmux session with matching name
|
||||||
|
2. Tmuxinator project (if exists)
|
||||||
|
3. Simple `.tmux` template
|
||||||
|
|
||||||
|
### Example Tmuxinator Project
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# ~/.config/tmuxinator/webapp.yml
|
||||||
|
name: webapp
|
||||||
|
root: ~/projects/webapp
|
||||||
|
|
||||||
|
# Activate virtualenv before all windows
|
||||||
|
pre_window: source venv/bin/activate
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- editor:
|
||||||
|
layout: main-vertical
|
||||||
|
panes:
|
||||||
|
- vim .
|
||||||
|
- # terminal
|
||||||
|
|
||||||
|
- server:
|
||||||
|
panes:
|
||||||
|
- python manage.py runserver
|
||||||
|
|
||||||
|
- frontend:
|
||||||
|
layout: even-horizontal
|
||||||
|
panes:
|
||||||
|
- npm run watch
|
||||||
|
- npm run tailwind
|
||||||
|
|
||||||
|
- database:
|
||||||
|
panes:
|
||||||
|
- pgcli mydb
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Add to `dotfiles.conf`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ============================================================================
|
||||||
|
# Tmuxinator Settings
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TMUXINATOR_ENABLED="auto" # auto, true, false
|
||||||
|
TMUXINATOR_CONFIG_DIR="$HOME/.config/tmuxinator"
|
||||||
|
TW_PREFER_TMUXINATOR="true" # Prefer tmuxinator over simple templates
|
||||||
|
```
|
||||||
|
|
||||||
|
### Simple Templates vs Tmuxinator
|
||||||
|
|
||||||
|
| Feature | Simple (.tmux) | Tmuxinator (.yml) |
|
||||||
|
|---------|---------------|-------------------|
|
||||||
|
| Learning curve | Minimal | Moderate |
|
||||||
|
| Per-pane commands | No | Yes |
|
||||||
|
| Environment variables | No | Yes |
|
||||||
|
| Pre/post hooks | No | Yes |
|
||||||
|
| Window names | No | Yes |
|
||||||
|
| Complex layouts | Limited | Full support |
|
||||||
|
| Startup speed | Fast | Slightly slower |
|
||||||
|
|
||||||
|
**Use simple templates for:**
|
||||||
|
- Quick, ad-hoc layouts
|
||||||
|
- Simple split configurations
|
||||||
|
- Layouts you'll customize each time
|
||||||
|
|
||||||
|
**Use tmuxinator for:**
|
||||||
|
- Persistent project configurations
|
||||||
|
- Projects with specific startup commands
|
||||||
|
- Complex multi-window setups
|
||||||
|
- Team-shared configurations
|
||||||
|
|
||||||
|
### Import Existing Templates
|
||||||
|
|
||||||
|
Convert your simple `.tmux` templates to tmuxinator format:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Import the 'dev' template as a tmuxinator project
|
||||||
|
txi-import dev myproject
|
||||||
|
|
||||||
|
# Then customize it
|
||||||
|
txi-edit myproject
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
1. **Project Discovery**: The `tw` and `twf` commands show both active sessions and available tmuxinator projects
|
||||||
|
|
||||||
|
2. **Git Integration**: When starting a workspace in a git repo, the first pane automatically `cd`s to the repo root
|
||||||
|
|
||||||
|
3. **Synchronized Input**: Toggle with `tw-sync` to type in all panes simultaneously
|
||||||
|
|
||||||
|
4. **Fuzzy Finding**: Use `twf` or `txif` for quick project selection with fzf
|
||||||
@@ -114,6 +114,17 @@ LIMINE_CONF="/boot/limine.conf"
|
|||||||
TW_SESSION_PREFIX="work"
|
TW_SESSION_PREFIX="work"
|
||||||
TW_DEFAULT_TEMPLATE="dev"
|
TW_DEFAULT_TEMPLATE="dev"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Tmuxinator Settings
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
TMUXINATOR_ENABLED="auto" # auto, true, false
|
||||||
|
TMUXINATOR_CONFIG_DIR="$HOME/.config/tmuxinator"
|
||||||
|
|
||||||
|
# When both a simple template and tmuxinator project exist with the same name,
|
||||||
|
# tmuxinator takes precedence. Set to "false" to prefer simple templates.
|
||||||
|
TW_PREFER_TMUXINATOR="true"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Python Template Settings
|
# Python Template Settings
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
@@ -1,116 +1,471 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Tmux Workspace Manager - Project Templates & Layouts
|
# Tmux Workspace Manager - Project Templates & Layouts
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
# Enhanced with optional tmuxinator integration for complex projects.
|
||||||
|
#
|
||||||
|
# Simple templates (.tmux files) for quick layouts
|
||||||
|
# Tmuxinator (optional) for full project configurations with commands
|
||||||
|
#
|
||||||
|
# Priority: tmuxinator project > simple template > create new
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
source "${0:A:h}/../lib/utils.zsh" 2>/dev/null || \
|
source "${0:A:h}/../lib/bootstrap.zsh" 2>/dev/null || \
|
||||||
source "$HOME/.dotfiles/zsh/lib/utils.zsh" 2>/dev/null
|
source "$HOME/.dotfiles/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Configuration
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
typeset -g TW_TEMPLATES="${TW_TEMPLATES:-$HOME/.dotfiles/.tmux-templates}"
|
typeset -g TW_TEMPLATES="${TW_TEMPLATES:-$HOME/.dotfiles/.tmux-templates}"
|
||||||
typeset -g TW_PREFIX="${TW_PREFIX:-work}"
|
typeset -g TW_PREFIX="${TW_PREFIX:-work}"
|
||||||
typeset -g TW_DEFAULT="${TW_DEFAULT:-dev}"
|
typeset -g TW_DEFAULT="${TW_DEFAULT:-dev}"
|
||||||
|
|
||||||
|
# Tmuxinator integration (auto-detect if available)
|
||||||
|
typeset -g TW_USE_TMUXINATOR="${TW_USE_TMUXINATOR:-auto}"
|
||||||
|
typeset -g TMUXINATOR_CONFIG_DIR="${TMUXINATOR_CONFIG_DIR:-$HOME/.config/tmuxinator}"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Internal Functions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
_tw_check() { df_require_cmd tmux || return 1; }
|
_tw_check() { df_require_cmd tmux || return 1; }
|
||||||
|
|
||||||
|
_tw_has_tmuxinator() {
|
||||||
|
[[ "$TW_USE_TMUXINATOR" == "false" ]] && return 1
|
||||||
|
command -v tmuxinator &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_tw_tmuxinator_project_exists() {
|
||||||
|
[[ -f "$TMUXINATOR_CONFIG_DIR/${1}.yml" ]]
|
||||||
|
}
|
||||||
|
|
||||||
_tw_init() {
|
_tw_init() {
|
||||||
df_ensure_dir "$TW_TEMPLATES"
|
df_ensure_dir "$TW_TEMPLATES"
|
||||||
|
|
||||||
|
# Create default templates if they don't exist
|
||||||
[[ ! -f "$TW_TEMPLATES/dev.tmux" ]] && {
|
[[ ! -f "$TW_TEMPLATES/dev.tmux" ]] && {
|
||||||
echo -e "# Dev layout\nsplit-window -h -p 50\nsplit-window -v -p 50\nselect-pane -t 0" > "$TW_TEMPLATES/dev.tmux"
|
cat > "$TW_TEMPLATES/dev.tmux" << 'EOF'
|
||||||
echo -e "# Ops layout\nsplit-window -h\nsplit-window -v\nselect-pane -t 0\nsplit-window -v\nselect-pane -t 0" > "$TW_TEMPLATES/ops.tmux"
|
# Development workspace
|
||||||
echo "# Full\n" > "$TW_TEMPLATES/full.tmux"
|
# Layout: Editor (50%) | Terminal (25%) / Logs (25%)
|
||||||
df_print_success "Created default templates"
|
split-window -h -p 50
|
||||||
|
split-window -v -p 50
|
||||||
|
select-pane -t 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TW_TEMPLATES/ops.tmux" << 'EOF'
|
||||||
|
# Operations workspace - 2x2 grid
|
||||||
|
split-window -h -p 50
|
||||||
|
split-window -v -p 50
|
||||||
|
select-pane -t 0
|
||||||
|
split-window -v -p 50
|
||||||
|
select-pane -t 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TW_TEMPLATES/full.tmux" << 'EOF'
|
||||||
|
# Full screen - single pane (default)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TW_TEMPLATES/review.tmux" << 'EOF'
|
||||||
|
# Code review - side by side
|
||||||
|
split-window -h -p 50
|
||||||
|
select-pane -t 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TW_TEMPLATES/debug.tmux" << 'EOF'
|
||||||
|
# Debug workspace - main (70%) + helper (30%)
|
||||||
|
split-window -h -p 30
|
||||||
|
select-pane -t 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TW_TEMPLATES/ssh-multi.tmux" << 'EOF'
|
||||||
|
# Multi-server SSH - 4 panes with sync option
|
||||||
|
split-window -h -p 50
|
||||||
|
split-window -v -p 50
|
||||||
|
select-pane -t 0
|
||||||
|
split-window -v -p 50
|
||||||
|
# Uncomment to enable synchronized input:
|
||||||
|
# set-window-option synchronize-panes on
|
||||||
|
select-pane -t 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
df_print_success "Created default templates in $TW_TEMPLATES"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Template Functions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
tw-templates() {
|
tw-templates() {
|
||||||
_tw_init
|
_tw_init
|
||||||
df_print_func_name "Tmux Templates"
|
df_print_func_name "Workspace Templates"
|
||||||
for t in "$TW_TEMPLATES"/*.tmux; do
|
|
||||||
[[ -f "$t" ]] && df_print_indent "● $(basename "$t" .tmux)"
|
|
||||||
done
|
|
||||||
echo ""
|
echo ""
|
||||||
df_print_info "Create: tw-create <name> <template>"
|
df_print_section "Simple Templates (.tmux)"
|
||||||
|
for t in "$TW_TEMPLATES"/*.tmux(N); do
|
||||||
|
[[ -f "$t" ]] || continue
|
||||||
|
local name=$(basename "$t" .tmux)
|
||||||
|
local desc=$(head -1 "$t" | sed 's/^#[[:space:]]*//')
|
||||||
|
df_print_indent "● $name"
|
||||||
|
[[ -n "$desc" ]] && df_print_indent " └─ $desc"
|
||||||
|
done
|
||||||
|
|
||||||
|
if _tw_has_tmuxinator; then
|
||||||
|
echo ""
|
||||||
|
df_print_section "Tmuxinator Projects"
|
||||||
|
local found=false
|
||||||
|
for p in "$TMUXINATOR_CONFIG_DIR"/*.yml(N); do
|
||||||
|
[[ -f "$p" ]] || continue
|
||||||
|
found=true
|
||||||
|
local name=$(basename "$p" .yml)
|
||||||
|
df_print_indent "● $name (tmuxinator)"
|
||||||
|
done
|
||||||
|
[[ "$found" != true ]] && df_print_indent "(none - create with txi-new)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
df_print_info "Create workspace: tw-create <name> <template>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Workspace Management
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
tw-create() {
|
tw-create() {
|
||||||
local name="$1" tmpl="${2:-$TW_DEFAULT}"
|
local name="$1"
|
||||||
|
local tmpl="${2:-$TW_DEFAULT}"
|
||||||
|
|
||||||
[[ -z "$name" ]] && { tw-templates; return 1; }
|
[[ -z "$name" ]] && { tw-templates; return 1; }
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
_tw_init
|
_tw_init
|
||||||
|
|
||||||
local session="${TW_PREFIX}-${name}"
|
local session="${TW_PREFIX}-${name}"
|
||||||
tmux has-session -t "$session" 2>/dev/null && { df_print_error "'$name' exists"; return 1; }
|
|
||||||
|
|
||||||
|
# Check if session exists
|
||||||
|
if tmux has-session -t "$session" 2>/dev/null; then
|
||||||
|
df_print_warning "Workspace '$name' already exists"
|
||||||
|
df_confirm "Attach to it?" && tw-attach "$name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for tmuxinator project first
|
||||||
|
if _tw_has_tmuxinator && _tw_tmuxinator_project_exists "$name"; then
|
||||||
|
df_print_step "Starting tmuxinator project: $name"
|
||||||
|
tmuxinator start "$name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for simple template
|
||||||
local tfile="$TW_TEMPLATES/${tmpl}.tmux"
|
local tfile="$TW_TEMPLATES/${tmpl}.tmux"
|
||||||
[[ ! -f "$tfile" ]] && { df_print_error "Template '$tmpl' not found"; tw-templates; return 1; }
|
if [[ ! -f "$tfile" ]]; then
|
||||||
|
df_print_error "Template not found: $tmpl"
|
||||||
|
tw-templates
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
df_print_step "Creating: $name (template: $tmpl)"
|
df_print_step "Creating workspace: $name (template: $tmpl)"
|
||||||
|
|
||||||
|
# Create session and apply template
|
||||||
tmux new-session -d -s "$session"
|
tmux new-session -d -s "$session"
|
||||||
tmux source-file "$tfile" -t "$session"
|
|
||||||
|
|
||||||
df_in_git_repo && {
|
# Source the template file in the context of the session
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ "$line" =~ ^#.*$ ]] && continue
|
||||||
|
[[ "$line" =~ ^[[:space:]]*$ ]] && continue
|
||||||
|
tmux $line -t "$session" 2>/dev/null
|
||||||
|
done < "$tfile"
|
||||||
|
|
||||||
|
# If in a git repo, cd to root in first pane
|
||||||
|
if df_in_git_repo; then
|
||||||
local root=$(df_git_root)
|
local root=$(df_git_root)
|
||||||
df_print_info "Git root: $root"
|
df_print_info "Git root: $root"
|
||||||
tmux send-keys -t "$session:0" "cd $root" C-m
|
tmux send-keys -t "$session:0.0" "cd '$root'" C-m
|
||||||
}
|
fi
|
||||||
|
|
||||||
df_print_success "Created: $name"
|
df_print_success "Created: $name"
|
||||||
[[ -z "$TMUX" ]] && tmux attach -t "$session" || df_print_info "Switch: tmux switch -t $session"
|
|
||||||
|
# Attach or switch
|
||||||
|
if [[ -z "$TMUX" ]]; then
|
||||||
|
tmux attach -t "$session"
|
||||||
|
else
|
||||||
|
df_print_info "Switch with: tmux switch -t $session"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
tw-list() {
|
tw-list() {
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
df_print_func_name "Tmux Workspaces"
|
df_print_func_name "Active Workspaces"
|
||||||
|
|
||||||
local found=false
|
local found=false
|
||||||
tmux list-sessions 2>/dev/null | while IFS=: read -r sess rest; do
|
tmux list-sessions -F "#{session_name}|#{session_windows}|#{session_attached}" 2>/dev/null | while IFS='|' read -r sess windows attached; do
|
||||||
[[ "$sess" == ${TW_PREFIX}-* ]] && { found=true; df_print_indent "● ${sess#${TW_PREFIX}-}"; }
|
[[ "$sess" == ${TW_PREFIX}-* ]] || continue
|
||||||
|
found=true
|
||||||
|
local name="${sess#${TW_PREFIX}-}"
|
||||||
|
local status=""
|
||||||
|
[[ "$attached" == "1" ]] && status=" (attached)"
|
||||||
|
df_print_indent "● $name [${windows} window(s)]${status}"
|
||||||
done
|
done
|
||||||
[[ "$found" != true ]] && df_print_info "No workspaces. Use: tw-create <name>"
|
|
||||||
|
[[ "$found" != true ]] && df_print_info "No active workspaces"
|
||||||
|
|
||||||
|
# Also show tmuxinator projects if available
|
||||||
|
if _tw_has_tmuxinator; then
|
||||||
|
local txi_projects=()
|
||||||
|
for p in "$TMUXINATOR_CONFIG_DIR"/*.yml(N); do
|
||||||
|
[[ -f "$p" ]] && txi_projects+=("$(basename "$p" .yml)")
|
||||||
|
done
|
||||||
|
if [[ ${#txi_projects[@]} -gt 0 ]]; then
|
||||||
|
echo ""
|
||||||
|
df_print_section "Available Tmuxinator Projects"
|
||||||
|
printf ' %s\n' "${txi_projects[@]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
tw-attach() {
|
tw-attach() {
|
||||||
local name="$1"
|
local name="$1"
|
||||||
[[ -z "$name" ]] && { tw-list; return 1; }
|
[[ -z "$name" ]] && { tw-list; return 1; }
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
|
|
||||||
local session="${TW_PREFIX}-${name}"
|
local session="${TW_PREFIX}-${name}"
|
||||||
tmux has-session -t "$session" 2>/dev/null || { df_print_error "'$name' not found"; return 1; }
|
|
||||||
[[ -z "$TMUX" ]] && tmux attach -t "$session" || tmux switch -t "$session"
|
# Check for tmuxinator project
|
||||||
|
if _tw_has_tmuxinator && _tw_tmuxinator_project_exists "$name"; then
|
||||||
|
if tmux has-session -t "$name" 2>/dev/null; then
|
||||||
|
[[ -z "$TMUX" ]] && tmux attach -t "$name" || tmux switch-client -t "$name"
|
||||||
|
else
|
||||||
|
df_print_step "Starting tmuxinator project: $name"
|
||||||
|
tmuxinator start "$name"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Regular workspace
|
||||||
|
if ! tmux has-session -t "$session" 2>/dev/null; then
|
||||||
|
df_print_error "Workspace '$name' not found"
|
||||||
|
df_confirm "Create it?" && tw-create "$name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$TMUX" ]] && tmux attach -t "$session" || tmux switch-client -t "$session"
|
||||||
}
|
}
|
||||||
|
|
||||||
tw-delete() {
|
tw-delete() {
|
||||||
[[ -z "$1" ]] && { tw-list; return 1; }
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { tw-list; return 1; }
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
local session="${TW_PREFIX}-${1}"
|
|
||||||
tmux has-session -t "$session" 2>/dev/null || { df_print_error "'$1' not found"; return 1; }
|
local session="${TW_PREFIX}-${name}"
|
||||||
|
|
||||||
|
# Handle tmuxinator project
|
||||||
|
if _tw_has_tmuxinator && _tw_tmuxinator_project_exists "$name"; then
|
||||||
|
tmuxinator stop "$name" 2>/dev/null
|
||||||
|
df_print_success "Stopped tmuxinator session: $name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! tmux has-session -t "$session" 2>/dev/null; then
|
||||||
|
df_print_error "Workspace '$name' not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
tmux kill-session -t "$session"
|
tmux kill-session -t "$session"
|
||||||
df_print_success "Deleted: $1"
|
df_print_success "Deleted: $name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Main entry point - intelligent routing
|
||||||
tw() {
|
tw() {
|
||||||
local name="$1" tmpl="${2:-$TW_DEFAULT}"
|
local name="$1"
|
||||||
|
local tmpl="${2:-$TW_DEFAULT}"
|
||||||
|
|
||||||
[[ -z "$name" ]] && { tw-list; return; }
|
[[ -z "$name" ]] && { tw-list; return; }
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
|
|
||||||
local session="${TW_PREFIX}-${name}"
|
local session="${TW_PREFIX}-${name}"
|
||||||
tmux has-session -t "$session" 2>/dev/null && tw-attach "$name" || tw-create "$name" "$tmpl"
|
|
||||||
|
# Priority 1: Running tmux session
|
||||||
|
if tmux has-session -t "$session" 2>/dev/null; then
|
||||||
|
tw-attach "$name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Priority 2: Tmuxinator project (if available)
|
||||||
|
if _tw_has_tmuxinator && _tw_tmuxinator_project_exists "$name"; then
|
||||||
|
if tmux has-session -t "$name" 2>/dev/null; then
|
||||||
|
tw-attach "$name"
|
||||||
|
else
|
||||||
|
df_print_step "Starting tmuxinator project: $name"
|
||||||
|
tmuxinator start "$name"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Priority 3: Create new with template
|
||||||
|
tw-create "$name" "$tmpl"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Fuzzy finder
|
||||||
twf() {
|
twf() {
|
||||||
df_require_cmd fzf || return 1
|
df_require_cmd fzf || return 1
|
||||||
_tw_check || return 1
|
_tw_check || return 1
|
||||||
local sessions=()
|
|
||||||
tmux list-sessions 2>/dev/null | while IFS=: read -r sess rest; do
|
local entries=()
|
||||||
[[ "$sess" == ${TW_PREFIX}-* ]] && sessions+=("${sess#${TW_PREFIX}-}")
|
|
||||||
|
# Add running sessions
|
||||||
|
tmux list-sessions -F "#{session_name}" 2>/dev/null | while read -r sess; do
|
||||||
|
[[ "$sess" == ${TW_PREFIX}-* ]] && entries+=("${sess#${TW_PREFIX}-}|session")
|
||||||
done
|
done
|
||||||
[[ ${#sessions[@]} -eq 0 ]] && { df_print_info "No workspaces"; return 1; }
|
|
||||||
local sel=$(printf '%s\n' "${sessions[@]}" | fzf $(df_fzf_opts) --prompt='Workspace > ')
|
# Add tmuxinator projects
|
||||||
[[ -n "$sel" ]] && tw-attach "$sel"
|
if _tw_has_tmuxinator; then
|
||||||
|
for p in "$TMUXINATOR_CONFIG_DIR"/*.yml(N); do
|
||||||
|
[[ -f "$p" ]] && entries+=("$(basename "$p" .yml)|tmuxinator")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ ${#entries[@]} -eq 0 ]] && { df_print_info "No workspaces or projects"; return 1; }
|
||||||
|
|
||||||
|
local sel=$(printf '%s\n' "${entries[@]}" | fzf $(df_fzf_opts) --delimiter='|' --with-nth=1 --prompt='Workspace > ')
|
||||||
|
[[ -n "$sel" ]] && tw "${sel%%|*}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Save current layout as template
|
||||||
|
tw-save() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { echo "Usage: tw-save <template-name>"; return 1; }
|
||||||
|
[[ -z "$TMUX" ]] && { df_print_error "Must be inside tmux"; return 1; }
|
||||||
|
|
||||||
|
_tw_init
|
||||||
|
local outfile="$TW_TEMPLATES/${name}.tmux"
|
||||||
|
|
||||||
|
df_print_func_name "Save Template: ${name}"
|
||||||
|
|
||||||
|
# Get current layout info
|
||||||
|
local pane_count=$(tmux list-panes | wc -l)
|
||||||
|
local layout=$(tmux display-message -p '#{window_layout}')
|
||||||
|
|
||||||
|
cat > "$outfile" << EOF
|
||||||
|
# Custom template: ${name}
|
||||||
|
# Saved: $(date)
|
||||||
|
# Panes: ${pane_count}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate split commands based on pane count
|
||||||
|
# This is a simplified approach - complex layouts need manual adjustment
|
||||||
|
case $pane_count in
|
||||||
|
2)
|
||||||
|
echo "split-window -h -p 50" >> "$outfile"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
echo "split-window -h -p 50" >> "$outfile"
|
||||||
|
echo "split-window -v -p 50" >> "$outfile"
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
echo "split-window -h -p 50" >> "$outfile"
|
||||||
|
echo "split-window -v -p 50" >> "$outfile"
|
||||||
|
echo "select-pane -t 0" >> "$outfile"
|
||||||
|
echo "split-window -v -p 50" >> "$outfile"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
df_print_warning "Complex layout - manual adjustment may be needed"
|
||||||
|
for ((i=1; i<pane_count; i++)); do
|
||||||
|
echo "split-window -h -p 50" >> "$outfile"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "" >> "$outfile"
|
||||||
|
echo "select-pane -t 0" >> "$outfile"
|
||||||
|
|
||||||
|
df_print_success "Saved: $outfile"
|
||||||
|
df_print_info "Edit to refine: ${EDITOR:-vim} $outfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
tw-template-edit() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { tw-templates; return 1; }
|
||||||
|
|
||||||
|
local tfile="$TW_TEMPLATES/${name}.tmux"
|
||||||
|
[[ ! -f "$tfile" ]] && { df_print_error "Template not found: $name"; return 1; }
|
||||||
|
|
||||||
|
${EDITOR:-vim} "$tfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
tw-sync() {
|
tw-sync() {
|
||||||
[[ -z "$TMUX" ]] && { df_print_error "Must be in tmux"; return 1; }
|
[[ -z "$TMUX" ]] && { df_print_error "Must be inside tmux"; return 1; }
|
||||||
local cur=$(tmux show-window-option -v synchronize-panes 2>/dev/null)
|
|
||||||
[[ "$cur" == "on" ]] && { tmux set-window-option synchronize-panes off; df_print_info "Sync: OFF"; } || \
|
local current=$(tmux show-window-option -v synchronize-panes 2>/dev/null)
|
||||||
{ tmux set-window-option synchronize-panes on; df_print_info "Sync: ON"; }
|
if [[ "$current" == "on" ]]; then
|
||||||
|
tmux set-window-option synchronize-panes off
|
||||||
|
df_print_info "Pane sync: OFF"
|
||||||
|
else
|
||||||
|
tmux set-window-option synchronize-panes on
|
||||||
|
df_print_info "Pane sync: ON"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
alias twl='tw-list' twc='tw-create' twa='tw-attach' twd='tw-delete' twt='tw-templates'
|
tw-rename() {
|
||||||
|
local old="$1" new="$2"
|
||||||
|
[[ -z "$old" || -z "$new" ]] && { echo "Usage: tw-rename <old> <new>"; return 1; }
|
||||||
|
_tw_check || return 1
|
||||||
|
|
||||||
|
local old_session="${TW_PREFIX}-${old}"
|
||||||
|
local new_session="${TW_PREFIX}-${new}"
|
||||||
|
|
||||||
|
tmux has-session -t "$old_session" 2>/dev/null || { df_print_error "Not found: $old"; return 1; }
|
||||||
|
tmux rename-session -t "$old_session" "$new_session"
|
||||||
|
df_print_success "Renamed: $old → $new"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Help
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
tw-help() {
|
||||||
|
df_print_func_name "Tmux Workspace Manager"
|
||||||
|
cat << 'EOF'
|
||||||
|
|
||||||
|
Quick Commands:
|
||||||
|
tw <name> [tmpl] Create/attach to workspace
|
||||||
|
twf Fuzzy search workspaces
|
||||||
|
|
||||||
|
Workspace Management:
|
||||||
|
tw-create <n> [t] Create with template
|
||||||
|
tw-attach <n> Attach to workspace
|
||||||
|
tw-list List active workspaces
|
||||||
|
tw-delete <n> Delete workspace
|
||||||
|
tw-rename <old> <new> Rename workspace
|
||||||
|
|
||||||
|
Templates:
|
||||||
|
tw-templates Show available templates
|
||||||
|
tw-save <n> Save current layout as template
|
||||||
|
tw-template-edit <n> Edit template file
|
||||||
|
|
||||||
|
Pane Control:
|
||||||
|
tw-sync Toggle synchronized panes
|
||||||
|
|
||||||
|
Tmuxinator Integration:
|
||||||
|
If tmuxinator is installed, projects in ~/.config/tmuxinator/
|
||||||
|
are automatically detected. Use txi-* commands for management.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Aliases
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
alias twl='tw-list'
|
||||||
|
alias twc='tw-create'
|
||||||
|
alias twa='tw-attach'
|
||||||
|
alias twd='tw-delete'
|
||||||
|
alias tws='tw-save'
|
||||||
|
alias twt='tw-templates'
|
||||||
|
alias twe='tw-template-edit'
|
||||||
|
alias twh='tw-help'
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Initialize
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
_tw_init
|
_tw_init
|
||||||
|
|||||||
510
zsh/functions/tmuxinator.zsh
Normal file
510
zsh/functions/tmuxinator.zsh
Normal file
@@ -0,0 +1,510 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# Tmuxinator Integration for Dotfiles
|
||||||
|
# ============================================================================
|
||||||
|
# Extends tmux-workspaces with tmuxinator support for more powerful
|
||||||
|
# project configurations with per-pane commands, environment variables,
|
||||||
|
# and complex layouts.
|
||||||
|
#
|
||||||
|
# Features:
|
||||||
|
# - Seamless integration with existing tw-* commands
|
||||||
|
# - Auto-detection: uses tmuxinator if project exists, falls back to templates
|
||||||
|
# - Project scaffolding with sensible defaults
|
||||||
|
# - Import/export between tmuxinator and simple templates
|
||||||
|
#
|
||||||
|
# Requirements:
|
||||||
|
# - tmuxinator (gem install tmuxinator or pacman -S tmuxinator)
|
||||||
|
# - tmux
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
source "${0:A:h}/../lib/bootstrap.zsh" 2>/dev/null || \
|
||||||
|
source "$HOME/.dotfiles/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Configuration
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
typeset -g TMUXINATOR_CONFIG_DIR="${TMUXINATOR_CONFIG_DIR:-$HOME/.config/tmuxinator}"
|
||||||
|
typeset -g TMUXINATOR_ENABLED="${TMUXINATOR_ENABLED:-auto}" # auto, true, false
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Detection & Initialization
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
_txi_check() {
|
||||||
|
[[ "$TMUXINATOR_ENABLED" == "false" ]] && return 1
|
||||||
|
df_require_cmd tmuxinator "tmuxinator (gem install tmuxinator)" 2>/dev/null || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_init() {
|
||||||
|
df_ensure_dir "$TMUXINATOR_CONFIG_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_project_exists() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -f "$TMUXINATOR_CONFIG_DIR/${name}.yml" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Project Management
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Create a new tmuxinator project
|
||||||
|
# Usage: txi-new <name> [template]
|
||||||
|
txi-new() {
|
||||||
|
local name="$1"
|
||||||
|
local template="${2:-dev}"
|
||||||
|
|
||||||
|
[[ -z "$name" ]] && { echo "Usage: txi-new <name> [template]"; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
_txi_init
|
||||||
|
|
||||||
|
if _txi_project_exists "$name"; then
|
||||||
|
df_print_warning "Project '$name' already exists"
|
||||||
|
df_confirm "Overwrite?" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
df_print_func_name "New Tmuxinator Project: ${name}"
|
||||||
|
|
||||||
|
local project_file="$TMUXINATOR_CONFIG_DIR/${name}.yml"
|
||||||
|
|
||||||
|
case "$template" in
|
||||||
|
dev)
|
||||||
|
_txi_template_dev "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
ops)
|
||||||
|
_txi_template_ops "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
web)
|
||||||
|
_txi_template_web "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
data)
|
||||||
|
_txi_template_data "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
minimal)
|
||||||
|
_txi_template_minimal "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
df_print_warning "Unknown template: $template"
|
||||||
|
df_print_info "Available: dev, ops, web, data, minimal"
|
||||||
|
_txi_template_dev "$name" > "$project_file"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
df_print_success "Created: $project_file"
|
||||||
|
df_print_info "Edit with: txi-edit $name"
|
||||||
|
df_print_info "Start with: txi $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Edit a tmuxinator project
|
||||||
|
# Usage: txi-edit <name>
|
||||||
|
txi-edit() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { txi-list; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
|
||||||
|
local project_file="$TMUXINATOR_CONFIG_DIR/${name}.yml"
|
||||||
|
|
||||||
|
if [[ ! -f "$project_file" ]]; then
|
||||||
|
df_print_error "Project not found: $name"
|
||||||
|
df_confirm "Create it?" && txi-new "$name" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
${EDITOR:-vim} "$project_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# List tmuxinator projects
|
||||||
|
txi-list() {
|
||||||
|
_txi_check || return 1
|
||||||
|
_txi_init
|
||||||
|
|
||||||
|
df_print_func_name "Tmuxinator Projects"
|
||||||
|
|
||||||
|
local found=false
|
||||||
|
for project in "$TMUXINATOR_CONFIG_DIR"/*.yml(N); do
|
||||||
|
[[ -f "$project" ]] || continue
|
||||||
|
found=true
|
||||||
|
local name=$(basename "$project" .yml)
|
||||||
|
local root=$(grep -m1 "^root:" "$project" 2>/dev/null | sed 's/root:[[:space:]]*//')
|
||||||
|
df_print_indent "● $name"
|
||||||
|
[[ -n "$root" && "$root" != "~" ]] && df_print_indent " └─ $root"
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$found" != true ]] && df_print_info "No projects. Create with: txi-new <name>"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Delete a tmuxinator project
|
||||||
|
# Usage: txi-delete <name>
|
||||||
|
txi-delete() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { echo "Usage: txi-delete <name>"; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
|
||||||
|
local project_file="$TMUXINATOR_CONFIG_DIR/${name}.yml"
|
||||||
|
|
||||||
|
if [[ ! -f "$project_file" ]]; then
|
||||||
|
df_print_error "Project not found: $name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
df_confirm "Delete project '$name'?" || return 1
|
||||||
|
rm "$project_file"
|
||||||
|
df_print_success "Deleted: $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start/attach to a tmuxinator project
|
||||||
|
# Usage: txi <name>
|
||||||
|
txi() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { txi-list; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
|
||||||
|
if ! _txi_project_exists "$name"; then
|
||||||
|
df_print_error "Project not found: $name"
|
||||||
|
df_print_info "Create with: txi-new $name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if session already exists
|
||||||
|
if tmux has-session -t "$name" 2>/dev/null; then
|
||||||
|
df_print_info "Attaching to existing session: $name"
|
||||||
|
if [[ -z "$TMUX" ]]; then
|
||||||
|
tmux attach -t "$name"
|
||||||
|
else
|
||||||
|
tmux switch-client -t "$name"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
df_print_step "Starting project: $name"
|
||||||
|
tmuxinator start "$name"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stop a tmuxinator session
|
||||||
|
# Usage: txi-stop <name>
|
||||||
|
txi-stop() {
|
||||||
|
local name="$1"
|
||||||
|
[[ -z "$name" ]] && { echo "Usage: txi-stop <name>"; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
|
||||||
|
tmuxinator stop "$name" 2>/dev/null && df_print_success "Stopped: $name" || df_print_error "Session not running: $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fuzzy search and start project
|
||||||
|
txif() {
|
||||||
|
_txi_check || return 1
|
||||||
|
df_require_cmd fzf || return 1
|
||||||
|
_txi_init
|
||||||
|
|
||||||
|
local projects=()
|
||||||
|
for project in "$TMUXINATOR_CONFIG_DIR"/*.yml(N); do
|
||||||
|
[[ -f "$project" ]] && projects+=("$(basename "$project" .yml)")
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ ${#projects[@]} -eq 0 ]] && { df_print_info "No projects"; return 1; }
|
||||||
|
|
||||||
|
local sel=$(printf '%s\n' "${projects[@]}" | fzf $(df_fzf_opts) --prompt='Tmuxinator > ')
|
||||||
|
[[ -n "$sel" ]] && txi "$sel"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Template Generators
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
_txi_template_dev() {
|
||||||
|
local name="$1"
|
||||||
|
cat << EOF
|
||||||
|
# ${name} - Development Workspace
|
||||||
|
name: ${name}
|
||||||
|
root: ~/projects/${name}
|
||||||
|
|
||||||
|
# Optional: pre-commands before windows are created
|
||||||
|
# pre_window: nvm use default
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- editor:
|
||||||
|
layout: main-vertical
|
||||||
|
panes:
|
||||||
|
- # Editor pane - opens vim/nvim
|
||||||
|
- # Terminal pane
|
||||||
|
|
||||||
|
- server:
|
||||||
|
panes:
|
||||||
|
- # Server/dev server pane
|
||||||
|
|
||||||
|
- logs:
|
||||||
|
panes:
|
||||||
|
- # Log watching pane
|
||||||
|
- # Additional monitoring
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_template_ops() {
|
||||||
|
local name="$1"
|
||||||
|
cat << EOF
|
||||||
|
# ${name} - Operations/Monitoring Workspace
|
||||||
|
name: ${name}
|
||||||
|
root: ~
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- monitoring:
|
||||||
|
layout: tiled
|
||||||
|
panes:
|
||||||
|
- htop
|
||||||
|
- # System logs
|
||||||
|
- # Network monitoring
|
||||||
|
- # Disk usage
|
||||||
|
|
||||||
|
- services:
|
||||||
|
layout: even-horizontal
|
||||||
|
panes:
|
||||||
|
- # Service management
|
||||||
|
- # Container management
|
||||||
|
|
||||||
|
- ssh:
|
||||||
|
layout: tiled
|
||||||
|
panes:
|
||||||
|
- # SSH session 1
|
||||||
|
- # SSH session 2
|
||||||
|
- # SSH session 3
|
||||||
|
- # SSH session 4
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_template_web() {
|
||||||
|
local name="$1"
|
||||||
|
cat << EOF
|
||||||
|
# ${name} - Web Development Workspace
|
||||||
|
name: ${name}
|
||||||
|
root: ~/projects/${name}
|
||||||
|
|
||||||
|
# Uncomment and adjust for your stack
|
||||||
|
# pre_window: nvm use 18
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- editor:
|
||||||
|
layout: main-vertical
|
||||||
|
panes:
|
||||||
|
- # \${EDITOR:-vim} .
|
||||||
|
- # Terminal
|
||||||
|
|
||||||
|
- server:
|
||||||
|
panes:
|
||||||
|
- # npm run dev # or: python manage.py runserver
|
||||||
|
|
||||||
|
- frontend:
|
||||||
|
layout: even-horizontal
|
||||||
|
panes:
|
||||||
|
- # npm run watch
|
||||||
|
- # Browser sync / tailwind watch
|
||||||
|
|
||||||
|
- database:
|
||||||
|
panes:
|
||||||
|
- # Database client or psql/mysql
|
||||||
|
|
||||||
|
- git:
|
||||||
|
panes:
|
||||||
|
- # Git operations
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_template_data() {
|
||||||
|
local name="$1"
|
||||||
|
cat << EOF
|
||||||
|
# ${name} - Data Science Workspace
|
||||||
|
name: ${name}
|
||||||
|
root: ~/projects/${name}
|
||||||
|
|
||||||
|
# Uncomment to activate conda/venv
|
||||||
|
# pre_window: source venv/bin/activate
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- jupyter:
|
||||||
|
panes:
|
||||||
|
- # jupyter lab
|
||||||
|
|
||||||
|
- code:
|
||||||
|
layout: main-vertical
|
||||||
|
panes:
|
||||||
|
- # Editor
|
||||||
|
- # Python REPL: python or ipython
|
||||||
|
|
||||||
|
- data:
|
||||||
|
panes:
|
||||||
|
- # Data exploration / file management
|
||||||
|
|
||||||
|
- terminal:
|
||||||
|
panes:
|
||||||
|
- # General terminal
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
_txi_template_minimal() {
|
||||||
|
local name="$1"
|
||||||
|
cat << EOF
|
||||||
|
# ${name} - Minimal Workspace
|
||||||
|
name: ${name}
|
||||||
|
root: ~
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- main:
|
||||||
|
panes:
|
||||||
|
- # Main pane
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Integration with tw-* Commands
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Enhanced tw function that checks tmuxinator first
|
||||||
|
_txi_tw_enhanced() {
|
||||||
|
local name="$1"
|
||||||
|
local template="${2:-}"
|
||||||
|
|
||||||
|
[[ -z "$name" ]] && {
|
||||||
|
# List both tw workspaces and tmuxinator projects
|
||||||
|
tw-list 2>/dev/null
|
||||||
|
echo ""
|
||||||
|
txi-list 2>/dev/null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if tmuxinator project exists
|
||||||
|
if _txi_check 2>/dev/null && _txi_project_exists "$name"; then
|
||||||
|
txi "$name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fall back to tw
|
||||||
|
tw "$name" "$template"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Import/Export
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Import a simple .tmux template to tmuxinator format
|
||||||
|
# Usage: txi-import <template-name> [new-project-name]
|
||||||
|
txi-import() {
|
||||||
|
local tmpl_name="$1"
|
||||||
|
local project_name="${2:-$tmpl_name}"
|
||||||
|
|
||||||
|
[[ -z "$tmpl_name" ]] && { echo "Usage: txi-import <template-name> [project-name]"; return 1; }
|
||||||
|
_txi_check || return 1
|
||||||
|
|
||||||
|
local tmpl_file="${TW_TEMPLATES:-$HOME/.dotfiles/.tmux-templates}/${tmpl_name}.tmux"
|
||||||
|
|
||||||
|
if [[ ! -f "$tmpl_file" ]]; then
|
||||||
|
df_print_error "Template not found: $tmpl_name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
df_print_func_name "Import Template: ${tmpl_name}"
|
||||||
|
|
||||||
|
_txi_init
|
||||||
|
local project_file="$TMUXINATOR_CONFIG_DIR/${project_name}.yml"
|
||||||
|
|
||||||
|
if _txi_project_exists "$project_name"; then
|
||||||
|
df_confirm "Overwrite existing project '$project_name'?" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse the simple template and convert to tmuxinator format
|
||||||
|
local pane_count=0
|
||||||
|
local panes=""
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ "$line" =~ ^#.*$ ]] && continue
|
||||||
|
[[ "$line" =~ ^[[:space:]]*$ ]] && continue
|
||||||
|
|
||||||
|
if [[ "$line" =~ split-window ]]; then
|
||||||
|
((pane_count++))
|
||||||
|
fi
|
||||||
|
done < "$tmpl_file"
|
||||||
|
|
||||||
|
# Generate panes list
|
||||||
|
panes=" - # Pane 1"
|
||||||
|
for ((i=1; i<=pane_count; i++)); do
|
||||||
|
panes+="\n - # Pane $((i+1))"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create the project file
|
||||||
|
cat > "$project_file" << EOF
|
||||||
|
# Imported from template: ${tmpl_name}
|
||||||
|
name: ${project_name}
|
||||||
|
root: ~
|
||||||
|
|
||||||
|
windows:
|
||||||
|
- main:
|
||||||
|
layout: tiled
|
||||||
|
panes:
|
||||||
|
$(echo -e "$panes")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
df_print_success "Imported: $project_file"
|
||||||
|
df_print_info "Edit to customize: txi-edit $project_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Available Templates
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
txi-templates() {
|
||||||
|
df_print_func_name "Tmuxinator Templates"
|
||||||
|
echo ""
|
||||||
|
df_print_indent "dev Development (editor + terminal + server + logs)"
|
||||||
|
df_print_indent "ops Operations (monitoring + services + SSH grid)"
|
||||||
|
df_print_indent "web Web development (editor + server + frontend + db)"
|
||||||
|
df_print_indent "data Data science (jupyter + code + data + terminal)"
|
||||||
|
df_print_indent "minimal Single window, single pane"
|
||||||
|
echo ""
|
||||||
|
df_print_info "Usage: txi-new myproject dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Help
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
txi-help() {
|
||||||
|
df_print_func_name "Tmuxinator Commands"
|
||||||
|
cat << 'EOF'
|
||||||
|
|
||||||
|
Project Management:
|
||||||
|
txi <name> Start/attach to project
|
||||||
|
txi-new <n> [tmpl] Create new project (templates: dev, ops, web, data, minimal)
|
||||||
|
txi-edit <name> Edit project configuration
|
||||||
|
txi-list List all projects
|
||||||
|
txi-delete <name> Delete project
|
||||||
|
txi-stop <name> Stop running session
|
||||||
|
txif Fuzzy search and start
|
||||||
|
|
||||||
|
Templates:
|
||||||
|
txi-templates Show available templates
|
||||||
|
txi-import <t> [n] Import simple .tmux template to tmuxinator
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Projects stored in: ~/.config/tmuxinator/
|
||||||
|
|
||||||
|
Integration:
|
||||||
|
Tmuxinator projects are automatically detected by tw commands.
|
||||||
|
If a tmuxinator project exists with the same name, it takes precedence.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Aliases
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
alias txil='txi-list'
|
||||||
|
alias txin='txi-new'
|
||||||
|
alias txie='txi-edit'
|
||||||
|
alias txid='txi-delete'
|
||||||
|
alias txis='txi-stop'
|
||||||
|
alias txit='txi-templates'
|
||||||
|
alias txih='txi-help'
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Initialize
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
_txi_init
|
||||||
Reference in New Issue
Block a user