refactor: simplify settings manager with generic setter helpers (#1461)

Replace 30+ repetitive setter method bodies with four generic private
helpers: setGlobalSetting, setScopedSetting, setNestedGlobalSetting,
and setProjectSetting. Each setter method retains its original public
signature and behavior — only the internal implementation is consolidated.

Methods with custom logic (setEditorPaddingX, setAutocompleteMaxVisible,
setSearchExcludeDirs, setFallbackChain, removeFallbackChain,
setDefaultModelAndProvider) are left unchanged or minimally adapted.

Net reduction: 79 lines (164 deleted, 85 added).
This commit is contained in:
Juan Francisco Lebrero 2026-03-19 18:37:24 -03:00 committed by GitHub
parent 29a1882c04
commit 54b1446fb2

View file

@ -595,14 +595,56 @@ export class SettingsManager {
return drained;
}
// ── Generic setter helpers ──────────────────────────────────────────
/** Set a top-level global setting field, mark modified, and save. */
private setGlobalSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
this.globalSettings[key] = value;
this.markModified(key);
this.save();
}
/** Set a top-level setting, scoped to project when project settings are active. */
private setScopedSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
if (this.hasProjectSettings()) {
this.projectSettings[key] = value;
this.markProjectModified(key);
this.saveProjectSettings(this.projectSettings);
} else {
this.setGlobalSetting(key, value);
}
}
/** Set a nested field within a global settings object (e.g. compaction.enabled). */
private setNestedGlobalSetting<K extends keyof Settings, NK extends string & keyof NonNullable<Settings[K]>>(
key: K,
nestedKey: NK,
value: NonNullable<Settings[K]>[NK],
): void {
if (!this.globalSettings[key]) {
(this.globalSettings as Record<string, unknown>)[key] = {};
}
(this.globalSettings[key] as Record<string, unknown>)[nestedKey] = value;
this.markModified(key, nestedKey);
this.save();
}
/** Set a field on project settings (clone, set, mark modified, save). */
private setProjectSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings[key] = value;
this.markProjectModified(key);
this.saveProjectSettings(projectSettings);
}
// ── Public getters and setters ──────────────────────────────────────
getLastChangelogVersion(): string | undefined {
return this.settings.lastChangelogVersion;
}
setLastChangelogVersion(version: string): void {
this.globalSettings.lastChangelogVersion = version;
this.markModified("lastChangelogVersion");
this.save();
this.setGlobalSetting("lastChangelogVersion", version);
}
getDefaultProvider(): string | undefined {
@ -614,27 +656,11 @@ export class SettingsManager {
}
setDefaultProvider(provider: string): void {
if (this.hasProjectSettings()) {
this.projectSettings.defaultProvider = provider;
this.markProjectModified("defaultProvider");
this.saveProjectSettings(this.projectSettings);
} else {
this.globalSettings.defaultProvider = provider;
this.markModified("defaultProvider");
this.save();
}
this.setScopedSetting("defaultProvider", provider);
}
setDefaultModel(modelId: string): void {
if (this.hasProjectSettings()) {
this.projectSettings.defaultModel = modelId;
this.markProjectModified("defaultModel");
this.saveProjectSettings(this.projectSettings);
} else {
this.globalSettings.defaultModel = modelId;
this.markModified("defaultModel");
this.save();
}
this.setScopedSetting("defaultModel", modelId);
}
setDefaultModelAndProvider(provider: string, modelId: string): void {
@ -658,9 +684,7 @@ export class SettingsManager {
}
setSteeringMode(mode: "all" | "one-at-a-time"): void {
this.globalSettings.steeringMode = mode;
this.markModified("steeringMode");
this.save();
this.setGlobalSetting("steeringMode", mode);
}
getFollowUpMode(): "all" | "one-at-a-time" {
@ -668,9 +692,7 @@ export class SettingsManager {
}
setFollowUpMode(mode: "all" | "one-at-a-time"): void {
this.globalSettings.followUpMode = mode;
this.markModified("followUpMode");
this.save();
this.setGlobalSetting("followUpMode", mode);
}
getTheme(): string | undefined {
@ -678,9 +700,7 @@ export class SettingsManager {
}
setTheme(theme: string): void {
this.globalSettings.theme = theme;
this.markModified("theme");
this.save();
this.setGlobalSetting("theme", theme);
}
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
@ -688,9 +708,7 @@ export class SettingsManager {
}
setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void {
this.globalSettings.defaultThinkingLevel = level;
this.markModified("defaultThinkingLevel");
this.save();
this.setGlobalSetting("defaultThinkingLevel", level);
}
getTransport(): TransportSetting {
@ -698,9 +716,7 @@ export class SettingsManager {
}
setTransport(transport: TransportSetting): void {
this.globalSettings.transport = transport;
this.markModified("transport");
this.save();
this.setGlobalSetting("transport", transport);
}
getCompactionEnabled(): boolean {
@ -708,12 +724,7 @@ export class SettingsManager {
}
setCompactionEnabled(enabled: boolean): void {
if (!this.globalSettings.compaction) {
this.globalSettings.compaction = {};
}
this.globalSettings.compaction.enabled = enabled;
this.markModified("compaction", "enabled");
this.save();
this.setNestedGlobalSetting("compaction", "enabled", enabled);
}
getCompactionReserveTokens(): number {
@ -748,12 +759,7 @@ export class SettingsManager {
}
setRetryEnabled(enabled: boolean): void {
if (!this.globalSettings.retry) {
this.globalSettings.retry = {};
}
this.globalSettings.retry.enabled = enabled;
this.markModified("retry", "enabled");
this.save();
this.setNestedGlobalSetting("retry", "enabled", enabled);
}
getRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number; maxDelayMs: number } {
@ -770,9 +776,7 @@ export class SettingsManager {
}
setHideThinkingBlock(hide: boolean): void {
this.globalSettings.hideThinkingBlock = hide;
this.markModified("hideThinkingBlock");
this.save();
this.setGlobalSetting("hideThinkingBlock", hide);
}
getShellPath(): string | undefined {
@ -780,9 +784,7 @@ export class SettingsManager {
}
setShellPath(path: string | undefined): void {
this.globalSettings.shellPath = path;
this.markModified("shellPath");
this.save();
this.setGlobalSetting("shellPath", path);
}
getQuietStartup(): boolean {
@ -790,9 +792,7 @@ export class SettingsManager {
}
setQuietStartup(quiet: boolean): void {
this.globalSettings.quietStartup = quiet;
this.markModified("quietStartup");
this.save();
this.setGlobalSetting("quietStartup", quiet);
}
getShellCommandPrefix(): string | undefined {
@ -800,9 +800,7 @@ export class SettingsManager {
}
setShellCommandPrefix(prefix: string | undefined): void {
this.globalSettings.shellCommandPrefix = prefix;
this.markModified("shellCommandPrefix");
this.save();
this.setGlobalSetting("shellCommandPrefix", prefix);
}
getCollapseChangelog(): boolean {
@ -810,9 +808,7 @@ export class SettingsManager {
}
setCollapseChangelog(collapse: boolean): void {
this.globalSettings.collapseChangelog = collapse;
this.markModified("collapseChangelog");
this.save();
this.setGlobalSetting("collapseChangelog", collapse);
}
getPackages(): PackageSource[] {
@ -820,16 +816,11 @@ export class SettingsManager {
}
setPackages(packages: PackageSource[]): void {
this.globalSettings.packages = packages;
this.markModified("packages");
this.save();
this.setGlobalSetting("packages", packages);
}
setProjectPackages(packages: PackageSource[]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings.packages = packages;
this.markProjectModified("packages");
this.saveProjectSettings(projectSettings);
this.setProjectSetting("packages", packages);
}
getExtensionPaths(): string[] {
@ -837,16 +828,11 @@ export class SettingsManager {
}
setExtensionPaths(paths: string[]): void {
this.globalSettings.extensions = paths;
this.markModified("extensions");
this.save();
this.setGlobalSetting("extensions", paths);
}
setProjectExtensionPaths(paths: string[]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings.extensions = paths;
this.markProjectModified("extensions");
this.saveProjectSettings(projectSettings);
this.setProjectSetting("extensions", paths);
}
getSkillPaths(): string[] {
@ -854,16 +840,11 @@ export class SettingsManager {
}
setSkillPaths(paths: string[]): void {
this.globalSettings.skills = paths;
this.markModified("skills");
this.save();
this.setGlobalSetting("skills", paths);
}
setProjectSkillPaths(paths: string[]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings.skills = paths;
this.markProjectModified("skills");
this.saveProjectSettings(projectSettings);
this.setProjectSetting("skills", paths);
}
getPromptTemplatePaths(): string[] {
@ -871,16 +852,11 @@ export class SettingsManager {
}
setPromptTemplatePaths(paths: string[]): void {
this.globalSettings.prompts = paths;
this.markModified("prompts");
this.save();
this.setGlobalSetting("prompts", paths);
}
setProjectPromptTemplatePaths(paths: string[]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings.prompts = paths;
this.markProjectModified("prompts");
this.saveProjectSettings(projectSettings);
this.setProjectSetting("prompts", paths);
}
getThemePaths(): string[] {
@ -888,16 +864,11 @@ export class SettingsManager {
}
setThemePaths(paths: string[]): void {
this.globalSettings.themes = paths;
this.markModified("themes");
this.save();
this.setGlobalSetting("themes", paths);
}
setProjectThemePaths(paths: string[]): void {
const projectSettings = structuredClone(this.projectSettings);
projectSettings.themes = paths;
this.markProjectModified("themes");
this.saveProjectSettings(projectSettings);
this.setProjectSetting("themes", paths);
}
getEnableSkillCommands(): boolean {
@ -905,9 +876,7 @@ export class SettingsManager {
}
setEnableSkillCommands(enabled: boolean): void {
this.globalSettings.enableSkillCommands = enabled;
this.markModified("enableSkillCommands");
this.save();
this.setGlobalSetting("enableSkillCommands", enabled);
}
getThinkingBudgets(): ThinkingBudgetsSettings | undefined {
@ -919,12 +888,7 @@ export class SettingsManager {
}
setShowImages(show: boolean): void {
if (!this.globalSettings.terminal) {
this.globalSettings.terminal = {};
}
this.globalSettings.terminal.showImages = show;
this.markModified("terminal", "showImages");
this.save();
this.setNestedGlobalSetting("terminal", "showImages", show);
}
getClearOnShrink(): boolean {
@ -936,12 +900,7 @@ export class SettingsManager {
}
setClearOnShrink(enabled: boolean): void {
if (!this.globalSettings.terminal) {
this.globalSettings.terminal = {};
}
this.globalSettings.terminal.clearOnShrink = enabled;
this.markModified("terminal", "clearOnShrink");
this.save();
this.setNestedGlobalSetting("terminal", "clearOnShrink", enabled);
}
getImageAutoResize(): boolean {
@ -949,12 +908,7 @@ export class SettingsManager {
}
setImageAutoResize(enabled: boolean): void {
if (!this.globalSettings.images) {
this.globalSettings.images = {};
}
this.globalSettings.images.autoResize = enabled;
this.markModified("images", "autoResize");
this.save();
this.setNestedGlobalSetting("images", "autoResize", enabled);
}
getBlockImages(): boolean {
@ -962,12 +916,7 @@ export class SettingsManager {
}
setBlockImages(blocked: boolean): void {
if (!this.globalSettings.images) {
this.globalSettings.images = {};
}
this.globalSettings.images.blockImages = blocked;
this.markModified("images", "blockImages");
this.save();
this.setNestedGlobalSetting("images", "blockImages", blocked);
}
getEnabledModels(): string[] | undefined {
@ -975,9 +924,7 @@ export class SettingsManager {
}
setEnabledModels(patterns: string[] | undefined): void {
this.globalSettings.enabledModels = patterns;
this.markModified("enabledModels");
this.save();
this.setGlobalSetting("enabledModels", patterns);
}
getDoubleEscapeAction(): "fork" | "tree" | "none" {
@ -985,9 +932,7 @@ export class SettingsManager {
}
setDoubleEscapeAction(action: "fork" | "tree" | "none"): void {
this.globalSettings.doubleEscapeAction = action;
this.markModified("doubleEscapeAction");
this.save();
this.setGlobalSetting("doubleEscapeAction", action);
}
getTreeFilterMode(): "default" | "no-tools" | "user-only" | "labeled-only" | "all" {
@ -997,9 +942,7 @@ export class SettingsManager {
}
setTreeFilterMode(mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): void {
this.globalSettings.treeFilterMode = mode;
this.markModified("treeFilterMode");
this.save();
this.setGlobalSetting("treeFilterMode", mode);
}
getShowHardwareCursor(): boolean {
@ -1007,9 +950,7 @@ export class SettingsManager {
}
setShowHardwareCursor(enabled: boolean): void {
this.globalSettings.showHardwareCursor = enabled;
this.markModified("showHardwareCursor");
this.save();
this.setGlobalSetting("showHardwareCursor", enabled);
}
getEditorPaddingX(): number {
@ -1017,9 +958,7 @@ export class SettingsManager {
}
setEditorPaddingX(padding: number): void {
this.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));
this.markModified("editorPaddingX");
this.save();
this.setGlobalSetting("editorPaddingX", Math.max(0, Math.min(3, Math.floor(padding))));
}
getAutocompleteMaxVisible(): number {
@ -1027,9 +966,7 @@ export class SettingsManager {
}
setAutocompleteMaxVisible(maxVisible: number): void {
this.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));
this.markModified("autocompleteMaxVisible");
this.save();
this.setGlobalSetting("autocompleteMaxVisible", Math.max(3, Math.min(20, Math.floor(maxVisible))));
}
getRespectGitignoreInPicker(): boolean {
@ -1037,9 +974,7 @@ export class SettingsManager {
}
setRespectGitignoreInPicker(value: boolean): void {
this.globalSettings.respectGitignoreInPicker = value;
this.markModified("respectGitignoreInPicker");
this.save();
this.setGlobalSetting("respectGitignoreInPicker", value);
}
getSearchExcludeDirs(): string[] {
@ -1047,9 +982,7 @@ export class SettingsManager {
}
setSearchExcludeDirs(dirs: string[]): void {
this.globalSettings.searchExcludeDirs = dirs.filter(Boolean);
this.markModified("searchExcludeDirs");
this.save();
this.setGlobalSetting("searchExcludeDirs", dirs.filter(Boolean));
}
getCodeBlockIndent(): string {
@ -1095,12 +1028,7 @@ export class SettingsManager {
}
setFallbackEnabled(enabled: boolean): void {
if (!this.globalSettings.fallback) {
this.globalSettings.fallback = {};
}
this.globalSettings.fallback.enabled = enabled;
this.markModified("fallback", "enabled");
this.save();
this.setNestedGlobalSetting("fallback", "enabled", enabled);
}
getFallbackChains(): Record<string, FallbackChainEntry[]> {
@ -1149,12 +1077,7 @@ export class SettingsManager {
}
setModelDiscoveryEnabled(enabled: boolean): void {
if (!this.globalSettings.modelDiscovery) {
this.globalSettings.modelDiscovery = {};
}
this.globalSettings.modelDiscovery.enabled = enabled;
this.markModified("modelDiscovery", "enabled");
this.save();
this.setNestedGlobalSetting("modelDiscovery", "enabled", enabled);
}
getEditMode(): "standard" | "hashline" {
@ -1162,8 +1085,6 @@ export class SettingsManager {
}
setEditMode(mode: "standard" | "hashline"): void {
this.globalSettings.editMode = mode;
this.markModified("editMode");
this.save();
this.setGlobalSetting("editMode", mode);
}
}