Skip to content

feat(ui): add "Enter sends" composer keymap setting - #1128

Open
marcomayer wants to merge 2 commits into
backnotprop:mainfrom
marcomayer:feat/save-on-enter-ai-on-cmd-enter
Open

feat(ui): add "Enter sends" composer keymap setting#1128
marcomayer wants to merge 2 commits into
backnotprop:mainfrom
marcomayer:feat/save-on-enter-ai-on-cmd-enter

Conversation

@marcomayer

@marcomayer marcomayer commented Jul 26, 2026

Copy link
Copy Markdown

feat(ui): "Enter sends" composer keymap setting

Adds an opt-in setting that makes Enter submit comments and AI messages, Shift+Enter insert a newline, and Mod+Enter ask AI. Default is unchanged (Mod+Enter submits), so nobody's muscle memory moves without opting in.

Toggle lives in Settings → Shortcuts → "Enter sends", directly above the shortcut reference table, which rerenders from the same value.

Behavior

Keystroke Off (default) On
Enter newline submit
Shift+Enter newline newline
Mod+Enter submit Ask AI (submits where Ask AI is unavailable)

Applies to every text composer, so the two halves of the app stay consistent: plan-review comment popover (dialog + inline), annotation panel cards, code-file popout, document AI chat; code-review annotation toolbar, expanded comment dialog, file comment banner, Ask AI input, AI tab.

Two intentional changes that apply with the setting off

Routing every composer through one resolver tightened two loose behaviors. Both are deliberate, and both ship in the default keymap:

  1. Empty edits no longer submit. Four edit cards (annotation card, code annotation card, code-file popout, file comment banner) used to accept Mod+Enter on a cleared textarea, saving an empty comment and closing the editor. The shared handler gates submit on non-empty trimmed text, so that keystroke is now a no-op. Clearing a comment to delete it was never the intended gesture.
  2. Extra modifiers no longer submit. The old per-site checks were Enter && (metaKey || ctrlKey), which also fired on Cmd+Shift+Enter and Cmd+Alt+Enter. The registry matcher requires exact modifiers, so those combinations do nothing in a composer now. (The review toolbar's suggested-code textarea kept its hardcoded check and still accepts them.)

Implementation

  • packages/core/config-types.ts - ComposerSubmitKey = 'mod-enter' | 'enter'.
  • packages/ui/utils/composerKeymap.ts - keymap table plus a pure resolveComposerIntent(event, keymap, caps) resolver. Bindings are written in the shortcut-registry language and matched with matchesShortcutBinding, so one place decides what "Mod+Enter" means. Returning null (rather than a "newline" intent) is what lets Shift+Enter and Enter-while-empty fall through to the textarea: the caller must not preventDefault.
  • packages/ui/hooks/useComposerKeys.ts - the React handler each composer wires up, plus useComposerSubmitHint / useComposerAskAIHint keycaps. A local handler rather than a useShortcutScope window listener because composers are portaled and nested and the shortcut engine has no cross-scope arbitration.
  • packages/ui/config/settings.ts - composerSubmitKey, cookie-only, default 'mod-enter'.
  • KeyboardShortcuts.tsx - reference sections became functions of the active submit key, so the help table tells the truth in both modes.

Notes

  • IME: with Enter submitting, isComposing / keyCode === 229 decides whether CJK input works at all. Guarded in the resolver and covered by tests.
  • Expanded comment dialog: the handler sits on the popup rather than the textarea, so Mod+Enter keeps working with focus anywhere in the dialog, as before. Bare Enter only drives the keymap from the textarea, otherwise it would preventDefault the activation of a focused Collapse/Close/Ask AI button. Mod+Enter is also stopped from propagating, so it can't reach the window listener that submits the whole review while the dialog is open.
  • Suggested-code textarea in the review toolbar deliberately stays on hardcoded Mod+Enter - Enter is a newline in a code block.
  • ToggleSwitch gained shrink-0 + gap-4: a long description used to squeeze the track below its width and push the thumb outside it.

Testing

  • New unit tests for the resolver (9 cases: both keymaps, Shift+Enter passthrough, Ask AI fallback, canSubmit gating, IME guards).
  • Full bun test and all 7 typecheck projects match the pre-change baseline.
  • Manually exercised in a compiled binary: plan review and code review, both keymap modes.

@backnotprop

Copy link
Copy Markdown
Owner

Thanks, this is well built. The IME handling, the registry usage, and the fallback design are all right. Three things before merge:

  1. Expanded comment dialog: on main, Mod+Enter submits with focus anywhere in the dialog. Your version only handles it when focus is in the textarea, so on any button Mod+Enter now does nothing, in both modes. Please run the composer intent for Mod+Enter on non-textarea targets too (bare Enter can still fall through to buttons).
  2. Four edit cards changed behavior with the setting off: Mod+Enter on a cleared textarea used to save empty and close, now it does nothing. We are fine with the new behavior, but state it in the PR description as intentional rather than leaving it silent.
  3. Your matcher requires exact modifiers, so Cmd+Shift+Enter and Cmd+Alt+Enter no longer submit anywhere. Probably fine, but say so in the description too.

Also heads up: this will need a rebase once #1127 lands, it touches the same two files.

If you are short on time, say the word and we are happy to push these changes to your branch ourselves.

@marcomayer
marcomayer force-pushed the feat/save-on-enter-ai-on-cmd-enter branch from 66caaa4 to edb9454 Compare July 27, 2026 07:44
@marcomayer

marcomayer commented Jul 27, 2026

Copy link
Copy Markdown
Author

Also heads up: this will need a rebase once #1127 lands, it touches the same two files.

If you are short on time, say the word and we are happy to push these changes to your branch ourselves.

@backnotprop: Thanks for the feedback, good catch on the expanded comment dialog - fixed this. Also updated the PR desc and rebased on main, would be great to see this as part of the next release!

Just saw https://github.com/backnotprop/plannotator/releases/tag/v0.25.0 my day's ruined. 😆

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