sent-dev.sh (3837B)
1 #!/bin/sh 2 set -eu 3 # sent-dev.sh — tmux-based development environment for sent slide decks 4 # 5 # This script: 6 # - Opens your editor on a sent slide spec file, creating it if missing. 7 # - Watches that file for changes and recompiles it to .sent. 8 # - Provides a pane with a shell for interactive work. 9 # - Watches the tables/ directory for Markdown tables + auto compiles. 10 # 11 # Each process runs in its own tmux pane/window. 12 # Requires: tmux, entr, compile-sentspec-wrapper, compile-sentspec, compile-sent-tables 13 # 14 # Usage: sent-dev.sh <deck.sentspec> 15 # 16 17 # === Globals === 18 SPEC="" 19 SPECDIR="" 20 CONFIG_FILE="" 21 SESSION="" 22 COMPILE_SENTSPEC_ARGS="" 23 EDITOR_CMD="${EDITOR:-vi}" 24 25 # === Functions === 26 27 error() { 28 printf "Error: %s\n" "$1" >&2 29 exit 1 30 } 31 32 usage() { 33 printf "Usage: %s <deck.sentspec>\n" "$0" >&2 34 exit 1 35 } 36 37 check_deps() { 38 missing=0 39 for dep in tmux entr compile-sentspec-wrapper compile-sentspec compile-sent-tables; do 40 if ! command -v "$dep" > /dev/null 2>&1; then 41 printf "Dependency not found: %s\n" "$dep" >&2 42 missing=1 43 fi 44 done 45 if [ "$missing" -eq 1 ]; then 46 error "Please install the missing dependencies and try again." 47 fi 48 } 49 50 parse_args() { 51 if [ "$#" -ne 1 ]; then 52 usage 53 fi 54 55 case "$1" in 56 *.sentspec) ;; 57 *) error "Input file must have .sentspec extension." ;; 58 esac 59 60 # Make SPEC absolute 61 case "$1" in 62 /*) SPEC="$1" ;; 63 *) 64 SPEC=$(cd "$(dirname -- "$1")" && pwd)/$(basename -- "$1") \ 65 || error "Invalid spec path: $1" 66 ;; 67 esac 68 69 [ -f "$SPEC" ] || : > "$SPEC" 70 71 SPECDIR=$(dirname -- "$SPEC") 72 CONFIG_FILE="$SPECDIR/config" 73 74 if [ -f "$CONFIG_FILE" ]; then 75 # shellcheck disable=SC1090 76 . "$CONFIG_FILE" 77 fi 78 79 COMPILE_SENTSPEC_ARGS=${COMPILE_SENTSPEC_ARGS:-} 80 } 81 82 ensure_workdirs() { 83 [ -d "$SPECDIR/tables" ] || mkdir -p "$SPECDIR/tables" 84 } 85 86 start_tmux() { 87 # Detect if inside tmux BEFORE unsetting TMUX 88 inside_tmux=0 89 if [ -n "${TMUX:-}" ]; then 90 inside_tmux=1 91 fi 92 93 if tmux has-session -t "$SESSION" 2> /dev/null; then 94 if [ "$inside_tmux" -eq 1 ]; then 95 tmux switch-client -t "$SESSION" 96 else 97 exec tmux attach-session -t "$SESSION" 98 fi 99 exit 0 100 fi 101 102 unset TMUX # Prevent nesting issues 103 104 # === Pane Layout === 105 106 # 1. Editor pane 107 tmux new-session -d -s "$SESSION" -n edit -c "$SPECDIR" 108 tmux send-keys -t "$SESSION:0.0" "$EDITOR_CMD '$SPEC'" C-m 109 110 # 2. Compile watcher (top right) 111 tmux split-window -h -t "$SESSION:0" -c "$SPECDIR" 112 tmux send-keys -t "$SESSION:0.1" "ls '$SPEC' | entr -c compile-sentspec-wrapper '$SPEC'" C-m 113 114 # 3. Table watcher (below compile watcher) 115 if [ -d "$SPECDIR/tables" ]; then 116 if ! find "$SPECDIR/tables" -name '*.md' | grep -q .; then 117 : > "$SPECDIR/tables/.sent-empty.md" 118 fi 119 tmux split-window -v -t "$SESSION:0.1" -c "$SPECDIR" 120 tmux send-keys -t "$SESSION:0.2" \ 121 "while true; do find \"$SPECDIR/tables\" -name '*.md' | entr -d compile-sent-tables; done" C-m 122 else 123 # Table dir doesn't exist – create pane as shell 124 tmux split-window -v -t "$SESSION:0.1" -c "$SPECDIR" 125 fi 126 127 # 4. Shell pane (always at bottom) 128 tmux split-window -v -t "$SESSION:0.2" 129 tmux send-keys -t "$SESSION:0.2" "sleep 0.1; cd '$SPECDIR'" C-m 130 131 # Cleanup: Focus back to editor 132 tmux select-window -t "$SESSION:0" 133 tmux select-pane -t "$SESSION:0.0" 134 135 # Attach or switch based on whether inside tmux *detected earlier* 136 if [ "$inside_tmux" -eq 1 ]; then 137 tmux switch-client -t "$SESSION" 138 else 139 exec tmux attach-session -t "$SESSION" 140 fi 141 } 142 143 main() { 144 check_deps 145 parse_args "$@" 146 147 # Unique session name based on SPEC path 148 basename=$(basename "$SPEC" | sed 's|\.sentspec$||') 149 cksum_val=$(printf "%s" "$SPEC" | cksum | awk '{print $1}') 150 SESSION="sentdev-${basename}-${cksum_val}" 151 152 ensure_workdirs 153 start_tmux 154 } 155 156 main "$@"