Skip to content

feat: add modal controls for dialog inputs#206

Merged
leohenon merged 11 commits into
ocvfrom
feat/dialog-modal-input
Jun 30, 2026
Merged

feat: add modal controls for dialog inputs#206
leohenon merged 11 commits into
ocvfrom
feat/dialog-modal-input

Conversation

@leohenon

@leohenon leohenon commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Adds vim modal controls to dialog inputs, including searchable pickers and custom question answers.

  • Esc enters normal mode
  • j/k move selection in normal mode
  • Supports single line motions: h/j/k/l, w/b/e, 0/$, I/A, dd

Summary by CodeRabbit

  • New Features
    • Added optional Vim-style modal input (insert/normal) for the command palette and dialog/question text/filter fields, with motion-based navigation and mode-dependent cursor behavior.
  • Bug Fixes
    • Enhanced TUI config migration and defaults: supports legacy vim_modal_input, normalizes it as a boolean, and defaults to true when unset.
  • Documentation
    • Reformatted the README “Copy Mode” table and added guidance for modal dialog inputs, including how to disable them.
  • Tests
    • Added/expanded Bun test coverage for modal input controls and single-line Vim motions.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f24ad3c1-77e1-4561-b99f-b9cf6ac6529a

📥 Commits

Reviewing files that changed from the base of the PR and between 37d0352 and cd82804.

📒 Files selected for processing (6)
  • packages/tui/src/routes/session/question.tsx
  • packages/tui/src/ui/dialog-select.tsx
  • packages/tui/src/ui/modal-input-controls.ts
  • packages/tui/src/ui/single-line-vim-motions.ts
  • packages/tui/test/modal-input-controls.test.ts
  • packages/tui/test/single-line-vim-motions.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/tui/src/ui/single-line-vim-motions.ts
  • packages/tui/test/single-line-vim-motions.test.ts
  • packages/tui/src/ui/modal-input-controls.ts
  • packages/tui/test/modal-input-controls.test.ts
  • packages/tui/src/ui/dialog-select.tsx
  • packages/tui/src/routes/session/question.tsx

📝 Walkthrough

Walkthrough

Adds a vim_modal_input TUI configuration flag, defaults it to true, and uses it to enable modal insert/normal handling for dialog filter inputs and question answer editing. It also adds Vim-style motion helpers, legacy config migration support, and README documentation.

Changes

Vim Modal Input Feature

