Skip to content

Commit 76399c9

Browse files
authored
Increasing likelihood of users encountering codelenses (#1115)
This change is twofold: * We now activate the toolkit on a user opening a JS, C#, Python, or YAML file * If the user doesn't have the RedHat YAML Language Support extension installed, we prompt them to install it. This is required for codelenses in YAML files.
1 parent 03f0750 commit 76399c9

File tree

5 files changed

+137
-2
lines changed

5 files changed

+137
-2
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@
5555
"onView:aws.cdk.explorer",
5656
"onCommand:aws.refreshCdkExplorer",
5757
"onCommand:aws.aboutToolkit",
58-
"onLanguage:asl"
58+
"onLanguage:asl",
59+
"onLanguage:javascript",
60+
"onLanguage:python",
61+
"onLanguage:csharp",
62+
"onLanguage:yaml"
5963
],
6064
"main": "./extensionMain",
6165
"contributes": {

package.nls.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@
193193
"AWS.message.info.stepFunctions.publishStateMachine.creating": "Creating state machine '{0}' in {1}...",
194194
"AWS.message.info.stepFunctions.publishStateMachine.updateSuccess": "Successfully updated state machine '{0}'",
195195
"AWS.message.info.stepFunctions.publishStateMachine.updating": "Updating state machine '{0}' in {1}...",
196+
"AWS.message.info.yaml.prompt": "Install YAML extension for additional AWS features.",
197+
"AWS.message.info.yaml.goToMarketplace": "Open Marketplace Page",
198+
"AWS.message.info.yaml.suppressPrompt": "Dismiss, and don't show again",
196199
"AWS.schemas.downloadCodeBindings.initWizard.language.prompt": "Select a code binding language",
197200
"AWS.schemas.downloadCodeBindings.initWizard.version.prompt": "Select a version for schema {0} :",
198201
"AWS.schemas.downloadCodeBindings.initWizard.location.prompt": "Select a workspace folder to download code binding",
@@ -352,6 +355,7 @@
352355
"AWS.stepfunctions.visualisation.errors.rename": "State machine visualization closed due to file renaming or closure.",
353356
"AWS.submitFeedback.title": "Submit Quick Feedback",
354357
"AWS.wizard.selectedPreviously": "Selected Previously",
358+
"AWS.generic.response.dismiss": "Dismiss",
355359
"AWS.generic.response.no": "No",
356360
"AWS.generic.response.yes": "Yes",
357361
"AWS.generic.notImplemented": "Not implemented",

src/shared/extensionUtilities.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@ import { getLogger } from './logger'
1616

1717
const localize = nls.loadMessageBundle()
1818

19+
const VSCODE_APPNAME = 'Visual Studio Code'
20+
21+
export enum IDE {
22+
vscode,
23+
unknown,
24+
}
25+
26+
export function getIdeType(): IDE {
27+
// Theia doesn't necessarily have all env propertie
28+
// so we should be defensive and assume appName is nullable.
29+
if (vscode.env.appName?.startsWith(VSCODE_APPNAME)) {
30+
return IDE.vscode
31+
}
32+
33+
return IDE.unknown
34+
}
35+
1936
export class ExtensionUtilities {
2037
public static getLibrariesForHtml(names: string[]): ScriptResource[] {
2138
const basePath = path.join(ext.context.extensionPath, 'media', 'libs')

src/shared/extensions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ChannelLogger } from './utilities/vsCodeUtils'
1313
export const VSCODE_EXTENSION_ID = {
1414
awstoolkit: 'amazonwebservices.aws-toolkit-vscode',
1515
python: 'ms-python.python',
16+
yaml: 'redhat.vscode-yaml',
1617
}
1718

1819
/**

src/shared/sam/activation.ts

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import * as nls from 'vscode-nls'
7+
const localize = nls.loadMessageBundle()
8+
69
import * as vscode from 'vscode'
710
import { createNewSamApplication, resumeCreateNewSamApp } from '../../lambda/commands/createNewSamApp'
811
import { deploySamApplication, SamDeployWizardResponseProvider } from '../../lambda/commands/deploySamApplication'
@@ -17,7 +20,10 @@ import * as codelensUtils from '../codelens/codeLensUtils'
1720
import * as csLensProvider from '../codelens/csharpCodeLensProvider'
1821
import * as pyLensProvider from '../codelens/pythonCodeLensProvider'
1922
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'
2127
import { SettingsConfiguration } from '../settingsConfiguration'
2228
import { TelemetryService } from '../telemetry/telemetryService'
2329
import { PromiseSharer } from '../utilities/promiseUtilities'
@@ -28,12 +34,16 @@ import { addSamDebugConfiguration } from './debugger/commands/addSamDebugConfigu
2834
import { SamDebugSession } from './debugger/samDebugSession'
2935
import { AWS_SAM_DEBUG_TYPE } from './debugger/awsSamDebugConfiguration'
3036

37+
const STATE_NAME_SUPPRESS_YAML_PROMPT = 'aws.sam.suppressYamlPrompt'
38+
3139
/**
3240
* Activate SAM-related functionality.
3341
*/
3442
export async function activate(ctx: ExtContext): Promise<void> {
3543
initializeSamCliContext({ settingsConfiguration: ctx.settings })
3644

45+
createYamlExtensionPrompt()
46+
3747
ctx.extensionContext.subscriptions.push(
3848
...(await activateCodeLensProviders(ctx, ctx.settings, ctx.outputChannel, ctx.telemetryService))
3949
)
@@ -182,3 +192,102 @@ class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory
182192
return new vscode.DebugAdapterInlineImplementation(new SamDebugSession(this.ctx))
183193
}
184194
}
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

Comments
 (0)