feat: replace large text pastes with [Pasted Text: X lines] placeholder (#16422)

This commit is contained in:
Jack Wotherspoon
2026-01-21 21:09:24 -05:00
committed by GitHub
parent 27d21f9921
commit 75e4f492ab
7 changed files with 619 additions and 28 deletions
@@ -176,6 +176,8 @@ describe('InputPrompt', () => {
visualToTransformedMap: [0],
transformationsByLine: [],
getOffset: vi.fn().mockReturnValue(0),
pastedContent: {},
addPastedContent: vi.fn().mockReturnValue('[Pasted Text: 6 lines]'),
} as unknown as TextBuffer;
mockShellHistory = {
@@ -248,6 +250,8 @@ describe('InputPrompt', () => {
checking: false,
});
vi.mocked(clipboardy.read).mockResolvedValue('');
props = {
buffer: mockBuffer,
onSubmit: vi.fn(),
@@ -632,10 +636,9 @@ describe('InputPrompt', () => {
await waitFor(() => {
expect(clipboardy.read).toHaveBeenCalled();
expect(mockBuffer.replaceRangeByOffset).toHaveBeenCalledWith(
expect.any(Number),
expect.any(Number),
expect(mockBuffer.insert).toHaveBeenCalledWith(
'pasted text',
expect.objectContaining({ paste: true }),
);
});
unmount();
@@ -1718,6 +1721,99 @@ describe('InputPrompt', () => {
});
});
describe('large paste placeholder', () => {
it('should handle large clipboard paste (lines > 5) by calling buffer.insert', async () => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
const largeText = '1\n2\n3\n4\n5\n6';
vi.mocked(clipboardy.read).mockResolvedValue(largeText);
const { stdin, unmount } = renderWithProviders(
<InputPrompt {...props} />,
);
await act(async () => {
stdin.write('\x16'); // Ctrl+V
});
await waitFor(() => {
expect(mockBuffer.insert).toHaveBeenCalledWith(
largeText,
expect.objectContaining({ paste: true }),
);
});
unmount();
});
it('should handle large clipboard paste (chars > 500) by calling buffer.insert', async () => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
const largeText = 'a'.repeat(501);
vi.mocked(clipboardy.read).mockResolvedValue(largeText);
const { stdin, unmount } = renderWithProviders(
<InputPrompt {...props} />,
);
await act(async () => {
stdin.write('\x16'); // Ctrl+V
});
await waitFor(() => {
expect(mockBuffer.insert).toHaveBeenCalledWith(
largeText,
expect.objectContaining({ paste: true }),
);
});
unmount();
});
it('should handle normal clipboard paste by calling buffer.insert', async () => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
const smallText = 'hello world';
vi.mocked(clipboardy.read).mockResolvedValue(smallText);
const { stdin, unmount } = renderWithProviders(
<InputPrompt {...props} />,
);
await act(async () => {
stdin.write('\x16'); // Ctrl+V
});
await waitFor(() => {
expect(mockBuffer.insert).toHaveBeenCalledWith(
smallText,
expect.objectContaining({ paste: true }),
);
});
unmount();
});
it('should replace placeholder with actual content on submit', async () => {
// Setup buffer to have the placeholder
const largeText = '1\n2\n3\n4\n5\n6';
const id = '[Pasted Text: 6 lines]';
mockBuffer.text = `Check this: ${id}`;
mockBuffer.pastedContent = { [id]: largeText };
const { stdin, unmount } = renderWithProviders(
<InputPrompt {...props} />,
);
await act(async () => {
stdin.write('\r'); // Enter
});
await waitFor(() => {
expect(props.onSubmit).toHaveBeenCalledWith(`Check this: ${largeText}`);
});
unmount();
});
});
describe('paste auto-submission protection', () => {
beforeEach(() => {
vi.useFakeTimers();