@@ -8,6 +8,7 @@ import * as config from './config'
8
8
import { ExtContext } from '../shared/extensions'
9
9
import { createCommonButtons } from '../shared/ui/buttons'
10
10
import { createQuickPick } from '../shared/ui/pickerPrompter'
11
+ import { SkipPrompter } from '../shared/ui/common/skipPrompter'
11
12
import { DevSettings } from '../shared/settings'
12
13
import { FileProvider , VirtualFileSystem } from '../shared/virtualFilesystem'
13
14
import { Commands } from '../shared/vscode/commands2'
@@ -45,7 +46,7 @@ const menuOptions: Record<string, MenuOption> = {
45
46
openTerminal : {
46
47
label : 'Open Remote Terminal' ,
47
48
description : 'CodeCatalyst' ,
48
- detail : 'Open a new terminal connected to the remote environment' ,
49
+ detail : 'Opens a new terminal connected to the remote environment' ,
49
50
executor : openTerminalCommand ,
50
51
} ,
51
52
deleteDevEnv : {
@@ -55,16 +56,16 @@ const menuOptions: Record<string, MenuOption> = {
55
56
executor : deleteDevEnvCommand ,
56
57
} ,
57
58
editStorage : {
58
- label : 'Edit Storage' ,
59
+ label : 'Show or Edit Global Storage' ,
59
60
description : 'VS Code' ,
60
- detail : 'Edit a key in global /secret storage as a JSON document' ,
61
+ detail : 'Shows all globalState values, or edit a specific globalState /secret key as a JSON document' ,
61
62
executor : openStorageFromInput ,
62
63
} ,
63
- showGlobalState : {
64
- label : 'Show Global State ' ,
64
+ showEnvVars : {
65
+ label : 'Show Environment Variables ' ,
65
66
description : 'AWS Toolkit' ,
66
- detail : 'Shows various state (including environment variables) ' ,
67
- executor : showGlobalState ,
67
+ detail : 'Shows all environment variable values ' ,
68
+ executor : ( ) => showState ( 'envvars' ) ,
68
69
} ,
69
70
deleteSsoConnections : {
70
71
label : 'Auth: Delete SSO Connections' ,
@@ -78,13 +79,33 @@ const menuOptions: Record<string, MenuOption> = {
78
79
} ,
79
80
}
80
81
81
- export class GlobalStateDocumentProvider implements vscode . TextDocumentContentProvider {
82
+ /**
83
+ * Provides (readonly, as opposed to `ObjectEditor`) content for the aws-dev2:/ URI scheme.
84
+ *
85
+ * ```
86
+ * aws-dev2:/state/envvars
87
+ * aws-dev2:/state/globalstate
88
+ * ```
89
+ *
90
+ * TODO: This only purpose of this provider is to avoid an annoying unsaved, empty document that
91
+ * re-appears after vscode restart. Ideally there should be only one scheme (aws-dev:/).
92
+ */
93
+ export class DevDocumentProvider implements vscode . TextDocumentContentProvider {
94
+ constructor ( private readonly ctx : ExtContext ) { }
82
95
provideTextDocumentContent ( uri : vscode . Uri ) : string {
83
- let s = 'Environment variables known to AWS Toolkit:\n'
84
- for ( const [ k , v ] of Object . entries ( process . env ) ) {
85
- s += `${ k } =${ v } \n`
96
+ if ( uri . path === '/envvars' ) {
97
+ let s = 'Environment variables known to AWS Toolkit:\n\n'
98
+ for ( const [ k , v ] of Object . entries ( process . env ) ) {
99
+ s += `${ k } =${ v } \n`
100
+ }
101
+ return s
102
+ } else if ( uri . path === '/globalstate' ) {
103
+ // lol hax
104
+ // as of November 2023, all of a memento's properties are stored as property `f` when minified
105
+ return JSON . stringify ( ( this . ctx . extensionContext . globalState as any ) . f , undefined , 4 )
106
+ } else {
107
+ return `unknown URI path: ${ uri } `
86
108
}
87
- return s
88
109
}
89
110
}
90
111
@@ -105,7 +126,7 @@ export function activate(ctx: ExtContext): void {
105
126
ctx . extensionContext . subscriptions . push (
106
127
devSettings . onDidChangeActiveSettings ( updateMode ) ,
107
128
vscode . commands . registerCommand ( 'aws.dev.openMenu' , ( ) => openMenu ( ctx , menuOptions ) ) ,
108
- vscode . workspace . registerTextDocumentContentProvider ( 'aws-dev2' , new GlobalStateDocumentProvider ( ) )
129
+ vscode . workspace . registerTextDocumentContentProvider ( 'aws-dev2' , new DevDocumentProvider ( ctx ) )
109
130
)
110
131
111
132
updateMode ( )
@@ -130,6 +151,8 @@ async function openMenu(ctx: ExtContext, options: typeof menuOptions): Promise<v
130
151
const prompter = createQuickPick ( items , {
131
152
title : 'Developer Menu' ,
132
153
buttons : createCommonButtons ( ) ,
154
+ matchOnDescription : true ,
155
+ matchOnDetail : true ,
133
156
} )
134
157
135
158
await prompter . prompt ( )
@@ -169,6 +192,9 @@ class VirtualObjectFile implements FileProvider {
169
192
const value = ( await this . storage . get ( key ) ) ?? ''
170
193
return JSON . stringify ( JSON . parse ( value ) , undefined , 4 )
171
194
} else {
195
+ if ( key === '' ) {
196
+ return '(empty key)'
197
+ }
172
198
return JSON . stringify ( this . storage . get ( key , { } ) , undefined , 4 )
173
199
}
174
200
}
@@ -203,8 +229,10 @@ class ObjectEditor {
203
229
vscode . workspace . registerFileSystemProvider ( ObjectEditor . scheme , this . fs )
204
230
}
205
231
206
- public async openStorage ( type : 'globals' | 'secrets' , key : string ) : Promise < void > {
232
+ public async openStorage ( type : 'globalsView' | ' globals' | 'secrets' , key : string ) : Promise < void > {
207
233
switch ( type ) {
234
+ case 'globalsView' :
235
+ return showState ( 'globalstate' )
208
236
case 'globals' :
209
237
return this . openState ( this . context . globalState , key )
210
238
case 'secrets' :
@@ -226,14 +254,24 @@ class ObjectEditor {
226
254
}
227
255
228
256
private async createTab ( storage : vscode . Memento | vscode . SecretStorage , key : string ) : Promise < Tab > {
229
- const uri = this . uriFromKey ( key , storage )
230
- const disposable = this . fs . registerProvider ( uri , new VirtualObjectFile ( storage , key ) )
231
- const document = await vscode . workspace . openTextDocument ( uri )
257
+ const virtualFile = new VirtualObjectFile ( storage , key )
258
+ let disposable : vscode . Disposable
259
+ let document : vscode . TextDocument
260
+ if ( key !== '' ) {
261
+ const uri = this . uriFromKey ( key , storage )
262
+ disposable = this . fs . registerProvider ( uri , virtualFile )
263
+ document = await vscode . workspace . openTextDocument ( uri )
264
+ } else {
265
+ // don't tie it to a URI so you can't save this view
266
+ const stream = await virtualFile . read ( )
267
+ document = await vscode . workspace . openTextDocument ( {
268
+ content : new TextDecoder ( ) . decode ( stream ) ,
269
+ } )
270
+ }
232
271
const withLanguage = await vscode . languages . setTextDocumentLanguage ( document , 'json' )
233
- const editor = await vscode . window . showTextDocument ( withLanguage )
234
272
235
273
return {
236
- editor,
274
+ editor : await vscode . window . showTextDocument ( withLanguage ) ,
237
275
dispose : ( ) => disposable . dispose ( ) ,
238
276
}
239
277
}
@@ -247,15 +285,16 @@ class ObjectEditor {
247
285
}
248
286
}
249
287
250
- async function openStorageFromInput ( ) {
251
- const wizard = new ( class extends Wizard < { target : 'globals' | 'secrets' ; key : string } > {
288
+ async function openStorageFromInput ( ctx : ExtContext ) {
289
+ const wizard = new ( class extends Wizard < { target : 'globalsView' | ' globals' | 'secrets' ; key : string } > {
252
290
constructor ( ) {
253
291
super ( )
254
292
255
293
this . form . target . bindPrompter ( ( ) =>
256
294
createQuickPick (
257
295
[
258
- { label : 'Global State' , data : 'globals' } ,
296
+ { label : 'Show all globalState' , data : 'globalsView' } ,
297
+ { label : 'Edit globalState' , data : 'globals' } ,
259
298
{ label : 'Secrets' , data : 'secrets' } ,
260
299
] ,
261
300
{
@@ -264,12 +303,32 @@ async function openStorageFromInput() {
264
303
)
265
304
)
266
305
267
- this . form . key . bindPrompter ( ( { target } ) =>
268
- createInputBox ( {
269
- title : 'Enter a key' ,
270
- placeholder : target === 'globals' ? 'region' : '' ,
271
- } )
272
- )
306
+ this . form . key . bindPrompter ( ( { target } ) => {
307
+ if ( target === 'secrets' ) {
308
+ return createInputBox ( {
309
+ title : 'Enter a key' ,
310
+ } )
311
+ } else if ( target === 'globalsView' ) {
312
+ return new SkipPrompter ( '' )
313
+ } else if ( target === 'globals' ) {
314
+ // List all globalState keys in the quickpick menu.
315
+ const items = ctx . extensionContext . globalState
316
+ . keys ( )
317
+ . map ( key => {
318
+ return {
319
+ label : key ,
320
+ data : key ,
321
+ }
322
+ } )
323
+ . sort ( ( a , b ) => {
324
+ return a . data . localeCompare ( b . data )
325
+ } )
326
+
327
+ return createQuickPick ( items , { title : 'Select a key' } )
328
+ } else {
329
+ throw new Error ( 'invalid storage target' )
330
+ }
331
+ } )
273
332
}
274
333
} ) ( )
275
334
@@ -294,8 +353,8 @@ async function expireSsoConnections() {
294
353
vscode . window . showInformationMessage ( `Expired: ${ ssoConns . map ( c => c . startUrl ) . join ( ', ' ) } ` )
295
354
}
296
355
297
- async function showGlobalState ( ) {
298
- const uri = vscode . Uri . parse ( ' aws-dev2:global- state' )
356
+ async function showState ( path : string ) {
357
+ const uri = vscode . Uri . parse ( ` aws-dev2:// state/ ${ path } ` )
299
358
const doc = await vscode . workspace . openTextDocument ( uri )
300
359
await vscode . window . showTextDocument ( doc , { preview : false } )
301
360
}
0 commit comments