mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-02 19:32:43 +00:00
fix(cli): ghostty-tmux skips pj task sessions; confirm ctrl-c before stopping bg tasks
This commit is contained in:
1 parent
954e1e1ae0
commit
04ade162b4
5 files changed
+20
-16
No files matched your search
@@ -383,7 +383,7 @@ The project root is the git toplevel, else the pane's directory.
|
|||||||
|
|
||||||
**Run.** One-off items open a full-width split along the bottom of the window (`split-window -v -f -l 25%`), 25% of its height, in the task's directory. The command is passed to `split-window` as separate arguments, so no shell reparses it. `--run` calls `pj --run`, which keeps pj's `openlogs` wrapping of `dev`/`start`/`serve`/`watch` tasks, and `--cmd` runs a quick action. While the command runs, <kbd>ctrl-c</kbd> stops only the command (the script traps `SIGINT`), so the output stays. Once the command exits, the script prints `[exit N] enter or ctrl-c to close`, and <kbd>enter</kbd> or <kbd>ctrl-c</kbd> closes the pane; other keys are ignored.
|
**Run.** One-off items open a full-width split along the bottom of the window (`split-window -v -f -l 25%`), 25% of its height, in the task's directory. The command is passed to `split-window` as separate arguments, so no shell reparses it. `--run` calls `pj --run`, which keeps pj's `openlogs` wrapping of `dev`/`start`/`serve`/`watch` tasks, and `--cmd` runs a quick action. While the command runs, <kbd>ctrl-c</kbd> stops only the command (the script traps `SIGINT`), so the output stays. Once the command exits, the script prints `[exit N] enter or ctrl-c to close`, and <kbd>enter</kbd> or <kbd>ctrl-c</kbd> closes the pane; other keys are ignored.
|
||||||
|
|
||||||
**Background.** Long-running items, marked `· background`, are `<pm> run dev`, `docker compose up`, and pj tasks named `dev`/`start`/`serve`/`watch`/`preview` or with one of those as a `:` segment (`dev:web`, `api:dev`). They run through `--bg` in a detached session named `<session>:<tool-and-command>` (`leetcode:bun-run-dev`, `leetcode:docker-compose-up`), shown in a rounded 90%×80% popup attached to it. <kbd>q</kbd> detaches the popup and leaves the task running: the session's `key-table` is `pj-task`, which binds only `q`, so other keys reach the task instead of root-table bindings (prefix bindings still work). <kbd>ctrl-c</kbd> stops the task and ends the session, closing the popup. If the task exits on its own, the `[exit N]` prompt keeps its output until <kbd>enter</kbd>. Picking the item again, or its **Running** entry, reopens the popup instead of starting a second copy. The session has `status off`, `detach-on-destroy on`, and `@pj_task` set to the task's root, which is how the Running group finds it. Session names contain `:`, so the script targets them by id (`$N`).
|
**Background.** Long-running items, marked `· background`, are `<pm> run dev`, `docker compose up`, and pj tasks named `dev`/`start`/`serve`/`watch`/`preview` or with one of those as a `:` segment (`dev:web`, `api:dev`). They run through `--bg` in a detached session named `<session>:<tool-and-command>` (`leetcode:bun-run-dev`, `leetcode:docker-compose-up`), shown in a rounded 90%×80% popup attached to it. <kbd>q</kbd> detaches the popup and leaves the task running: the session's `key-table` is `pj-task`, which binds only `q` and <kbd>ctrl-c</kbd>, so other keys reach the task instead of root-table bindings (prefix bindings still work). <kbd>ctrl-c</kbd> runs `confirm-before` (`Stop <session>? (y/n)`); <kbd>y</kbd> sends ctrl-c to the task, which stops it and ends the session, closing the popup, and any other key cancels. If the task exits on its own, the `[exit N]` prompt keeps its output until <kbd>enter</kbd>. Picking the item again, or its **Running** entry, reopens the popup instead of starting a second copy. The session has `status off`, `detach-on-destroy on`, and `@pj_task` set to the task's root, which is how the Running group finds it. Session names contain `:`, so the script targets them by id (`$N`).
|
||||||
|
|
||||||
**omp.** tmux `prefix a` (Ghostty <kbd>ctrl+shift+a</kbd>) runs `pj-palette --bg <session>:omp <pane cwd> omp`, so omp gets the same kind of background session and Running entry. Its popup docks in the bottom-right corner of the client, 35% wide and 60% tall. omp runs directly (no `[exit N]` prompt) and needs <kbd>q</kbd>, so its session uses the `pj-app` key table instead: <kbd>ctrl-c</kbd> hides the popup, <kbd>ctrl-q</kbd> kills the session (quits omp). `prefix a` inside any session with `@pj_task` also hides, which makes <kbd>ctrl+shift+a</kbd> a toggle. The popup border shows only the session name.
|
**omp.** tmux `prefix a` (Ghostty <kbd>ctrl+shift+a</kbd>) runs `pj-palette --bg <session>:omp <pane cwd> omp`, so omp gets the same kind of background session and Running entry. Its popup docks in the bottom-right corner of the client, 35% wide and 60% tall. omp runs directly (no `[exit N]` prompt) and needs <kbd>q</kbd>, so its session uses the `pj-app` key table instead: <kbd>ctrl-c</kbd> hides the popup, <kbd>ctrl-q</kbd> kills the session (quits omp). `prefix a` inside any session with `@pj_task` also hides, which makes <kbd>ctrl+shift+a</kbd> a toggle. The popup border shows only the session name.
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Ghostty reads both `config` and `config.ghostty`. `config` holds all settings; `
|
|||||||
|
|
||||||
Every Ghostty window gets its own tmux session; no two windows mirror the same one. `~/.local/bin/ghostty-tmux` (source `dot_local/bin/executable_ghostty-tmux`) runs for each new window:
|
Every Ghostty window gets its own tmux session; no two windows mirror the same one. `~/.local/bin/ghostty-tmux` (source `dot_local/bin/executable_ghostty-tmux`) runs for each new window:
|
||||||
|
|
||||||
1. If a detached session exists (left by a closed window, or restored by continuum after a reboot), it attaches to the oldest one.
|
1. If a detached session exists (left by a closed window, or restored by continuum after a reboot), it attaches to the oldest one, by session id. Background task sessions from `pj-palette` (`@pj_task` set, named `<session>:<task>`) are never reclaimed.
|
||||||
2. Otherwise it starts a new session.
|
2. Otherwise it starts a new session.
|
||||||
|
|
||||||
Before starting tmux, the script puts mise's shims on `PATH`. A server started from a desktop-launched Ghostty therefore finds the tools tmux plugins shell out to: bun for the palette, fzf, and zoxide.
|
Before starting tmux, the script puts mise's shims on `PATH`. A server started from a desktop-launched Ghostty therefore finds the tools tmux plugins shell out to: bun for the palette, fzf, and zoxide.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ These settings are what [yazi](/tools/yazi) needs inside tmux. `allow-passthroug
|
|||||||
| `prefix q` | Reload config |
|
| `prefix q` | Reload config |
|
||||||
| `prefix /` | Copy mode, then search upward |
|
| `prefix /` | Copy mode, then search upward |
|
||||||
| `prefix o` | tmux-sessionx: fuzzy-find, switch to, create, rename (`ctrl-r`), or kill (`alt-backspace`) sessions, with a preview |
|
| `prefix o` | tmux-sessionx: fuzzy-find, switch to, create, rename (`ctrl-r`), or kill (`alt-backspace`) sessions, with a preview |
|
||||||
| `prefix t` | Project Tasks palette ([`pj-palette`](/shell/scripts#pj-palette)): install/dev/sync/make/compose quick actions plus every `pj` task. One-off tasks run in a full-width bottom split (25% of the window); dev servers and `docker compose up` run in a background `<session>:<tool-and-command>` session shown in a popup (`q` hides, `ctrl-c` stops), listed under Running to reopen |
|
| `prefix t` | Project Tasks palette ([`pj-palette`](/shell/scripts#pj-palette)): install/dev/sync/make/compose quick actions plus every `pj` task. One-off tasks run in a full-width bottom split (25% of the window); dev servers and `docker compose up` run in a background `<session>:<tool-and-command>` session shown in a popup (`q` hides, `ctrl-c` asks `y/n` then stops), listed under Running to reopen |
|
||||||
| `prefix y` / `prefix e` | Yazi / Neovim in a new window in the pane cwd (Ghostty `ctrl+shift+f` / `ctrl+shift+e`) |
|
| `prefix y` / `prefix e` | Yazi / Neovim in a new window in the pane cwd (Ghostty `ctrl+shift+f` / `ctrl+shift+e`) |
|
||||||
| `prefix g` | Lazygit in a 90% popup in the pane cwd (Ghostty `ctrl+shift+g`) |
|
| `prefix g` | Lazygit in a 90% popup in the pane cwd (Ghostty `ctrl+shift+g`) |
|
||||||
| `prefix a` | omp in a background session `<session>:omp` (pane cwd), shown in a popup docked bottom-right (35% × 60%) and listed in the [omp palette](/shell/scripts#pj-palette) and under Running in the tasks palette. In the popup, `ctrl-c` hides it and `ctrl-q` quits omp. Inside any background-task popup, `prefix a` hides it too, so Ghostty `ctrl+shift+a` toggles omp |
|
| `prefix a` | omp in a background session `<session>:omp` (pane cwd), shown in a popup docked bottom-right (35% × 60%) and listed in the [omp palette](/shell/scripts#pj-palette) and under Running in the tasks palette. In the popup, `ctrl-c` hides it and `ctrl-q` quits omp. Inside any background-task popup, `prefix a` hides it too, so Ghostty `ctrl+shift+a` toggles omp |
|
||||||
@@ -97,7 +97,7 @@ Labels longer than 27 characters end in `…`. The icon comes from tmux-nerd-fon
|
|||||||
| File | Contents |
|
| File | Contents |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `commands.json` | The kitty launchers ported as palette items: **Lazygit** (90% popup in the pane's cwd; kitty `ctrl+shift+g`), **Yazi** (new window; kitty `ctrl+shift+f`), **Neovim Split** (nvim in a split to the left, 60% of the pane; alias `nv`; kitty `ctrl+shift+e`), **Shell History (atuin)** (`atuin-pick` in a 25% split below; kitty `ctrl+shift+p`). Also **btop** (80% popup; aliases `top`, `htop`), **Lazydocker** (90% popup in the pane's cwd; alias `dd`), **mandible** (80% popup running [`mandible-pick`](/shell/scripts#mandible-pick); alias `man`), **television** (`tv channels`, the [channel picker](/tools/television), in a new window in the pane's cwd; alias `tv`), **gitframe** (git diff viewer in a new window in the pane's cwd; alias `gf`), **omp** (opens the omp palette; aliases `agent`, `ai`), **Project Tasks** (opens the tasks palette), **Sessions (sessionx)**, **Save Sessions**, and **Restore Sessions** (resurrect). Programs are started with `exec`, so the tab icon is the program's, not the shell's |
|
| `commands.json` | The kitty launchers ported as palette items: **Lazygit** (90% popup in the pane's cwd; kitty `ctrl+shift+g`), **Yazi** (new window; kitty `ctrl+shift+f`), **Neovim Split** (nvim in a split to the left, 60% of the pane; alias `nv`; kitty `ctrl+shift+e`), **Shell History (atuin)** (`atuin-pick` in a 25% split below; kitty `ctrl+shift+p`). Also **btop** (80% popup; aliases `top`, `htop`), **Lazydocker** (90% popup in the pane's cwd; alias `dd`), **mandible** (80% popup running [`mandible-pick`](/shell/scripts#mandible-pick); alias `man`), **television** (`tv channels`, the [channel picker](/tools/television), in a new window in the pane's cwd; alias `tv`), **gitframe** (git diff viewer in a new window in the pane's cwd; alias `gf`), **omp** (opens the omp palette; aliases `agent`, `ai`), **Project Tasks** (opens the tasks palette), **Sessions (sessionx)**, **Save Sessions**, and **Restore Sessions** (resurrect). Programs are started with `exec`, so the tab icon is the program's, not the shell's |
|
||||||
| `palettes/tasks.json` | The **Project Tasks** palette (`prefix t`, Ghostty `ctrl+shift+p` / `ctrl+shift+space`), fed by [`pj-palette`](/shell/scripts#pj-palette): running background tasks under Running, then `bun install`, `bun run dev`, `uv sync`, `uv run python`, `make`, `go run .`, `cargo run`, `docker compose up` as Quick items when the project has them, then every task `pj` finds, grouped by tool. One-off tasks run in a full-width split along the bottom (25% of the window) in their directory; `ctrl-c` stops a running task, and once it has exited, `enter` or `ctrl-c` closes the pane. Dev servers (`dev`/`start`/`serve`/`watch`/`preview` tasks) and `docker compose up` run in a background session `<session>:<tool-and-command>` shown in a popup: `q` hides it with the task still running, `ctrl-c` stops the task and closes it |
|
| `palettes/tasks.json` | The **Project Tasks** palette (`prefix t`, Ghostty `ctrl+shift+p` / `ctrl+shift+space`), fed by [`pj-palette`](/shell/scripts#pj-palette): running background tasks under Running, then `bun install`, `bun run dev`, `uv sync`, `uv run python`, `make`, `go run .`, `cargo run`, `docker compose up` as Quick items when the project has them, then every task `pj` finds, grouped by tool. One-off tasks run in a full-width split along the bottom (25% of the window) in their directory; `ctrl-c` stops a running task, and once it has exited, `enter` or `ctrl-c` closes the pane. Dev servers (`dev`/`start`/`serve`/`watch`/`preview` tasks) and `docker compose up` run in a background session `<session>:<tool-and-command>` shown in a popup: `q` hides it with the task still running, `ctrl-c` asks `Stop <session>? (y/n)` and on `y` stops the task and closes it |
|
||||||
| `palettes/omp.json` | The **omp** palette, fed by [`pj-palette --omp`](/shell/scripts#pj-palette): this tmux session's `<session>:omp` (open it, or start it when not running), every other tmux session's running omp, and a Quit item per session. Running agents have a green icon and show `open` or `hidden` |
|
| `palettes/omp.json` | The **omp** palette, fed by [`pj-palette --omp`](/shell/scripts#pj-palette): this tmux session's `<session>:omp` (open it, or start it when not running), every other tmux session's running omp, and a Quit item per session. Running agents have a green icon and show `open` or `hidden` |
|
||||||
| `hidden.json` | Hides the built-in **Switch Theme...** item, and with it the Appearance section: the palette stays on the fixed cyberdream `theme.json` |
|
| `hidden.json` | Hides the built-in **Switch Theme...** item, and with it the Appearance section: the palette stays on the fixed cyberdream `theme.json` |
|
||||||
| `shortcuts.json` | Ghostty `ctrl+shift` chords shown next to the built-in items they trigger (New Window → `Ctrl+Shift+T`, …) |
|
| `shortcuts.json` | Ghostty `ctrl+shift` chords shown next to the built-in items they trigger (New Window → `Ctrl+Shift+T`, …) |
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
# Ghostty's `command`: every Ghostty window gets its own tmux session, never
|
# Ghostty's `command`: every Ghostty window gets its own tmux session, never
|
||||||
# a mirror of another window's. Reclaim the oldest detached session (left by
|
# a mirror of another window's. Reclaim the oldest detached session (left by
|
||||||
# a closed window, or restored by tmux-continuum after a reboot) so closed
|
# a closed window, or restored by tmux-continuum after a reboot) so closed
|
||||||
# windows don't pile up sessions; otherwise start a new one. The first window
|
# windows don't pile up sessions; otherwise start a new one. pj-palette's
|
||||||
# after boot starts the server, which is what triggers continuum's restore.
|
# background task sessions (@pj_task, named <session>:<task>) are never
|
||||||
|
# reclaimed, and targets use the session id since names may contain ':'.
|
||||||
|
# The first window after boot starts the server, which is what triggers
|
||||||
|
# continuum's restore.
|
||||||
# ponytail: two windows opened in the same instant can claim the same detached
|
# ponytail: two windows opened in the same instant can claim the same detached
|
||||||
# session; take a lock (flock) here if that ever bites.
|
# session; take a lock (flock) here if that ever bites.
|
||||||
|
|
||||||
@@ -12,8 +15,8 @@
|
|||||||
# (bun for tmux-palette, fzf, zoxide).
|
# (bun for tmux-palette, fzf, zoxide).
|
||||||
[[ -d $HOME/.local/share/mise/shims ]] && PATH="$HOME/.local/share/mise/shims:$PATH"
|
[[ -d $HOME/.local/share/mise/shims ]] && PATH="$HOME/.local/share/mise/shims:$PATH"
|
||||||
|
|
||||||
oldest=$(tmux list-sessions -f '#{==:#{session_attached},0}' \
|
oldest=$(tmux list-sessions -f '#{&&:#{==:#{session_attached},0},#{!:#{@pj_task}}}' \
|
||||||
-F '#{session_created} #{session_name}' 2>/dev/null | sort -n | head -1 | cut -d' ' -f2-)
|
-F '#{session_created} #{session_id}' 2>/dev/null | sort -n | head -1 | cut -d' ' -f2)
|
||||||
|
|
||||||
[[ -n $oldest ]] && exec tmux attach-session -t "=$oldest"
|
[[ -n $oldest ]] && exec tmux attach-session -t "$oldest"
|
||||||
exec tmux new-session
|
exec tmux new-session
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
# Long-running items (dev/start/serve/watch/preview tasks, compose up) run in a
|
# Long-running items (dev/start/serve/watch/preview tasks, compose up) run in a
|
||||||
# detached session named <session>:<tool-and-command> (leetcode:bun-run-dev),
|
# detached session named <session>:<tool-and-command> (leetcode:bun-run-dev),
|
||||||
# shown in a popup: q hides the popup and leaves the task running, ctrl-c
|
# shown in a popup: q hides the popup and leaves the task running, ctrl-c
|
||||||
# stops the task and ends its session. Running ones are listed first, under
|
# asks for confirmation, then stops the task and ends its session. Running
|
||||||
# Running, to bring them back. tmux.conf's prefix + a starts omp the same way
|
# ones are listed first, under Running, to bring them back. tmux.conf's
|
||||||
# (<session>:omp); omp needs q, so its popup hides with ctrl-c (or prefix + a)
|
# prefix + a starts omp the same way (<session>:omp); omp needs q, so its
|
||||||
# and ctrl-q quits it.
|
# popup hides with ctrl-c (or prefix + a) and ctrl-q quits it.
|
||||||
|
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
self=$(readlink -f "$0")
|
self=$(readlink -f "$0")
|
||||||
@@ -86,10 +86,11 @@ case ${1-} in
|
|||||||
set -t "$id" detach-on-destroy on
|
set -t "$id" detach-on-destroy on
|
||||||
# Each session gets a key table for its hide/quit keys; other keys
|
# Each session gets a key table for its hide/quit keys; other keys
|
||||||
# reach the program. A task's output takes no input, so q hides and
|
# reach the program. A task's output takes no input, so q hides and
|
||||||
# ctrl-c stops the task. Interactive programs (omp) need q and typing,
|
# ctrl-c (after a y/n confirm) stops the task. Interactive programs
|
||||||
# so ctrl-c hides and ctrl-q kills the session.
|
# (omp) need q and typing, so ctrl-c hides and ctrl-q kills the session.
|
||||||
if [ "$1" = "$self" ]; then
|
if [ "$1" = "$self" ]; then
|
||||||
tmux set -t "$id" key-table pj-task \; bind -T pj-task q detach-client
|
tmux set -t "$id" key-table pj-task \; bind -T pj-task q detach-client \; \
|
||||||
|
bind -T pj-task C-c confirm-before -p 'Stop #{session_name}? (y/n)' 'send-keys C-c'
|
||||||
else
|
else
|
||||||
tmux set -t "$id" key-table pj-app \; bind -T pj-app C-c detach-client \; \
|
tmux set -t "$id" key-table pj-app \; bind -T pj-app C-c detach-client \; \
|
||||||
bind -T pj-app C-q kill-session
|
bind -T pj-app C-q kill-session
|
||||||
|
|||||||
Reference in new issue
Block a user