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:
co-authored by
Claude Fable 5
parent
6ed267dcde
commit
a77c4c7ebe
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,6 +125,14 @@ export class OpenCodeInlinePrompt extends Widget {
|
||||
const modelId = this._modelSelect?.value || undefined;
|
||||
options.onSubmit(text, providerId, modelId);
|
||||
});
|
||||
// Chat-input convention: Enter submits, Shift+Enter / Ctrl+Enter
|
||||
// insert a newline (textarea default).
|
||||
this._textarea.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
this._sendBtn.click();
|
||||
}
|
||||
});
|
||||
this._cancelBtn = document.createElement('button');
|
||||
this._cancelBtn.className = 'opencode-btn-cancel';
|
||||
this._cancelBtn.textContent = '取消';
|
||||
|
||||
Reference in New Issue
Block a user