Skip to content

Repair installed Neovim input and document projection - #1343

Merged
trissim merged 6 commits into
mainfrom
work/vim-neovim-live-input
Oct 30, 2026
Merged

trissim merged 6 commits into
mainfrom
work/vim-neovim-live-input

Conversation

@trissim

@trissim trissim commented Oct 30, 2026 •

Copy link
Copy Markdown

Summary — installed Neovim repair

6 files, +150/-17; 4 production files +22/-16, 2 existing control files +128/-1. Three repair commits with current-main integration; published head 5989377, remote-verified, checkout clean. Continues P928 after #1320 merged as 36719ff22. No revert, old Textual pin, compatibility layer or handwritten Vim replacement.

The installed engine had three wrong decisions: refresh size before its cursor was projected; await a native reply in every editor key handler; classify app shortcuts as ordinary late bindings. This PR deletes those decisions at their existing owners. STANDARD is already declared; its settings shortcut was in the same late app-binding family. Source delivery, not runtime qualification, merged status or an installation claim.

1. Document and cursor publish together

Before: NeovimEditing.publish applied line changes and called finish_projection, whose TextArea size refresh could synchronously inspect the old second-line cursor. The cursor changed only later in render. Installed traceback: WorkerFailed_2026-10-29T21_22_43_167780.txt, line index 1 outside a one-line document.

After:

DetachedReceiver.project(changes, cursor)     no attached view
  RetainedReceiver                          retains/applies document changes
    AttachedReceiver.project                shared edits, then current view cursor
NeovimEditing.publish                       project both before size-dependent finish
NeovimEditing.render                        paint only; late cursor mutation deleted

AttachedReceiver.project at neovim_editing.py:419 owns the cursor projection. Reattachment uses that same projection. Publish at :1076 precedes size/layout refresh. No new clamp, exception suppression or second cursor field. Existing selected-region, generation and retained-document owners remain.

2. Stop serializing UI keys on RPC replies

Before: handle_key awaited _input; NeovimRequest.result waited for the native reply. An async await still holds the editor message handler and later keys. App.prepare_key fences that widget queue before priority dispatch, so a held editor queue also delays app commands.

After: handle_key at neovim_editing.py:1156 queues through the existing FIFO writer and returns. The existing pending-request/result callbacks still consume replies, validate accepted bytes and report failure. The local catch-and-ignore block is deleted. No second queue, worker, acknowledgement store or uncertain-input replay. SafeState still certifies completion; flush still refuses pending input.

3. App shortcuts are declared before editor input

Before: ApplicationAction inherited Action.priority=False (widget_actions.py:179). Textual's existing App._check_bindings(priority=True) therefore skipped CommanderAction/F2 and SettingsAction/ctrl+comma; Neovim consumed the event before the ordinary bubbling phase. Three siblings separately declared True.

After:

Action.priority = False
ApplicationAction.priority = True             one app-shortcut declaration
  VimWorkspaceAction                          inherits it; keeps modal availability
  KeymapAction, QuitAction                    inherited copies deleted
YieldingKey.priority = False                  local editor binding still wins
  HelpQuitAction(System, YieldingKey, ApplicationAction)

The existing native priority/filter/modal binding machinery does the routing. No extra Textual dispatcher or companion PR is needed for this source change. YieldingKey is essential: making every app key priority without it would steal ctrl+c from CopyOrClearInputAction. Three repeated True declarations are deleted; P917's separate navigation/catalog work remains with its owner, who confirmed preserving this priority ownership.

Formal deletion: MEMB-2, fact app shortcuts precede editor input; at the three sibling priority assignments; derive by the ApplicationAction parent. Yielding behavior remains a distinct declared capability, not a whitelist.

4. Standard remains the native editor and actual saved chooser

Standard remains key_modes.py:13; preferences.py:79 derives its chooser through FamilyChoices, not a new roster. The existing ChoicesEditor sends the selected class to SavedSettings; setting_effects.key_mode reaches PromptTextArea._apply_keyboard_profile, then TextArea.switch_editing_mode. That owner finishes and closes the previous engine before attaching the native Standard instance; returning to Neovim starts a new owner/child. The visible label is read from the active mode. The settings shortcut now reaches this workflow rather than being eaten by Neovim. No second mode flag, chooser or child lifecycle is added. Pending/uncertain input still refuses transfer under the existing flush contract.

