mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 01:07:46 +00:00
refactor: refactor settings to a nested structure (#7244)
This commit is contained in:
@@ -313,6 +313,7 @@ describe('App UI', () => {
|
||||
workspaceSettingsFile,
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -684,7 +685,10 @@ describe('App UI', () => {
|
||||
|
||||
it('should display custom contextFileName in footer when set and count is 1', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
workspace: { contextFileName: 'AGENTS.md', theme: 'Default' },
|
||||
workspace: {
|
||||
context: { fileName: 'AGENTS.md' },
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
mockConfig.getGeminiMdFileCount.mockReturnValue(1);
|
||||
mockConfig.getAllGeminiMdFilenames.mockReturnValue(['AGENTS.md']);
|
||||
@@ -706,8 +710,8 @@ describe('App UI', () => {
|
||||
it('should display a generic message when multiple context files with different names are provided', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
workspace: {
|
||||
contextFileName: ['AGENTS.md', 'CONTEXT.md'],
|
||||
theme: 'Default',
|
||||
context: { fileName: ['AGENTS.md', 'CONTEXT.md'] },
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
mockConfig.getGeminiMdFileCount.mockReturnValue(2);
|
||||
@@ -732,7 +736,10 @@ describe('App UI', () => {
|
||||
|
||||
it('should display custom contextFileName with plural when set and count is > 1', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
workspace: { contextFileName: 'MY_NOTES.TXT', theme: 'Default' },
|
||||
workspace: {
|
||||
context: { fileName: 'MY_NOTES.TXT' },
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
mockConfig.getGeminiMdFileCount.mockReturnValue(3);
|
||||
mockConfig.getAllGeminiMdFilenames.mockReturnValue([
|
||||
@@ -757,7 +764,10 @@ describe('App UI', () => {
|
||||
|
||||
it('should not display context file message if count is 0, even if contextFileName is set', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
workspace: { contextFileName: 'ANY_FILE.MD', theme: 'Default' },
|
||||
workspace: {
|
||||
context: { fileName: 'ANY_FILE.MD' },
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
mockConfig.getGeminiMdFileCount.mockReturnValue(0);
|
||||
mockConfig.getAllGeminiMdFilenames.mockReturnValue([]);
|
||||
@@ -838,7 +848,7 @@ describe('App UI', () => {
|
||||
it('should not display Tips component when hideTips is true', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
workspace: {
|
||||
hideTips: true,
|
||||
ui: { hideTips: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -871,7 +881,7 @@ describe('App UI', () => {
|
||||
it('should not display Header component when hideBanner is true', async () => {
|
||||
const { Header } = await import('./components/Header.js');
|
||||
mockSettings = createMockSettings({
|
||||
user: { hideBanner: true },
|
||||
user: { ui: { hideBanner: true } },
|
||||
});
|
||||
|
||||
const { unmount } = renderWithProviders(
|
||||
@@ -902,7 +912,7 @@ describe('App UI', () => {
|
||||
|
||||
it('should not display Footer component when hideFooter is true', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
user: { hideFooter: true },
|
||||
user: { ui: { hideFooter: true } },
|
||||
});
|
||||
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
@@ -920,9 +930,9 @@ describe('App UI', () => {
|
||||
|
||||
it('should show footer if system says show, but workspace and user settings say hide', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
system: { hideFooter: false },
|
||||
user: { hideFooter: true },
|
||||
workspace: { hideFooter: true },
|
||||
system: { ui: { hideFooter: false } },
|
||||
user: { ui: { hideFooter: true } },
|
||||
workspace: { ui: { hideFooter: true } },
|
||||
});
|
||||
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
@@ -940,9 +950,9 @@ describe('App UI', () => {
|
||||
|
||||
it('should show tips if system says show, but workspace and user settings say hide', async () => {
|
||||
mockSettings = createMockSettings({
|
||||
system: { hideTips: false },
|
||||
user: { hideTips: true },
|
||||
workspace: { hideTips: true },
|
||||
system: { ui: { hideTips: false } },
|
||||
user: { ui: { hideTips: true } },
|
||||
workspace: { ui: { hideTips: true } },
|
||||
});
|
||||
|
||||
const { unmount } = renderWithProviders(
|
||||
@@ -1117,9 +1127,13 @@ describe('App UI', () => {
|
||||
const validateAuthMethodSpy = vi.spyOn(auth, 'validateAuthMethod');
|
||||
mockSettings = createMockSettings({
|
||||
workspace: {
|
||||
selectedAuthType: 'USE_GEMINI' as AuthType,
|
||||
useExternalAuth: false,
|
||||
theme: 'Default',
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: 'USE_GEMINI' as AuthType,
|
||||
useExternal: false,
|
||||
},
|
||||
},
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1139,9 +1153,13 @@ describe('App UI', () => {
|
||||
const validateAuthMethodSpy = vi.spyOn(auth, 'validateAuthMethod');
|
||||
mockSettings = createMockSettings({
|
||||
workspace: {
|
||||
selectedAuthType: 'USE_GEMINI' as AuthType,
|
||||
useExternalAuth: true,
|
||||
theme: 'Default',
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: 'USE_GEMINI' as AuthType,
|
||||
useExternal: true,
|
||||
},
|
||||
},
|
||||
ui: { theme: 'Default' },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1536,8 +1554,8 @@ describe('App UI', () => {
|
||||
it('should pass debugKeystrokeLogging setting to KeypressProvider', () => {
|
||||
const mockSettingsWithDebug = createMockSettings({
|
||||
workspace: {
|
||||
theme: 'Default',
|
||||
debugKeystrokeLogging: true,
|
||||
ui: { theme: 'Default' },
|
||||
advanced: { debugKeystrokeLogging: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1553,7 +1571,9 @@ describe('App UI', () => {
|
||||
const output = lastFrame();
|
||||
|
||||
expect(output).toBeDefined();
|
||||
expect(mockSettingsWithDebug.merged.debugKeystrokeLogging).toBe(true);
|
||||
expect(mockSettingsWithDebug.merged.advanced?.debugKeystrokeLogging).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('should use default false value when debugKeystrokeLogging is not set', () => {
|
||||
@@ -1569,7 +1589,9 @@ describe('App UI', () => {
|
||||
const output = lastFrame();
|
||||
|
||||
expect(output).toBeDefined();
|
||||
expect(mockSettings.merged.debugKeystrokeLogging).toBeUndefined();
|
||||
expect(
|
||||
mockSettings.merged.advanced?.debugKeystrokeLogging,
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -134,7 +134,9 @@ export const AppWrapper = (props: AppProps) => {
|
||||
<KeypressProvider
|
||||
kittyProtocolEnabled={kittyProtocolStatus.enabled}
|
||||
config={props.config}
|
||||
debugKeystrokeLogging={props.settings.merged.debugKeystrokeLogging}
|
||||
debugKeystrokeLogging={
|
||||
props.settings.merged.general?.debugKeystrokeLogging
|
||||
}
|
||||
>
|
||||
<SessionStatsProvider>
|
||||
<VimModeProvider settings={props.settings}>
|
||||
@@ -161,7 +163,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
const shouldShowIdePrompt =
|
||||
currentIDE &&
|
||||
!config.getIdeMode() &&
|
||||
!settings.merged.hasSeenIdeIntegrationNudge &&
|
||||
!settings.merged.ide?.hasSeenNudge &&
|
||||
!idePromptAnswered;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -301,16 +303,21 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
} = useAuthCommand(settings, setAuthError, config);
|
||||
|
||||
useEffect(() => {
|
||||
if (settings.merged.selectedAuthType && !settings.merged.useExternalAuth) {
|
||||
const error = validateAuthMethod(settings.merged.selectedAuthType);
|
||||
if (
|
||||
settings.merged.security?.auth?.selectedType &&
|
||||
!settings.merged.security?.auth?.useExternal
|
||||
) {
|
||||
const error = validateAuthMethod(
|
||||
settings.merged.security.auth.selectedType,
|
||||
);
|
||||
if (error) {
|
||||
setAuthError(error);
|
||||
openAuthDialog();
|
||||
}
|
||||
}
|
||||
}, [
|
||||
settings.merged.selectedAuthType,
|
||||
settings.merged.useExternalAuth,
|
||||
settings.merged.security?.auth?.selectedType,
|
||||
settings.merged.security?.auth?.useExternal,
|
||||
openAuthDialog,
|
||||
setAuthError,
|
||||
]);
|
||||
@@ -345,14 +352,14 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
try {
|
||||
const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(
|
||||
process.cwd(),
|
||||
settings.merged.loadMemoryFromIncludeDirectories
|
||||
settings.merged.context?.loadMemoryFromIncludeDirectories
|
||||
? config.getWorkspaceContext().getDirectories()
|
||||
: [],
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
settings.merged,
|
||||
config.getExtensionContextFilePaths(),
|
||||
settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
||||
settings.merged.context?.importFormat || 'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
);
|
||||
|
||||
@@ -510,7 +517,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
}, []);
|
||||
|
||||
const getPreferredEditor = useCallback(() => {
|
||||
const editorType = settings.merged.preferredEditor;
|
||||
const editorType = settings.merged.general?.preferredEditor;
|
||||
const isValidEditor = isEditorAvailable(editorType);
|
||||
if (!isValidEditor) {
|
||||
openEditorDialog();
|
||||
@@ -701,7 +708,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
const handleGlobalKeypress = useCallback(
|
||||
(key: Key) => {
|
||||
// Debug log keystrokes if enabled
|
||||
if (settings.merged.debugKeystrokeLogging) {
|
||||
if (settings.merged.general?.debugKeystrokeLogging) {
|
||||
console.log('[DEBUG] Keystroke:', JSON.stringify(key));
|
||||
}
|
||||
|
||||
@@ -768,7 +775,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
handleSlashCommand,
|
||||
isAuthenticating,
|
||||
cancelOngoingRequest,
|
||||
settings.merged.debugKeystrokeLogging,
|
||||
settings.merged.general?.debugKeystrokeLogging,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -884,12 +891,12 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
const branchName = useGitBranchName(config.getTargetDir());
|
||||
|
||||
const contextFileNames = useMemo(() => {
|
||||
const fromSettings = settings.merged.contextFileName;
|
||||
const fromSettings = settings.merged.context?.fileName;
|
||||
if (fromSettings) {
|
||||
return Array.isArray(fromSettings) ? fromSettings : [fromSettings];
|
||||
}
|
||||
return getAllGeminiMdFilenames();
|
||||
}, [settings.merged.contextFileName]);
|
||||
}, [settings.merged.context?.fileName]);
|
||||
|
||||
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
|
||||
const geminiClient = config.getGeminiClient();
|
||||
@@ -965,10 +972,10 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
key={staticKey}
|
||||
items={[
|
||||
<Box flexDirection="column" key="header">
|
||||
{!(settings.merged.hideBanner || config.getScreenReader()) && (
|
||||
<Header version={version} nightly={nightly} />
|
||||
)}
|
||||
{!(settings.merged.hideTips || config.getScreenReader()) && (
|
||||
{!(
|
||||
settings.merged.ui?.hideBanner || config.getScreenReader()
|
||||
) && <Header version={version} nightly={nightly} />}
|
||||
{!(settings.merged.ui?.hideTips || config.getScreenReader()) && (
|
||||
<Tips config={config} />
|
||||
)}
|
||||
</Box>,
|
||||
@@ -1300,7 +1307,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
{!settings.merged.hideFooter && (
|
||||
{!settings.merged.ui?.hideFooter && (
|
||||
<Footer
|
||||
model={currentModel}
|
||||
targetDir={config.getTargetDir()}
|
||||
@@ -1312,7 +1319,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
showErrorDetails={showErrorDetails}
|
||||
showMemoryUsage={
|
||||
config.getDebugMode() ||
|
||||
settings.merged.showMemoryUsage ||
|
||||
settings.merged.ui?.showMemoryUsage ||
|
||||
false
|
||||
}
|
||||
promptTokenCount={sessionStats.lastPromptTokenCount}
|
||||
|
||||
@@ -32,7 +32,11 @@ describe('aboutCommand', () => {
|
||||
},
|
||||
settings: {
|
||||
merged: {
|
||||
selectedAuthType: 'test-auth',
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: 'test-auth',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export const aboutCommand: SlashCommand = {
|
||||
const modelVersion = context.services.config?.getModel() || 'Unknown';
|
||||
const cliVersion = await getCliVersion();
|
||||
const selectedAuthType =
|
||||
context.services.settings.merged.selectedAuthType || '';
|
||||
context.services.settings.merged.security?.auth?.selectedType || '';
|
||||
const gcpProject = process.env['GOOGLE_CLOUD_PROJECT'] || '';
|
||||
const ideClient =
|
||||
(context.services.config?.getIdeMode() &&
|
||||
|
||||
@@ -104,9 +104,10 @@ export const directoryCommand: SlashCommand = {
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
config.getExtensionContextFilePaths(),
|
||||
context.services.settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
||||
context.services.settings.merged.context?.importFormat ||
|
||||
'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
context.services.settings.merged.memoryDiscoveryMaxDirs,
|
||||
context.services.settings.merged.context?.discoveryMaxDirs,
|
||||
);
|
||||
config.setUserMemory(memoryContent);
|
||||
config.setGeminiMdFileCount(fileCount);
|
||||
|
||||
@@ -187,7 +187,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
Date.now(),
|
||||
);
|
||||
if (result.success) {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', true);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
true,
|
||||
);
|
||||
// Poll for up to 5 seconds for the extension to activate.
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await config.setIdeModeAndSyncConnection(true);
|
||||
@@ -227,7 +231,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
description: 'enable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', true);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
true,
|
||||
);
|
||||
await config.setIdeModeAndSyncConnection(true);
|
||||
const { messageType, content } = getIdeStatusMessage(ideClient);
|
||||
context.ui.addItem(
|
||||
@@ -245,7 +253,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
description: 'disable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', false);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
false,
|
||||
);
|
||||
await config.setIdeModeAndSyncConnection(false);
|
||||
const { messageType, content } = getIdeStatusMessage(ideClient);
|
||||
context.ui.addItem(
|
||||
|
||||
@@ -92,9 +92,10 @@ export const memoryCommand: SlashCommand = {
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
config.getExtensionContextFilePaths(),
|
||||
context.services.settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
||||
context.services.settings.merged.context?.importFormat ||
|
||||
'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
context.services.settings.merged.memoryDiscoveryMaxDirs,
|
||||
context.services.settings.merged.context?.discoveryMaxDirs,
|
||||
);
|
||||
config.setUserMemory(memoryContent);
|
||||
config.setGeminiMdFileCount(fileCount);
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('AuthDialog', () => {
|
||||
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
@@ -40,16 +40,21 @@ describe('AuthDialog', () => {
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: AuthType.USE_GEMINI,
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: AuthType.USE_GEMINI,
|
||||
},
|
||||
},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -72,8 +77,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -83,15 +88,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -110,8 +116,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -121,15 +127,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -148,8 +155,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -159,15 +166,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -187,8 +195,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -198,15 +206,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -221,8 +230,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -232,15 +241,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -257,8 +267,8 @@ describe('AuthDialog', () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
@@ -268,15 +278,16 @@ describe('AuthDialog', () => {
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
@@ -296,7 +307,7 @@ describe('AuthDialog', () => {
|
||||
const onSelect = vi.fn();
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
@@ -305,18 +316,19 @@ describe('AuthDialog', () => {
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame, stdin, unmount } = renderWithProviders(
|
||||
@@ -340,7 +352,7 @@ describe('AuthDialog', () => {
|
||||
const onSelect = vi.fn();
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
@@ -349,18 +361,19 @@ describe('AuthDialog', () => {
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: undefined,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame, stdin, unmount } = renderWithProviders(
|
||||
@@ -387,7 +400,7 @@ describe('AuthDialog', () => {
|
||||
const onSelect = vi.fn();
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
@@ -396,18 +409,19 @@ describe('AuthDialog', () => {
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
selectedAuthType: AuthType.USE_GEMINI,
|
||||
customThemes: {},
|
||||
security: { auth: { selectedType: AuthType.LOGIN_WITH_GOOGLE } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {} },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { stdin, unmount } = renderWithProviders(
|
||||
|
||||
@@ -83,8 +83,8 @@ export function AuthDialog({
|
||||
];
|
||||
|
||||
const initialAuthIndex = items.findIndex((item) => {
|
||||
if (settings.merged.selectedAuthType) {
|
||||
return item.value === settings.merged.selectedAuthType;
|
||||
if (settings.merged.security?.auth?.selectedType) {
|
||||
return item.value === settings.merged.security.auth.selectedType;
|
||||
}
|
||||
|
||||
const defaultAuthType = parseDefaultAuthType(
|
||||
@@ -119,7 +119,7 @@ export function AuthDialog({
|
||||
if (errorMessage) {
|
||||
return;
|
||||
}
|
||||
if (settings.merged.selectedAuthType === undefined) {
|
||||
if (settings.merged.security?.auth?.selectedType === undefined) {
|
||||
// Prevent exiting if no auth method is set
|
||||
setErrorMessage(
|
||||
'You must select an auth method to proceed. Press Ctrl+C twice to exit.',
|
||||
|
||||
@@ -53,7 +53,7 @@ export function EditorSettingsDialog({
|
||||
editorSettingsManager.getAvailableEditorDisplays();
|
||||
|
||||
const currentPreference =
|
||||
settings.forScope(selectedScope).settings.preferredEditor;
|
||||
settings.forScope(selectedScope).settings.general?.preferredEditor;
|
||||
let editorIndex = currentPreference
|
||||
? editorItems.findIndex(
|
||||
(item: EditorDisplay) => item.type === currentPreference,
|
||||
@@ -87,20 +87,26 @@ export function EditorSettingsDialog({
|
||||
selectedScope === SettingScope.User
|
||||
? SettingScope.Workspace
|
||||
: SettingScope.User;
|
||||
if (settings.forScope(otherScope).settings.preferredEditor !== undefined) {
|
||||
if (
|
||||
settings.forScope(otherScope).settings.general?.preferredEditor !==
|
||||
undefined
|
||||
) {
|
||||
otherScopeModifiedMessage =
|
||||
settings.forScope(selectedScope).settings.preferredEditor !== undefined
|
||||
settings.forScope(selectedScope).settings.general?.preferredEditor !==
|
||||
undefined
|
||||
? `(Also modified in ${otherScope})`
|
||||
: `(Modified in ${otherScope})`;
|
||||
}
|
||||
|
||||
let mergedEditorName = 'None';
|
||||
if (
|
||||
settings.merged.preferredEditor &&
|
||||
isEditorAvailable(settings.merged.preferredEditor)
|
||||
settings.merged.general?.preferredEditor &&
|
||||
isEditorAvailable(settings.merged.general?.preferredEditor)
|
||||
) {
|
||||
mergedEditorName =
|
||||
EDITOR_DISPLAY_NAMES[settings.merged.preferredEditor as EditorType];
|
||||
EDITOR_DISPLAY_NAMES[
|
||||
settings.merged.general?.preferredEditor as EditorType
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -40,7 +40,7 @@ const createMockSettings = (
|
||||
) =>
|
||||
new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {}, ...systemSettings },
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {}, ...systemSettings },
|
||||
path: '/system/settings.json',
|
||||
},
|
||||
{
|
||||
@@ -49,18 +49,23 @@ const createMockSettings = (
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
customThemes: {},
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...userSettings,
|
||||
},
|
||||
path: '/user/settings.json',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {}, ...workspaceSettings },
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...workspaceSettings,
|
||||
},
|
||||
path: '/workspace/settings.json',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
vi.mock('../contexts/SettingsContext.js', async () => {
|
||||
@@ -156,7 +161,11 @@ describe('SettingsDialog', () => {
|
||||
) =>
|
||||
new LoadedSettings(
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {}, ...systemSettings },
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...systemSettings,
|
||||
},
|
||||
path: '/system/settings.json',
|
||||
},
|
||||
{
|
||||
@@ -165,18 +174,23 @@ describe('SettingsDialog', () => {
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
customThemes: {},
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...userSettings,
|
||||
},
|
||||
path: '/user/settings.json',
|
||||
},
|
||||
{
|
||||
settings: { customThemes: {}, mcpServers: {}, ...workspaceSettings },
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...workspaceSettings,
|
||||
},
|
||||
path: '/workspace/settings.json',
|
||||
},
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
describe('Initial Rendering', () => {
|
||||
@@ -392,11 +406,11 @@ describe('SettingsDialog', () => {
|
||||
|
||||
// Wait for initial render
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Hide Window Title');
|
||||
expect(lastFrame()).toContain('Vim Mode');
|
||||
});
|
||||
|
||||
// The UI should show the settings section is active and scope section is inactive
|
||||
expect(lastFrame()).toContain('● Hide Window Title'); // Settings section active
|
||||
expect(lastFrame()).toContain('● Vim Mode'); // Settings section active
|
||||
expect(lastFrame()).toContain(' Apply To'); // Scope section inactive
|
||||
|
||||
// This test validates the initial state - scope selection behavior
|
||||
@@ -814,11 +828,11 @@ describe('SettingsDialog', () => {
|
||||
|
||||
// Wait for initial render
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Hide Window Title');
|
||||
expect(lastFrame()).toContain('Vim Mode');
|
||||
});
|
||||
|
||||
// Verify initial state: settings section active, scope section inactive
|
||||
expect(lastFrame()).toContain('● Hide Window Title'); // Settings section active
|
||||
expect(lastFrame()).toContain('● Vim Mode'); // Settings section active
|
||||
expect(lastFrame()).toContain(' Apply To'); // Scope section inactive
|
||||
|
||||
// This test validates the rendered UI structure for tab navigation
|
||||
@@ -876,12 +890,12 @@ describe('SettingsDialog', () => {
|
||||
|
||||
// Wait for initial render
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Hide Window Title');
|
||||
expect(lastFrame()).toContain('Vim Mode');
|
||||
});
|
||||
|
||||
// Verify the complete UI is rendered with all necessary sections
|
||||
expect(lastFrame()).toContain('Settings'); // Title
|
||||
expect(lastFrame()).toContain('● Hide Window Title'); // Active setting
|
||||
expect(lastFrame()).toContain('● Vim Mode'); // Active setting
|
||||
expect(lastFrame()).toContain('Apply To'); // Scope section
|
||||
expect(lastFrame()).toContain('1. User Settings'); // Scope options
|
||||
expect(lastFrame()).toContain(
|
||||
|
||||
@@ -153,7 +153,7 @@ export function SettingsDialog({
|
||||
);
|
||||
|
||||
// Special handling for vim mode to sync with VimModeContext
|
||||
if (key === 'vimMode' && newValue !== vimEnabled) {
|
||||
if (key === 'general.vimMode' && newValue !== vimEnabled) {
|
||||
// Call toggleVimEnabled to sync the VimModeContext local state
|
||||
toggleVimEnabled().catch((error) => {
|
||||
console.error('Failed to toggle vim mode:', error);
|
||||
|
||||
@@ -46,13 +46,13 @@ export function ThemeDialog({
|
||||
// Track the currently highlighted theme name
|
||||
const [highlightedThemeName, setHighlightedThemeName] = useState<
|
||||
string | undefined
|
||||
>(settings.merged.theme || DEFAULT_THEME.name);
|
||||
>(settings.merged.ui?.theme || DEFAULT_THEME.name);
|
||||
|
||||
// Generate theme items filtered by selected scope
|
||||
const customThemes =
|
||||
selectedScope === SettingScope.User
|
||||
? settings.user.settings.customThemes || {}
|
||||
: settings.merged.customThemes || {};
|
||||
? settings.user.settings.ui?.customThemes || {}
|
||||
: settings.merged.ui?.customThemes || {};
|
||||
const builtInThemes = themeManager
|
||||
.getAvailableThemes()
|
||||
.filter((theme) => theme.type !== 'custom');
|
||||
@@ -76,7 +76,7 @@ export function ThemeDialog({
|
||||
const [selectInputKey, setSelectInputKey] = useState(Date.now());
|
||||
|
||||
// Find the index of the selected theme, but only if it exists in the list
|
||||
const selectedThemeName = settings.merged.theme || DEFAULT_THEME.name;
|
||||
const selectedThemeName = settings.merged.ui?.theme || DEFAULT_THEME.name;
|
||||
const initialThemeIndex = themeItems.findIndex(
|
||||
(item) => item.value === selectedThemeName,
|
||||
);
|
||||
@@ -128,7 +128,7 @@ export function ThemeDialog({
|
||||
|
||||
// Generate scope message for theme setting
|
||||
const otherScopeModifiedMessage = getScopeMessageForSetting(
|
||||
'theme',
|
||||
'ui.theme',
|
||||
selectedScope,
|
||||
settings,
|
||||
);
|
||||
|
||||
@@ -32,7 +32,7 @@ export const VimModeProvider = ({
|
||||
children: React.ReactNode;
|
||||
settings: LoadedSettings;
|
||||
}) => {
|
||||
const initialVimEnabled = settings.merged.vimMode ?? false;
|
||||
const initialVimEnabled = settings.merged.general?.vimMode ?? false;
|
||||
const [vimEnabled, setVimEnabled] = useState(initialVimEnabled);
|
||||
const [vimMode, setVimMode] = useState<VimMode>(
|
||||
initialVimEnabled ? 'NORMAL' : 'INSERT',
|
||||
@@ -40,13 +40,13 @@ export const VimModeProvider = ({
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize vimEnabled from settings on mount
|
||||
const enabled = settings.merged.vimMode ?? false;
|
||||
const enabled = settings.merged.general?.vimMode ?? false;
|
||||
setVimEnabled(enabled);
|
||||
// When vim mode is enabled, always start in NORMAL mode
|
||||
if (enabled) {
|
||||
setVimMode('NORMAL');
|
||||
}
|
||||
}, [settings.merged.vimMode]);
|
||||
}, [settings.merged.general?.vimMode]);
|
||||
|
||||
const toggleVimEnabled = useCallback(async () => {
|
||||
const newValue = !vimEnabled;
|
||||
@@ -55,7 +55,7 @@ export const VimModeProvider = ({
|
||||
if (newValue) {
|
||||
setVimMode('NORMAL');
|
||||
}
|
||||
await settings.setValue(SettingScope.User, 'vimMode', newValue);
|
||||
await settings.setValue(SettingScope.User, 'general.vimMode', newValue);
|
||||
return newValue;
|
||||
}, [vimEnabled, settings]);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useAuthCommand = (
|
||||
config: Config,
|
||||
) => {
|
||||
const [isAuthDialogOpen, setIsAuthDialogOpen] = useState(
|
||||
settings.merged.selectedAuthType === undefined,
|
||||
settings.merged.security?.auth?.selectedType === undefined,
|
||||
);
|
||||
|
||||
const openAuthDialog = useCallback(() => {
|
||||
@@ -30,7 +30,7 @@ export const useAuthCommand = (
|
||||
|
||||
useEffect(() => {
|
||||
const authFlow = async () => {
|
||||
const authType = settings.merged.selectedAuthType;
|
||||
const authType = settings.merged.security?.auth?.selectedType;
|
||||
if (isAuthDialogOpen || !authType) {
|
||||
return;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export const useAuthCommand = (
|
||||
if (authType) {
|
||||
await clearCachedCredentialFile();
|
||||
|
||||
settings.setValue(scope, 'selectedAuthType', authType);
|
||||
settings.setValue(scope, 'security.auth.selectedType', authType);
|
||||
if (
|
||||
authType === AuthType.LOGIN_WITH_GOOGLE &&
|
||||
config.isBrowserLaunchSuppressed()
|
||||
|
||||
@@ -22,7 +22,10 @@ export const useFolderTrust = (
|
||||
const [isFolderTrustDialogOpen, setIsFolderTrustDialogOpen] = useState(false);
|
||||
const [isRestarting, setIsRestarting] = useState(false);
|
||||
|
||||
const { folderTrust, folderTrustFeature } = settings.merged;
|
||||
const folderTrust = settings.merged.security?.folderTrust?.enabled;
|
||||
const folderTrustFeature =
|
||||
settings.merged.security?.folderTrust?.featureEnabled;
|
||||
|
||||
useEffect(() => {
|
||||
const trusted = isWorkspaceTrusted({
|
||||
folderTrust,
|
||||
|
||||
@@ -32,7 +32,7 @@ export function createShowMemoryAction(
|
||||
|
||||
const currentMemory = config.getUserMemory();
|
||||
const fileCount = config.getGeminiMdFileCount();
|
||||
const contextFileName = settings.merged.contextFileName;
|
||||
const contextFileName = settings.merged.context?.fileName;
|
||||
const contextFileNames = Array.isArray(contextFileName)
|
||||
? contextFileName
|
||||
: [contextFileName];
|
||||
|
||||
@@ -29,14 +29,14 @@ export const useThemeCommand = (
|
||||
|
||||
// Check for invalid theme configuration on startup
|
||||
useEffect(() => {
|
||||
const effectiveTheme = loadedSettings.merged.theme;
|
||||
const effectiveTheme = loadedSettings.merged.ui?.theme;
|
||||
if (effectiveTheme && !themeManager.findThemeByName(effectiveTheme)) {
|
||||
setIsThemeDialogOpen(true);
|
||||
setThemeError(`Theme "${effectiveTheme}" not found.`);
|
||||
} else {
|
||||
setThemeError(null);
|
||||
}
|
||||
}, [loadedSettings.merged.theme, setThemeError]);
|
||||
}, [loadedSettings.merged.ui?.theme, setThemeError]);
|
||||
|
||||
const openThemeDialog = useCallback(() => {
|
||||
if (process.env['NO_COLOR']) {
|
||||
@@ -77,8 +77,8 @@ export const useThemeCommand = (
|
||||
try {
|
||||
// Merge user and workspace custom themes (workspace takes precedence)
|
||||
const mergedCustomThemes = {
|
||||
...(loadedSettings.user.settings.customThemes || {}),
|
||||
...(loadedSettings.workspace.settings.customThemes || {}),
|
||||
...(loadedSettings.user.settings.ui?.customThemes || {}),
|
||||
...(loadedSettings.workspace.settings.ui?.customThemes || {}),
|
||||
};
|
||||
// Only allow selecting themes available in the merged custom themes or built-in themes
|
||||
const isBuiltIn = themeManager.findThemeByName(themeName);
|
||||
@@ -88,11 +88,11 @@ export const useThemeCommand = (
|
||||
setIsThemeDialogOpen(true);
|
||||
return;
|
||||
}
|
||||
loadedSettings.setValue(scope, 'theme', themeName); // Update the merged settings
|
||||
if (loadedSettings.merged.customThemes) {
|
||||
themeManager.loadCustomThemes(loadedSettings.merged.customThemes);
|
||||
loadedSettings.setValue(scope, 'ui.theme', themeName); // Update the merged settings
|
||||
if (loadedSettings.merged.ui?.customThemes) {
|
||||
themeManager.loadCustomThemes(loadedSettings.merged.ui?.customThemes);
|
||||
}
|
||||
applyTheme(loadedSettings.merged.theme); // Apply the current theme
|
||||
applyTheme(loadedSettings.merged.ui?.theme); // Apply the current theme
|
||||
setThemeError(null);
|
||||
} finally {
|
||||
setIsThemeDialogOpen(false); // Close the dialog
|
||||
|
||||
@@ -20,7 +20,7 @@ export function useWorkspaceMigration(settings: LoadedSettings) {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!settings.merged.extensionManagement) {
|
||||
if (!settings.merged.experimental?.extensionManagement) {
|
||||
return;
|
||||
}
|
||||
const cwd = process.cwd();
|
||||
@@ -33,7 +33,10 @@ export function useWorkspaceMigration(settings: LoadedSettings) {
|
||||
setShowWorkspaceMigrationDialog(true);
|
||||
console.log(settings.merged.extensions);
|
||||
}
|
||||
}, [settings.merged.extensions, settings.merged.extensionManagement]);
|
||||
}, [
|
||||
settings.merged.extensions,
|
||||
settings.merged.experimental?.extensionManagement,
|
||||
]);
|
||||
|
||||
const onWorkspaceMigrationDialogOpen = () => {
|
||||
const userSettings = settings.forScope(SettingScope.User);
|
||||
|
||||
@@ -134,7 +134,7 @@ export function colorizeCode(
|
||||
): React.ReactNode {
|
||||
const codeToHighlight = code.replace(/\n$/, '');
|
||||
const activeTheme = theme || themeManager.getActiveTheme();
|
||||
const showLineNumbers = settings?.merged.showLineNumbers ?? true;
|
||||
const showLineNumbers = settings?.merged.ui?.showLineNumbers ?? true;
|
||||
|
||||
try {
|
||||
// Render the HAST tree using the adapted theme
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('<MarkdownDisplay />', () => {
|
||||
{ path: '', settings: {} },
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -224,10 +225,11 @@ Another paragraph.
|
||||
const settings = new LoadedSettings(
|
||||
{ path: '', settings: {} },
|
||||
{ path: '', settings: {} },
|
||||
{ path: '', settings: { showLineNumbers: false } },
|
||||
{ path: '', settings: { ui: { showLineNumbers: false } } },
|
||||
{ path: '', settings: {} },
|
||||
[],
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { lastFrame } = render(
|
||||
|
||||
Reference in New Issue
Block a user