|
1 | | -import { WorkspaceConfiguration } from "vscode"; |
| 1 | +import * as vscode from 'vscode'; |
2 | 2 |
|
3 | | -const RENAMES: Record<string, string> = { |
4 | | - "emmylua.colors.mutableUnderline": "emmylua.colors.mutable_underline", |
5 | | - "emmylua.ls.executablePath": "emmylua.misc.executablePath", |
6 | | - "emmylua.ls.globalConfigPath": "emmylua.misc.globalConfigPath", |
7 | | - "emmylua.language.completeAnnotation": "emmylua.misc.autoInsertTripleDash", |
8 | | -}; |
| 3 | +/** |
| 4 | + * Configuration key rename mappings |
| 5 | + * Maps new keys to old keys for backward compatibility |
| 6 | + */ |
| 7 | +const CONFIG_RENAMES: ReadonlyMap<string, string> = new Map([ |
| 8 | + ['emmylua.colors.mutableUnderline', 'emmylua.colors.mutable_underline'], |
| 9 | + ['emmylua.ls.executablePath', 'emmylua.misc.executablePath'], |
| 10 | + ['emmylua.ls.globalConfigPath', 'emmylua.misc.globalConfigPath'], |
| 11 | + ['emmylua.language.completeAnnotation', 'emmylua.misc.autoInsertTripleDash'], |
| 12 | +]); |
9 | 13 |
|
| 14 | +/** |
| 15 | + * Track which deprecated configs have been warned about |
| 16 | + */ |
| 17 | +const warnedDeprecations = new Set<string>(); |
| 18 | + |
| 19 | +/** |
| 20 | + * Get configuration value with support for renamed keys |
| 21 | + * Automatically falls back to old configuration keys for backward compatibility |
| 22 | + * |
| 23 | + * @param config - Workspace configuration |
| 24 | + * @param key - Configuration key to retrieve |
| 25 | + * @param defaultValue - Optional default value if config doesn't exist |
| 26 | + * @returns Configuration value or default |
| 27 | + */ |
10 | 28 | export function get<T>( |
11 | | - config: WorkspaceConfiguration, |
12 | | - name: string |
| 29 | + config: vscode.WorkspaceConfiguration, |
| 30 | + key: string, |
| 31 | + defaultValue?: T |
13 | 32 | ): T | undefined { |
14 | | - const oldName = RENAMES[name]; |
15 | | - if ( |
16 | | - oldName && |
17 | | - config.get(oldName) !== null |
18 | | - ) { |
19 | | - return config.get<T>(oldName); |
20 | | - } else { |
21 | | - return config.get<T>(name); |
| 33 | + const oldKey = CONFIG_RENAMES.get(key); |
| 34 | + |
| 35 | + // Check if old config exists and has a non-null value |
| 36 | + if (oldKey && config.has(oldKey)) { |
| 37 | + const oldValue = config.get<T>(oldKey); |
| 38 | + if (oldValue !== undefined && oldValue !== null) { |
| 39 | + // Warn about deprecated config (only once per session) |
| 40 | + if (!warnedDeprecations.has(oldKey)) { |
| 41 | + warnedDeprecations.add(oldKey); |
| 42 | + showDeprecationWarning(oldKey, key); |
| 43 | + } |
| 44 | + return oldValue; |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + // Get from new config key |
| 49 | + return config.get<T>(key, defaultValue as T); |
| 50 | +} |
| 51 | + |
| 52 | +/** |
| 53 | + * Show a deprecation warning for old configuration keys |
| 54 | + */ |
| 55 | +function showDeprecationWarning(oldKey: string, newKey: string): void { |
| 56 | + const message = `Configuration "${oldKey}" is deprecated. Please use "${newKey}" instead.`; |
| 57 | + |
| 58 | + vscode.window.showWarningMessage( |
| 59 | + message, |
| 60 | + 'Update Now', |
| 61 | + 'Dismiss' |
| 62 | + ).then(action => { |
| 63 | + if (action === 'Update Now') { |
| 64 | + vscode.commands.executeCommand('workbench.action.openSettings', newKey); |
| 65 | + } |
| 66 | + }); |
| 67 | +} |
| 68 | + |
| 69 | +/** |
| 70 | + * Get configuration with proper typing and defaults |
| 71 | + */ |
| 72 | +export class ConfigurationManager { |
| 73 | + private readonly config: vscode.WorkspaceConfiguration; |
| 74 | + |
| 75 | + constructor(scope?: vscode.ConfigurationScope) { |
| 76 | + this.config = vscode.workspace.getConfiguration('emmylua', scope); |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * Get a configuration value with type safety |
| 81 | + */ |
| 82 | + get<T>(section: string, defaultValue?: T): T | undefined { |
| 83 | + return get<T>(this.config, `emmylua.${section}`, defaultValue); |
| 84 | + } |
| 85 | + |
| 86 | + /** |
| 87 | + * Check if a configuration affects language server behavior |
| 88 | + */ |
| 89 | + isLanguageServerConfig(section: string): boolean { |
| 90 | + const lsConfigPrefixes = [ |
| 91 | + 'emmylua.ls.', |
| 92 | + 'emmylua.misc.executablePath', |
| 93 | + 'emmylua.misc.globalConfigPath', |
| 94 | + ]; |
| 95 | + |
| 96 | + return lsConfigPrefixes.some(prefix => section.startsWith(prefix)); |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Get language server executable path |
| 101 | + */ |
| 102 | + getExecutablePath(): string | undefined { |
| 103 | + return this.get<string>('ls.executablePath'); |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Get language server global config path |
| 108 | + */ |
| 109 | + getGlobalConfigPath(): string | undefined { |
| 110 | + return this.get<string>('ls.globalConfigPath'); |
| 111 | + } |
| 112 | + |
| 113 | + /** |
| 114 | + * Get language server start parameters |
| 115 | + */ |
| 116 | + getStartParameters(): string[] { |
| 117 | + return this.get<string[]>('ls.startParameters', []) || []; |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Get language server debug port |
| 122 | + */ |
| 123 | + getDebugPort(): number | null { |
| 124 | + return this.get<number | null>('ls.debugPort', null) || null; |
| 125 | + } |
| 126 | + |
| 127 | + /** |
| 128 | + * Get color configuration |
| 129 | + */ |
| 130 | + getColor(colorType: string): string | undefined { |
| 131 | + return this.get<string>(`colors.${colorType}`); |
| 132 | + } |
| 133 | + |
| 134 | + /** |
| 135 | + * Check if mutable variables should have underline |
| 136 | + */ |
| 137 | + useMutableUnderline(): boolean { |
| 138 | + return this.get<boolean>('colors.mutableUnderline', false) || false; |
| 139 | + } |
| 140 | + |
| 141 | + /** |
| 142 | + * Check if auto-complete annotation is enabled |
| 143 | + */ |
| 144 | + isCompleteAnnotationEnabled(): boolean { |
| 145 | + return this.get<boolean>('language.completeAnnotation', true) ?? true; |
22 | 146 | } |
23 | 147 | } |
0 commit comments