diff options
| author | Jacob Richman <[email protected]> | 2025-05-01 10:34:07 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-05-01 10:34:07 -0700 |
| commit | 7e8f379dfbd4d70050ce301a42a38ba9c1f052f4 (patch) | |
| tree | 7d712dd0b3b6b246bc7dd92048cc91c5317a3a47 /packages/cli/src/config | |
| parent | a18eea8c23dfb6759472d6b0bb80e13c2d6ef736 (diff) | |
Save settings to ~/.gemini/settings.json and optionally /your/workspace/.gemini/settings.json (#237)
Diffstat (limited to 'packages/cli/src/config')
| -rw-r--r-- | packages/cli/src/config/settings.ts | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts new file mode 100644 index 00000000..0c877f8f --- /dev/null +++ b/packages/cli/src/config/settings.ts @@ -0,0 +1,132 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import { homedir } from 'os'; +import { Config } from '@gemini-code/server'; + +const SETTINGS_DIRECTORY_NAME = '.gemini'; +const USER_SETTINGS_DIR = path.join(homedir(), SETTINGS_DIRECTORY_NAME); +const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, 'settings.json'); + +export enum SettingScope { + User = 'User', + Workspace = 'Workspace', +} + +export interface Settings { + theme?: string; + // Add other settings here. +} + +export interface SettingsFile { + settings: Settings; + path: string; +} +export class LoadedSettings { + constructor(user: SettingsFile, workspace: SettingsFile) { + this.user = user; + this.workspace = workspace; + this.merged = this.computeMergedSettings(); + } + + readonly user: SettingsFile; + readonly workspace: SettingsFile; + + private merged: Settings; + + getMerged(): Settings { + return this.merged; + } + + private computeMergedSettings(): Settings { + return { + ...this.user.settings, + ...this.workspace.settings, + }; + } + + forScope(scope: SettingScope): SettingsFile { + switch (scope) { + case SettingScope.User: + return this.user; + case SettingScope.Workspace: + return this.workspace; + default: + throw new Error(`Invalid scope: ${scope}`); + } + } + + setValue( + scope: SettingScope, + key: keyof Settings, + value: string | undefined, + ): void { + const settingsFile = this.forScope(scope); + settingsFile.settings[key] = value; + this.merged = this.computeMergedSettings(); + saveSettings(settingsFile); + } +} + +/** + * Loads settings from user and project configuration files. + * Project settings override user settings. + */ +export function loadSettings(config: Config): LoadedSettings { + let userSettings: Settings = {}; + let workspaceSettings = {}; + + // Load user settings + try { + if (fs.existsSync(USER_SETTINGS_PATH)) { + const userContent = fs.readFileSync(USER_SETTINGS_PATH, 'utf-8'); + userSettings = JSON.parse(userContent); + } + } catch (error) { + console.error('Error reading user settings file:', error); + } + + const workspaceSettingsPath = path.join( + config.getTargetDir(), + SETTINGS_DIRECTORY_NAME, + 'settings.json', + ); + + // Load workspace settings + try { + if (fs.existsSync(workspaceSettingsPath)) { + const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8'); + workspaceSettings = JSON.parse(projectContent); + } + } catch (error) { + console.error('Error reading workspace settings file:', error); + } + + return new LoadedSettings( + { path: USER_SETTINGS_PATH, settings: userSettings }, + { path: workspaceSettingsPath, settings: workspaceSettings }, + ); +} + +export function saveSettings(settingsFile: SettingsFile): void { + try { + // Ensure the directory exists + const dirPath = path.dirname(settingsFile.path); + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + + fs.writeFileSync( + settingsFile.path, + JSON.stringify(settingsFile.settings, null, 2), + 'utf-8', + ); + } catch (error) { + console.error('Error saving user settings file:', error); + } +} |
