feat: Enter in the inline prompt textarea submits; Shift/Ctrl+Enter newline

Chat-input convention for the inline prompt's textarea:
  - Enter (no modifier): preventDefault() + click the send button
    (which validates non-empty text and calls onSubmit with the
    current text + the selected provider/model).
  - Shift+Enter / Ctrl+Enter: do NOT preventDefault, so the textarea
    inserts a newline (the default browser behavior).

Implementation:
  - opencode_inline_prompt.ts: add a keydown listener on the textarea
    in the constructor (right after the send button setup, so
    this._sendBtn is already assigned and the closure can call
    this._sendBtn.click()).

Tests:
  - 'Enter in the textarea submits; Shift+Enter does not':
    dispatches keydown Enter on the textarea and asserts the
    onSubmit jest.fn() is called once with the textarea value and the
    current provider/model. Then dispatches Shift+Enter and
    Ctrl+Enter and asserts onSubmit is NOT called.

Verification: pytest 37/37, jest 36/36 (was 35, +1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tao.chen
2026-07-23 19:39:54 +08:00
co-authored by Claude Fable 5
parent 6ed267dcde
commit a77c4c7ebe
2 changed files with 63 additions and 0 deletions
@@ -619,4 +619,59 @@ describe('OpenCodeInlinePrompt', () => {
const writeText = (navigator.clipboard.writeText as unknown as jest.Mock);
expect(writeText).toHaveBeenCalledWith('print(1)');
});
it('Enter in the textarea submits; Shift+Enter does not', () => {
const cell = makeFakeCell('x = 1');
const onSubmit = jest.fn();
const prompt = new OpenCodeInlinePrompt(cell, {
onSubmit,
onCancel: jest.fn(),
disabled: false,
providers: null
});
prompt.setMessages([
{ role: 'user', content: '' },
{ role: 'assistant', content: 'noop' }
]);
const textarea = prompt.node.querySelector(
'textarea'
) as HTMLTextAreaElement;
textarea.value = 'fix the bug';
// Plain Enter submits with the current text + the current
// provider/model selection (both default to "" / first when null).
textarea.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'Enter',
bubbles: true,
cancelable: true
})
);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith('fix the bug', undefined, undefined);
// Shift+Enter must NOT submit (chat convention: newline).
onSubmit.mockClear();
textarea.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'Enter',
shiftKey: true,
bubbles: true,
cancelable: true
})
);
expect(onSubmit).not.toHaveBeenCalled();
// Ctrl+Enter also must not submit (newline).
onSubmit.mockClear();
textarea.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'Enter',
ctrlKey: true,
bubbles: true,
cancelable: true
})
);
expect(onSubmit).not.toHaveBeenCalled();
});
});