mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-21 11:30:38 -07:00
feat: add double-click to expand/collapse large paste placeholders (#17471)
This commit is contained in:
@@ -57,6 +57,7 @@ const initialState: TextBufferState = {
|
||||
transformationsByLine: [[]],
|
||||
visualLayout: defaultVisualLayout,
|
||||
pastedContent: {},
|
||||
expandedPasteInfo: new Map(),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -531,6 +532,150 @@ describe('textBufferReducer', () => {
|
||||
expect(state.cursorCol).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggle_paste_expansion action', () => {
|
||||
const placeholder = '[Pasted Text: 6 lines]';
|
||||
const content = 'line1\nline2\nline3\nline4\nline5\nline6';
|
||||
|
||||
it('should expand a placeholder correctly', () => {
|
||||
const stateWithPlaceholder = createStateWithTransformations({
|
||||
lines: ['prefix ' + placeholder + ' suffix'],
|
||||
cursorRow: 0,
|
||||
cursorCol: 0,
|
||||
pastedContent: { [placeholder]: content },
|
||||
});
|
||||
|
||||
const action: TextBufferAction = {
|
||||
type: 'toggle_paste_expansion',
|
||||
payload: { id: placeholder },
|
||||
};
|
||||
|
||||
const state = textBufferReducer(stateWithPlaceholder, action);
|
||||
|
||||
expect(state.lines).toEqual([
|
||||
'prefix line1',
|
||||
'line2',
|
||||
'line3',
|
||||
'line4',
|
||||
'line5',
|
||||
'line6 suffix',
|
||||
]);
|
||||
expect(state.expandedPasteInfo.has(placeholder)).toBe(true);
|
||||
const info = state.expandedPasteInfo.get(placeholder);
|
||||
expect(info).toEqual({
|
||||
startLine: 0,
|
||||
lineCount: 6,
|
||||
prefix: 'prefix ',
|
||||
suffix: ' suffix',
|
||||
});
|
||||
// Cursor should be at the end of expanded content (before suffix)
|
||||
expect(state.cursorRow).toBe(5);
|
||||
expect(state.cursorCol).toBe(5); // length of 'line6'
|
||||
});
|
||||
|
||||
it('should collapse an expanded placeholder correctly', () => {
|
||||
const expandedState = createStateWithTransformations({
|
||||
lines: [
|
||||
'prefix line1',
|
||||
'line2',
|
||||
'line3',
|
||||
'line4',
|
||||
'line5',
|
||||
'line6 suffix',
|
||||
],
|
||||
cursorRow: 5,
|
||||
cursorCol: 5,
|
||||
pastedContent: { [placeholder]: content },
|
||||
expandedPasteInfo: new Map([
|
||||
[
|
||||
placeholder,
|
||||
{
|
||||
startLine: 0,
|
||||
lineCount: 6,
|
||||
prefix: 'prefix ',
|
||||
suffix: ' suffix',
|
||||
},
|
||||
],
|
||||
]),
|
||||
});
|
||||
|
||||
const action: TextBufferAction = {
|
||||
type: 'toggle_paste_expansion',
|
||||
payload: { id: placeholder },
|
||||
};
|
||||
|
||||
const state = textBufferReducer(expandedState, action);
|
||||
|
||||
expect(state.lines).toEqual(['prefix ' + placeholder + ' suffix']);
|
||||
expect(state.expandedPasteInfo.has(placeholder)).toBe(false);
|
||||
// Cursor should be at the end of the collapsed placeholder
|
||||
expect(state.cursorRow).toBe(0);
|
||||
expect(state.cursorCol).toBe(('prefix ' + placeholder).length);
|
||||
});
|
||||
|
||||
it('should expand single-line content correctly', () => {
|
||||
const singleLinePlaceholder = '[Pasted Text: 10 chars]';
|
||||
const singleLineContent = 'some text';
|
||||
const stateWithPlaceholder = createStateWithTransformations({
|
||||
lines: [singleLinePlaceholder],
|
||||
cursorRow: 0,
|
||||
cursorCol: 0,
|
||||
pastedContent: { [singleLinePlaceholder]: singleLineContent },
|
||||
});
|
||||
|
||||
const state = textBufferReducer(stateWithPlaceholder, {
|
||||
type: 'toggle_paste_expansion',
|
||||
payload: { id: singleLinePlaceholder },
|
||||
});
|
||||
|
||||
expect(state.lines).toEqual(['some text']);
|
||||
expect(state.cursorRow).toBe(0);
|
||||
expect(state.cursorCol).toBe(9);
|
||||
});
|
||||
|
||||
it('should return current state if placeholder ID not found in pastedContent', () => {
|
||||
const action: TextBufferAction = {
|
||||
type: 'toggle_paste_expansion',
|
||||
payload: { id: 'unknown' },
|
||||
};
|
||||
const state = textBufferReducer(initialState, action);
|
||||
expect(state).toBe(initialState);
|
||||
});
|
||||
|
||||
it('should preserve expandedPasteInfo when lines change from edits outside the region', () => {
|
||||
// Start with an expanded paste at line 0 (3 lines long)
|
||||
const placeholder = '[Pasted Text: 3 lines]';
|
||||
const expandedState = createStateWithTransformations({
|
||||
lines: ['line1', 'line2', 'line3', 'suffix'],
|
||||
cursorRow: 3,
|
||||
cursorCol: 0,
|
||||
pastedContent: { [placeholder]: 'line1\nline2\nline3' },
|
||||
expandedPasteInfo: new Map([
|
||||
[
|
||||
placeholder,
|
||||
{
|
||||
startLine: 0,
|
||||
lineCount: 3,
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
},
|
||||
],
|
||||
]),
|
||||
});
|
||||
|
||||
expect(expandedState.expandedPasteInfo.size).toBe(1);
|
||||
|
||||
// Insert a newline at the end - this changes lines but is OUTSIDE the expanded region
|
||||
const stateAfterInsert = textBufferReducer(expandedState, {
|
||||
type: 'insert',
|
||||
payload: '\n',
|
||||
});
|
||||
|
||||
// Lines changed, but expandedPasteInfo should be PRESERVED and optionally shifted (no shift here since edit is after)
|
||||
expect(stateAfterInsert.expandedPasteInfo.size).toBe(1);
|
||||
expect(stateAfterInsert.expandedPasteInfo.has(placeholder)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const getBufferState = (result: { current: TextBuffer }) => {
|
||||
|
||||
Reference in New Issue
Block a user