Repository navigation
Own derived editor bindings and reconcile footer groups in place - #210
Merged
Merged
Conversation
There was a problem hiding this comment.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
P966: retain Footer controls and stop rebuilding nominal bindings
7 changed files, +161/-111 against integrated main. Footer recompose calls: 2 -> 0; Footer readiness flag: 1 -> 0; persistent ordinary-node binding copies: 1 per accessed node -> 0; shared mutable cached binding tables: 1 per class/mode -> 0. Textual #211 is merged on the integrated main at 40873a8. This is source delivery, not installed/application acceptance.
1. Preserve current external editor ownership
Main replaced the native Vim implementation with external editing capabilities. The merge resolves
_editing.pyand_text_area.pyto main exactly. The obsoleteEditingMode.command_map,TextArea.binding_mapcommand-map overlay andeditor_command_bindingsexperiment are gone, not resurrected alongside the external engine. The earlier six-mode construction observations covered historical source and are not evidence for this head.Before: TextArea repeatedly constructed modal command maps; an intermediate checkpoint moved those maps onto native mode values. After main's external-editor replacement: there is no native modal command family here to cache. Existing external editing, document, selection, history and async engine lifecycle behavior is preserved unchanged from main.
2. Cache frozen declarations; give callers their own mutable projection
Before: DOMNode cached one mutable
BindingsMapper class/mode and returned it directly. Screen copied it before remapping, but actual Toad consumers atwidget_actions.py:112andwidgets/prompt_popup.py:50remap a directbinding_mapresult. One widget could therefore change the keys seen by every instance of its class.After: DOMNode._binding_defaults uses the existing functools class/mode cache, but its value is an immutable tuple of
(key, tuple[Binding, ...])pairs; Binding is frozen. Public binding_defaults/binding_map return a fresh dictionary and fresh lists over those frozen values. No cached mutable map escapes. Callers retain the existing mutating apply_keymap contract without a second remapping API, compatibility alias, per-widget cache or revision table. Map allocation remains per lookup; mode projection and binding-value construction are cached. No frame-time improvement is claimed without measurement.App alone keeps its existing runtime mutation layer for bind()/palette additions. The redundant empty-runtime-map branch is deleted; BindingsMap.merge supplies the same result. DOMNode's persistent per-instance declaration copy is deleted. Screen consumes keys into a fresh projection before applying user keymaps; filtering/remapping never rewrites declarations.
3. Native scopes expose their own keymap metadata
P917's catalog called an absent editor_command_bindings API and appended Menu as a second hand-written scope beside DOMNode.contexts(). The shared frozen KeymapClaim declaration moves from Toad into textual.binding with its unchanged fields and from_bindings conversion. DOMNode.keymap_claims(mode) derives native claims from binding_defaults. Menu can override that native scope hook with command declaration metadata without constructing uncaptured command instances, importing Menu inside the catalog, or adding a registry/dispatcher.
Toad consumer/Menu migration is owned by toad-keymap on existing Toad Textualize#1338; it must delete its KeymapClaim copy and absent-API call. The native hook is implemented here, not a compatibility alias. Pairing that consumer with this native head remains an integration obligation.
4. Footer containers and keys survive projection changes
Before: flat/grouped projections had incompatible DOM shapes. Group/palette changes selected full recomposition and remounted FooterKey controls.
After: KeyGroup owns one stable keys-and-label shape. Group slots update in place; existing action keys move across groups through Widget.reparent. Only removed actions and excess group slots retire. Descriptions, compact style, palette and mode label derive from FooterProjection. Mode-only changes skip key reconciliation. An empty projection replaces the nullable snapshot/readiness flag. Both recompose paths, the old structural compatibility switch, parent iterator/assert and per-parent destruction of migrating keys are deleted. Main's mode-label behavior remains.
Source evidence and limits
/home/ts/.cache/agent-scratch/queue-toad-fix/keymap-footer/current-ast-owner-map.jsonl. Whole production/test consumer search:projection-consumers.txtandfamily-consumers-after-main.txtin that directory._editing.pyand_text_area.pyhave zero diff from integrated main. No navigation keys from Finish native key declarations through shared navigation #211 are rebound here._binding_chain: standard ~0.6 ms; vim-normal ~0.85 ms. Those are not after measurements. Current after timing, Footer mount counts, visible behavior and frame target are UNMEASURED.Assumed: declared class bindings remain class-lifetime metadata, as required by the existing class/mode cache; external mutation of class declarations after creation is not supported by this change. No claim that installed Toad already uses this head.