From ecdc7a9471344553f2f188bd2d258443f66ddfb6 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sat, 18 Mar 2017 13:37:06 -0700 Subject: [PATCH] Second prototype of markdown extensions --- extensions/markdown/src/extension.ts | 56 ++++++++++++++----- extensions/markdown/src/markdownEngine.ts | 2 - .../markdown/src/previewContentProvider.ts | 10 +++- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 2961bfa374588..1af595912465e 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -40,7 +40,7 @@ interface PreviewSecurityPickItem extends vscode.QuickPickItem { id: PreviewSecuritySelection; } -class ExtensionContentSecurityProlicyArbiter implements ContentSecurityPolicyArbiter { +class ExtensionContentSecurityPolicyArbiter implements ContentSecurityPolicyArbiter { private readonly key = 'trusted_preview_workspace:'; constructor( @@ -58,9 +58,16 @@ class ExtensionContentSecurityProlicyArbiter implements ContentSecurityPolicyArb public removeTrustedWorkspace(rootPath: string): Thenable { return this.globalState.update(this.key + rootPath, false); } - } +const resolveExtensionResources = (extension: vscode.Extension, stylePath: string): vscode.Uri => { + const resource = vscode.Uri.parse(stylePath); + if (resource.scheme) { + return resource; + } + return vscode.Uri.file(path.join(extension.extensionPath, stylePath)); +}; + var telemetryReporter: TelemetryReporter | null; export function activate(context: vscode.ExtensionContext) { @@ -70,12 +77,43 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(telemetryReporter); } - const cspArbiter = new ExtensionContentSecurityProlicyArbiter(context.globalState); + const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState); const engine = new MarkdownEngine(); const contentProvider = new MDDocumentContentProvider(engine, context, cspArbiter); const contentProviderRegistration = vscode.workspace.registerTextDocumentContentProvider('markdown', contentProvider); + if (vscode.workspace.getConfiguration('markdown').get('enableExperimentalExtensionApi', false)) { + for (const extension of vscode.extensions.all) { + const contributes = extension.packageJSON && extension.packageJSON.contributes; + if (!contributes) { + continue; + } + + let styles = contributes['markdown.preview'] && contributes['markdown.preview'].styles; + if (styles) { + if (!Array.isArray(styles)) { + styles = [styles]; + } + for (const style of styles) { + try { + contentProvider.addStyle(resolveExtensionResources(extension, style)); + } catch (e) { + // noop + } + } + } + + if (contributes['markdownit.plugins']) { + extension.activate().then(() => { + if (extension.exports && extension.exports.extendMarkdownIt) { + engine.addPlugin((md: any) => extension.exports.extendMarkdownIt(md)); + } + }); + } + } + } + const symbolsProvider = new MDDocumentSymbolProvider(engine); const symbolsProviderRegistration = vscode.languages.registerDocumentSymbolProvider({ language: 'markdown' }, symbolsProvider); context.subscriptions.push(contentProviderRegistration, symbolsProviderRegistration); @@ -231,18 +269,6 @@ export function activate(context: vscode.ExtensionContext) { }); } })); - - if (vscode.workspace.getConfiguration('markdown').get('enableExperimentalExtensionApi', false)) { - vscode.commands.executeCommand('_markdown.onActivateExtensions') - .then(() => void 0, () => void 0); - - return { - addPlugin(factory: (md: any) => any) { - engine.addPlugin(factory); - } - }; - } - return undefined; } diff --git a/extensions/markdown/src/markdownEngine.ts b/extensions/markdown/src/markdownEngine.ts index f8dfdb1a6b55e..6c6c9e3dffbce 100644 --- a/extensions/markdown/src/markdownEngine.ts +++ b/extensions/markdown/src/markdownEngine.ts @@ -33,8 +33,6 @@ export class MarkdownEngine { private plugins: Array<(md: any) => any> = []; - constructor() { } - public addPlugin(factory: (md: any) => any): void { if (this.md) { this.usePlugin(factory); diff --git a/extensions/markdown/src/previewContentProvider.ts b/extensions/markdown/src/previewContentProvider.ts index 9de21f27063b5..078335d0d6b90 100644 --- a/extensions/markdown/src/previewContentProvider.ts +++ b/extensions/markdown/src/previewContentProvider.ts @@ -28,6 +28,7 @@ export function getMarkdownUri(uri: vscode.Uri) { export class MDDocumentContentProvider implements vscode.TextDocumentContentProvider { private _onDidChange = new vscode.EventEmitter(); private _waiting: boolean = false; + private extraStyles: Array = []; constructor( private engine: MarkdownEngine, @@ -35,6 +36,10 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv private cspArbiter: ContentSecurityPolicyArbiter ) { } + public addStyle(resource: vscode.Uri): void { + this.extraStyles.push(resource); + } + private getMediaPath(mediaFile: string): string { return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))).toString(); } @@ -97,7 +102,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv const baseStyles = [ this.getMediaPath('markdown.css'), this.getMediaPath('tomorrow.css') - ]; + ].concat(this.extraStyles.map(resource => resource.toString())); return `${baseStyles.map(href => ``).join('\n')} ${this.getSettingsOverrideStyles(nonce)} @@ -105,8 +110,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv } private getScripts(nonce: string): string { - const scripts = [this.getMediaPath('main.js')]; - return scripts + return [this.getMediaPath('main.js')] .map(source => ``) .join('\n'); }