mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-27 21:52:59 +00:00
Refactor markdown contributions
Reducing code duplication and reducing state
This commit is contained in:
@@ -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>[] = [];
|
||||
export namespace MarkdownContributions {
|
||||
export const Empty: MarkdownContributions = {
|
||||
previewScripts: [],
|
||||
previewStyles: [],
|
||||
previewResourceRoots: [],
|
||||
markdownItPlugins: []
|
||||
};
|
||||
|
||||
private _loaded = false;
|
||||
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],
|
||||
};
|
||||
}
|
||||
|
||||
export function fromExtension(
|
||||
extension: vscode.Extension<any>
|
||||
): MarkdownContributions {
|
||||
const contributes = extension.packageJSON && extension.packageJSON.contributes;
|
||||
if (!contributes) {
|
||||
return MarkdownContributions.Empty;
|
||||
}
|
||||
|
||||
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] : []
|
||||
};
|
||||
}
|
||||
|
||||
function tryLoadMarkdownItPlugins(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
): Thenable<(md: any) => any> | undefined {
|
||||
if (contributes['markdown.markdownItPlugins']) {
|
||||
return extension.activate().then(() => {
|
||||
if (extension.exports && extension.exports.extendMarkdownIt) {
|
||||
return (md: any) => extension.exports.extendMarkdownIt(md);
|
||||
}
|
||||
return (md: any) => md;
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryLoadPreviewScripts(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
) {
|
||||
return resolveExtensionResources(extension, contributes['markdown.previewScripts']);
|
||||
}
|
||||
|
||||
function tryLoadPreviewStyles(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
) {
|
||||
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 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;
|
||||
}
|
||||
|
||||
private ensureLoaded() {
|
||||
if (this._loaded) {
|
||||
return;
|
||||
public get contributions(): MarkdownContributions {
|
||||
if (!this._contributions) {
|
||||
this._contributions = vscode.extensions.all.reduce(
|
||||
(contributions, extension) => MarkdownContributions.merge(contributions, MarkdownContributions.fromExtension(extension)),
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private tryLoadMarkdownItPlugins(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
) {
|
||||
if (contributes['markdown.markdownItPlugins']) {
|
||||
this._plugins.push(extension.activate().then(() => {
|
||||
if (extension.exports && extension.exports.extendMarkdownIt) {
|
||||
return (md: any) => extension.exports.extendMarkdownIt(md);
|
||||
}
|
||||
return (md: any) => md;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private tryLoadPreviewScripts(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
) {
|
||||
this._scripts.push(...resolveExtensionResources(extension, contributes['markdown.previewScripts']));
|
||||
}
|
||||
|
||||
private tryLoadPreviewStyles(
|
||||
contributes: any,
|
||||
extension: vscode.Extension<any>
|
||||
) {
|
||||
this._styles.push(...resolveExtensionResources(extension, contributes['markdown.previewStyles']));
|
||||
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);
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user