From 4ffc8ed795ff58426aea28d3b3b38df1428d2980 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 2 Aug 2026 18:04:34 -0300 Subject: normal Esc toggles document/terminal focus --- src/config.zig | 6 +++--- src/output_pane.zig | 5 +---- src/pardes.zig | 15 ++++++++------- src/tutor.txt | 9 +++++++-- 4 files changed, 19 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/config.zig b/src/config.zig index cee3613e..fed4994a 100644 --- a/src/config.zig +++ b/src/config.zig @@ -769,9 +769,9 @@ pub const redo: []const Chord = &.{.{ .cp = 'U' }}; /// where it is still SIGINT. pub const comment_toggle: []const Chord = &.{.{ .cp = 'c', .ctrl = true }}; -/// Exit select mode / drop pending prefixes and the count; leave insert mode; -/// abandon a tag, an armed search or the topbar. On an OUTPUT buffer there is -/// nothing worth keeping, so Esc there is the Del builtin instead. +/// In body normal mode, clear modal residue and run Toggleterm (the same +/// builtin as `SPC w t`). Elsewhere: leave insert mode; abandon a leader path, +/// tag, armed search or the topbar; raw tty mode forwards it to the program. pub const escape: []const Chord = &.{.{ .cp = Key.escape }}; // ---- insert mode ---- diff --git a/src/output_pane.zig b/src/output_pane.zig index bd11a227..4b62a06e 100644 --- a/src/output_pane.zig +++ b/src/output_pane.zig @@ -105,9 +105,6 @@ pub const Traits = struct { /// that asked for it, lands directly below it and takes its rows from /// there, so opening or closing one never resizes a bystander. doc: bool = false, - /// Esc dismisses it: there is no file behind the pane and nothing worth - /// keeping, so "never mind" means close it — Esc IS the Del its tag offers. - dismiss: bool = true, /// there is a file behind it to write. Also what its tag says: no Save to /// offer means the plain pane tail rather than the file one. saves: bool = false, @@ -116,7 +113,7 @@ pub const Traits = struct { /// A REAL file pane, as a row of the same table — so kind-agnostic code asks /// one question and gets one answer whichever it is holding. `name` is unused: /// a file already has a path. -const file_row: Traits = .{ .name = "", .doc = true, .dismiss = false, .saves = true }; +const file_row: Traits = .{ .name = "", .doc = true, .saves = true }; /// THE TABLE. Everything above, answered from the command that opened the /// buffer. Exhaustive on purpose: a new `lsp.Kind` or a new output-opening diff --git a/src/pardes.zig b/src/pardes.zig index 86dcb97f..7b359f0d 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4151,19 +4151,20 @@ pub const Pardes = struct { const text = p.flatSurface(pane, pl) catch return; const lines = pl.lines; - // Esc: exit select mode / drop pending prefixes + count. The - // selection itself SURVIVES (helix; `;` collapses it) — motions - // replace it anyway. A buffer the table marks `dismiss` (every output - // buffer today) instead takes Esc as "never mind" and closes: Esc IS - // Del, the same builtin its tag offers. + // Esc: the fast document<->terminal hop, running the SAME Toggleterm + // builtin `SPC w t` does. Clear the normal-mode residue it used to + // cancel first: select mode and pending prefixes/count end here, while + // the selection itself SURVIVES (helix; `;` collapses it). Scoped Esc + // meanings (leader/tag/topbar/search cancel, insert -> normal, raw tty + // forwarding) are intercepted in handleKey before this body-normal + // handler and therefore stay unchanged. if (hit(key, config.escape)) { - if (pane.file) |f| if (output_pane.fileTraits(f.output).dismiss) return p.runBuiltin(.Del, p.active, "", null); pane.select = false; pane.pending = 0; pane.pending2 = 0; pane.pending_ch = 0; pane.count = 0; - return; + return p.runBuiltin(.Toggleterm, p.active, "", null); } // count prefix: digits accumulate while no prefix op is in flight // (`0` stays line-start until a count begins) diff --git a/src/tutor.txt b/src/tutor.txt index 71a8fabb..6721e9e8 100644 --- a/src/tutor.txt +++ b/src/tutor.txt @@ -225,7 +225,9 @@ TTY ($) the REAL shell — prompts + typed input shown, and keys go straight to the pty as terminal input. - ESC: insert -> normal. (A plain Esc never reaches tty.) + ESC: insert -> normal; from body NORMAL it hops between the last + document and last terminal (the same Toggleterm as SPC w t). + In raw TTY it still goes to the program. Ctrl-b: toggles TTY on a terminal by default; SHIFT-ESC is the same toggle, where the host reports modifiers on Escape. Those are the ONLY ways in or out. @@ -490,6 +492,8 @@ Ctrl-w h/j/k/l focus the pane left/down/up/right (SPC w h/j/k/l does the same; Ctrl-w also reaches a tty pane, where SPC belongs to the shell) + Esc hop between the last document and last terminal + (body normal mode; the same builtin as SPC w t) Alt-n new terminal below the active one Alt-c move the active terminal into a fresh column @@ -554,12 +558,13 @@ the selection; the mode+path selects but never edits; k off the TOPMOST tagline = the top bar, j back down) zt zz zb Ctrl-d/u Ctrl-f Ctrl-w hjkl Alt-n/c + Esc = last document <-> last terminal (body normal) SPC = the leader: a key path runs a builtin (SPC ? lists them; SPC k Kill, SPC d Del, SPC f s Save, SPC f f Find, SPC w hjkl focus, SPC w t file <-> terminal) vs Helix: no multi-cursor; selection is LINE-first (x), plus v chars. - vs Vim: no verb+noun (dw); motions only move; Esc never reaches tty. + vs Vim: no verb+noun (dw); motions only move; body-normal Esc hops focus. vs both: a terminal is just a pane; the same keys edit text and navigate the shell screen, and the tty toggle reuses the shell's own prompt to position you precisely. -- cgit v1.3