Skip to content

Opt in to shared native Vim editing and navigation - #664

Merged
trissim merged 21 commits into
mainfrom
feat/vim-navigation
Oct 16, 2026
Merged

trissim merged 21 commits into
mainfrom
feat/vim-navigation

Conversation

@trissim

@trissim trissim commented Oct 15, 2026 •

Copy link
Copy Markdown

Opt-in native Vim editing, navigation and hints

Merged, installed by Codex, and hints/copy/navigation verified in the actual app: Toad main e8716b963a02f0844d4696ed6d5eb6e35b3a9dbf, pinned Textual 18f4e7a67403d56846ef5abf55c93e3e0639be33 (Textual main merge 2d3aecb5106db6e0048d8b8ec21a9837f6d7f64b). Current main's CLI changes retained by ordinary conflict-free merge.

Installed acceptance (10603)

Real ~/.local/bin/toad, plain st on isolated :278, published e871/Core2209/native6468 runtime; no source overlay. Existing running toad-ui-2 saved history, copied opt-in config, no model input or new participant. Menu hint reopening visibly went 2→0→2→0→2 at 250 ms intervals. Hint a opened the real export dialog; with its two hints visible, a pointer click focused the path Input and focus remained there in a later capture. Hint s cancelled the dialog without exporting. These close the two prior preview coverage gaps.

Visual 0/w/v/e selected beta and y copied exactly beta to the isolated system clipboard. Native Home/Shift+End and Ctrl+C copied the whole draft without clearing it. Edit/undo restored it. Ctrl+U/D navigated saved history, G returned latest, i returned to editing. Own original empty draft restored before Ctrl+Q; frontend/ACP/pool/display all closed, participant retained.

Evidence: .artifacts/vim/live-installed-e871-normal/OWNER, menu-cleared/reopened-{1,2}.png, dialog-active-at-click.png, dialog-click-focus{,-settled}.png, visual-word-selection.png, copied-word.txt, native-selected-copy.png, copied-native-selected.txt, vim-page-{up,down}.png. The workspace-active-at-click image has no labels and is not used as active-hint proof. Initial inherited-PATH failed launch and mistaken Ctrl+A/Home assumption are retained separately, not passed off as successes. No automated tests, performance claim, forced scheduler interleaving or exhaustive Vim/IME claim.

Single-owner hint repair (10285)

The old duplication was stupid: Screen kept a session pointer alongside native children, while HintSession repeated its targets in three collections. HintHost now supplies the three Screen hint methods through C3 and queries direct native children. The session pointer and targets/choices arrays are deleted; each label owns its target and its existing Static content supplies its key. Activation owns decoding exposed paint; the compositor retains published-geometry ownership.

Also removed a real bad dependency: the supposed immediate focus restoration used Widget.focus(), which queues a callback. HintSession now uses Screen.set_focus() immediately, so restoration does not enqueue a later overwrite of pointer focus.

Before/after source queries: .artifacts/vim/owner-repair-{before,after}.txt, 283 Toad / 254 Textual modules, no parse omissions. Imports and actual Screen/Workspace C3 hooks were checked. Shepherd reviewed this change in 10382. Original receiving commands were rerun: both still exit 1 with the installed heuristic checker; results remain in owner-repair-{toad,textual}-ratchet.json. Slop-census owns the separate checker correction; no thresholds, exemptions or product spelling changed to hide counts.

Plain st/:278 source preview using the existing running toad-ui-2 saved session, without model input: hints appeared; Settings removed them and return left no stale hints; reopening produced one visible label set; clicking the prompt left it visibly focused. This is not an installed-launcher check or a forced click/late-callback race. Screenshots in .artifacts/vim/live-owner-repair/, especially hints-settled.png, settings-painted.png, modal-physical-return.png, reopen-valid-escape-immediate.png, actual-click-settled.png. Initial read-only remote observations preceded the instruction to stop that inspection; later checks used only physical keys/pointer and screenshots. Early fast Escape/f sequences were ambiguous under the native 100 ms ESC delay; the separated-key run is retained too. No zero-ratchet or installed-app claim.

Earlier implementation and verification

Paired with OpenHCSDev/textual#134. Integration head: Toad 8c264fb0478354def9089ff8234eaef0f4cec79f, pinned Textual 9a18a0f0fe41a2d5edde25f9e2371de1c3877559 in both project and lock metadata. Normally merged main b28e368c6, including #668. The sole conflict was the HistoricalSessions import block: kept main's Contents migration and the shared Toad ModalScreen import. Broad editor checks were on 4a374eb89; the latest exact pair also has source-candidate modal-retirement verification, described below. The #668 merge itself has static/import preservation evidence, not archive acceptance. The size-review gate is deleted. Per 10261, Codex merges and installs this Vim pair FIRST, before the separate Forms changes (#670/#135). Source review of this pair is closed; normal-launcher behavior after installation remains unverified.

Ownership

  • ui.vim-keys remains default false. Enabled prompts start Insert; Normal Enter does not submit. The native TextArea retains its original document, selection and EditHistory, including across tab returns.
  • Application bindings derive from ApplicationAction; native action namespaces belong to the declarations. Navigation borrows the existing scroll/latest/focus/tab effects. No second key engine or maintained action roster.
  • One shared Toad ModalScreen supplies the declared, nonpriority hint binding to all 16 modal consumers. Input, popup and terminal key custody remain native.
  • Primary activation declarations borrow original effects across tabs, rows, disclosures, menu items, prompt controls and history controls. Pointer and hint effects are shared; no forged click events. Unavailable history controls use native disabled state, not CSS as authority.
  • PromptTextArea.can_enter_shell consumes submission_allowed, so Normal/pending modes and active popups cannot enter shell. Paste never invokes the key action. Prompt remains the shell_mode owner.
  • Ctrl+C's existing prompt action now arbitrates native selected-text copy before draft clearing. Merely declining Clear is insufficient: native DOM binding inheritance shadows the inherited Ctrl+C entry. The replacement action calls native action_copy, not another clipboard implementation.
  • Ctrl+Alt+X borrows existing cancellation eligibility and confirmation; Escape remains local. Submission/publication still owns delivery and clearing.

