From d42da87161dd42555dc10bae5ea36b03e75dbc79 Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Thu, 16 Oct 2025 20:38:49 -0700 Subject: [PATCH] fix(accessibility) allow line wrapper in screen reader mode (#11317) --- packages/cli/src/gemini.test.tsx | 43 ++++++++++++++++++++++++++++++++ packages/cli/src/gemini.tsx | 14 ++++++----- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/gemini.test.tsx b/packages/cli/src/gemini.test.tsx index 65779d263d..87708aa902 100644 --- a/packages/cli/src/gemini.test.tsx +++ b/packages/cli/src/gemini.test.tsx @@ -486,4 +486,47 @@ describe('startInteractiveUI', () => { await new Promise((resolve) => setTimeout(resolve, 0)); expect(checkForUpdates).toHaveBeenCalledTimes(1); }); + + it.each([ + { + screenReader: true, + expectedCalls: [], + name: 'should not disable line wrapping in screen reader mode', + }, + { + screenReader: false, + expectedCalls: [['\x1b[?7l']], + name: 'should disable line wrapping when not in screen reader mode', + }, + ])('$name', async ({ screenReader, expectedCalls }) => { + const writeSpy = vi + .spyOn(process.stdout, 'write') + .mockImplementation(() => true); + const mockConfigWithScreenReader = { + ...mockConfig, + getScreenReader: () => screenReader, + } as Config; + + const mockInitializationResult = { + authError: null, + themeError: null, + shouldOpenAuthDialog: false, + geminiMdFileCount: 0, + }; + + await startInteractiveUI( + mockConfigWithScreenReader, + mockSettings, + mockStartupWarnings, + mockWorkspaceRoot, + mockInitializationResult, + ); + + if (expectedCalls.length > 0) { + expect(writeSpy).toHaveBeenCalledWith(expectedCalls[0][0]); + } else { + expect(writeSpy).not.toHaveBeenCalledWith('\x1b[?7l'); + } + writeSpy.mockRestore(); + }); }); diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index 77ee378863..e266fcc048 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -145,7 +145,7 @@ export async function startInteractiveUI( workspaceRoot: string = process.cwd(), initializationResult: InitializationResult, ) { - // Disable line wrapping. + // When not in screen reader mode, disable line wrapping. // We rely on Ink to manage all line wrapping by forcing all content to be // narrower than the terminal width so there is no need for the terminal to // also attempt line wrapping. @@ -154,12 +154,14 @@ export async function startInteractiveUI( // such as Ghostty. Some terminals such as Iterm2 only respect line wrapping // when using the alternate buffer, which Gemini CLI does not use because we // do not yet have support for scrolling in that mode. - process.stdout.write('\x1b[?7l'); + if (!config.getScreenReader()) { + process.stdout.write('\x1b[?7l'); - registerCleanup(() => { - // Re-enable line wrapping on exit. - process.stdout.write('\x1b[?7h'); - }); + registerCleanup(() => { + // Re-enable line wrapping on exit. + process.stdout.write('\x1b[?7h'); + }); + } const version = await getCliVersion(); setWindowTitle(basename(workspaceRoot), settings);