Rename keys and support full context key expressions for check offs

This commit is contained in:
Jackson Kearl 2021-05-26 17:51:15 -07:00
parent 14b31425b9
commit 1fd2b4ed1e
No known key found for this signature in database
GPG key ID: DA09A59C409FC400
3 changed files with 61 additions and 19 deletions

View file

@ -117,7 +117,9 @@ export interface IWalkthroughStep {
readonly id: string;
readonly title: string;
readonly description: string | undefined;
readonly media: { path: string | { dark: string, light: string, hc: string }, altText?: string }
readonly media:
| { image: string | { dark: string, light: string, hc: string }, altText: string, markdown?: never }
| { markdown: string, image?: never }
readonly completionEvents?: string[];
/** @deprecated use `completionEvents: 'onCommand:...'` */
readonly doneOn?: { command: string };

View file

@ -76,10 +76,13 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo
defaultSnippets: [{ 'body': { 'type': '$1', 'path': '$2' } }],
oneOf: [
{
required: ['path', 'altText'],
required: ['image', 'altText'],
additionalProperties: false,
properties: {
path: {
deprecationMessage: localize('pathDeprecated', "Deprecated. Please use `image` or `markdown` instead")
},
image: {
description: localize('walkthroughs.steps.media.image.path.string', "Path to an image - or object consisting of paths to light, dark, and hc images - relative to extension directory. Depending on context, the image will be displayed from 400px to 800px wide, with similar bounds on height. To support HIDPI displays, the image will be rendered at 1.5x scaling, for example a 900 physical pixels wide image will be displayed as 600 logical pixels wide."),
oneOf: [
{
@ -111,10 +114,13 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo
}
}
}, {
required: ['path'],
required: ['markdown'],
additionalProperties: false,
properties: {
path: {
deprecationMessage: localize('pathDeprecated', "Deprecated. Please use `image` or `markdown` instead")
},
markdown: {
description: localize('walkthroughs.steps.media.markdown.path', "Path to the markdown document, relative to extension directory."),
type: 'string',
}
@ -149,9 +155,9 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo
body: 'onSettingChanged:${2:settingName}'
},
{
label: 'onContextKeyDefined',
description: localize('walkthroughs.steps.completionEvents.onContextKeyDefined', 'Check off step when a context key is defined to a truthy value. Note: this only accepts single context keys, not full context key expressions'),
body: 'onContextKeyDefined:${2:key}'
label: 'onContext',
description: localize('walkthroughs.steps.completionEvents.onContext', 'Check off step when a context key expression is true.'),
body: 'onContext:${2:key}'
},
{
label: 'extensionInstalled',

View file

@ -171,6 +171,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted
private sessionInstalledExtensions = new Set<string>();
private categoryVisibilityContextKeys = new Set<string>();
private stepCompletionContextKeyExpressions = new Set<ContextKeyExpression>();
private stepCompletionContextKeys = new Set<string>();
private triggerInstalledExtensionsRegistered!: () => void;
@ -217,9 +218,9 @@ export class GettingStartedService extends Disposable implements IGettingStarted
this._register(this.contextService.onDidChangeContext(event => {
if (event.affectsSome(this.categoryVisibilityContextKeys)) { this._onDidAddCategory.fire(); }
if (event.affectsSome(this.stepCompletionContextKeys)) {
this.stepCompletionContextKeys.forEach(key => {
if (event.affectsSome(new Set([key])) && this.contextService.getContextKeyValue(key)) {
this.progressByEvent(`onContextKeyDefined:` + key);
this.stepCompletionContextKeyExpressions.forEach(expression => {
if (event.affectsSome(new Set(expression.keys())) && this.contextService.contextMatchesRules(expression)) {
this.progressByEvent(`onContext:` + expression.serialize());
}
});
}
@ -444,19 +445,41 @@ export class GettingStartedService extends Disposable implements IGettingStarted
const fullyQualifiedID = extension.identifier.value + '#' + walkthrough.id + '#' + step.id;
let media: IGettingStartedStep['media'];
if (typeof step.media.path === 'string' && step.media.path.endsWith('.md')) {
media = {
type: 'markdown',
path: convertExtensionPathToFileURI(step.media.path),
base: convertExtensionPathToFileURI(dirname(step.media.path)),
root: FileAccess.asFileUri(extension.extensionLocation),
};
} else {
if (step.media.image) {
const altText = (step.media as any).altText;
if (altText === undefined) {
console.error('Getting Started: item', fullyQualifiedID, 'is missing altText for its media element.');
}
media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(step.media.path) };
media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(step.media.image) };
}
else if (step.media.markdown) {
media = {
type: 'markdown',
path: convertExtensionPathToFileURI(step.media.markdown),
base: convertExtensionPathToFileURI(dirname(step.media.markdown)),
root: FileAccess.asFileUri(extension.extensionLocation),
};
}
// Legacy media config
else {
const legacyMedia = step.media as unknown as { path: string, altText: string };
if (typeof legacyMedia.path === 'string' && legacyMedia.path.endsWith('.md')) {
media = {
type: 'markdown',
path: convertExtensionPathToFileURI(legacyMedia.path),
base: convertExtensionPathToFileURI(dirname(legacyMedia.path)),
root: FileAccess.asFileUri(extension.extensionLocation),
};
}
else {
const altText = legacyMedia.altText;
if (altText === undefined) {
console.error('Getting Started: item', fullyQualifiedID, 'is missing altText for its media element.');
}
media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(legacyMedia.path) };
}
}
return ({
@ -539,8 +562,19 @@ export class GettingStartedService extends Disposable implements IGettingStarted
}
switch (eventType) {
case 'onLink': case 'onEvent': case 'onView': case 'onContextKeyDefined': case 'onSettingChanged':
case 'onLink': case 'onEvent': case 'onView': case 'onSettingChanged':
break;
case 'onContext': {
const expression = ContextKeyExpr.deserialize(argument);
if (expression) {
this.stepCompletionContextKeyExpressions.add(expression);
expression.keys().forEach(key => this.stepCompletionContextKeys.add(key));
event = eventType + ':' + expression.serialize();
} else {
console.error('Unable to parse context key expression:', expression, 'in getting started step', step.id);
}
break;
}
case 'stepSelected':
event = eventType + ':' + step.id;
break;