Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ source ~/.bashrc # or source ~/.zshrc
## Usage

```
tmux-ws create <name> [--detach|-d] [--force|-f] Create and attach to a workspace
tmux-ws add <name> [dir] [--template <name>] Scaffold workspace config
tmux-ws launch <name> [--detach|-d] Create and attach to a workspace
tmux-ws attach <name> Attach to a running workspace
tmux-ws list List available and running workspaces
tmux-ws kill <name> Kill a workspace session
Expand All @@ -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
Expand Down Expand Up @@ -145,28 +152,29 @@ 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

```bash
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

Expand Down
119 changes: 89 additions & 30 deletions bin/tmux-ws
Original file line number Diff line number Diff line change
Expand Up @@ -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 <name> [--detach|-d] Create and attach to a workspace"
echo -e " $SCRIPT_NAME attach <name> Attach to a running workspace"
echo -e " $SCRIPT_NAME list List available and running workspaces"
echo -e " $SCRIPT_NAME kill <name> Kill a workspace session"
echo -e " $SCRIPT_NAME edit <name> 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 <name> [dir] [--template <name>] Scaffold workspace config"
echo -e " $SCRIPT_NAME launch <name> [--detach|-d] Launch and attach to workspace"
echo -e " $SCRIPT_NAME attach <name> Attach to running workspace"
echo -e " $SCRIPT_NAME list List available and running workspaces"
echo -e " $SCRIPT_NAME kill <name> Kill workspace session"
echo -e " $SCRIPT_NAME edit <name> 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 <name> Use a specific template (default: default)"
echo -e ""
echo -e "${BOLD}Config:${NC}"
echo -e " $CONFIG_DIR/<name>/workspace.conf"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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[@]}"}")
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 "$@" ;;
Expand Down
Loading
Loading