diff --git a/.vscode/launch.json b/.vscode/launch.json index 5b9bd2fff8b..e55a5f5bd4a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -162,7 +162,7 @@ { "type": "extensionHost", "request": "launch", - "name": "VS Code Markdown Extension Tests", + "name": "Markdown Extension Tests", "runtimeExecutable": "${execPath}", "args": [ "${workspaceFolder}/extensions/markdown-language-features/test-fixtures", diff --git a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts index 077afe7831f..8093f86b76a 100644 --- a/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts +++ b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts @@ -8,55 +8,65 @@ import { disposeAll } from '../util/dispose'; import { isMarkdownFile } from '../util/file'; import MDDocumentSymbolProvider from './documentSymbolProvider'; -export default class MarkdownWorkspaceSymbolProvider implements WorkspaceSymbolProvider { - private symbolProvider: MDDocumentSymbolProvider; - private symbolCache = new Map(); - private symbolCachePopulated: boolean; - private disposables: Disposable[] = []; +export interface WorkspaceMarkdownDocumentProvider { + getAllMarkdownDocuments(): Thenable; +} - public constructor(symbolProvider: MDDocumentSymbolProvider) { - this.symbolProvider = symbolProvider; - this.symbolCachePopulated = false; +class VSCodeWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocumentProvider { + getAllMarkdownDocuments() { + return workspace.findFiles('**/*.md'); } +} + + +export default class MarkdownWorkspaceSymbolProvider implements WorkspaceSymbolProvider { + private _symbolCache = new Map(); + private _symbolCachePopulated: boolean = false; + private _disposables: Disposable[] = []; + + public constructor( + private _symbolProvider: MDDocumentSymbolProvider, + private _workspaceMarkdownDocumentProvider: WorkspaceMarkdownDocumentProvider = new VSCodeWorkspaceMarkdownDocumentProvider() + ) { } public async provideWorkspaceSymbols(query: string): Promise { - if (!this.symbolCachePopulated) { + if (!this._symbolCachePopulated) { await this.populateSymbolCache(); - this.symbolCachePopulated = true; + this._symbolCachePopulated = true; const watcher = workspace.createFileSystemWatcher('**/*.md'); - this.disposables.push(watcher); - watcher.onDidChange(this.onDidChange, this, this.disposables); + this._disposables.push(watcher); + watcher.onDidChange(this.onDidChange, this, this._disposables); } - return Array.prototype.concat.apply([], Array.from(this.symbolCache.values()) + return Array.prototype.concat.apply([], Array.from(this._symbolCache.values()) .filter(symbols => symbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1))); } public async populateSymbolCache(): Promise { - const markDownDocumentUris = await workspace.findFiles('**/*.md'); + const markDownDocumentUris = await this._workspaceMarkdownDocumentProvider.getAllMarkdownDocuments(); for (const uri of markDownDocumentUris) { const document = await workspace.openTextDocument(uri); if (isMarkdownFile(document)) { const symbols = await this.getSymbol(document); - this.symbolCache.set(document.fileName, symbols); + this._symbolCache.set(document.fileName, symbols); } } } public dispose(): void { - disposeAll(this.disposables); + disposeAll(this._disposables); } private async getSymbol(document: TextDocument): Promise { - return this.symbolProvider.provideDocumentSymbols(document); + return this._symbolProvider.provideDocumentSymbols(document); } private async onDidChange(resource: Uri) { const document = await workspace.openTextDocument(resource); if (isMarkdownFile(document)) { const symbols = await this.getSymbol(document); - this.symbolCache.set(document.fileName, symbols); + this._symbolCache.set(document.fileName, symbols); } } } \ No newline at end of file diff --git a/extensions/markdown-language-features/src/test/engine.ts b/extensions/markdown-language-features/src/test/engine.ts new file mode 100644 index 00000000000..a7a30a89ce0 --- /dev/null +++ b/extensions/markdown-language-features/src/test/engine.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * 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'; + +export function createNewMarkdownEngine(): MarkdownEngine { + return new MarkdownEngine(new class implements MarkdownContributions { + readonly previewScripts: vscode.Uri[] = []; + readonly previewStyles: vscode.Uri[] = []; + readonly previewResourceRoots: vscode.Uri[] = []; + readonly markdownItPlugins: Promise<(md: any) => any>[] = []; + }); +} + diff --git a/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts index 5474b7a8146..5095bcbbed0 100644 --- a/extensions/markdown-language-features/src/test/foldingProvider.test.ts +++ b/extensions/markdown-language-features/src/test/foldingProvider.test.ts @@ -7,10 +7,9 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import 'mocha'; -import { MarkdownEngine } from '../markdownEngine'; -import { MarkdownContributions } from '../markdownExtensions'; import MarkdownFoldingProvider from '../features/foldingProvider'; import { InMemoryDocument } from './inMemoryDocument'; +import { createNewMarkdownEngine } from './engine'; const testFileName = vscode.Uri.parse('test.md'); @@ -84,16 +83,6 @@ y`); async function getFoldsForDocument(contents: string) { const doc = new InMemoryDocument(testFileName, contents); - const provider = new MarkdownFoldingProvider(newEngine()); + const provider = new MarkdownFoldingProvider(createNewMarkdownEngine()); return await provider.provideFoldingRanges(doc, {}, new vscode.CancellationTokenSource().token); } - -function newEngine(): MarkdownEngine { - return new MarkdownEngine(new class implements MarkdownContributions { - readonly previewScripts: vscode.Uri[] = []; - readonly previewStyles: vscode.Uri[] = []; - readonly previewResourceRoots: vscode.Uri[] = []; - readonly markdownItPlugins: Promise<(md: any) => any>[] = []; - }); -} - diff --git a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts index df6fb0558cc..d2f6c180b69 100644 --- a/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts +++ b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts @@ -8,16 +8,15 @@ import * as vscode from 'vscode'; import 'mocha'; import { TableOfContentsProvider } from '../tableOfContentsProvider'; -import { MarkdownEngine } from '../markdownEngine'; -import { MarkdownContributions } from '../markdownExtensions'; import { InMemoryDocument } from './inMemoryDocument'; +import { createNewMarkdownEngine } from './engine'; const testFileName = vscode.Uri.parse('test.md'); suite('markdown.TableOfContentsProvider', () => { test('Lookup should not return anything for empty document', async () => { const doc = new InMemoryDocument(testFileName, ''); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual(await provider.lookup(''), undefined); assert.strictEqual(await provider.lookup('foo'), undefined); @@ -25,7 +24,7 @@ suite('markdown.TableOfContentsProvider', () => { test('Lookup should not return anything for document with no headers', async () => { const doc = new InMemoryDocument(testFileName, 'a *b*\nc'); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual(await provider.lookup(''), undefined); assert.strictEqual(await provider.lookup('foo'), undefined); @@ -35,7 +34,7 @@ suite('markdown.TableOfContentsProvider', () => { test('Lookup should return basic #header', async () => { const doc = new InMemoryDocument(testFileName, `# a\nx\n# c`); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); { const entry = await provider.lookup('a'); @@ -54,7 +53,7 @@ suite('markdown.TableOfContentsProvider', () => { test('Lookups should be case in-sensitive', async () => { const doc = new InMemoryDocument(testFileName, `# fOo\n`); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual((await provider.lookup('fOo'))!.line, 0); assert.strictEqual((await provider.lookup('foo'))!.line, 0); @@ -63,7 +62,7 @@ suite('markdown.TableOfContentsProvider', () => { test('Lookups should ignore leading and trailing white-space, and collapse internal whitespace', async () => { const doc = new InMemoryDocument(testFileName, `# f o o \n`); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual((await provider.lookup('f o o'))!.line, 0); assert.strictEqual((await provider.lookup(' f o o'))!.line, 0); @@ -78,27 +77,16 @@ suite('markdown.TableOfContentsProvider', () => { test('should normalize special characters #44779', async () => { const doc = new InMemoryDocument(testFileName, `# Indentação\n`); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual((await provider.lookup('indentacao'))!.line, 0); }); test('should map special З, #37079', async () => { const doc = new InMemoryDocument(testFileName, `### Заголовок Header 3`); - const provider = new TableOfContentsProvider(newEngine(), doc); + const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc); assert.strictEqual((await provider.lookup('Заголовок-header-3'))!.line, 0); assert.strictEqual((await provider.lookup('3аголовок-header-3'))!.line, 0); }); }); - -function newEngine(): MarkdownEngine { - return new MarkdownEngine(new class implements MarkdownContributions { - readonly previewScripts: vscode.Uri[] = []; - readonly previewStyles: vscode.Uri[] = []; - readonly previewResourceRoots: vscode.Uri[] = []; - readonly markdownItPlugins: Promise<(md: any) => any>[] = []; - - }); -} - diff --git a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts new file mode 100644 index 00000000000..0c21bb25715 --- /dev/null +++ b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import 'mocha'; +import MDDocumentSymbolProvider from '../features/documentSymbolProvider'; +import MarkdownWorkspaceSymbolProvider, { WorkspaceMarkdownDocumentProvider } from '../features/workspaceSymbolProvider'; +import { createNewMarkdownEngine } from './engine'; + + +suite('markdown.WorkspaceSymbolProvider', () => { + test('Should not return anything for empty workspace', async () => { + const provider = new MarkdownWorkspaceSymbolProvider(new MDDocumentSymbolProvider(createNewMarkdownEngine()), new class implements WorkspaceMarkdownDocumentProvider { + async getAllMarkdownDocuments() { + return []; + } + }); + + assert.deepEqual(await provider.provideWorkspaceSymbols(''), []); + }); +});