mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-26 21:36:31 +02:00
tweak(tui): ctrl+c no longer interrupts a running turn
A single ctrl+c during a busy turn used to cancel the turn
(same as esc). That misfired a lot in practice because ctrl+c
is reflex muscle-memory ("be quiet" in a shell) rather than a
deliberate decision to kill a multi-minute model call you have
already paid tokens for. Users kept aborting expensive turns by
accident.
New behavior:
- busy + first ctrl+c -> arms the exit hint, status line
reads "press ctrl+c again to exit,
esc to cancel the turn"; the turn
keeps running.
- busy + second ctrl+c (within ctrlCExitWindow = 2s)
-> exits zot.
- busy + esc -> cancels the running turn (unchanged).
- idle + ctrl+c -> clears editor/queue as before;
second press within 2s exits.
The double-tap-to-exit pattern now works the same from busy and
idle, which also matches the habits from python repls and
similar tools.
Also:
- assistant body keeps a 4-cell right gutter that mirrors the
4-space left indent so wrapped prose sits in a symmetric
column instead of kissing the terminal edge on ultra-wide
windows. The prose cap itself is gone; the new
assistantBodyRightPad constant replaces maxAssistantWidth.
- README Keys table + Queued messages paragraph updated to
describe the new ctrl+c / esc split so the docs match the
code.
This commit is contained in:
parent
5a70030bb6
commit
13b8947fba
3 changed files with 29 additions and 24 deletions
|
|
@ -274,7 +274,7 @@ Frames containing images are full-repainted (no differential diff) to prevent st
|
|||
|
||||
## Queued messages
|
||||
|
||||
You can keep typing while the agent is working. Pressing `enter` during a turn queues the message instead of interrupting: it shows up above the status bar as `sliding in: <text>` and is delivered as the next user turn the moment the current one finishes. Queue as many as you want; they run in order. `esc` or `ctrl+c` cancels the active turn and drops the queue so a runaway turn doesn't flood you with stale follow-ups.
|
||||
You can keep typing while the agent is working. Pressing `enter` during a turn queues the message instead of interrupting: it shows up above the status bar as `sliding in: <text>` and is delivered as the next user turn the moment the current one finishes. Queue as many as you want; they run in order. `esc` cancels the active turn and drops the queue so a runaway turn doesn't flood you with stale follow-ups; `ctrl+c` while busy arms the exit hint instead of interrupting, a second `ctrl+c` within two seconds exits zot.
|
||||
|
||||
Slash commands also work while the agent is busy. Read-only ones (`/help`, `/jump`, `/btw`, `/sessions`, `/skills`, `/jail`, `/unjail`, `/exit`) take effect immediately. Destructive ones (`/clear`, `/compact`, `/login`, `/logout`, `/model`, `/reload-ext`) cancel the active turn first and then run.
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ Slash commands also work while the agent is busy. Read-only ones (`/help`, `/jum
|
|||
| `alt+enter` | Newline. |
|
||||
| `tab` | Complete the selected slash command. |
|
||||
| `esc` | Cancel the current turn (while busy); clear input (while idle). |
|
||||
| `ctrl+c` | Clear the input and queue (or cancel the current turn). Press again within 2s to exit. |
|
||||
| `ctrl+c` | Clear the input and queue (while idle) or arm the exit hint (while busy). Press again within 2s to exit. Use `esc` to cancel a running turn. |
|
||||
| `ctrl+d` | Exit on empty input. |
|
||||
| `ctrl+l` | Redraw the screen. |
|
||||
| `ctrl+o` | Expand or collapse long tool results (read, write, edit, bash outputs over ~12 lines). |
|
||||
|
|
|
|||
|
|
@ -1040,11 +1040,22 @@ func (i *Interactive) handleKey(ctx context.Context, k tui.Key) (done bool) {
|
|||
// Global keys.
|
||||
switch k.Kind {
|
||||
case tui.KeyCtrlC:
|
||||
// While busy: cancel the active turn (same as esc). The exit
|
||||
// hint stays armed so a quick second ctrl+c after the turn
|
||||
// dies still exits, matching habits from other repls.
|
||||
if i.busy && i.cancelTurn != nil {
|
||||
i.cancelTurn()
|
||||
// While busy: do NOT cancel the turn. ctrl+c during a
|
||||
// running turn is almost always reflex muscle memory
|
||||
// ("be quiet" in a shell) rather than a deliberate
|
||||
// decision to kill a multi-minute model call that's
|
||||
// already cost tokens. Use esc to interrupt a turn; use
|
||||
// a deliberate double-ctrl+c to exit zot entirely. First
|
||||
// press arms the exit hint, second press within
|
||||
// ctrlCExitWindow quits.
|
||||
if i.busy {
|
||||
if i.ctrlCExitArmed() {
|
||||
return true
|
||||
}
|
||||
i.mu.Lock()
|
||||
i.statusOK = "press ctrl+c again to exit, esc to cancel the turn"
|
||||
i.statusErr = ""
|
||||
i.mu.Unlock()
|
||||
i.armCtrlCExit()
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,26 +367,20 @@ const (
|
|||
fnv64aPrime uint64 = 0x100000001b3
|
||||
)
|
||||
|
||||
// maxAssistantWidth caps the rendered width of assistant prose
|
||||
// (and the code fences embedded in it) in both the finalised
|
||||
// transcript and the streaming overlay. Unbounded lines on
|
||||
// ultra-wide terminals (300+ columns) produce prose that's hard
|
||||
// to read and rule strokes that run edge-to-edge in the window.
|
||||
// Tool output (read, bash, edit diffs) is unaffected — it
|
||||
// deliberately uses the full width so long paths and diff rows
|
||||
// aren't artificially truncated.
|
||||
const maxAssistantWidth = 120
|
||||
// assistantBodyRightPad is the blank gutter kept on the right
|
||||
// side of every assistant prose line so text doesn't kiss the
|
||||
// terminal edge. Matches the 4-cell left indent, so a line of
|
||||
// fully-wrapped prose sits in a symmetric column.
|
||||
const assistantBodyRightPad = 4
|
||||
|
||||
// assistantBodyWidth returns the usable width for the assistant
|
||||
// message body (markdown prose + code fence rules), clamped at
|
||||
// maxAssistantWidth and at 1 so wrap helpers don't divide by
|
||||
// zero on absurdly narrow terminals. outer is the total width
|
||||
// of the column the body will sit inside (the terminal width
|
||||
// minus any surrounding indent).
|
||||
// message body (markdown prose + code fences). Uses the full
|
||||
// column width passed in minus assistantBodyRightPad, clamped
|
||||
// at 1 so wrap helpers don't divide by zero on absurdly narrow
|
||||
// terminals. The right-side padding keeps a small breathing
|
||||
// column to the terminal edge that mirrors the left indent.
|
||||
func assistantBodyWidth(outer int) int {
|
||||
if outer > maxAssistantWidth {
|
||||
return maxAssistantWidth
|
||||
}
|
||||
outer -= assistantBodyRightPad
|
||||
if outer < 1 {
|
||||
return 1
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue