diff --git a/extensions/markdown-language-features/src/languageFeatures/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/languageFeatures/workspaceSymbolProvider.ts index 049cef793bb..968f67ad97b 100644 --- a/extensions/markdown-language-features/src/languageFeatures/workspaceSymbolProvider.ts +++ b/extensions/markdown-language-features/src/languageFeatures/workspaceSymbolProvider.ts @@ -12,49 +12,68 @@ import { MdDocumentSymbolProvider } from './documentSymbolProvider'; export class MdWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider { - private readonly _symbolCache = new Map>>(); - private _symbolCachePopulated: boolean = false; + private readonly _cache: MdWorkspaceCache>; public constructor( - private _symbolProvider: MdDocumentSymbolProvider, - private _workspaceMarkdownDocumentProvider: MdWorkspaceContents, + symbolProvider: MdDocumentSymbolProvider, + workspaceContents: MdWorkspaceContents, + ) { + super(); + + this._cache = this._register(new MdWorkspaceCache(workspaceContents, doc => symbolProvider.provideDocumentSymbolInformation(doc))); + } + + public async provideWorkspaceSymbols(query: string): Promise { + const allSymbolSets = await this._cache.getAll(); + const allSymbols = (await Promise.all(allSymbolSets)).flat(); + return allSymbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1); + } +} + +/** + * Cache of information for markdown files in the workspace. + */ +class MdWorkspaceCache extends Disposable { + + private readonly _cache = new Map>(); + private _hasPopulatedCache = false; + + public constructor( + private readonly workspaceContents: MdWorkspaceContents, + private readonly getValue: (document: SkinnyTextDocument) => T, ) { super(); } - public async provideWorkspaceSymbols(query: string): Promise { - if (!this._symbolCachePopulated) { + public async getAll(): Promise { + if (!this._hasPopulatedCache) { await this.populateSymbolCache(); - this._symbolCachePopulated = true; + this._hasPopulatedCache = true; - this._workspaceMarkdownDocumentProvider.onDidChangeMarkdownDocument(this.onDidChangeDocument, this, this._disposables); - this._workspaceMarkdownDocumentProvider.onDidCreateMarkdownDocument(this.onDidChangeDocument, this, this._disposables); - this._workspaceMarkdownDocumentProvider.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this, this._disposables); + this.workspaceContents.onDidChangeMarkdownDocument(this.onDidChangeDocument, this, this._disposables); + this.workspaceContents.onDidCreateMarkdownDocument(this.onDidChangeDocument, this, this._disposables); + this.workspaceContents.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this, this._disposables); } - const allSymbolsSets = await Promise.all(Array.from(this._symbolCache.values(), x => x.value)); - const allSymbols = allSymbolsSets.flat(); - return allSymbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1); + return Array.from(this._cache.values(), x => x.value); } - public async populateSymbolCache(): Promise { - const markdownDocumentUris = await this._workspaceMarkdownDocumentProvider.getAllMarkdownDocuments(); + private async populateSymbolCache(): Promise { + const markdownDocumentUris = await this.workspaceContents.getAllMarkdownDocuments(); for (const document of markdownDocumentUris) { - this._symbolCache.set(document.uri.toString(), this.getSymbols(document)); + this._cache.set(document.uri.toString(), this.update(document)); } } - private getSymbols(document: SkinnyTextDocument): Lazy> { - return lazy(() => { - return this._symbolProvider.provideDocumentSymbolInformation(document); - }); + private update(document: SkinnyTextDocument): Lazy { + return lazy(() => this.getValue(document)); } private onDidChangeDocument(document: SkinnyTextDocument) { - this._symbolCache.set(document.uri.toString(), this.getSymbols(document)); + this._cache.set(document.uri.toString(), this.update(document)); } private onDidDeleteDocument(resource: vscode.Uri) { - this._symbolCache.delete(resource.toString()); + this._cache.delete(resource.toString()); } }