Layer / File(s) Summary
Config field and migration
packages/tui/src/config/index.tsx, packages/opencode/src/config/tui-migrate.ts, packages/opencode/test/config/tui.test.ts
Adds vim_modal_input?: boolean to the TUI config schema, defaults it to true in resolution, extends legacy TUI normalization to decode the field, and updates config tests for defaults and migration.
Single-line Vim motions primitives
packages/tui/src/ui/single-line-vim-motions.ts, packages/tui/test/single-line-vim-motions.test.ts
Adds SingleLineVimKeyEvent, createSingleLineVimMotions, key-name normalization, printable-key classification, modifier detection, word-boundary helpers, and tests for the motion handler.
Modal input controller
packages/tui/src/ui/modal-input-controls.ts, packages/tui/test/modal-input-controls.test.ts
Adds ModalInputMode, ModalInputKeyEvent, and createModalInputControls, which manages insert/normal transitions, pending g sequences, cursor movement, modifier handling, and modal-input tests.
Dialog and question prompt wiring
packages/tui/src/ui/dialog-select.tsx, packages/tui/src/routes/session/question.tsx
Adds modal input state and key handling to DialogSelect and QuestionPrompt, including cursor-style updates, conditional escape behavior, and normal-mode cursor normalization.
README documentation
README.md
Updates the Copy Mode table formatting and adds a “Modal dialog inputs” section describing the modal control behavior and the vim_modal_input: false configuration snippet.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I hopped through insert and back again,
With gg and dd and a Vim-like pen.
The dialog blinked, the cursor knew its place,
And escape led the rabbit to normal space.
A carrot for config, a nibble for flow —
Modal little motions, let the garden grow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding modal controls for dialog inputs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dialog-modal-input

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tui/src/routes/session/question.tsx`:
- Around line 63-77: The motion state managed by createSingleLineVimMotions is
not being reset when leaving normal mode or when the editor transitions, so the
pending operator can leak across sessions and turn a later d into dd
unexpectedly. Update the question route’s input handling around answerMotions,
modalInputEnabled, and the shared modal controller so that any pending
motion/operator state is cleared whenever editing mode changes or focus returns,
matching the ownership expected by the modal controller.
- Around line 152-156: The key handler in question.tsx currently treats "a" the
same as "i" inside the input mode switch, so append mode never moves the caret
forward. Update the keyboard branch that handles key === "a" to advance the
textarea cursor one character before setting inputMode to "insert" and focusing
the textarea, using the same handler that manages the existing insert-mode
transition. If Vim-style append is not intended, remove the "a" case from this
key handling path.

In `@packages/tui/src/ui/dialog-select.tsx`:
- Around line 133-136: The shared end-navigation path in dialog-select.tsx can
call moveTo() with -1 when flat() is empty, which leaves the selection state
invalid after clearing filters. Update moveToEnd and the shared selection
handling around moveTo()/flat() so the target index is clamped or skipped when
there are no results, ensuring both the modal G jump and existing end navigation
never set store.selected to an invalid item.

In `@packages/tui/src/ui/modal-input-controls.ts`:
- Around line 43-48: The escape path in modal-input-controls should normalize
the caret before switching out of insert mode, because input.setMode("normal")
currently leaves the cursor at the insert position. Update the Esc branch in the
insert-mode handling so the caret is moved to the normal-mode character index
expected by createSingleLineVimMotions and the rest of this module, then clear
pending and prevent default as it already does.

In `@README.md`:
- Around line 191-199: The README section for “Modal dialog inputs” is too
narrow because vim_modal_input also affects custom question answers in the
session question flow. Update the wording in the Markdown docs to mention that
this setting controls modal editing in
packages/tui/src/routes/session/question.tsx as well, so users understand it
applies beyond searchable dialog inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 090664af-9c79-41a8-8ff3-08ac027a0970

📥 Commits

Reviewing files that changed from the base of the PR and between d162aa9 and 11d42f0.

📒 Files selected for processing (10)
  • README.md
  • packages/opencode/src/config/tui-migrate.ts
  • packages/opencode/test/config/tui.test.ts
  • packages/tui/src/config/index.tsx
  • packages/tui/src/routes/session/question.tsx
  • packages/tui/src/ui/dialog-select.tsx
  • packages/tui/src/ui/modal-input-controls.ts
  • packages/tui/src/ui/single-line-vim-motions.ts
  • packages/tui/test/modal-input-controls.test.ts
  • packages/tui/test/single-line-vim-motions.test.ts

Comment thread packages/tui/src/routes/session/question.tsx Outdated
Comment thread packages/tui/src/routes/session/question.tsx
Comment thread packages/tui/src/ui/dialog-select.tsx
Comment thread packages/tui/src/ui/modal-input-controls.ts
Comment thread README.md

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 193: The README wording for the modal controls sentence should be updated
to use “question-answer” instead of “question answer” so the user-facing docs
read naturally. Locate the sentence in README.md that mentions searchable dialog
inputs and custom question answer inputs, and revise that phrase to “custom
question-answer inputs” while keeping the rest of the wording unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ce057b0b-e82d-4c64-bfa2-575ab4515915

📥 Commits

Reviewing files that changed from the base of the PR and between 1bce32e and 37d0352.

📒 Files selected for processing (5)
  • README.md
  • packages/tui/src/routes/session/question.tsx
  • packages/tui/src/ui/dialog-select.tsx
  • packages/tui/src/ui/modal-input-controls.ts
  • packages/tui/test/modal-input-controls.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/tui/src/ui/modal-input-controls.ts
  • packages/tui/test/modal-input-controls.test.ts
  • packages/tui/src/routes/session/question.tsx
  • packages/tui/src/ui/dialog-select.tsx

Comment thread README.md
@leohenon leohenon force-pushed the feat/dialog-modal-input branch from cd82804 to 1866e91 Compare June 30, 2026 06:40
@leohenon leohenon merged commit 0792b45 into ocv Jun 30, 2026
3 checks passed
@leohenon leohenon deleted the feat/dialog-modal-input branch June 30, 2026 06:43
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.

1 participant