diff --git a/README.md b/README.md index 22e9089..e960edc 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ source ~/.bashrc # or source ~/.zshrc ## Usage ``` -tmux-ws create [--detach|-d] [--force|-f] Create and attach to a workspace +tmux-ws add [dir] [--template ] Scaffold workspace config +tmux-ws launch [--detach|-d] Create and attach to a workspace tmux-ws attach Attach to a running workspace tmux-ws list List available and running workspaces tmux-ws kill Kill a workspace session @@ -34,11 +35,17 @@ tmux-ws help Show help ### Examples ```bash -# Create a workspace and attach -tmux-ws create project +# Scaffold a new workspace config from template +tmux-ws add myproject + +# Scaffold with a custom project directory +tmux-ws add myproject ~/projects/myapp + +# Create workspace and attach +tmux-ws launch project # Create in background, stay in current shell -tmux-ws create project --detach +tmux-ws launch project --detach # Attach to a running workspace tmux-ws attach project @@ -145,20 +152,21 @@ Hooks run in a subshell, so they cannot modify the script's state (WINDOWS, DEFA ## Creating a New Workspace -Copy an existing workspace or the example: +Use `add` to scaffold a workspace config from a template: -```bash -# From the example -cp -r ~/.config/tmux-ws/_examples ~/.config/tmux-ws/myproject + # Scaffold with defaults + tmux-ws add myproject -# From an existing workspace -cp -r ~/.config/tmux-ws/project ~/.config/tmux-ws/myproject + # Scaffold with a specific project directory + tmux-ws add myproject ~/projects/myapp -# Edit it -tmux-ws edit myproject -``` + # Edit the config + tmux-ws edit myproject + +Or copy an existing workspace manually: -Directories starting with `_` (like `_templates`, `_examples`) are hidden from `tmux-ws list` but still usable with `tmux-ws create`. + cp -r ~/.config/tmux-ws/project ~/.config/tmux-ws/myproject + tmux-ws edit myproject ## Testing @@ -166,7 +174,7 @@ Directories starting with `_` (like `_templates`, `_examples`) are hidden from ` make test ``` -Requires [bats](https://github.com/bats-core/bats-core). Tests cover: help, version, list, create, inheritance, hooks, validation, kill, attach, edit, and init. +Requires [bats](https://github.com/bats-core/bats-core). Tests cover: help, version, list, add, launch, inheritance, hooks, validation, kill, attach, edit, and init. ## tmux Configuration diff --git a/bin/tmux-ws b/bin/tmux-ws index bebeb54..a3c9961 100755 --- a/bin/tmux-ws +++ b/bin/tmux-ws @@ -20,18 +20,19 @@ usage() { echo -e "${BOLD}$SCRIPT_NAME${NC} — tmux workspace manager" echo -e "" echo -e "${BOLD}Usage:${NC}" - echo -e " $SCRIPT_NAME create [--detach|-d] Create and attach to a workspace" - echo -e " $SCRIPT_NAME attach Attach to a running workspace" - echo -e " $SCRIPT_NAME list List available and running workspaces" - echo -e " $SCRIPT_NAME kill Kill a workspace session" - echo -e " $SCRIPT_NAME edit Open workspace config in \$EDITOR" - echo -e " $SCRIPT_NAME init Create config directory structure" - echo -e " $SCRIPT_NAME version Show version" - echo -e " $SCRIPT_NAME help Show this help" + echo -e " $SCRIPT_NAME add [dir] [--template ] Scaffold workspace config" + echo -e " $SCRIPT_NAME launch [--detach|-d] Launch and attach to workspace" + echo -e " $SCRIPT_NAME attach Attach to running workspace" + echo -e " $SCRIPT_NAME list List available and running workspaces" + echo -e " $SCRIPT_NAME kill Kill workspace session" + echo -e " $SCRIPT_NAME edit Open workspace config in \$EDITOR" + echo -e " $SCRIPT_NAME init Create config directory structure" + echo -e " $SCRIPT_NAME version Show version" + echo -e " $SCRIPT_NAME help Show this help" echo -e "" echo -e "${BOLD}Options:${NC}" - echo -e " --detach, -d Create workspace without attaching" - echo -e " --force, -f Kill existing session before creating" + echo -e " --detach, -d Launch workspace without attaching" + echo -e " --template Use a specific template (default: default)" echo -e "" echo -e "${BOLD}Config:${NC}" echo -e " $CONFIG_DIR//workspace.conf" @@ -99,6 +100,16 @@ validate_dir() { } # --- Config Loading --- +resolve_template_path() { + local template_name="$1" + local template_file="$CONFIG_DIR/_templates/${template_name}.conf" + if [[ ! -f "$template_file" ]]; then + error "Template '$template_name' not found at $template_file" + exit 1 + fi + echo "$template_file" +} + load_config() { local name="$1" local config_dir="$CONFIG_DIR/$name" @@ -127,7 +138,8 @@ load_config() { # Inherit from base template if _BASE is set if [[ -n "$_BASE" ]]; then - local base_file="$CONFIG_DIR/_templates/${_BASE}.conf" + local base_file + base_file=$(resolve_template_path "$_BASE") if [[ -f "$base_file" ]]; then # Save workspace values local ws_windows=("${WINDOWS[@]+"${WINDOWS[@]}"}") @@ -153,10 +165,6 @@ load_config() { if [[ "$DEFAULT_DIR" == "$HOME" && "$tmpl_default" != "$HOME" ]]; then DEFAULT_DIR="$tmpl_default" fi - else - error "Base template '$_BASE' not found at $base_file" - error " Create it with: $SCRIPT_NAME init" - exit 1 fi fi @@ -207,16 +215,14 @@ parse_window_entry() { } # --- Core Commands --- -cmd_create() { +cmd_launch() { local name="" local detach=false - local force=false # Parse args while [[ $# -gt 0 ]]; do case "$1" in --detach|-d) detach=true; shift ;; - --force|-f) force=true; shift ;; -*) error "Unknown option: $1"; usage; exit 1 ;; *) name="$1"; shift ;; esac @@ -233,18 +239,13 @@ cmd_create() { # Check if session already exists if tmux has-session -t "$name" 2>/dev/null; then - if [[ "$force" == true ]]; then - warn "Killing existing session '$name'" - tmux kill-session -t "$name" + info "Session '$name' already exists" + if [[ "$detach" == true ]]; then + echo " Attach with: tmux attach -t $name" else - info "Session '$name' already exists" - if [[ "$detach" == true ]]; then - echo " Attach with: tmux attach -t $name" - else - tmux attach -t "$name" - fi - return + tmux attach -t "$name" fi + return fi # Run pre-create hooks @@ -287,6 +288,63 @@ cmd_create() { fi } +cmd_add() { + local name="" + local dir="" + local template="default" + + # Parse args + while [[ $# -gt 0 ]]; do + case "$1" in + --template) template="$2"; shift 2 ;; + -*) error "Unknown option: $1"; usage; exit 1 ;; + *) if [[ -z "$name" ]]; then name="$1"; else dir="$1"; fi; shift ;; + esac + done + + if [[ -z "$name" ]]; then + error "Workspace name required" + usage + exit 1 + fi + + local config_file="$CONFIG_DIR/$name/workspace.conf" + if [[ -f "$config_file" ]]; then + error "Workspace '$name' already exists at $config_file" + exit 1 + fi + + # Resolve and validate template + local template_file + template_file=$(resolve_template_path "$template") + + # Create workspace directory + mkdir -p "$CONFIG_DIR/$name/hooks" + + # Copy template and substitute DEFAULT_DIR if dir arg given + if [[ -n "$dir" ]]; then + sed "s|^DEFAULT_DIR=.*|DEFAULT_DIR=\"$dir\"|" "$template_file" > "$config_file" + validate_dir "$dir" "Workspace directory" + else + cp "$template_file" "$config_file" + fi + + # Create hook stubs + cat > "$CONFIG_DIR/$name/hooks/pre-create.sh" <<'STUB' +#!/bin/bash +# Runs before the tmux session is created. +# Use this to start services, check prerequisites, etc. +STUB + + cat > "$CONFIG_DIR/$name/hooks/post-create.sh" <<'STUB' +#!/bin/bash +# Runs after the tmux session is created. +# Use this to wait for services, open URLs, send notifications, etc. +STUB + + info "Workspace '$name' scaffolded at $CONFIG_DIR/$name/" +} + cmd_list() { header "Available workspaces" local count=0 @@ -354,7 +412,7 @@ cmd_attach() { if ! tmux has-session -t "$name" 2>/dev/null; then error "Session '$name' is not running" - echo " Create it with: $SCRIPT_NAME create $name" + echo " Create it with: $SCRIPT_NAME launch $name" exit 1 fi @@ -431,7 +489,8 @@ main() { shift case "$command" in - create) cmd_create "$@" ;; + add) cmd_add "$@" ;; + launch) cmd_launch "$@" ;; attach) cmd_attach "$@" ;; list) cmd_list ;; kill) cmd_kill "$@" ;; diff --git a/tests/test_tmux_ws.bats b/tests/test_tmux_ws.bats index 5030f6b..146174f 100644 --- a/tests/test_tmux_ws.bats +++ b/tests/test_tmux_ws.bats @@ -20,6 +20,14 @@ setup() { mkdir -p "$TEST_CONFIG_DIR/bad-format" mkdir -p "$TEST_CONFIG_DIR/no-template/hooks" mkdir -p "$TEST_CONFIG_DIR/fail-hook/hooks" + cat > "$TEST_CONFIG_DIR/_templates/node.conf" < "$TEST_CONFIG_DIR/_templates/default.conf" <