Source evidence

Existing refactor-audit Package census: 283 Toad / 254 Textual modules, zero parse omissions. Before/after evidence under .artifacts/vim/{owners-before,admission-before,owners-final}.txt; .artifacts/vim/main-668-merge.txt compares main's definitions with the merged source: no main functions removed, all #668 preparation/category/destination functions unchanged, only previously reviewed Vim key/cancel and shared scroll delegations differ; selection and activation family searches are alongside them. Includes imports, inheritance, declarations and consumers. Computed callbacks, generic available attributes and binding/MRO resolution require semantic reading and physical verification, not AST inference.

Owner searches:

  • rg -n 'def can_enter_shell|class CopyOrClearInputAction|from textual.screen import ModalScreen' src/toad: one eligibility declaration, one Ctrl+C arbitration action, one native-modal import at the shared base.
  • rg -n 'editing_mode:|_word_pattern' ../textual-vim/src/textual: one active TextArea reactive declaration plus its explicit retained-state transfer field; word regex owned by DocumentNavigator.

Physical source-candidate verification

Plain st on owned isolated display :278, copied configuration, configured native provider and a fresh fork of saved history. This is not installed-PATH acceptance.

  • Native Insert submission reached configured openai-codex/gpt-6.1-sol, returned VIM9142, and became Ready. Normal Enter kept the draft. Active f/r-pending cancellation used the existing confirmation; the g check cancelled queued input only. Evidence: .artifacts/vim/live-native/ and native-acceptance/.
  • Latest candidate: inclusive Visual Ctrl+C copied exactly v; Insert selection copied exactly retained; unselected Ctrl+C cleared; undo restored a cleared draft. Normal/pending ! did not enter shell, pasted leading ! remained text, physical Insert ! entered shell.
  • Confirmed actual ShellTerminal focus, then f/j/k/g reached a local head -n 1 process and its output; the child exited. No navigation/hint interception while terminal-focused.
  • Global hints opened the original menu; modal hints opened the export dialog and activated native Cancel. No export-effect acceptance claimed. Disabled back/forward controls were not offered; a wheel/pointer journey retired active hints.
  • Ctrl+G opened the comms tab; K returned with draft and Normal mode intact; native undo removed the retained insertion.
  • Earlier candidate checks cover slash popup Enter/Escape, committed Unicode, image paste, typed clipboard provenance, resize dismissal and styled-link activation.

Latest screenshots/clipboard bytes: .artifacts/vim/live-final-controls/; ordinary-profile literal-key/clear checks: live-ordinary/. Failed exploratory captures remain preserved. Literal !cat and an early terminal probe reached the verification agent before shell entry/focus was established; both attempts and replies are retained, not replayed. Original uncertain a and older UNKNOWN inputs remain untouched. Older live-native/st.log contains four free(): invalid pointer warnings while the app remained usable; latest live-final-controls/st.log has none. Raw logs retained, no causal attribution claimed.

Earlier mount-pointer correction (9292, replaced above)

Screen now calls native mount, records custody before awaiting it, and focuses afterward only if custody still matches, the session is not disabled, and this is App.screen. Native Screen.is_current includes visible modal backdrops, so it is not the active-screen authority. No new flag or competing retirement path.

Exact latest source pair, existing running toad-ui-2 participant, plain st/:278, no new agent or model input: before F2, one focused HintSession / 46 labels; while Settings was active, Workspace custody null / zero sessions / zero labels; after Escape returned, still null/zero/zero and focus was not a HintSession. Evidence: .artifacts/vim/live-hint-custody-final/{states.jsonl,hints-before-modal.png,modal-open.png,modal-return.png}. Before/after source census: hint-custody-{before,after}.txt, 283 Toad / 254 Textual modules, zero parse omissions. No forced mount/suspend interleaving claimed. Preview closed afterward; existing participant and blocked goal untouched.

Delivery order (10261)

This pair goes first: Toad #664 8c264fb0478354def9089ff8234eaef0f4cec79f and Textual #134 9a18a0f0fe41a2d5edde25f9e2371de1c3877559. The previous Forms-first instruction is superseded. Forms is not required for this Vim change; its remaining source defects stay with its existing owner.

Codex owns merging current main normally, retaining the current Core/schema changes, and building the resulting exact pair into a fresh output path. Do not downgrade the installed application to an older base or replay the uncertain build. Provider inputs remain untouched.

The required installed journey covers ordinary-profile literal keys; enabled Insert/Normal submission; native copy/paste/undo; popup and terminal key handling; hints across modal open/return; cancellation through the existing confirmation; and retained draft/mode/history on tab return. The earlier app observations above are source previews, not proof that the normal launcher works after installation.

Remaining boundary

Ready for Codex integration and installation, followed by normal-launcher verification. No automated tests, fixtures, fake responses, synthetic apps, build or installation performed by this worker. No frame-time/performance acceptance, full IME composition, true oldest-history gg, full Vim, arbitrary widget activation, or exhaustive stale-target/stream/retirement matrix claimed. Hints cover declared primary/style targets; they do not invent effects for every native control.

@trissim
trissim marked this pull request as ready for review October 16, 2026 01:16
Copilot AI balanced review requested due to automatic review settings October 16, 2026 01:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@trissim
trissim merged commit e8716b9 into main Oct 16, 2026
@trissim
trissim deleted the feat/vim-navigation branch October 17, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants