diff --git a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts index f1a69d3f5ef..abc16f32b27 100644 --- a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts +++ b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts @@ -11,17 +11,21 @@ import MDDocumentSymbolProvider from './documentSymbolProvider'; export interface WorkspaceMarkdownDocumentProvider { getAllMarkdownDocuments(): Thenable; - onDidChangeMarkdownDocument: vscode.Event; + readonly onDidChangeMarkdownDocument: vscode.Event; + readonly onDidDeleteMarkdownDocument: vscode.Event; } class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocumentProvider { private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter(); + private readonly _onDidDeleteMarkdownDocumentEmitter = new vscode.EventEmitter(); + private _watcher: vscode.FileSystemWatcher | undefined; private _disposables: vscode.Disposable[] = []; public dispose() { this._onDidChangeMarkdownDocumentEmitter.dispose(); + this._onDidDeleteMarkdownDocumentEmitter.dispose(); if (this._watcher) { this._watcher.dispose(); @@ -42,6 +46,11 @@ class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocume return this._onDidChangeMarkdownDocumentEmitter.event; } + public get onDidDeleteMarkdownDocument() { + this.ensureWatcher(); + return this._onDidDeleteMarkdownDocumentEmitter.event; + } + private ensureWatcher(): void { if (this._watcher) { return; @@ -55,6 +64,10 @@ class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocume this._onDidChangeMarkdownDocumentEmitter.fire(document); } }, this, this._disposables); + + this._watcher.onDidDelete(async resource => { + this._onDidDeleteMarkdownDocumentEmitter.fire(resource); + }, this, this._disposables); } } @@ -74,7 +87,8 @@ export default class MarkdownWorkspaceSymbolProvider implements vscode.Workspace await this.populateSymbolCache(); this._symbolCachePopulated = true; - this._workspaceMarkdownDocumentProvider.onDidChangeMarkdownDocument(this.onDidChange, this, this._disposables); + this._workspaceMarkdownDocumentProvider.onDidChangeMarkdownDocument(this.onDidChangeDocument, this, this._disposables); + this._workspaceMarkdownDocumentProvider.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this, this._disposables); } const allSymbolsSets = await Promise.all(Array.from(this._symbolCache.values())); @@ -97,7 +111,11 @@ export default class MarkdownWorkspaceSymbolProvider implements vscode.Workspace return this._symbolProvider.provideDocumentSymbols(document); } - private onDidChange(document: vscode.TextDocument) { + private onDidChangeDocument(document: vscode.TextDocument) { this._symbolCache.set(document.fileName, this.getSymbols(document)); } + + private onDidDeleteDocument(resource: vscode.Uri) { + this._symbolCache.delete(resource.fsPath); + } } \ No newline at end of file diff --git a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts index edd87af13cf..be51bf5773b 100644 --- a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts +++ b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts @@ -48,7 +48,7 @@ suite('markdown.WorkspaceSymbolProvider', () => { assert.strictEqual(symbols.length, fileNameCount * 2); }); - test('Should update results when file changes symbols from workspace with one markdown file', async () => { + test('Should update results when markdown file changes symbols', async () => { const testFileName = vscode.Uri.parse('test.md'); const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocumentProvider([ @@ -66,6 +66,23 @@ suite('markdown.WorkspaceSymbolProvider', () => { assert.strictEqual(newSymbols[0].name, '# new header'); assert.strictEqual(newSymbols[1].name, '## header2'); }); + + test('Should remove results when file is deleted', async () => { + const testFileName = vscode.Uri.parse('test.md'); + + const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocumentProvider([ + new InMemoryDocument(testFileName, `# header1`) + ]); + + const provider = new MarkdownWorkspaceSymbolProvider(symbolProvider, workspaceFileProvider); + + assert.strictEqual((await provider.provideWorkspaceSymbols('')).length, 1); + + // delete file + workspaceFileProvider.deleteDocument(testFileName); + const newSymbols = await provider.provideWorkspaceSymbols(''); + assert.strictEqual(newSymbols.length, 0); + }); }); @@ -85,8 +102,16 @@ class InMemoryWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocu private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter(); public onDidChangeMarkdownDocument = this._onDidChangeMarkdownDocumentEmitter.event; + private readonly _onDidDeleteMarkdownDocumentEmitter = new vscode.EventEmitter(); + public onDidDeleteMarkdownDocument = this._onDidDeleteMarkdownDocumentEmitter.event; + public updateDocument(document: vscode.TextDocument) { this._documents.set(document.fileName, document); this._onDidChangeMarkdownDocumentEmitter.fire(document); } + + public deleteDocument(resource: vscode.Uri) { + this._documents.delete(resource.fsPath); + this._onDidDeleteMarkdownDocumentEmitter.fire(resource); + } }