3
3
* SPDX-License-Identifier: Apache-2.0
4
4
*/
5
5
6
+ import * as nls from 'vscode-nls'
7
+ const localize = nls . loadMessageBundle ( )
8
+
6
9
import * as vscode from 'vscode'
7
10
import { createNewSamApplication , resumeCreateNewSamApp } from '../../lambda/commands/createNewSamApp'
8
11
import { deploySamApplication , SamDeployWizardResponseProvider } from '../../lambda/commands/deploySamApplication'
@@ -17,7 +20,10 @@ import * as codelensUtils from '../codelens/codeLensUtils'
17
20
import * as csLensProvider from '../codelens/csharpCodeLensProvider'
18
21
import * as pyLensProvider from '../codelens/pythonCodeLensProvider'
19
22
import { SamTemplateCodeLensProvider } from '../codelens/samTemplateCodeLensProvider'
20
- import { ExtContext } from '../extensions'
23
+ import { ext } from '../extensionGlobals'
24
+ import { ExtContext , VSCODE_EXTENSION_ID } from '../extensions'
25
+ import { getIdeType , IDE } from '../extensionUtilities'
26
+ import { getLogger } from '../logger/logger'
21
27
import { SettingsConfiguration } from '../settingsConfiguration'
22
28
import { TelemetryService } from '../telemetry/telemetryService'
23
29
import { PromiseSharer } from '../utilities/promiseUtilities'
@@ -28,12 +34,16 @@ import { addSamDebugConfiguration } from './debugger/commands/addSamDebugConfigu
28
34
import { SamDebugSession } from './debugger/samDebugSession'
29
35
import { AWS_SAM_DEBUG_TYPE } from './debugger/awsSamDebugConfiguration'
30
36
37
+ const STATE_NAME_SUPPRESS_YAML_PROMPT = 'aws.sam.suppressYamlPrompt'
38
+
31
39
/**
32
40
* Activate SAM-related functionality.
33
41
*/
34
42
export async function activate ( ctx : ExtContext ) : Promise < void > {
35
43
initializeSamCliContext ( { settingsConfiguration : ctx . settings } )
36
44
45
+ createYamlExtensionPrompt ( )
46
+
37
47
ctx . extensionContext . subscriptions . push (
38
48
...( await activateCodeLensProviders ( ctx , ctx . settings , ctx . outputChannel , ctx . telemetryService ) )
39
49
)
@@ -182,3 +192,102 @@ class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory
182
192
return new vscode . DebugAdapterInlineImplementation ( new SamDebugSession ( this . ctx ) )
183
193
}
184
194
}
195
+
196
+ /**
197
+ * Creates a prompt (via toast) to guide users to installing the Red Hat YAML extension.
198
+ * This is necessary for displaying codelenses on templaye YAML files.
199
+ * Will show once per extension activation at most (all prompting triggers are disposed of on first trigger)
200
+ * Will not show if the YAML extension is installed or if a user has permanently dismissed the message.
201
+ */
202
+ function createYamlExtensionPrompt ( ) : void {
203
+ const neverPromptAgain = ext . context . globalState . get < boolean > ( STATE_NAME_SUPPRESS_YAML_PROMPT )
204
+
205
+ // only pop this up in VS Code and Insiders since other VS Code-like IDEs (e.g. Theia) may not have a marketplace or contain the YAML plugin
206
+ if ( ! neverPromptAgain && getIdeType ( ) === IDE . vscode && ! vscode . extensions . getExtension ( VSCODE_EXTENSION_ID . yaml ) ) {
207
+ // these will all be disposed immediately after showing one so the user isn't prompted more than once per session
208
+ const yamlPromptDisposables : vscode . Disposable [ ] = [ ]
209
+
210
+ // user opens a template file
211
+ vscode . workspace . onDidOpenTextDocument (
212
+ async ( doc : vscode . TextDocument ) => {
213
+ promptInstallYamlPlugin ( doc . fileName , yamlPromptDisposables )
214
+ } ,
215
+ undefined ,
216
+ yamlPromptDisposables
217
+ )
218
+
219
+ // user swaps to an already-open template file that didn't have focus
220
+ vscode . window . onDidChangeActiveTextEditor (
221
+ async ( editor : vscode . TextEditor | undefined ) => {
222
+ await promptInstallYamlPluginFromEditor ( editor , yamlPromptDisposables )
223
+ } ,
224
+ undefined ,
225
+ yamlPromptDisposables
226
+ )
227
+
228
+ // user already has an open template with focus
229
+ // prescreen if a template.yaml is current open so we only call once
230
+ const openTemplateYamls = vscode . window . visibleTextEditors . filter ( editor => {
231
+ const fileName = editor . document . fileName
232
+ return fileName . endsWith ( 'template.yaml' ) || fileName . endsWith ( 'template.yml' )
233
+ } )
234
+
235
+ if ( openTemplateYamls . length > 0 ) {
236
+ promptInstallYamlPluginFromEditor ( openTemplateYamls [ 0 ] , yamlPromptDisposables )
237
+ }
238
+ }
239
+ }
240
+
241
+ async function promptInstallYamlPluginFromEditor (
242
+ editor : vscode . TextEditor | undefined ,
243
+ disposables : vscode . Disposable [ ]
244
+ ) : Promise < void > {
245
+ if ( editor ) {
246
+ promptInstallYamlPlugin ( editor . document . fileName , disposables )
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Looks for template.yaml and template.yml files and disp[oses prompts
252
+ * @param fileName File name to check against
253
+ * @param disposables List of disposables to dispose of when the filename is a template YAML file
254
+ */
255
+ async function promptInstallYamlPlugin ( fileName : string , disposables : vscode . Disposable [ ] ) : Promise < void > {
256
+ if ( fileName . endsWith ( 'template.yaml' ) || fileName . endsWith ( 'template.yml' ) ) {
257
+ // immediately dispose other triggers so it doesn't flash again
258
+ for ( const prompt of disposables ) {
259
+ prompt . dispose ( )
260
+ }
261
+
262
+ const goToMarketplace = localize ( 'AWS.message.info.yaml.goToMarketplace' , 'Open Marketplace Page' )
263
+ const dismiss = localize ( 'AWS.generic.response.dismiss' , 'Dismiss' )
264
+ const permanentlySuppress = localize ( 'AWS.message.info.yaml.suppressPrompt' , "Dismiss, and don't show again" )
265
+
266
+ const response = await vscode . window . showInformationMessage (
267
+ localize ( 'AWS.message.info.yaml.prompt' , 'Install YAML extension for additional AWS features.' ) ,
268
+ goToMarketplace ,
269
+ dismiss ,
270
+ permanentlySuppress
271
+ )
272
+
273
+ switch ( response ) {
274
+ case goToMarketplace :
275
+ // Available options are:
276
+ // extension.open: opens extension page in VS Code extension marketplace view
277
+ // workspace.extension.installPlugin: autoinstalls plugin with no additional feedback
278
+ // workspace.extension.search: preloads and executes a search in the extension sidebar with the given term
279
+
280
+ // not sure if these are 100% stable.
281
+ // Opting for `extension.open` as this gives the user a good path forward to install while not doing anything potentially unexpected.
282
+ try {
283
+ await vscode . commands . executeCommand ( 'extension.open' , VSCODE_EXTENSION_ID . yaml )
284
+ } catch ( e ) {
285
+ const err = e as Error
286
+ getLogger ( ) . error ( `Extension ${ VSCODE_EXTENSION_ID . yaml } could not be opened: ` , err . message )
287
+ }
288
+ break
289
+ case permanentlySuppress :
290
+ ext . context . globalState . update ( STATE_NAME_SUPPRESS_YAML_PROMPT , true )
291
+ }
292
+ }
293
+ }
0 commit comments