This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / tools / workspace-manager / workspace-menu.sh
6.7 kB 256 lines
1#!/usr/bin/env bash 2# Workspace Menu - rofi-based menu for workspace management 3# Provides: save layout, restore workspace, delete config, edit config 4 5set -euo pipefail 6 7WORKSPACES_DIR="${HOME}/workspaces" 8mkdir -p "$WORKSPACES_DIR" 9 10# Get current workspace name from sway 11get_current_workspace() { 12 swaymsg -r -t get_workspaces | jq -r '.[] | select(.focused == true).name' 13} 14 15# Get the sway tree for the current workspace (app_id for each window) 16capture_layout() { 17 local ws_name="$1" 18 swaymsg -r -t get_tree | jq --arg ws "$ws_name" ' 19 [.nodes[].nodes[] | 20 select(.name == $ws) | 21 .. | 22 select(.type? == "con" and .app_id? != null) | 23 {app_id: .app_id}] 24 ' 25} 26 27# Save current workspace layout 28action_save() { 29 local ws_name 30 ws_name=$(get_current_workspace) 31 local config_file="${WORKSPACES_DIR}/${ws_name}.json" 32 33 # Capture current windows 34 local layout 35 layout=$(capture_layout "$ws_name") 36 37 # Load existing config or start fresh 38 local existing="{}" 39 if [ -f "$config_file" ]; then 40 existing=$(cat "$config_file") 41 fi 42 43 # Merge layout into existing config 44 echo "$existing" | jq --argjson layout "$layout" '. + {layout: $layout}' > "$config_file" 45 46 notify-send "Workspace Manager" "Saved layout for workspace '${ws_name}' ($(echo "$layout" | jq 'length') windows)" 47} 48 49# Launch an app by its app_id in the given working directory 50launch_app() { 51 local app_id="$1" 52 local work_dir="$2" 53 54 case "$app_id" in 55 kitty|foot|alacritty|wezterm) 56 # Terminal emulators: open in workspace directory 57 cd "$work_dir" && "$app_id" & 58 ;; 59 *) 60 # Skip everything else (browsers handled by Firefox extension) 61 ;; 62 esac 63} 64 65# Restore workspace to its original state (kill windows + re-run on_create + reopen layout) 66action_restore() { 67 local ws_name 68 ws_name=$(get_current_workspace) 69 local config_file="${WORKSPACES_DIR}/${ws_name}.json" 70 71 if [ ! -f "$config_file" ]; then 72 notify-send "Workspace Manager" "No config found for workspace '${ws_name}'" 73 return 1 74 fi 75 76 # Confirm via rofi 77 local confirm 78 confirm=$(printf "Yes\nNo" | rofi -dmenu -p "Restore workspace '${ws_name}'? (kills all windows)") 79 if [ "$confirm" != "Yes" ]; then 80 return 0 81 fi 82 83 # Kill all windows on current workspace 84 local pids 85 pids=$(swaymsg -r -t get_tree | jq --arg ws "$ws_name" ' 86 [.nodes[].nodes[] | 87 select(.name == $ws) | 88 .. | 89 select(.type? == "con" and .pid? != null) | 90 .pid] | unique | .[] 91 ') 92 93 for pid in $pids; do 94 kill "$pid" 2>/dev/null || true 95 done 96 97 # Wait a moment for windows to close 98 sleep 1 99 100 local directory 101 directory=$(jq -r '.directory // "~"' "$config_file" 2>/dev/null) 102 directory="${directory/#\~/$HOME}" 103 104 # Run on_create commands in tmux sessions 105 local on_create 106 on_create=$(jq -r '.on_create // [] | .[]' "$config_file" 2>/dev/null) 107 108 if [ -n "$on_create" ]; then 109 local i=1 110 while IFS= read -r cmd; do 111 local session_name="${ws_name}-start${i}" 112 # Kill existing tmux session if present 113 tmux kill-session -t "$session_name" 2>/dev/null || true 114 # Create new tmux session 115 tmux new-session -d -s "$session_name" -c "$directory" "$cmd" 116 # Open terminal attached to it 117 kitty -T "$session_name" tmux attach -t "$session_name" & 118 i=$((i + 1)) 119 done <<< "$on_create" 120 fi 121 122 # Reopen windows from saved layout 123 local layout_count 124 layout_count=$(jq '.layout // [] | length' "$config_file" 2>/dev/null) 125 126 if [ "$layout_count" -gt 0 ]; then 127 local app_ids 128 app_ids=$(jq -r '.layout // [] | .[].app_id // empty' "$config_file" 2>/dev/null) 129 130 while IFS= read -r app_id; do 131 [ -n "$app_id" ] && launch_app "$app_id" "$directory" 132 done <<< "$app_ids" 133 fi 134 135 notify-send "Workspace Manager" "Restored workspace '${ws_name}'" 136} 137 138# Delete a workspace configuration 139action_delete() { 140 local configs 141 configs=$(find "$WORKSPACES_DIR" -name '*.json' -printf '%f\n' | sed 's/\.json$//' | sort) 142 143 if [ -z "$configs" ]; then 144 notify-send "Workspace Manager" "No workspace configs found" 145 return 0 146 fi 147 148 local selected 149 selected=$(echo "$configs" | rofi -dmenu -p "Delete workspace config") 150 if [ -z "$selected" ]; then 151 return 0 152 fi 153 154 local confirm 155 confirm=$(printf "Yes\nNo" | rofi -dmenu -p "Delete config for '${selected}'?") 156 if [ "$confirm" = "Yes" ]; then 157 rm "${WORKSPACES_DIR}/${selected}.json" 158 notify-send "Workspace Manager" "Deleted config for '${selected}'" 159 fi 160} 161 162# Edit a workspace configuration 163action_edit() { 164 local ws_name 165 ws_name=$(get_current_workspace) 166 167 # List existing configs + option for current workspace 168 local configs 169 configs=$(find "$WORKSPACES_DIR" -name '*.json' -printf '%f\n' | sed 's/\.json$//' | sort) 170 171 # Prepend current workspace if not already in list 172 if ! echo "$configs" | grep -qx "$ws_name"; then 173 configs="${ws_name}"$'\n'"${configs}" 174 fi 175 176 local selected 177 selected=$(echo "$configs" | rofi -dmenu -p "Edit workspace config") 178 if [ -z "$selected" ]; then 179 return 0 180 fi 181 182 local config_file="${WORKSPACES_DIR}/${selected}.json" 183 184 # Create default config if it doesn't exist 185 if [ ! -f "$config_file" ]; then 186 echo '{}' > "$config_file" 187 fi 188 189 # Open in terminal with $EDITOR 190 kitty "${EDITOR:-vim}" "$config_file" & 191} 192 193# Close workspace: kill all windows and remove the workspace 194action_close() { 195 local ws_name 196 ws_name=$(get_current_workspace) 197 198 local confirm 199 confirm=$(printf "Yes\nNo" | rofi -dmenu -p "Close workspace '${ws_name}'? (kills all windows)") 200 if [ "$confirm" != "Yes" ]; then 201 return 0 202 fi 203 204 # Kill all windows on current workspace 205 local pids 206 pids=$(swaymsg -r -t get_tree | jq --arg ws "$ws_name" ' 207 [.nodes[].nodes[] | 208 select(.name == $ws) | 209 .. | 210 select(.type? == "con" and .pid? != null) | 211 .pid] | unique | .[] 212 ') 213 214 for pid in $pids; do 215 kill "$pid" 2>/dev/null || true 216 done 217 218 # Kill associated tmux sessions 219 local i=1 220 while tmux has-session -t "${ws_name}-start${i}" 2>/dev/null; do 221 tmux kill-session -t "${ws_name}-start${i}" 2>/dev/null || true 222 i=$((i + 1)) 223 done 224 225 notify-send "Workspace Manager" "Closed workspace '${ws_name}'" 226} 227 228# Main menu 229main() { 230 local ws_name 231 ws_name=$(get_current_workspace) 232 233 local choice 234 choice=$(printf "Save layout\nRestore workspace\nClose workspace\nEdit config\nDelete config" | \ 235 rofi -dmenu -p "Workspace: ${ws_name}") 236 237 case "$choice" in 238 "Save layout") 239 action_save 240 ;; 241 "Restore workspace") 242 action_restore 243 ;; 244 "Close workspace") 245 action_close 246 ;; 247 "Edit config") 248 action_edit 249 ;; 250 "Delete config") 251 action_delete 252 ;; 253 esac 254} 255 256main