Vscode merge (#4582)

* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
This commit is contained in:
Anthony Dresser
2019-03-19 17:44:35 -07:00
committed by GitHub
parent 833d197412
commit 87765e8673
1879 changed files with 54505 additions and 38058 deletions

View File

@@ -15,8 +15,8 @@ import MarkdownWorkspaceSymbolProvider from './features/workspaceSymbolProvider'
import { Logger } from './logger';
import { MarkdownEngine } from './markdownEngine';
import { getMarkdownExtensionContributions } from './markdownExtensions';
import { ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './security';
import { loadDefaultTelemetryReporter } from './telemetryReporter';
import { ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector, ContentSecurityPolicyArbiter } from './security';
import { loadDefaultTelemetryReporter, TelemetryReporter } from './telemetryReporter';
import { githubSlugifier } from './slugify';
@@ -25,33 +25,55 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(telemetryReporter);
const contributions = getMarkdownExtensionContributions(context);
context.subscriptions.push(contributions);
const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState);
const engine = new MarkdownEngine(contributions, githubSlugifier);
const logger = new Logger();
const selector: vscode.DocumentSelector = [
{ language: 'markdown', scheme: 'file' },
{ language: 'markdown', scheme: 'untitled' }
];
const contentProvider = new MarkdownContentProvider(engine, context, cspArbiter, contributions, logger);
const symbolProvider = new MDDocumentSymbolProvider(engine);
const previewManager = new MarkdownPreviewManager(contentProvider, logger, contributions);
context.subscriptions.push(previewManager);
context.subscriptions.push(vscode.languages.setLanguageConfiguration('markdown', {
wordPattern: new RegExp('(\\p{Alphabetic}|\\p{Number})+', 'ug'),
}));
context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider));
context.subscriptions.push(vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider()));
context.subscriptions.push(vscode.languages.registerFoldingRangeProvider(selector, new MarkdownFoldingProvider(engine)));
context.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(new MarkdownWorkspaceSymbolProvider(symbolProvider)));
context.subscriptions.push(registerMarkdownLanguageFeatures(symbolProvider, engine));
context.subscriptions.push(registerMarkdownCommands(previewManager, telemetryReporter, cspArbiter, engine));
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
logger.updateConfiguration();
previewManager.updateConfiguration();
}));
}
function registerMarkdownLanguageFeatures(
symbolProvider: MDDocumentSymbolProvider,
engine: MarkdownEngine
): vscode.Disposable {
const selector: vscode.DocumentSelector = [
{ language: 'markdown', scheme: 'file' },
{ language: 'markdown', scheme: 'untitled' }
];
return vscode.Disposable.from(
vscode.languages.setLanguageConfiguration('markdown', {
wordPattern: new RegExp('(\\p{Alphabetic}|\\p{Number})+', 'ug'),
}),
vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider),
vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider()),
vscode.languages.registerFoldingRangeProvider(selector, new MarkdownFoldingProvider(engine)),
vscode.languages.registerWorkspaceSymbolProvider(new MarkdownWorkspaceSymbolProvider(symbolProvider))
);
}
function registerMarkdownCommands(
previewManager: MarkdownPreviewManager,
telemetryReporter: TelemetryReporter,
cspArbiter: ContentSecurityPolicyArbiter,
engine: MarkdownEngine
): vscode.Disposable {
const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, previewManager);
const commandManager = new CommandManager();
context.subscriptions.push(commandManager);
commandManager.register(new commands.ShowPreviewCommand(previewManager, telemetryReporter));
commandManager.register(new commands.ShowPreviewToSideCommand(previewManager, telemetryReporter));
commandManager.register(new commands.ShowLockedPreviewToSideCommand(previewManager, telemetryReporter));
@@ -63,9 +85,5 @@ export function activate(context: vscode.ExtensionContext) {
commandManager.register(new commands.ToggleLockCommand(previewManager));
// {{SQL CARBON EDIT}}
commandManager.register(new commands.ShowNotebookPreview(engine));
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
logger.updateConfiguration();
previewManager.updateConfiguration();
}));
return commandManager;
}

View File

