Skip to content

Commit 8cae90f

Browse files
Fix up/down arrow regression and add test. (google-gemini#18108)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent c5d0fc2 commit 8cae90f

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

packages/cli/src/ui/components/shared/text-buffer.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,61 @@ describe('useTextBuffer', () => {
13841384
expect(state.visualCursor).toEqual([0, 1]);
13851385
});
13861386

1387+
it('move: up/down should work on wrapped lines (regression test)', () => {
1388+
// Line that wraps into two visual lines
1389+
// Viewport width 10. "0123456789ABCDE" (15 chars)
1390+
// Visual Line 0: "0123456789"
1391+
// Visual Line 1: "ABCDE"
1392+
const { result } = renderHook(() =>
1393+
useTextBuffer({
1394+
viewport: { width: 10, height: 5 },
1395+
isValidPath: () => false,
1396+
}),
1397+
);
1398+
1399+
act(() => {
1400+
result.current.setText('0123456789ABCDE');
1401+
});
1402+
1403+
// Cursor should be at the end: logical [0, 15], visual [1, 5]
1404+
expect(getBufferState(result).cursor).toEqual([0, 15]);
1405+
expect(getBufferState(result).visualCursor).toEqual([1, 5]);
1406+
1407+
// Press Up arrow - should move to first visual line
1408+
// This currently fails because handleInput returns false if cursorRow === 0
1409+
let handledUp = false;
1410+
act(() => {
1411+
handledUp = result.current.handleInput({
1412+
name: 'up',
1413+
shift: false,
1414+
alt: false,
1415+
ctrl: false,
1416+
cmd: false,
1417+
insertable: false,
1418+
sequence: '\x1b[A',
1419+
});
1420+
});
1421+
expect(handledUp).toBe(true);
1422+
expect(getBufferState(result).visualCursor[0]).toBe(0);
1423+
1424+
// Press Down arrow - should move back to second visual line
1425+
// This would also fail if cursorRow is the last logical row
1426+
let handledDown = false;
1427+
act(() => {
1428+
handledDown = result.current.handleInput({
1429+
name: 'down',
1430+
shift: false,
1431+
alt: false,
1432+
ctrl: false,
1433+
cmd: false,
1434+
insertable: false,
1435+
sequence: '\x1b[B',
1436+
});
1437+
});
1438+
expect(handledDown).toBe(true);
1439+
expect(getBufferState(result).visualCursor[0]).toBe(1);
1440+
});
1441+
13871442
it('moveToVisualPosition: should correctly handle wide characters (Chinese)', () => {
13881443
const { result } = renderHook(() =>
13891444
useTextBuffer({

packages/cli/src/ui/components/shared/text-buffer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2905,12 +2905,12 @@ export function useTextBuffer({
29052905
return true;
29062906
}
29072907
if (keyMatchers[Command.MOVE_UP](key)) {
2908-
if (cursorRow === 0) return false;
2908+
if (visualCursor[0] === 0) return false;
29092909
move('up');
29102910
return true;
29112911
}
29122912
if (keyMatchers[Command.MOVE_DOWN](key)) {
2913-
if (cursorRow === lines.length - 1) return false;
2913+
if (visualCursor[0] === visualLines.length - 1) return false;
29142914
move('down');
29152915
return true;
29162916
}
@@ -2990,6 +2990,8 @@ export function useTextBuffer({
29902990
singleLine,
29912991
setText,
29922992
text,
2993+
visualCursor,
2994+
visualLines,
29932995
],
29942996
);
29952997

0 commit comments

Comments
 (0)