Root actually ran the new controls at b3aa: 4 PASS / 1 FAIL in 80.48s. Submission/shrink and all three app-key profiles passed. The Standard test selected Standard, retained the draft and returned to a fresh native child, but its second switch to Standard failed at test_prompt_enter_insert.py:94. The failed assertion is unchanged.

The new correction at prompt.py:297 makes the existing NeovimUpdated handler reconcile through the existing _apply_keyboard_profile after painting. Before, a one-shot transfer refusal dropped the requested transition even though its target remained in saved settings. Later completion already emits NeovimUpdated (resolve_reply), but the handler only painted. The existing reconciler reads the canonical selected class and skips unchanged modes; it now consumes the actual completion/display edge too. No pending-profile flag, queue, timer, forced flush or second preference setter. Transport resize is one source-reachable cause of temporary pending requests; the failed run did not record the exact pending request, so resize is not claimed as its observed cause. This correction remains author-UNRUN and awaits root's changed-control qualification.

Controls — root ran 4 PASS / 1 FAIL at b3aa; latest correction author-UNRUN

Existing private workspace/prompt fixture and real embedded Neovim, no mocked cursor, fake editor or synthetic app:

  • test_prompt_enter_insert.py::test_real_neovim_submission_shrinks_document_and_cursor_together: type two real lines, require cursor (1,6), submit to the existing echo peer, require one empty line/cursor (0,0), type again, exercise local ctrl+c.
  • test_prompt_enter_insert.py::test_standard_chooser_retires_neovim_and_saved_selection_reopens: open settings by its actual key, select Standard through the actual chooser, require old child returncode and retained draft, visible label, native typing, a distinct new child on return, retirement and saved Standard after reopening.
  • test_active_mode_keymap.py::test_application_binding_precedes_real_engine_in_each_profile: family-derived Neovim profiles, actual F2 and remapped F3 from the focused prompt, commander close and retained draft. Existing sidebar/close coverage stays intact.

Root owns the necessary combined control execution and the installed Standard, app-key/tab/palette and typing journey. No repository tests/checkers, profiles, import probes, provider/UI input, installation or runtime measurements were run by this author. The first publication command included Git's whitespace-only diff --check; it is not behavioral evidence. Latest root42815 explicitly says no new profiling pass; existing before measurements already identify the defect. Existing timestamp sites, if needed for ordinary acceptance: frame_meter.py:674 display, :708 post, :715 dispatch, :1923-1925 input-to-paint summaries; capture_live.py remains the existing entrypoint, not a new harness.

Source map and remaining acceptance

Retained NRA SourceModule map: 566 production modules, zero omissions, 3,667 relevant sites; dynamic dispatch read semantically, Lua read separately. Initial wrong invocation parsed zero with 566 omissions; corrected before editing and not offered as evidence. Current priority/consumer search is retained in live-priority-family.log.

Durable executable prerequisite is still open. CI installs official Neovim 0.12.4 at ci.yml:63-70; production still launches bare nvim through the existing AttachedChild owner. Laptop's inspection found no executable (which returned None; PATH search ended EACCES). Manual user-local 0.12.4 supply allowed a distinct journey with native navigation and normal quit, reported by its owner. That is host evidence, not a product bootstrap implementation or acceptance of this head. The existing install/executable source owner is being traced; no alias, silent fallback or second editor is being added.

P3 remains preserved/non-gating at 4ef5a1a568d4a3f29d49f5a0a3c587003a69c871 on work/vim-neovim--P928--textual, with its existing patch retained. It resumes after the installed failures close, as ordered. No pin or workflow diagnostic changes were authored here; current main, including startup and CI landings, was merged normally.

F2 declared at the application; editor ate it first
the priority now lives where the key was declared

Assumed: root/NRA review this exact head; root runs the combined controls and real installed journey. Root42877 corrected the collection-owner report: DetachedChildStdio exists on open Core #3619, not current main; Toad #1340 landed its future caller early. Existing install-speed/#3619 owns that dependency gap, not P972 and not a compatibility class here. This is the single P928 continuation, and it is not declared working before those controls and installed acceptance.

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

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 insufficient remaining quota.

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 8e5bd63 into main Oct 30, 2026
2 of 3 checks passed
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