提交 476d7fe0 编写于 作者: M Matt Bierner

Refactor markdown contributions

Reducing code duplication and reducing state
上级 c39efd9a
......@@ -13,7 +13,7 @@ import { disposeAll } from '../util/dispose';
import * as nls from 'vscode-nls';
import { getVisibleLine, MarkdownFileTopmostLineMonitor } from '../util/topmostLineMonitor';
import { MarkdownPreviewConfigurationManager } from './previewConfig';
import { MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider, MarkdownContributions } from '../markdownExtensions';
import { isMarkdownFile } from '../util/file';
import { resolveLinkToMarkdownFile } from '../commands/openDocumentLink';
const localize = nls.loadMessageBundle();
......@@ -85,7 +85,7 @@ export class MarkdownPreview {
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
contributions: MarkdownContributions,
contributionProvider: MarkdownContributionProvider,
): Promise<MarkdownPreview> {
const resource = vscode.Uri.parse(state.resource);
const locked = state.locked;
......@@ -99,9 +99,9 @@ export class MarkdownPreview {
previewConfigurations,
logger,
topmostLineMonitor,
contributions);
contributionProvider);
preview.editor.webview.options = MarkdownPreview.getWebviewOptions(resource, contributions);
preview.editor.webview.options = MarkdownPreview.getWebviewOptions(resource, contributionProvider.contributions);
if (!isNaN(line)) {
preview.line = line;
......@@ -118,14 +118,14 @@ export class MarkdownPreview {
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
contributions: MarkdownContributions
contributionProvider: MarkdownContributionProvider
): MarkdownPreview {
const webview = vscode.window.createWebviewPanel(
MarkdownPreview.viewType,
MarkdownPreview.getPreviewTitle(resource, locked),
previewColumn, {
enableFindWidget: true,
...MarkdownPreview.getWebviewOptions(resource, contributions)
...MarkdownPreview.getWebviewOptions(resource, contributionProvider.contributions)
});
return new MarkdownPreview(
......@@ -136,7 +136,7 @@ export class MarkdownPreview {
previewConfigurations,
logger,
topmostLineMonitor,
contributions);
contributionProvider);
}
private constructor(
......@@ -147,7 +147,7 @@ export class MarkdownPreview {
private readonly _previewConfigurations: MarkdownPreviewConfigurationManager,
private readonly _logger: Logger,
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
private readonly _contributions: MarkdownContributions,
private readonly _contributionProvider: MarkdownContributionProvider,
) {
this._resource = resource;
this._locked = locked;
......@@ -328,7 +328,7 @@ export class MarkdownPreview {
}
private get iconPath() {
const root = path.join(this._contributions.extensionPath, 'media');
const root = path.join(this._contributionProvider.extensionPath, 'media');
return {
light: vscode.Uri.file(path.join(root, 'Preview.svg')),
dark: vscode.Uri.file(path.join(root, 'Preview_inverse.svg'))
......@@ -392,7 +392,7 @@ export class MarkdownPreview {
if (this._resource === resource) {
this.editor.title = MarkdownPreview.getPreviewTitle(this._resource, this._locked);
this.editor.iconPath = this.iconPath;
this.editor.webview.options = MarkdownPreview.getWebviewOptions(resource, this._contributions);
this.editor.webview.options = MarkdownPreview.getWebviewOptions(resource, this._contributionProvider.contributions);
this.editor.webview.html = content;
}
}
......@@ -410,7 +410,7 @@ export class MarkdownPreview {
private static getLocalResourceRoots(
resource: vscode.Uri,
contributions: MarkdownContributions
): vscode.Uri[] {
): ReadonlyArray<vscode.Uri> {
const baseRoots = contributions.previewResourceRoots;
const folder = vscode.workspace.getWorkspaceFolder(resource);
......
......@@ -13,7 +13,7 @@ const localize = nls.loadMessageBundle();
import { Logger } from '../logger';
import { ContentSecurityPolicyArbiter, MarkdownPreviewSecurityLevel } from '../security';
import { MarkdownPreviewConfigurationManager, MarkdownPreviewConfiguration } from './previewConfig';
import { MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider } from '../markdownExtensions';
/**
* Strings used inside the markdown preview.
......@@ -40,7 +40,7 @@ export class MarkdownContentProvider {
private readonly engine: MarkdownEngine,
private readonly context: vscode.ExtensionContext,
private readonly cspArbiter: ContentSecurityPolicyArbiter,
private readonly contributions: MarkdownContributions,
private readonly contributionProvider: MarkdownContributionProvider,
private readonly logger: Logger
) { }
......@@ -163,7 +163,7 @@ export class MarkdownContentProvider {
}
private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string {
const baseStyles = this.contributions.previewStyles
const baseStyles = this.contributionProvider.contributions.previewStyles
.map(resource => `<link rel="stylesheet" type="text/css" href="${resource.toString()}">`)
.join('\n');
......@@ -174,7 +174,7 @@ export class MarkdownContentProvider {
}
private getScripts(nonce: string): string {
return this.contributions.previewScripts
return this.contributionProvider.contributions.previewScripts
.map(resource => `<script async src="${resource.toString()}" nonce="${nonce}" charset="UTF-8"></script>`)
.join('\n');
}
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { Logger } from '../logger';
import { MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider } from '../markdownExtensions';
import { disposeAll } from '../util/dispose';
import { MarkdownFileTopmostLineMonitor } from '../util/topmostLineMonitor';
import { MarkdownPreview, PreviewSettings } from './preview';
......@@ -25,7 +25,7 @@ export class MarkdownPreviewManager implements vscode.WebviewPanelSerializer {
public constructor(
private readonly _contentProvider: MarkdownContentProvider,
private readonly _logger: Logger,
private readonly _contributions: MarkdownContributions
private readonly _contributions: MarkdownContributionProvider
) {
this._disposables.push(vscode.window.registerWebviewPanelSerializer(MarkdownPreview.viewType, this));
}
......
......@@ -7,7 +7,7 @@ import * as crypto from 'crypto';
import { MarkdownIt, Token } from 'markdown-it';
import * as path from 'path';
import * as vscode from 'vscode';
import { MarkdownContributions } from './markdownExtensions';
import { MarkdownContributionProvider as MarkdownContributionProvider } from './markdownExtensions';
import { Slugifier } from './slugify';
import { SkinnyTextDocument } from './tableOfContentsProvider';
import { getUriForLinkWithKnownExternalScheme } from './util/links';
......@@ -57,7 +57,7 @@ export class MarkdownEngine {
private _tokenCache = new TokenCache();
public constructor(
private readonly extensionPreviewResourceProvider: MarkdownContributions,
private readonly contributionProvider: MarkdownContributionProvider,
private readonly slugifier: Slugifier,
) { }
......@@ -66,7 +66,7 @@ export class MarkdownEngine {
this.md = import('markdown-it').then(async markdownIt => {
let md: MarkdownIt = markdownIt(await getMarkdownOptions(() => md));
for (const plugin of this.extensionPreviewResourceProvider.markdownItPlugins) {
for (const plugin of this.contributionProvider.contributions.markdownItPlugins) {
try {
md = (await plugin)(md);
} catch {
......
......@@ -26,96 +26,105 @@ const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePat
};
export interface MarkdownContributions {
readonly extensionPath: string;
readonly previewScripts: vscode.Uri[];
readonly previewStyles: vscode.Uri[];
readonly markdownItPlugins: Thenable<(md: any) => any>[];
readonly previewResourceRoots: vscode.Uri[];
readonly previewScripts: ReadonlyArray<vscode.Uri>;
readonly previewStyles: ReadonlyArray<vscode.Uri>;
readonly previewResourceRoots: ReadonlyArray<vscode.Uri>;
readonly markdownItPlugins: ReadonlyArray<Thenable<(md: any) => any>>;
}
class MarkdownExtensionContributions implements MarkdownContributions {
private readonly _scripts: vscode.Uri[] = [];
private readonly _styles: vscode.Uri[] = [];
private readonly _previewResourceRoots: vscode.Uri[] = [];
private readonly _plugins: Thenable<(md: any) => any>[] = [];
private _loaded = false;
public constructor(
public readonly extensionPath: string,
) { }
public get previewScripts(): vscode.Uri[] {
this.ensureLoaded();
return this._scripts;
}
public get previewStyles(): vscode.Uri[] {
this.ensureLoaded();
return this._styles;
}
public get previewResourceRoots(): vscode.Uri[] {
this.ensureLoaded();
return this._previewResourceRoots;
}
public get markdownItPlugins(): Thenable<(md: any) => any>[] {
this.ensureLoaded();
return this._plugins;
export namespace MarkdownContributions {
export const Empty: MarkdownContributions = {
previewScripts: [],
previewStyles: [],
previewResourceRoots: [],
markdownItPlugins: []
};
export function merge(a: MarkdownContributions, b: MarkdownContributions): MarkdownContributions {
return {
previewScripts: [...a.previewScripts, ...b.previewScripts],
previewStyles: [...a.previewStyles, ...b.previewStyles],
previewResourceRoots: [...a.previewResourceRoots, ...b.previewResourceRoots],
markdownItPlugins: [...a.markdownItPlugins, ...b.markdownItPlugins],
};
}
private ensureLoaded() {
if (this._loaded) {
return;
export function fromExtension(
extension: vscode.Extension<any>
): MarkdownContributions {
const contributes = extension.packageJSON && extension.packageJSON.contributes;
if (!contributes) {
return MarkdownContributions.Empty;
}
this._loaded = true;
for (const extension of vscode.extensions.all) {
const contributes = extension.packageJSON && extension.packageJSON.contributes;
if (!contributes) {
continue;
}
this.tryLoadPreviewStyles(contributes, extension);
this.tryLoadPreviewScripts(contributes, extension);
this.tryLoadMarkdownItPlugins(contributes, extension);
if (contributes['markdown.previewScripts'] || contributes['markdown.previewStyles']) {
this._previewResourceRoots.push(vscode.Uri.file(extension.extensionPath));
}
const styles = tryLoadPreviewStyles(contributes, extension);
const scripts = tryLoadPreviewScripts(contributes, extension);
const previewResourceRoots: vscode.Uri[] = [];
if (styles.length || scripts.length) {
previewResourceRoots.push(vscode.Uri.file(extension.extensionPath));
}
const plugins = tryLoadMarkdownItPlugins(contributes, extension);
return {
previewScripts: scripts,
previewStyles: styles,
previewResourceRoots,
markdownItPlugins: plugins ? [plugins] : []
};
}
private tryLoadMarkdownItPlugins(
function tryLoadMarkdownItPlugins(
contributes: any,
extension: vscode.Extension<any>
) {
): Thenable<(md: any) => any> | undefined {
if (contributes['markdown.markdownItPlugins']) {
this._plugins.push(extension.activate().then(() => {
return extension.activate().then(() => {
if (extension.exports && extension.exports.extendMarkdownIt) {
return (md: any) => extension.exports.extendMarkdownIt(md);
}
return (md: any) => md;
}));
});
}
return undefined;
}
private tryLoadPreviewScripts(
function tryLoadPreviewScripts(
contributes: any,
extension: vscode.Extension<any>
) {
this._scripts.push(...resolveExtensionResources(extension, contributes['markdown.previewScripts']));
return resolveExtensionResources(extension, contributes['markdown.previewScripts']);
}
private tryLoadPreviewStyles(
function tryLoadPreviewStyles(
contributes: any,
extension: vscode.Extension<any>
) {
this._styles.push(...resolveExtensionResources(extension, contributes['markdown.previewStyles']));
return resolveExtensionResources(extension, contributes['markdown.previewStyles']);
}
}
export interface MarkdownContributionProvider {
readonly extensionPath: string;
readonly contributions: MarkdownContributions;
}
class VSCodeExtensionMarkdownContributionProvider implements MarkdownContributionProvider {
private _contributions?: MarkdownContributions;
public constructor(
public readonly extensionPath: string,
) { }
public get contributions(): MarkdownContributions {
if (!this._contributions) {
this._contributions = vscode.extensions.all.reduce(
(contributions, extension) => MarkdownContributions.merge(contributions, MarkdownContributions.fromExtension(extension)),
MarkdownContributions.Empty);
}
return this._contributions;
}
}
export function getMarkdownExtensionContributions(context: vscode.ExtensionContext): MarkdownContributions {
return new MarkdownExtensionContributions(context.extensionPath);
export function getMarkdownExtensionContributions(context: vscode.ExtensionContext): MarkdownContributionProvider {
return new VSCodeExtensionMarkdownContributionProvider(context.extensionPath);
}
\ No newline at end of file
......@@ -3,17 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { MarkdownEngine } from '../markdownEngine';
import { MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider, MarkdownContributions } from '../markdownExtensions';
import { githubSlugifier } from '../slugify';
const emptyContributions = new class implements MarkdownContributions {
const emptyContributions = new class implements MarkdownContributionProvider {
readonly extensionPath = '';
readonly previewScripts: vscode.Uri[] = [];
readonly previewStyles: vscode.Uri[] = [];
readonly previewResourceRoots: vscode.Uri[] = [];
readonly markdownItPlugins: Promise<(md: any) => any>[] = [];
readonly contributions = MarkdownContributions.Empty;
};
export function createNewMarkdownEngine(): MarkdownEngine {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册