@@ -8,12 +8,12 @@ import * as path from 'path';
import { Logger } from '../logger';
import { MarkdownContentProvider } from './previewContentProvider';
import { disposeAll } from '../util/dispose';
import { Disposable } 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();
@@ -60,7 +60,7 @@ interface PreviewStyleLoadErrorMessage extends WebviewMessage {
};
}
export class MarkdownPreview {
export class MarkdownPreview extends Disposable {
public static viewType = 'markdown.preview';
@@ -70,7 +70,6 @@ export class MarkdownPreview {
private readonly editor: vscode.WebviewPanel;
private throttleTimer: any;
private line: number | undefined = undefined;
private readonly disposables: vscode.Disposable[] = [];
private firstUpdate = true;
private currentVersion?: { resource: vscode.Uri, version: number };
private forceUpdate = false;
@@ -85,7 +84,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 +98,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 +117,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 +135,7 @@ export class MarkdownPreview {
previewConfigurations,
logger,
topmostLineMonitor,
contributions);
contributionProvider);
}
private constructor(
@@ -147,19 +146,24 @@ export class MarkdownPreview {
private readonly _previewConfigurations: MarkdownPreviewConfigurationManager,
private readonly _logger: Logger,
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
private readonly _contributions: MarkdownContributions,
private readonly _contributionProvider: MarkdownContributionProvider,
) {
super();
this._resource = resource;
this._locked = locked;
this.editor = webview;
this.editor.onDidDispose(() => {
this.dispose();
}, null, this.disposables);
}, null, this._disposables);
this.editor.onDidChangeViewState(e => {
this._onDidChangeViewStateEmitter.fire(e);
}, null, this.disposables);
}, null, this._disposables);
_contributionProvider.onContributionsChanged(() => {
setImmediate(() => this.refresh());
}, null, this._disposables);
this.editor.webview.onDidReceiveMessage((e: CacheImageSizesMessage | RevealLineMessage | DidClickMessage | ClickLinkMessage | ShowPreviewSecuritySelectorMessage | PreviewStyleLoadErrorMessage) => {
if (e.source !== this._resource.toString()) {
@@ -191,19 +195,19 @@ export class MarkdownPreview {
vscode.window.showWarningMessage(localize('onPreviewStyleLoadError', "Could not load 'markdown.styles': {0}", e.body.unloadedStyles.join(', ')));
break;
}
}, null, this.disposables);
}, null, this._disposables);
vscode.workspace.onDidChangeTextDocument(event => {
if (this.isPreviewOf(event.document.uri)) {
this.refresh();
}
}, null, this.disposables);
}, null, this._disposables);
topmostLineMonitor.onDidChangeTopmostLine(event => {
if (this.isPreviewOf(event.resource)) {
this.updateForView(event.resource, event.line);
}
}, null, this.disposables);
}, null, this._disposables);
vscode.window.onDidChangeTextEditorSelection(event => {
if (this.isPreviewOf(event.textEditor.document.uri)) {
@@ -213,13 +217,13 @@ export class MarkdownPreview {
source: this.resource.toString()
});
}
}, null, this.disposables);
}, null, this._disposables);
vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor && isMarkdownFile(editor.document) && !this._locked) {
this.update(editor.document.uri);
}
}, null, this.disposables);
}, null, this._disposables);
}
private readonly _onDisposeEmitter = new vscode.EventEmitter<void>();
@@ -242,18 +246,17 @@ export class MarkdownPreview {
}
public dispose() {
super.dispose();
if (this._disposed) {
return;
}
this._disposed = true;
this._onDisposeEmitter.fire();
this._onDisposeEmitter.dispose();
this._onDidChangeViewStateEmitter.dispose();
this.editor.dispose();
disposeAll(this.disposables);
}
public update(resource: vscode.Uri) {
@@ -328,7 +331,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 +395,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 +413,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);

View File

@@ -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');
}

View File

