Created
October 28, 2025 20:18
-
-
Save baldwindavid/4c4095ac09c663d9ace93f5efac247aa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Wrapper around zellij run that adds move-or-create behavior for directional panes | |
| # Usage: run.sh [OPTIONS] -- <command> [args...] | |
| # | |
| # Accepts all zellij run options. Key options: | |
| # --floating Open in a floating pane | |
| # --direction <dir> Open in direction (up, down, left, right) | |
| # --close-on-exit Close pane when command exits | |
| # --name <name> Name the pane | |
| # --cwd <path> Set working directory | |
| # | |
| # For --direction, will reuse existing pane if one exists in that direction, | |
| # otherwise creates a new pane. | |
| # | |
| # Caches the last command per-directory for rerun functionality. | |
| set -e | |
| # Cache the command for rerun functionality | |
| CACHE_DIR="/tmp/helix_last_command_$USER" | |
| mkdir -p "$CACHE_DIR" | |
| # Use PWD hash for per-directory caching (portable across macOS and Linux) | |
| if command -v md5sum &> /dev/null; then | |
| PWD_HASH=$(echo -n "$PWD" | md5sum | cut -d' ' -f1) | |
| elif command -v md5 &> /dev/null; then | |
| PWD_HASH=$(echo -n "$PWD" | md5) | |
| else | |
| # Fallback: use base64-encoded path (less elegant but works everywhere) | |
| PWD_HASH=$(echo -n "$PWD" | base64 | tr -d '=\n' | tr '/' '_') | |
| fi | |
| CACHE_FILE="$CACHE_DIR/$PWD_HASH" | |
| # Save all args and PWD to cache file | |
| cache_command() { | |
| { | |
| echo "PWD=$PWD" | |
| echo -n "ARGS=(" | |
| printf '%q ' "$@" | |
| echo ")" | |
| } > "$CACHE_FILE" | |
| } | |
| # Cache the command with all original arguments | |
| cache_command "$@" | |
| # Parse args to find --floating or --direction | |
| is_floating=false | |
| direction="" | |
| remaining_args=() | |
| while [ "$#" -gt 0 ]; do | |
| case "$1" in | |
| --floating|-f) | |
| is_floating=true | |
| remaining_args+=("$1") | |
| shift | |
| ;; | |
| --direction|-d) | |
| direction="$2" | |
| remaining_args+=("$1" "$2") | |
| shift 2 | |
| ;; | |
| *) | |
| remaining_args+=("$1") | |
| shift | |
| ;; | |
| esac | |
| done | |
| # For floating, add default size/position if not specified, then delegate to zellij run | |
| if [ "$is_floating" = true ]; then | |
| # Check if user specified dimensions/position | |
| has_width=false | |
| has_height=false | |
| has_x=false | |
| has_y=false | |
| for arg in "${remaining_args[@]}"; do | |
| case "$arg" in | |
| --width) has_width=true ;; | |
| --height) has_height=true ;; | |
| --x|-x) has_x=true ;; | |
| --y|-y) has_y=true ;; | |
| esac | |
| done | |
| # Build default args for large centered floating pane (90% width/height, centered at 5%/5%) | |
| default_args=() | |
| [ "$has_width" = false ] && default_args+=(--width "90%") | |
| [ "$has_height" = false ] && default_args+=(--height "90%") | |
| [ "$has_x" = false ] && default_args+=(--x "5%") | |
| [ "$has_y" = false ] && default_args+=(--y "5%") | |
| exec zellij run --cwd "$PWD" "${default_args[@]}" "${remaining_args[@]}" | |
| fi | |
| # If no direction specified, delegate to zellij run (it will pick best location) | |
| if [ -z "$direction" ]; then | |
| exec zellij run --cwd "$PWD" "${remaining_args[@]}" | |
| fi | |
| # For directional targets, implement move-or-create behavior | |
| # Get current focused pane ID before moving | |
| pane_before=$(zellij action list-clients | tail -n +2 | head -n 1 | awk '{print $2}') | |
| # Try to move in the specified direction | |
| zellij action move-focus "$direction" | |
| # Get focused pane ID after moving | |
| pane_after=$(zellij action list-clients | tail -n +2 | head -n 1 | awk '{print $2}') | |
| # Remove --direction from remaining_args since we'll replace it | |
| final_args=() | |
| skip_next=false | |
| for arg in "${remaining_args[@]}"; do | |
| if [ "$skip_next" = true ]; then | |
| skip_next=false | |
| continue | |
| fi | |
| if [ "$arg" = "--direction" ] || [ "$arg" = "-d" ]; then | |
| skip_next=true | |
| continue | |
| fi | |
| final_args+=("$arg") | |
| done | |
| # If pane IDs are different, we moved to an existing pane - write command to it | |
| # If same, create new pane in that direction | |
| # NOTE: --close-on-exit and other zellij run flags only affect newly created panes. | |
| # Existing panes retain their original behavior regardless of flags passed to this script. | |
| if [ "$pane_before" != "$pane_after" ]; then | |
| # Existing pane - extract the command after "--" and write it | |
| # Find the command after "--" | |
| found_separator=false | |
| command_parts=() | |
| for arg in "${final_args[@]}"; do | |
| if [ "$found_separator" = true ]; then | |
| command_parts+=("$arg") | |
| elif [ "$arg" = "--" ]; then | |
| found_separator=true | |
| fi | |
| done | |
| # Build the command string | |
| command_str="${command_parts[*]}" | |
| # Write command to the existing pane | |
| zellij action write-chars "cd '$PWD' && $command_str" | |
| zellij action write 13 # Send enter | |
| else | |
| # No pane exists - create new one | |
| exec zellij run --direction "$direction" --cwd "$PWD" "${final_args[@]}" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment