diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index 53e0c6286e1..6bac15639fb 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -14,6 +14,7 @@ import { loadDefaultTelemetryReporter } from './telemetryReporter'; import { getMarkdownExtensionContributions } from './markdownExtensions'; import LinkProvider from './features/documentLinkProvider'; import MDDocumentSymbolProvider from './features/documentSymbolProvider'; +import MarkdownWorkspaceSymbolProvider from './features/workspaceSymbolProvider'; import { MarkdownContentProvider } from './features/previewContentProvider'; import { MarkdownPreviewManager } from './features/previewManager'; import MarkdownFoldingProvider from './features/foldingProvider'; @@ -32,13 +33,14 @@ export function activate(context: vscode.ExtensionContext) { const selector = 'markdown'; 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.registerDocumentSymbolProvider(selector, new MDDocumentSymbolProvider(engine))); + context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider)); context.subscriptions.push(vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider())); context.subscriptions.push(vscode.languages.registerFoldingProvider(selector, new MarkdownFoldingProvider(engine))); + context.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(new MarkdownWorkspaceSymbolProvider(symbolProvider))); const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, previewManager); diff --git a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts new file mode 100644 index 00000000000..c1ccb6761be --- /dev/null +++ b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { workspace, WorkspaceSymbolProvider, SymbolInformation, TextDocument, Disposable } from 'vscode'; +import { isMarkdownFile } from '../util/file'; +import MDDocumentSymbolProvider from './documentSymbolProvider'; +import { Dictionary, flatMap } from 'lodash'; + +export default class MarkdownWorkspaceSymbolProvider implements WorkspaceSymbolProvider { + private symbolProvider: MDDocumentSymbolProvider; + private symbolCache: Dictionary = {}; + private symbolCachePopulated: boolean; + private deRegisterOnSaveEvent: Disposable; + + public constructor(symbolProvider: MDDocumentSymbolProvider) { + this.symbolProvider = symbolProvider; + this.symbolCachePopulated = false; + this.deRegisterOnSaveEvent = this.registerOnSaveEvent(); + } + + public async provideWorkspaceSymbols(query: string): Promise { + if (!this.symbolCachePopulated) { + await this.populateSymbolCache(); + this.symbolCachePopulated = true; + } + + return flatMap(this.symbolCache) + .filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1); + } + + public async populateSymbolCache(): Promise { + const markDownDocumentUris = await workspace.findFiles('**/*.md'); + for (const uri of markDownDocumentUris) { + const document = await workspace.openTextDocument(uri); + if (isMarkdownFile(document)) { + const symbols = await this.getSymbol(document); + this.symbolCache[document.fileName] = symbols; + } + } + } + + public dispose(): void { + this.deRegisterOnSaveEvent.dispose(); + } + + private async getSymbol(document: TextDocument): Promise { + return this.symbolProvider.provideDocumentSymbols(document); + } + + private registerOnSaveEvent(): Disposable { + return workspace.onDidSaveTextDocument(async document => { + if (isMarkdownFile(document)) { + const symbols = await this.getSymbol(document); + this.symbolCache[document.fileName] = symbols; + } + }); + } + +} \ No newline at end of file