diff --git a/dot_local/bin/executable_pj-palette b/dot_local/bin/executable_pj-palette new file mode 100755 index 0000000..ef11e14 --- /dev/null +++ b/dot_local/bin/executable_pj-palette @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# pj-palette — pj's task runner as a tmux-palette source (the "tasks" palette, +# ~/.config/tmux-palette/palettes/tasks.json). +# +# pj-palette print palette items (JSON) for the active pane's +# project: quick actions (install, dev, sync, make, +# …) and every task `pj --list` finds +# pj-palette --run KIND TARGET ROOT RUNNER +# run a pj task (the item's action) +# pj-palette --cmd ROOT CMD… +# run a quick-action command in ROOT +# +# Every item opens a new tmux window in the project root. The command runs in +# the foreground; when it exits the window keeps a shell (with the output +# above it) instead of closing. + +set -uo pipefail +self=$(readlink -f "$0") + +finish() { + local status=$1 + printf '\n\033[2m[exit %s]\033[0m\n' "$status" + exec "${SHELL:-bash}" +} + +case ${1-} in +--run) + shift + pj --run "$@" + finish $? + ;; +--cmd) + cd "$2" || exit 1 + shift 2 + printf '→ %s\n' "$*" >&2 + "$@" + finish $? + ;; +esac + +have() { command -v "$1" >/dev/null 2>&1; } +cwd=$(tmux display -p '#{pane_current_path}' 2>/dev/null) || cwd=$PWD +cd "$cwd" || exit 1 +root=$(git rev-parse --show-toplevel 2>/dev/null) || root=$cwd + +icon_for() { + case $1 in + bun) printf '' ;; + npm | yarn) printf '' ;; + pnpm) printf '' ;; + make) printf '' ;; + go) printf '' ;; + cargo) printf '' ;; + uv | py | poe | pdm | rye | taskipy | hatch | script) printf '' ;; + *) printf '' ;; + esac +} + +# tmux action that opens a new window in DIR running ARGV directly (no shell, +# so nothing is re-parsed by fish). The palette wrapper evals the string in +# bash, hence %q. +window_action() { + local dir=$1 + shift + local q + q=$(printf '%q ' "$@") + printf 'new-window -c %q %s' "$dir" "$q" +} + +items=() +item() { # category icon title description aliases(csv) tmux-action + items+=("$(jq -cn --arg c "$1" --arg i "$2" --arg t "$3" --arg d "$4" --arg a "$5" --arg x "$6" \ + '{category: $c, icon: $i, title: $t, description: $d, + aliases: ($a | split(",") | map(select(. != ""))), action: {tmux: $x}}')") +} +quick() { # icon title aliases dir argv… + local icon=$1 title=$2 aliases=$3 dir=$4 + shift 4 + item Quick "$icon" "$title" "in ${dir/#$HOME/~}" "$aliases" "$(window_action "$dir" "$self" --cmd "$dir" "$@")" +} + +# ── Quick actions, from the files at the project root ───────────────────── +if [ -f "$root/package.json" ]; then + pm=$(jq -r '.packageManager // empty' "$root/package.json" 2>/dev/null) + pm=${pm%%@*} + if [ -z "$pm" ]; then + if [ -f "$root/bun.lock" ] || [ -f "$root/bun.lockb" ]; then pm=bun + elif [ -f "$root/pnpm-lock.yaml" ]; then pm=pnpm + elif [ -f "$root/yarn.lock" ]; then pm=yarn + else pm=npm + fi + fi + if have "$pm"; then + quick "$(icon_for "$pm")" "$pm install" "install,i" "$root" "$pm" install + jq -e '.scripts.dev' "$root/package.json" >/dev/null 2>&1 && + quick "$(icon_for "$pm")" "$pm run dev" "dev" "$root" "$pm" run dev + fi +fi +if [ -f "$root/pyproject.toml" ] && have uv; then + quick "$(icon_for uv)" "uv sync" "sync,install" "$root" uv sync + quick "$(icon_for uv)" "uv run python" "py,repl" "$root" uv run python +fi +if have make && { [ -f "$root/Makefile" ] || [ -f "$root/makefile" ] || [ -f "$root/GNUmakefile" ]; }; then + quick "$(icon_for make)" "make" "m,build" "$root" make +fi +[ -f "$root/go.mod" ] && have go && quick "$(icon_for go)" "go run ." "run" "$root" go run . +[ -f "$root/Cargo.toml" ] && have cargo && quick "$(icon_for cargo)" "cargo run" "run" "$root" cargo run + +# ── Every task pj finds (npm/bun/pnpm scripts, make, just, mise, devbox, +# pyproject task tables and console scripts) ───────────────────────────── +while IFS=$'\t' read -r display kind target troot runner _file; do + [ -n "$kind" ] || continue + tag=${display%% *} + desc="$runner $target" + [ "$troot" != "$root" ] && desc+=" (${troot#"$root"/})" + item "Tasks: $tag" "$(icon_for "$tag")" "$target" "$desc" "" \ + "$(window_action "$troot" "$self" --run "$kind" "$target" "$troot" "$runner")" +done < <(PJ_QUIET=1 pj --list 2>/dev/null) + +if [ ${#items[@]} -eq 0 ]; then + item Tasks '' "No tasks found" "in ${cwd/#$HOME/~}" "" "display-message 'pj: no task sources here'" +fi +printf '%s\n' "${items[@]}" | jq -s .