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);
|
const writeText = (navigator.clipboard.writeText as unknown as jest.Mock);
|
||||||
expect(writeText).toHaveBeenCalledWith('print(1)');
|
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;
|
const modelId = this._modelSelect?.value || undefined;
|
||||||
options.onSubmit(text, providerId, modelId);
|
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 = document.createElement('button');
|
||||||
this._cancelBtn.className = 'opencode-btn-cancel';
|
this._cancelBtn.className = 'opencode-btn-cancel';
|
||||||
this._cancelBtn.textContent = '取消';
|
this._cancelBtn.textContent = '取消';
|
||||||
|
|||||||
Reference in New Issue
Block a user