feat(extensions): add interactive file-view modes - #675
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds opt-in interactive keyboard modes for extension file views, including public API controls, host routing, lifecycle containment, status feedback, documentation, and end-to-end tests.
Confidence Score: 4/5The mode replacement lifecycle defect should be fixed before merging because a valid extension callback or command can skip an active mode's required cleanup. beginFileViewMode unconditionally publishes a new activation, so nested or repeated enterMode calls can overwrite the current activation without invoking its onExit callback and can report success after reentrant teardown. Files Needing Attention: src/ui/App.tsx Important Files Changed
Sequence DiagramsequenceDiagram
participant E as Extension command
participant A as App mode state
participant K as Keyboard router
participant M as File-view mode
participant C as Command table
E->>A: enterMode(view)
A->>M: onEnter(context)
K->>M: onKey(key)
alt handled
M-->>K: handled
K-->>K: consume key
else pass
M-->>K: pass
K->>C: dispatch key
else exit or Escape
M-->>K: exit
K->>A: exit mode
A->>M: onExit(context)
end
Prompt To Fix All With AI### Issue 1
src/ui/App.tsx:719-720
**Mode replacement skips teardown**
When an active mode's `onKey` callback or a passed-through command calls `enterMode`, `beginFileViewMode` overwrites the current activation without invoking its `onExit`, causing that activation's cleanup and extension state teardown to be skipped. Reentrant entry from `onEnter` can also replace or exit the activation while the outer `enterMode` still reports success.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "chore: add changeset for interactive fil..." | Re-trigger Greptile |
| setActiveFileViewMode(active); | ||
| if (!runFileViewModeLifecycle(active, "onEnter", warnFileViewMode)) { |
There was a problem hiding this comment.
Mode replacement skips teardown
When an active mode's onKey callback or a passed-through command calls enterMode, beginFileViewMode overwrites the current activation without invoking its onExit, causing that activation's cleanup and extension state teardown to be skipped. Reentrant entry from onEnter can also replace or exit the activation while the outer enterMode still reports success.
Knowledge Base Used: Extension System: API, Loading, and Host Integration
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ui/App.tsx
Line: 719-720
Comment:
**Mode replacement skips teardown**
When an active mode's `onKey` callback or a passed-through command calls `enterMode`, `beginFileViewMode` overwrites the current activation without invoking its `onExit`, causing that activation's cleanup and extension state teardown to be skipped. Reentrant entry from `onEnter` can also replace or exit the activation while the outer `enterMode` still reports success.
**Knowledge Base Used:** [Extension System: API, Loading, and Host Integration](https://app.greptile.com/modem/-/custom-context/knowledge-base/modem-dev/hunk/-/docs/extension-system.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.356e70a to
5cec20e
Compare
c62bfe6 to
1a478cd
Compare
1a478cd to
88f3ce8
Compare
5cec20e to
41d71cc
Compare
88f3ce8 to
143749e
Compare
4d9adcb to
b2edc6f
Compare
9ace620 to
b3ca3f0
Compare
File views were pure presentations: the host owned all input, so a stateful view (folds, pickers, a future inline editor) had no way to receive keys. A view may now register an opt-in mode; while active, keys the modal surfaces do not claim route to its onKey ahead of the command table, with "pass" declining back to normal handling. Escape stays host-owned so there is always a way out, the mode auto-exits on file change, deselection, and reload, and a throwing handler is contained to a warning. Entering is one step: enterMode makes the view the selected file's presentation and gives its mode the keys, since requiring a prior select cost every mode entry a second keypress for an invariant selection itself preserves. ExtensionKeyEvent moved into the contract module so the mode types stay import-free; its published path is unchanged. The published chord matcher also learned the bare C0 form of ctrl+<letter> that some terminals send, so mode and host bindings match it without hand-rolled control-byte checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015aJpBUupsP9L7Wtd7MEzmU
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015aJpBUupsP9L7Wtd7MEzmU
…andoffs A mode entered by an async handler that resumed after a soft reload was tagged with the closed-over pre-reload bootstrap, so the auto-exit effect tore the fresh mode down on its first render; the generation now reads through the live ref like every other input to activation. Entering a mode over an active one silently replaced it, skipping the old mode's onExit — activation now funnels through the single exit path first, so onExit stays exactly-once per activation. Escape ownership in the key chain answered from a render-refreshed mirror, letting a second Escape in one input flush be swallowed after the mode had already exited; both branches now ask the same live App-side authority. The C0 chord fallback's stated rationale is corrected to what it actually is — a compatibility net for structural events the OpenTUI parser never produced — with no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015aJpBUupsP9L7Wtd7MEzmU
b3ca3f0 to
9f8dd96
Compare
Summary
Adds opt-in keyboard modes for extension file views. A command can activate a view and its mode with
fileViews.enterMode(viewId); the view then handles keys throughonKey.This also makes
ctrl+<letter>chord matching accept bare C0 control bytes from synthetic or embedded input sources.Mode behavior
enterMode(viewId)selects the view and activates its mode in one step. Invalid or unavailable views are refused with a warning.onEnterandonExitcallbacks, including re-entrant handoffs.onKeyreturns:"handled"to consume the key"pass"to continue through Hunk's commands and scrolling"exit"to consume the key and leave the mode<extension>:<view> mode — Esc exitswhile active.C0 matching applies only to unnamed bare control-byte events. Named Tab and Enter events remain distinct, so
ctrl+iandctrl+mdo not claim them.Validation
Coverage includes activation and refusal policy, lifecycle ordering and re-entrancy, reload behavior, key routing, double-Escape handling, callback failures, C0 matching, scrollbox pass-through, and a real PTY interaction flow.
Typecheck, unit tests, PTY integration, TTY smoke tests, lint, package checks, documentation checks, and CI pass. Documentation and changesets are included.
This PR description was generated by Pi using gpt-5.6-sol