Skip to content

Commit 7e1938c

Browse files
authored
fix(cli): switch default back to terminalBuffer=false and fix regressions introduced for that mode (google-gemini#24873)
1 parent b9f1d83 commit 7e1938c

21 files changed

Lines changed: 363 additions & 244 deletions

docs/cli/settings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ they appear in the UI.
7575
| Show User Identity | `ui.showUserIdentity` | Show the signed-in user's identity (e.g. email) in the UI. | `true` |
7676
| Use Alternate Screen Buffer | `ui.useAlternateBuffer` | Use an alternate screen buffer for the UI, preserving shell history. | `false` |
7777
| Render Process | `ui.renderProcess` | Enable Ink render process for the UI. | `true` |
78-
| Terminal Buffer | `ui.terminalBuffer` | Use the new terminal buffer architecture for rendering. | `true` |
78+
| Terminal Buffer | `ui.terminalBuffer` | Use the new terminal buffer architecture for rendering. | `false` |
7979
| Use Background Color | `ui.useBackgroundColor` | Whether to use background colors in the UI. | `true` |
8080
| Incremental Rendering | `ui.incrementalRendering` | Enable incremental rendering for the UI. This option will reduce flickering but may cause rendering artifacts. Only supported when useAlternateBuffer is enabled. | `true` |
8181
| Show Spinner | `ui.showSpinner` | Show the spinner during operations. | `true` |

docs/reference/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ their corresponding top-level category object in your `settings.json` file.
346346

347347
- **`ui.terminalBuffer`** (boolean):
348348
- **Description:** Use the new terminal buffer architecture for rendering.
349-
- **Default:** `true`
349+
- **Default:** `false`
350350
- **Requires restart:** Yes
351351

352352
- **`ui.useBackgroundColor`** (boolean):

packages/cli/src/config/settingsSchema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ const SETTINGS_SCHEMA = {
757757
label: 'Terminal Buffer',
758758
category: 'UI',
759759
requiresRestart: true,
760-
default: true,
760+
default: false,
761761
description: 'Use the new terminal buffer architecture for rendering.',
762762
showInDialog: true,
763763
},

packages/cli/src/interactiveCli.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,9 @@ export async function startInteractiveUI(
156156
useAlternateBuffer || config.getUseTerminalBuffer(),
157157
patchConsole: false,
158158
alternateBuffer: useAlternateBuffer,
159-
renderProcess: config.getUseRenderProcess(),
160159
terminalBuffer: config.getUseTerminalBuffer(),
160+
renderProcess:
161+
config.getUseRenderProcess() && config.getUseTerminalBuffer(),
161162
incrementalRendering:
162163
settings.merged.ui.incrementalRendering !== false &&
163164
useAlternateBuffer &&

packages/cli/src/ui/__snapshots__/App.test.tsx.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ Footer
5555
Gemini CLI v1.2.3
5656
5757
58+
59+
Tips for getting started:
60+
1. Create GEMINI.md files to customize your interactions
61+
2. /help for more information
62+
3. Ask coding questions, edit code or run commands
63+
4. Be specific for the best results
5864
Composer
5965
"
6066
`;

packages/cli/src/ui/components/InputPrompt.test.tsx

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import {
6969
AppEvent,
7070
TransientMessageType,
7171
} from '../../utils/events.js';
72+
import '../../test-utils/customMatchers.js';
7273

7374
vi.mock('../hooks/useShellHistory.js');
7475
vi.mock('../hooks/useCommandCompletion.js');
@@ -254,7 +255,7 @@ describe('InputPrompt', () => {
254255
setText: vi.fn(
255256
(newText: string, cursorPosition?: 'start' | 'end' | number) => {
256257
mockBuffer.text = newText;
257-
mockBuffer.lines = [newText];
258+
mockBuffer.lines = newText.split('\n');
258259
let col = 0;
259260
if (typeof cursorPosition === 'number') {
260261
col = cursorPosition;
@@ -264,18 +265,26 @@ describe('InputPrompt', () => {
264265
col = newText.length;
265266
}
266267
mockBuffer.cursor = [0, col];
267-
mockBuffer.allVisualLines = [newText];
268-
mockBuffer.viewportVisualLines = [newText];
269-
mockBuffer.allVisualLines = [newText];
270-
mockBuffer.visualToLogicalMap = [[0, 0]];
268+
mockBuffer.allVisualLines = newText.split('\n');
269+
mockBuffer.viewportVisualLines = newText.split('\n');
270+
mockBuffer.visualToLogicalMap = newText
271+
.split('\n')
272+
.map((_, i) => [i, 0] as [number, number]);
271273
mockBuffer.visualCursor = [0, col];
274+
mockBuffer.visualScrollRow = 0;
275+
mockBuffer.viewportHeight = 10;
276+
mockBuffer.visualToTransformedMap = newText
277+
.split('\n')
278+
.map((_, i) => i);
279+
mockBuffer.transformationsByLine = newText.split('\n').map(() => []);
272280
},
273281
),
274282
replaceRangeByOffset: vi.fn(),
275283
viewportVisualLines: [''],
276284
allVisualLines: [''],
277285
visualCursor: [0, 0],
278286
visualScrollRow: 0,
287+
viewportHeight: 10,
279288
handleInput: vi.fn((key: Key) => {
280289
if (defaultKeyMatchers[Command.CLEAR_INPUT](key)) {
281290
if (mockBuffer.text.length > 0) {
@@ -409,6 +418,7 @@ describe('InputPrompt', () => {
409418
getTargetDir: () => path.join('test', 'project', 'src'),
410419
getVimMode: () => false,
411420
getUseBackgroundColor: () => true,
421+
getUseTerminalBuffer: () => false,
412422
getTerminalBackground: () => undefined,
413423
getWorkspaceContext: () => ({
414424
getDirectories: () => ['/test/project/src'],
@@ -3779,11 +3789,7 @@ describe('InputPrompt', () => {
37793789
);
37803790

37813791
it('should unfocus embedded shell on click', async () => {
3782-
props.buffer.text = 'hello';
3783-
props.buffer.lines = ['hello'];
3784-
props.buffer.allVisualLines = ['hello'];
3785-
props.buffer.viewportVisualLines = ['hello'];
3786-
props.buffer.visualToLogicalMap = [[0, 0]];
3792+
props.buffer.setText('hello');
37873793
props.isEmbeddedShellFocused = true;
37883794

37893795
const { stdin, stdout, unmount } = await renderWithProviders(
@@ -4291,11 +4297,7 @@ describe('InputPrompt', () => {
42914297
describe('IME Cursor Support', () => {
42924298
it('should report correct cursor position for simple ASCII text', async () => {
42934299
const text = 'hello';
4294-
mockBuffer.text = text;
4295-
mockBuffer.lines = [text];
4296-
mockBuffer.allVisualLines = [text];
4297-
mockBuffer.viewportVisualLines = [text];
4298-
mockBuffer.visualToLogicalMap = [[0, 0]];
4300+
mockBuffer.setText(text);
42994301
mockBuffer.visualCursor = [0, 3]; // Cursor after 'hel'
43004302
mockBuffer.visualScrollRow = 0;
43014303

@@ -4322,11 +4324,7 @@ describe('InputPrompt', () => {
43224324

43234325
it('should report correct cursor position for text with double-width characters', async () => {
43244326
const text = '👍hello';
4325-
mockBuffer.text = text;
4326-
mockBuffer.lines = [text];
4327-
mockBuffer.allVisualLines = [text];
4328-
mockBuffer.viewportVisualLines = [text];
4329-
mockBuffer.visualToLogicalMap = [[0, 0]];
4327+
mockBuffer.setText(text);
43304328
mockBuffer.visualCursor = [0, 2]; // Cursor after '👍h' (Note: '👍' is one code point but width 2)
43314329
mockBuffer.visualScrollRow = 0;
43324330

@@ -4352,11 +4350,7 @@ describe('InputPrompt', () => {
43524350

43534351
it('should report correct cursor position for a line full of "😀" emojis', async () => {
43544352
const text = '😀😀😀';
4355-
mockBuffer.text = text;
4356-
mockBuffer.lines = [text];
4357-
mockBuffer.allVisualLines = [text];
4358-
mockBuffer.viewportVisualLines = [text];
4359-
mockBuffer.visualToLogicalMap = [[0, 0]];
4353+
mockBuffer.setText(text);
43604354
mockBuffer.visualCursor = [0, 2]; // Cursor after 2 emojis (each 1 code point, width 2)
43614355
mockBuffer.visualScrollRow = 0;
43624356

@@ -4501,12 +4495,12 @@ describe('InputPrompt', () => {
45014495
mockBuffer.lines = [logicalLine];
45024496
mockBuffer.allVisualLines = [visualLine];
45034497
mockBuffer.viewportVisualLines = [visualLine];
4504-
mockBuffer.allVisualLines = [visualLine];
45054498
mockBuffer.visualToLogicalMap = [[0, 0]];
45064499
mockBuffer.visualToTransformedMap = [0];
45074500
mockBuffer.transformationsByLine = [transformations];
45084501
mockBuffer.cursor = [0, cursorCol];
4509-
mockBuffer.visualCursor = [0, 0];
4502+
mockBuffer.visualCursor = [0, cursorCol];
4503+
mockBuffer.visualScrollRow = 0;
45104504
};
45114505

45124506
it('should snapshot collapsed image path', async () => {

packages/cli/src/ui/components/InputPrompt.tsx

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
*/
66

77
import type React from 'react';
8-
import { useCallback, useEffect, useState, useRef, useMemo } from 'react';
8+
import {
9+
useCallback,
10+
useEffect,
11+
useState,
12+
useRef,
13+
useMemo,
14+
Fragment,
15+
} from 'react';
916
import clipboardy from 'clipboardy';
1017
import { Box, Text, useStdout, type DOMElement } from 'ink';
1118
import { SuggestionsDisplay, MAX_WIDTH } from './SuggestionsDisplay.js';
@@ -1820,24 +1827,45 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
18201827
height={Math.min(buffer.viewportHeight, scrollableData.length)}
18211828
width="100%"
18221829
>
1823-
<ScrollableList
1824-
ref={listRef}
1825-
hasFocus={focus}
1826-
data={scrollableData}
1827-
renderItem={renderItem}
1828-
estimatedItemHeight={() => 1}
1829-
keyExtractor={(item) =>
1830-
item.type === 'visualLine'
1831-
? `line-${item.absoluteVisualIdx}`
1832-
: `ghost-${item.index}`
1833-
}
1834-
width="100%"
1835-
backgroundColor={listBackgroundColor}
1836-
containerHeight={Math.min(
1837-
buffer.viewportHeight,
1838-
scrollableData.length,
1839-
)}
1840-
/>
1830+
{isAlternateBuffer ? (
1831+
<ScrollableList
1832+
ref={listRef}
1833+
hasFocus={focus}
1834+
data={scrollableData}
1835+
renderItem={renderItem}
1836+
estimatedItemHeight={() => 1}
1837+
fixedItemHeight={true}
1838+
keyExtractor={(item) =>
1839+
item.type === 'visualLine'
1840+
? `line-${item.absoluteVisualIdx}`
1841+
: `ghost-${item.index}`
1842+
}
1843+
width={inputWidth}
1844+
backgroundColor={listBackgroundColor}
1845+
containerHeight={Math.min(
1846+
buffer.viewportHeight,
1847+
scrollableData.length,
1848+
)}
1849+
/>
1850+
) : (
1851+
scrollableData
1852+
.slice(
1853+
buffer.visualScrollRow,
1854+
buffer.visualScrollRow + buffer.viewportHeight,
1855+
)
1856+
.map((item, index) => {
1857+
const actualIndex = buffer.visualScrollRow + index;
1858+
const key =
1859+
item.type === 'visualLine'
1860+
? `line-${item.absoluteVisualIdx}`
1861+
: `ghost-${item.index}`;
1862+
return (
1863+
<Fragment key={key}>
1864+
{renderItem({ item, index: actualIndex })}
1865+
</Fragment>
1866+
);
1867+
})
1868+
)}
18411869
</Box>
18421870
)}
18431871
</Box>

packages/cli/src/ui/components/__snapshots__/HistoryItemDisplay.test.tsx.snap

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -112,48 +112,7 @@ exports[`<HistoryItemDisplay /> > gemini items (alternateBuffer=false) > should
112112

113113
exports[`<HistoryItemDisplay /> > gemini items (alternateBuffer=false) > should render a truncated gemini item 1`] = `
114114
"✦ Example code block:
115-
1 Line 1
116-
2 Line 2
117-
3 Line 3
118-
4 Line 4
119-
5 Line 5
120-
6 Line 6
121-
7 Line 7
122-
8 Line 8
123-
9 Line 9
124-
10 Line 10
125-
11 Line 11
126-
12 Line 12
127-
13 Line 13
128-
14 Line 14
129-
15 Line 15
130-
16 Line 16
131-
17 Line 17
132-
18 Line 18
133-
19 Line 19
134-
20 Line 20
135-
21 Line 21
136-
22 Line 22
137-
23 Line 23
138-
24 Line 24
139-
25 Line 25
140-
26 Line 26
141-
27 Line 27
142-
28 Line 28
143-
29 Line 29
144-
30 Line 30
145-
31 Line 31
146-
32 Line 32
147-
33 Line 33
148-
34 Line 34
149-
35 Line 35
150-
36 Line 36
151-
37 Line 37
152-
38 Line 38
153-
39 Line 39
154-
40 Line 40
155-
41 Line 41
156-
42 Line 42
115+
... 42 hidden (Ctrl+O) ...
157116
43 Line 43
158117
44 Line 44
159118
45 Line 45
@@ -167,48 +126,7 @@ exports[`<HistoryItemDisplay /> > gemini items (alternateBuffer=false) > should
167126

168127
exports[`<HistoryItemDisplay /> > gemini items (alternateBuffer=false) > should render a truncated gemini_content item 1`] = `
169128
" Example code block:
170-
1 Line 1
171-
2 Line 2
172-
3 Line 3
173-
4 Line 4
174-
5 Line 5
175-
6 Line 6
176-
7 Line 7
177-
8 Line 8
178-
9 Line 9
179-
10 Line 10
180-
11 Line 11
181-
12 Line 12
182-
13 Line 13
183-
14 Line 14
184-
15 Line 15
185-
16 Line 16
186-
17 Line 17
187-
18 Line 18
188-
19 Line 19
189-
20 Line 20
190-
21 Line 21
191-
22 Line 22
192-
23 Line 23
193-
24 Line 24
194-
25 Line 25
195-
26 Line 26
196-
27 Line 27
197-
28 Line 28
198-
29 Line 29
199-
30 Line 30
200-
31 Line 31
201-
32 Line 32
202-
33 Line 33
203-
34 Line 34
204-
35 Line 35
205-
36 Line 36
206-
37 Line 37
207-
38 Line 38
208-
39 Line 39
209-
40 Line 40
210-
41 Line 41
211-
42 Line 42
129+
... 42 hidden (Ctrl+O) ...
212130
43 Line 43
213131
44 Line 44
214132
45 Line 45

packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ exports[`InputPrompt > Highlighting and Cursor Display > single-line scenarios >
9393
exports[`InputPrompt > History Navigation and Completion Suppression > should not render suggestions during history navigation 1`] = `
9494
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
9595
> second message
96-
96+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
9797
"
9898
`;
9999

@@ -120,30 +120,30 @@ exports[`InputPrompt > command search (Ctrl+R when not in shell) > expands and c
120120
exports[`InputPrompt > command search (Ctrl+R when not in shell) > renders match window and expanded view (snapshots) > command-search-render-collapsed-match 1`] = `
121121
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
122122
(r:) commit
123-
124-
123+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
124+
git commit -m "feat: add search" in src/app
125125
"
126126
`;
127127

128128
exports[`InputPrompt > command search (Ctrl+R when not in shell) > renders match window and expanded view (snapshots) > command-search-render-expanded-match 1`] = `
129129
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
130130
(r:) commit
131-
132-
131+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
132+
git commit -m "feat: add search" in src/app
133133
"
134134
`;
135135

136136
exports[`InputPrompt > image path transformation snapshots > should snapshot collapsed image path 1`] = `
137137
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
138138
> [Image ...reenshot2x.png]
139-
139+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
140140
"
141141
`;
142142

143143
exports[`InputPrompt > image path transformation snapshots > should snapshot expanded image path when cursor is on it 1`] = `
144144
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
145145
> @/path/to/screenshots/screenshot2x.png
146-
146+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
147147
"
148148
`;
149149

0 commit comments

Comments
 (0)