diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx index 3f93c84d7..a2ade610b 100644 --- a/packages/cli/src/ui/components/ThemeDialog.tsx +++ b/packages/cli/src/ui/components/ThemeDialog.tsx @@ -260,6 +260,7 @@ def fibonacci(n): availableTerminalHeight={diffHeight} contentWidth={colorizeCodeWidth} theme={previewTheme} + settings={settings} /> ); diff --git a/packages/cli/src/ui/components/messages/DiffRenderer.test.tsx b/packages/cli/src/ui/components/messages/DiffRenderer.test.tsx index 923b3c28a..a725f5e64 100644 --- a/packages/cli/src/ui/components/messages/DiffRenderer.test.tsx +++ b/packages/cli/src/ui/components/messages/DiffRenderer.test.tsx @@ -11,6 +11,14 @@ import * as CodeColorizer from '../../utils/CodeColorizer.js'; import { vi } from 'vitest'; import type { LoadedSettings } from '../../../config/settings.js'; +const mockSettings: LoadedSettings = { + merged: { + ui: { + showLineNumbers: true, + }, + }, +} as LoadedSettings; + describe('', () => { const mockColorizeCode = vi.spyOn(CodeColorizer, 'colorizeCode'); @@ -18,8 +26,8 @@ describe('', () => { mockColorizeCode.mockClear(); }); - const sanitizeOutput = (output: string | undefined, terminalWidth: number) => - output?.replace(/GAP_INDICATOR/g, '═'.repeat(terminalWidth)); + const sanitizeOutput = (output: string | undefined, contentWidth: number) => + output?.replace(/GAP_INDICATOR/g, '═'.repeat(contentWidth)); it('should call colorizeCode with correct language for new file with known extension', () => { const newFileDiffContent = ` @@ -37,6 +45,7 @@ index 0000000..e69de29 diffContent={newFileDiffContent} filename="test.py" contentWidth={80} + settings={mockSettings} /> , ); @@ -46,7 +55,7 @@ index 0000000..e69de29 undefined, 80, undefined, - undefined, + mockSettings, ); }); @@ -66,6 +75,7 @@ index 0000000..e69de29 diffContent={newFileDiffContent} filename="test.unknown" contentWidth={80} + settings={mockSettings} /> , ); @@ -75,7 +85,7 @@ index 0000000..e69de29 undefined, 80, undefined, - undefined, + mockSettings, ); }); @@ -91,7 +101,11 @@ index 0000000..e69de29 `; render( - + , ); expect(mockColorizeCode).toHaveBeenCalledWith( @@ -100,7 +114,7 @@ index 0000000..e69de29 undefined, 80, undefined, - undefined, + mockSettings, ); }); @@ -120,6 +134,7 @@ index 0000001..0000002 100644 diffContent={existingFileDiffContent} filename="test.txt" contentWidth={80} + settings={mockSettings} /> , ); @@ -150,6 +165,7 @@ index 1234567..1234567 100644 diffContent={noChangeDiff} filename="file.txt" contentWidth={80} + settings={mockSettings} /> , ); @@ -160,7 +176,11 @@ index 1234567..1234567 100644 it('should handle empty diff content', () => { const { lastFrame } = render( - + , ); expect(lastFrame()).toContain('No diff content'); @@ -187,6 +207,7 @@ index 123..456 100644 diffContent={diffWithGap} filename="file.txt" contentWidth={80} + settings={mockSettings} /> , ); @@ -224,6 +245,7 @@ index abc..def 100644 diffContent={diffWithSmallGap} filename="file.txt" contentWidth={80} + settings={mockSettings} /> , ); @@ -255,7 +277,7 @@ index 123..789 100644 it.each([ { - terminalWidth: 80, + contentWidth: 80, height: undefined, expected: ` 1 console.log('first hunk'); 2 - const oldVar = 1; @@ -268,7 +290,7 @@ index 123..789 100644 22 console.log('end of second hunk');`, }, { - terminalWidth: 80, + contentWidth: 80, height: 6, expected: `... first 4 lines hidden ... ════════════════════════════════════════════════════════════════════════════════ @@ -278,7 +300,7 @@ index 123..789 100644 22 console.log('end of second hunk');`, }, { - terminalWidth: 30, + contentWidth: 30, height: 6, expected: `... first 10 lines hidden ... ; @@ -288,20 +310,21 @@ index 123..789 100644 second hunk');`, }, ])( - 'with terminalWidth $terminalWidth and height $height', - ({ terminalWidth, height, expected }) => { + 'with contentWidth $contentWidth and height $height', + ({ contentWidth, height, expected }) => { const { lastFrame } = render( , ); const output = lastFrame(); - expect(sanitizeOutput(output, terminalWidth)).toEqual(expected); + expect(sanitizeOutput(output, contentWidth)).toEqual(expected); }, ); }); @@ -328,6 +351,7 @@ fileDiff Index: file.txt diffContent={newFileDiff} filename="TEST" contentWidth={80} + settings={mockSettings} /> , ); @@ -358,6 +382,7 @@ fileDiff Index: Dockerfile diffContent={newFileDiff} filename="Dockerfile" contentWidth={80} + settings={mockSettings} /> , ); @@ -385,7 +410,7 @@ index 0000001..0000002 100644 , ); @@ -409,7 +434,7 @@ index 0000001..0000002 100644 , @@ -434,7 +459,7 @@ index 0000001..0000002 100644 , diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx index d8ded72a6..7bfe9a962 100644 --- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx @@ -226,6 +226,7 @@ export const ToolConfirmationMessage: React.FC< filename={confirmationDetails.fileName} availableTerminalHeight={availableBodyContentHeight()} contentWidth={contentWidth} + settings={settings} /> ); } else if (confirmationDetails.type === 'exec') { diff --git a/packages/cli/src/ui/components/messages/ToolMessage.test.tsx b/packages/cli/src/ui/components/messages/ToolMessage.test.tsx index f8bc7cb58..0c44a8ed9 100644 --- a/packages/cli/src/ui/components/messages/ToolMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ToolMessage.test.tsx @@ -11,11 +11,13 @@ import { ToolMessage } from './ToolMessage.js'; import { StreamingState, ToolCallStatus } from '../../types.js'; import { Text } from 'ink'; import { StreamingContext } from '../../contexts/StreamingContext.js'; +import { SettingsContext } from '../../contexts/SettingsContext.js'; import type { AnsiOutput, AnsiOutputDisplay, Config, } from '@qwen-code/qwen-code-core'; +import type { LoadedSettings } from '../../../config/settings.js'; vi.mock('../TerminalOutput.js', () => ({ TerminalOutput: function MockTerminalOutput({ @@ -90,6 +92,15 @@ vi.mock('../subagents/index.js', () => ({ }, })); +// Mock settings +const mockSettings: LoadedSettings = { + merged: { + ui: { + showLineNumbers: true, + }, + }, +} as LoadedSettings; + // Helper to render with context const renderWithContext = ( ui: React.ReactElement, @@ -97,9 +108,11 @@ const renderWithContext = ( ) => { const contextValue: StreamingState = streamingState; return render( - - {ui} - , + + + {ui} + + , ); }; diff --git a/packages/cli/src/ui/components/messages/ToolMessage.tsx b/packages/cli/src/ui/components/messages/ToolMessage.tsx index 5f7e12727..afc16317c 100644 --- a/packages/cli/src/ui/components/messages/ToolMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolMessage.tsx @@ -30,7 +30,7 @@ import { TOOL_STATUS, } from '../../constants.js'; import { theme } from '../../semantic-colors.js'; -import { SettingsContext } from '../../contexts/SettingsContext.js'; +import { useSettings } from '../../contexts/SettingsContext.js'; import type { LoadedSettings } from '../../../config/settings.js'; const STATIC_HEIGHT = 1; @@ -247,7 +247,7 @@ export const ToolMessage: React.FC = ({ ptyId, config, }) => { - const settings = React.useContext(SettingsContext); + const settings = useSettings(); const isThisShellFocused = (name === SHELL_COMMAND_NAME || name === 'Shell') && status === ToolCallStatus.Executing &&