@@ -25,7 +25,7 @@ type Workspace = Pick<typeof vscode.workspace, 'getConfiguration' | 'onDidChange
25
25
*/
26
26
export class Settings {
27
27
public constructor (
28
- private readonly target = vscode . ConfigurationTarget . Global ,
28
+ private readonly updateTarget = vscode . ConfigurationTarget . Global ,
29
29
private readonly scope : vscode . ConfigurationScope | undefined = undefined ,
30
30
private readonly workspace : Workspace = vscode . workspace
31
31
) { }
@@ -59,7 +59,7 @@ export class Settings {
59
59
*/
60
60
public async update ( key : string , value : unknown ) : Promise < boolean > {
61
61
try {
62
- await this . getConfig ( ) . update ( key , value , this . target )
62
+ await this . getConfig ( ) . update ( key , value , this . updateTarget )
63
63
64
64
return true
65
65
} catch ( error ) {
@@ -69,6 +69,20 @@ export class Settings {
69
69
}
70
70
}
71
71
72
+ /**
73
+ * Checks if the key has been set in any non-language scope.
74
+ */
75
+ public isSet ( key : string , section ?: string ) : boolean {
76
+ const config = this . getConfig ( section )
77
+ const info = config . inspect ( key )
78
+
79
+ return (
80
+ info ?. globalValue !== undefined ||
81
+ info ?. workspaceValue !== undefined ||
82
+ info ?. workspaceFolderValue !== undefined
83
+ )
84
+ }
85
+
72
86
/**
73
87
* Returns a scoped "slice" (or "view") of the settings configuration.
74
88
*
@@ -84,13 +98,11 @@ export class Settings {
84
98
* ```
85
99
*/
86
100
public getSection ( section : string ) : ResetableMemento {
87
- const parts = section . split ( '.' )
88
- const targetKey = parts . pop ( ) ?? section
89
- const parentSection = parts . join ( '.' )
101
+ const [ targetKey , parentSection ] = splitKey ( section )
90
102
91
103
return {
92
104
get : ( key , defaultValue ?) => this . getConfig ( section ) . get ( key , defaultValue ) ,
93
- reset : async ( ) => this . getConfig ( ) . update ( section , undefined , this . target ) ,
105
+ reset : async ( ) => this . getConfig ( ) . update ( section , undefined , this . updateTarget ) ,
94
106
update : async ( key , value ) => {
95
107
// VS Code's settings API can read nested props but not write to them.
96
108
// We need to write to the parent if we cannot write to the child.
@@ -99,13 +111,13 @@ export class Settings {
99
111
// handle this asymmetry with try/catch
100
112
101
113
try {
102
- return await this . getConfig ( section ) . update ( key , value , this . target )
114
+ return await this . getConfig ( section ) . update ( key , value , this . updateTarget )
103
115
} catch ( error ) {
104
116
const parent = this . getConfig ( parentSection )
105
117
const val = parent . get ( targetKey )
106
118
107
119
if ( typeof val === 'object' ) {
108
- return parent . update ( targetKey , { ...val , [ key ] : value } , this . target )
120
+ return parent . update ( targetKey , { ...val , [ key ] : value } , this . updateTarget )
109
121
}
110
122
111
123
throw error
@@ -161,6 +173,24 @@ export class Settings {
161
173
}
162
174
}
163
175
176
+ /**
177
+ * Splits a key into 'leaf' and 'section' components.
178
+ *
179
+ * The leaf is assumed to be the last dot-separated component. Example:
180
+ *
181
+ * ```ts
182
+ * const [leaf, section] = this.split('aws.cloudWatchLogs.limit')
183
+ * console.log(leaf, section) // aws.cloudWatchLogs limit
184
+ * ```
185
+ */
186
+ function splitKey ( key : string ) : [ leaf : string , section : string ] {
187
+ const parts = key . split ( '.' )
188
+ const leaf = parts . pop ( ) ?? key
189
+ const section = parts . join ( '.' )
190
+
191
+ return [ leaf , section ]
192
+ }
193
+
164
194
// Keeping a separate function without a return type allows us to infer protected methods
165
195
// TODO(sijaden): we can make this better in TS 4.7
166
196
function createSettingsClass < T extends TypeDescriptor > ( section : string , descriptor : T ) {
@@ -238,6 +268,10 @@ function createSettingsClass<T extends TypeDescriptor>(section: string, descript
238
268
return vscode . Disposable . from ( this . getChangedEmitter ( ) , ...this . disposables ) . dispose ( )
239
269
}
240
270
271
+ protected isSet ( key : keyof Inner & string ) {
272
+ return this . settings . isSet ( key , section )
273
+ }
274
+
241
275
protected getOrThrow < K extends keyof Inner > ( key : K & string , defaultValue ?: Inner [ K ] ) {
242
276
const value = this . config . get ( key , defaultValue )
243
277
@@ -594,12 +628,15 @@ export class DevSettings extends Settings.define('aws.dev', devSettings) {
594
628
}
595
629
596
630
public override get < K extends AwsDevSetting > ( key : K , defaultValue : ResolvedDevSettings [ K ] ) {
597
- const result = super . get ( key , defaultValue )
631
+ if ( ! this . isSet ( key ) ) {
632
+ this . unset ( key )
598
633
599
- if ( result !== defaultValue ) {
600
- this . trap ( key , result )
634
+ return defaultValue
601
635
}
602
636
637
+ const result = super . get ( key , defaultValue )
638
+ this . trap ( key , result )
639
+
603
640
return result
604
641
}
605
642
@@ -610,6 +647,13 @@ export class DevSettings extends Settings.define('aws.dev', devSettings) {
610
647
}
611
648
}
612
649
650
+ private unset ( key : AwsDevSetting ) {
651
+ if ( key in this . trappedSettings ) {
652
+ delete this . trappedSettings [ key ]
653
+ this . onDidChangeActiveSettingsEmitter . fire ( )
654
+ }
655
+ }
656
+
613
657
static #instance: DevSettings
614
658
615
659
public static get instance ( ) {
0 commit comments