@@ -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));
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { disposeAll } from '../util/dispose';
import { Disposable } from '../util/dispose';
import { isMarkdownFile } from '../util/file';
import { Lazy, lazy } from '../util/lazy';
import MDDocumentSymbolProvider from './documentSymbolProvider';
@@ -18,25 +18,13 @@ export interface WorkspaceMarkdownDocumentProvider {
readonly onDidDeleteMarkdownDocument: vscode.Event<vscode.Uri>;
}
class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocumentProvider {
class VSCodeWorkspaceMarkdownDocumentProvider extends Disposable implements WorkspaceMarkdownDocumentProvider {
private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter<SkinnyTextDocument>();
private readonly _onDidCreateMarkdownDocumentEmitter = new vscode.EventEmitter<SkinnyTextDocument>();
private readonly _onDidDeleteMarkdownDocumentEmitter = new vscode.EventEmitter<vscode.Uri>();
private readonly _onDidChangeMarkdownDocumentEmitter = this._register(new vscode.EventEmitter<SkinnyTextDocument>());
private readonly _onDidCreateMarkdownDocumentEmitter = this._register(new vscode.EventEmitter<SkinnyTextDocument>());
private readonly _onDidDeleteMarkdownDocumentEmitter = this._register(new vscode.EventEmitter<vscode.Uri>());
private _watcher: vscode.FileSystemWatcher | undefined;
private _disposables: vscode.Disposable[] = [];
public dispose() {
this._onDidChangeMarkdownDocumentEmitter.dispose();
this._onDidDeleteMarkdownDocumentEmitter.dispose();
if (this._watcher) {
this._watcher.dispose();
}
disposeAll(this._disposables);
}
async getAllMarkdownDocuments() {
const resources = await vscode.workspace.findFiles('**/*.md', '**/node_modules/**');
@@ -64,7 +52,7 @@ class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocume
return;
}
this._watcher = vscode.workspace.createFileSystemWatcher('**/*.md');
this._watcher = this._register(vscode.workspace.createFileSystemWatcher('**/*.md'));
this._watcher.onDidChange(async resource => {
const document = await this.getMarkdownDocument(resource);
@@ -98,15 +86,16 @@ class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocume
}
export default class MarkdownWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
export default class MarkdownWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider {
private _symbolCache = new Map<string, Lazy<Thenable<vscode.SymbolInformation[]>>>();
private _symbolCachePopulated: boolean = false;
private _disposables: vscode.Disposable[] = [];
public constructor(
private _symbolProvider: MDDocumentSymbolProvider,
private _workspaceMarkdownDocumentProvider: WorkspaceMarkdownDocumentProvider = new VSCodeWorkspaceMarkdownDocumentProvider()
) { }
) {
super();
}
public async provideWorkspaceSymbols(query: string): Promise<vscode.SymbolInformation[]> {
if (!this._symbolCachePopulated) {
@@ -130,10 +119,6 @@ export default class MarkdownWorkspaceSymbolProvider implements vscode.Workspace
}
}
public dispose(): void {
disposeAll(this._disposables);
}
private getSymbols(document: SkinnyTextDocument): Lazy<Thenable<vscode.SymbolInformation[]>> {
return lazy(async () => {
return this._symbolProvider.provideDocumentSymbolInformation(document);

View File

@@ -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,16 +57,21 @@ export class MarkdownEngine {
private _tokenCache = new TokenCache();
public constructor(
private readonly extensionPreviewResourceProvider: MarkdownContributions,
private readonly contributionProvider: MarkdownContributionProvider,
private readonly slugifier: Slugifier,
) { }
) {
contributionProvider.onContributionsChanged(() => {
// Markdown plugin contributions may have changed
this.md = undefined;
});
}
private async getEngine(config: MarkdownItConfig): Promise<MarkdownIt> {
if (!this.md) {
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.values()) {
try {
md = (await plugin)(md);
} catch {

View File

@@ -5,13 +5,15 @@
import * as vscode from 'vscode';
import * as path from 'path';
import { Disposable } from './util/dispose';
import * as arrays from './util/arrays';
const resolveExtensionResource = (extension: vscode.Extension<any>, resourcePath: string): vscode.Uri => {
return vscode.Uri.file(path.join(extension.extensionPath, resourcePath))
.with({ scheme: 'vscode-resource' });
};
const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePaths: any): vscode.Uri[] => {
const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePaths: unknown): vscode.Uri[] => {
const result: vscode.Uri[] = [];
if (Array.isArray(resourcePaths)) {
for (const resource of resourcePaths) {
@@ -26,96 +28,135 @@ 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: Map<string, 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: new Map()
};
private _loaded = false;
public constructor(
public readonly extensionPath: string,
) { }
public get previewScripts(): vscode.Uri[] {
this.ensureLoaded();
return this._scripts;
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: new Map([...a.markdownItPlugins.entries(), ...b.markdownItPlugins.entries()]),
};
}
public get previewStyles(): vscode.Uri[] {
this.ensureLoaded();
return this._styles;
function uriEqual(a: vscode.Uri, b: vscode.Uri): boolean {
return a.toString() === b.toString();
}
public get previewResourceRoots(): vscode.Uri[] {
this.ensureLoaded();
return this._previewResourceRoots;
export function equal(a: MarkdownContributions, b: MarkdownContributions): boolean {
return arrays.equals(a.previewScripts, b.previewScripts, uriEqual)
&& arrays.equals(a.previewStyles, b.previewStyles, uriEqual)
&& arrays.equals(a.previewResourceRoots, b.previewResourceRoots, uriEqual)
&& arrays.equals(Array.from(a.markdownItPlugins.keys()), Array.from(b.markdownItPlugins.keys()));
}
public get markdownItPlugins(): Thenable<(md: any) => any>[] {
this.ensureLoaded();
return this._plugins;
}
private ensureLoaded() {
if (this._loaded) {
return;
export function fromExtension(
extension: vscode.Extension<any>
): MarkdownContributions {
const contributions = extension.packageJSON && extension.packageJSON.contributes;
if (!contributions) {
return MarkdownContributions.Empty;
}
this._loaded = true;
for (const extension of vscode.extensions.all) {
const contributes = extension.packageJSON && extension.packageJSON.contributes;
if (!contributes) {
continue;
}
const previewStyles = getContributedStyles(contributions, extension);
const previewScripts = getContributedScripts(contributions, extension);
const previewResourceRoots = previewStyles.length || previewScripts.length ? [vscode.Uri.file(extension.extensionPath)] : [];
const markdownItPlugins = getContributedMarkdownItPlugins(contributions, extension);
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));
}
}
return {
previewScripts,
previewStyles,
previewResourceRoots,
markdownItPlugins
};
}
private tryLoadMarkdownItPlugins(
function getContributedMarkdownItPlugins(
contributes: any,
extension: vscode.Extension<any>
) {
): Map<string, Thenable<(md: any) => any>> {
const map = new Map<string, Thenable<(md: any) => any>>();
if (contributes['markdown.markdownItPlugins']) {
this._plugins.push(extension.activate().then(() => {
map.set(extension.id, extension.activate().then(() => {
if (extension.exports && extension.exports.extendMarkdownIt) {
return (md: any) => extension.exports.extendMarkdownIt(md);
}
return (md: any) => md;
}));
}
return map;
}
private tryLoadPreviewScripts(
function getContributedScripts(
contributes: any,
extension: vscode.Extension<any>
) {
this._scripts.push(...resolveExtensionResources(extension, contributes['markdown.previewScripts']));
return resolveExtensionResources(extension, contributes['markdown.previewScripts']);
}
private tryLoadPreviewStyles(
function getContributedStyles(
contributes: any,
extension: vscode.Extension<any>
) {
this._styles.push(...resolveExtensionResources(extension, contributes['markdown.previewStyles']));
return resolveExtensionResources(extension, contributes['markdown.previewStyles']);
}
}
export function getMarkdownExtensionContributions(context: vscode.ExtensionContext): MarkdownContributions {
return new MarkdownExtensionContributions(context.extensionPath);
export interface MarkdownContributionProvider {
readonly extensionPath: string;
readonly contributions: MarkdownContributions;
readonly onContributionsChanged: vscode.Event<this>;
dispose(): void;
}
class VSCodeExtensionMarkdownContributionProvider extends Disposable implements MarkdownContributionProvider {
private _contributions?: MarkdownContributions;
public constructor(
public readonly extensionPath: string,
) {
super();
vscode.extensions.onDidChange(() => {
const currentContributions = this.getCurrentContributions();
const existingContributions = this._contributions || MarkdownContributions.Empty;
if (!MarkdownContributions.equal(existingContributions, currentContributions)) {
this._contributions = currentContributions;
this._onContributionsChanged.fire(this);
}
}, undefined, this._disposables);
}
private readonly _onContributionsChanged = this._register(new vscode.EventEmitter<this>());
public readonly onContributionsChanged = this._onContributionsChanged.event;
public get contributions(): MarkdownContributions {
if (!this._contributions) {
this._contributions = this.getCurrentContributions();
}
return this._contributions;
}
private getCurrentContributions(): MarkdownContributions {
return vscode.extensions.all
.map(MarkdownContributions.fromExtension)
.reduce(MarkdownContributions.merge, MarkdownContributions.Empty);
}
}
export function getMarkdownExtensionContributions(context: vscode.ExtensionContext): MarkdownContributionProvider {
return new VSCodeExtensionMarkdownContributionProvider(context.extensionPath);
}

View File

@@ -5,15 +5,14 @@
import * as vscode from 'vscode';
import { MarkdownEngine } from '../markdownEngine';
import { MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider, MarkdownContributions } from '../markdownExtensions';
import { githubSlugifier } from '../slugify';
import { Disposable } from '../util/dispose';
const emptyContributions = new class implements MarkdownContributions {
const emptyContributions = new class extends Disposable 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;
readonly onContributionsChanged = this._register(new vscode.EventEmitter<this>()).event;
};
export function createNewMarkdownEngine(): MarkdownEngine {

View File

@@ -38,7 +38,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
const fileNameCount = 10;
const files: vscode.TextDocument[] = [];
for (let i = 0; i < fileNameCount; ++i) {
const testFileName = vscode.Uri.parse(`test${i}.md`);
const testFileName = vscode.Uri.file(`test${i}.md`);
files.push(new InMemoryDocument(testFileName, `# common\nabc\n## header${i}`));
}

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function equals<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
if (one.length !== other.length) {
return false;
}
for (let i = 0, len = one.length; i < len; i++) {
if (!itemEquals(one[i], other[i])) {
return false;
}
}
return true;
}

View File

@@ -14,3 +14,29 @@ export function disposeAll(disposables: vscode.Disposable[]) {
}
}
export abstract class Disposable {
private _isDisposed = false;
protected _disposables: vscode.Disposable[] = [];
public dispose(): any {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
disposeAll(this._disposables);
}
protected _register<T extends vscode.Disposable>(value: T): T {
if (this._isDisposed) {
value.dispose();
} else {
this._disposables.push(value);
}
return value;
}
protected get isDisposed() {
return this._isDisposed;
}
}