mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Add table of contents provider abstraction (#152504)
We currently re-compute the same table of contents for markdown files multiple times. This is because multiple language features all need table of contents With this change, we introduce a new `TableOfContentsProvider` which maintains a cache of the table of contents per file. This provider is then passed into every caller that needs a toc
This commit is contained in:
parent
5947c2a93c
commit
dea813ff7c
|
@ -26,6 +26,7 @@ import { MarkdownContentProvider } from './preview/previewContentProvider';
|
|||
import { MarkdownPreviewManager } from './preview/previewManager';
|
||||
import { ContentSecurityPolicyArbiter, ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './preview/security';
|
||||
import { githubSlugifier } from './slugify';
|
||||
import { MdTableOfContentsProvider } from './tableOfContents';
|
||||
import { loadDefaultTelemetryReporter, TelemetryReporter } from './telemetryReporter';
|
||||
import { VsCodeMdWorkspaceContents } from './workspaceContents';
|
||||
|
||||
|
@ -64,27 +65,29 @@ function registerMarkdownLanguageFeatures(
|
|||
const workspaceContents = new VsCodeMdWorkspaceContents();
|
||||
|
||||
const linkProvider = new MdLinkProvider(engine, workspaceContents);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspaceContents);
|
||||
const symbolProvider = new MdDocumentSymbolProvider(engine);
|
||||
const tocProvider = new MdTableOfContentsProvider(engine, workspaceContents);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspaceContents, tocProvider);
|
||||
const symbolProvider = new MdDocumentSymbolProvider(tocProvider);
|
||||
|
||||
return vscode.Disposable.from(
|
||||
workspaceContents,
|
||||
linkProvider,
|
||||
referencesProvider,
|
||||
tocProvider,
|
||||
|
||||
// Language features
|
||||
registerDefinitionSupport(selector, referencesProvider),
|
||||
registerDiagnosticSupport(selector, engine, workspaceContents, linkProvider, commandManager, referencesProvider),
|
||||
registerDiagnosticSupport(selector, engine, workspaceContents, linkProvider, commandManager, referencesProvider, tocProvider),
|
||||
registerDocumentLinkSupport(selector, linkProvider),
|
||||
registerDocumentSymbolSupport(selector, engine),
|
||||
registerDocumentSymbolSupport(selector, tocProvider),
|
||||
registerDropIntoEditorSupport(selector),
|
||||
registerFindFileReferenceSupport(commandManager, referencesProvider),
|
||||
registerFoldingSupport(selector, engine),
|
||||
registerFoldingSupport(selector, engine, tocProvider),
|
||||
registerPasteSupport(selector),
|
||||
registerPathCompletionSupport(selector, engine, linkProvider),
|
||||
registerReferencesSupport(selector, referencesProvider),
|
||||
registerRenameSupport(selector, workspaceContents, referencesProvider, engine.slugifier),
|
||||
registerSmartSelectSupport(selector, engine),
|
||||
registerSmartSelectSupport(selector, engine, tocProvider),
|
||||
registerWorkspaceSymbolSupport(workspaceContents, symbolProvider),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,16 +8,16 @@ import * as vscode from 'vscode';
|
|||
import * as nls from 'vscode-nls';
|
||||
import { CommandManager } from '../commandManager';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContents } from '../tableOfContents';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { MdTableOfContentsWatcher } from '../test/tableOfContentsWatcher';
|
||||
import { Delayer } from '../util/async';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { isMarkdownFile } from '../util/file';
|
||||
import { Limiter } from '../util/limiter';
|
||||
import { ResourceMap } from '../util/resourceMap';
|
||||
import { MdTableOfContentsWatcher } from '../test/tableOfContentsWatcher';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref, MdLink, MdLinkSource, MdLinkProvider, LinkDefinitionSet } from './documentLinkProvider';
|
||||
import { InternalHref, LinkDefinitionSet, MdLink, MdLinkProvider, MdLinkSource } from './documentLinkProvider';
|
||||
import { MdReferencesProvider, tryFindMdDocumentForLink } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
@ -448,9 +448,9 @@ class FileLinkMap {
|
|||
export class DiagnosticComputer {
|
||||
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly linkProvider: MdLinkProvider,
|
||||
private readonly tocProvider: MdTableOfContentsProvider,
|
||||
) { }
|
||||
|
||||
public async getDiagnostics(doc: SkinnyTextDocument, options: DiagnosticOptions, token: vscode.CancellationToken): Promise<{ readonly diagnostics: vscode.Diagnostic[]; readonly links: readonly MdLink[] }> {
|
||||
|
@ -475,7 +475,7 @@ export class DiagnosticComputer {
|
|||
return [];
|
||||
}
|
||||
|
||||
const toc = await TableOfContents.create(this.engine, doc);
|
||||
const toc = await this.tocProvider.get(doc.uri);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ export class DiagnosticComputer {
|
|||
// Validate each of the links to headers in the file
|
||||
const fragmentLinks = links.filter(x => x.fragment);
|
||||
if (fragmentLinks.length) {
|
||||
const toc = await TableOfContents.create(this.engine, hrefDoc);
|
||||
const toc = await this.tocProvider.get(hrefDoc.uri);
|
||||
for (const link of fragmentLinks) {
|
||||
if (!toc.lookup(link.fragment) && !this.isIgnoredLink(options, link.source.pathText) && !this.isIgnoredLink(options, link.source.text)) {
|
||||
const msg = localize('invalidLinkToHeaderInOtherFile', 'Header does not exist in file: {0}', link.fragment);
|
||||
|
@ -625,16 +625,17 @@ export function registerDiagnosticSupport(
|
|||
workspaceContents: MdWorkspaceContents,
|
||||
linkProvider: MdLinkProvider,
|
||||
commandManager: CommandManager,
|
||||
referenceComputer: MdReferencesProvider,
|
||||
referenceProvider: MdReferencesProvider,
|
||||
tocProvider: MdTableOfContentsProvider,
|
||||
): vscode.Disposable {
|
||||
const configuration = new VSCodeDiagnosticConfiguration();
|
||||
const manager = new DiagnosticManager(
|
||||
engine,
|
||||
workspaceContents,
|
||||
new DiagnosticComputer(engine, workspaceContents, linkProvider),
|
||||
new DiagnosticComputer(workspaceContents, linkProvider, tocProvider),
|
||||
configuration,
|
||||
new DiagnosticCollectionReporter(),
|
||||
referenceComputer);
|
||||
referenceProvider);
|
||||
return vscode.Disposable.from(
|
||||
configuration,
|
||||
manager,
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContents, TocEntry } from '../tableOfContents';
|
||||
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
|
||||
interface MarkdownSymbol {
|
||||
|
@ -17,16 +16,16 @@ interface MarkdownSymbol {
|
|||
export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
||||
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine
|
||||
private readonly tocProvider: MdTableOfContentsProvider,
|
||||
) { }
|
||||
|
||||
public async provideDocumentSymbolInformation(document: SkinnyTextDocument): Promise<vscode.SymbolInformation[]> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
const toc = await this.tocProvider.get(document.uri);
|
||||
return toc.entries.map(entry => this.toSymbolInformation(entry));
|
||||
}
|
||||
|
||||
public async provideDocumentSymbols(document: SkinnyTextDocument): Promise<vscode.DocumentSymbol[]> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
const toc = await this.tocProvider.get(document.uri);
|
||||
const root: MarkdownSymbol = {
|
||||
level: -Infinity,
|
||||
children: [],
|
||||
|
@ -77,7 +76,7 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||
|
||||
export function registerDocumentSymbolSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
tocProvider: MdTableOfContentsProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerDocumentSymbolProvider(selector, new MdDocumentSymbolProvider(engine));
|
||||
return vscode.languages.registerDocumentSymbolProvider(selector, new MdDocumentSymbolProvider(tocProvider));
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import Token = require('markdown-it/lib/token');
|
||||
import * as vscode from 'vscode';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContents } from '../tableOfContents';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
|
||||
const rangeLimit = 5000;
|
||||
|
@ -18,7 +18,8 @@ interface MarkdownItTokenWithMap extends Token {
|
|||
export class MdFoldingProvider implements vscode.FoldingRangeProvider {
|
||||
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly tocProvide: MdTableOfContentsProvider,
|
||||
) { }
|
||||
|
||||
public async provideFoldingRanges(
|
||||
|
@ -54,8 +55,8 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
|
|||
.filter((region: vscode.FoldingRange | null): region is vscode.FoldingRange => !!region);
|
||||
}
|
||||
|
||||
private async getHeaderFoldingRanges(document: SkinnyTextDocument) {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
private async getHeaderFoldingRanges(document: SkinnyTextDocument): Promise<vscode.FoldingRange[]> {
|
||||
const toc = await this.tocProvide.get(document.uri);
|
||||
return toc.entries.map(entry => {
|
||||
let endLine = entry.sectionLocation.range.end.line;
|
||||
if (document.lineAt(endLine).isEmptyOrWhitespace && endLine >= entry.line + 1) {
|
||||
|
@ -115,6 +116,7 @@ const isFoldableToken = (token: Token): token is MarkdownItTokenWithMap => {
|
|||
export function registerFoldingSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
tocProvider: MdTableOfContentsProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(engine));
|
||||
return vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(engine, tocProvider));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as uri from 'vscode-uri';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContents, TocEntry } from '../tableOfContents';
|
||||
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
|
@ -69,6 +69,7 @@ export class MdReferencesProvider extends Disposable {
|
|||
public constructor(
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly tocProvider: MdTableOfContentsProvider,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -77,7 +78,7 @@ export class MdReferencesProvider extends Disposable {
|
|||
}
|
||||
|
||||
public async getReferencesAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
const toc = await this.tocProvider.get(document.uri);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
@ -184,7 +185,7 @@ export class MdReferencesProvider extends Disposable {
|
|||
const references: MdReference[] = [];
|
||||
|
||||
if (targetDoc && sourceLink.href.fragment && sourceLink.source.fragmentRange?.contains(triggerPosition)) {
|
||||
const toc = await TableOfContents.create(this.engine, targetDoc);
|
||||
const toc = await this.tocProvider.get(targetDoc.uri);
|
||||
const entry = toc.lookup(sourceLink.href.fragment);
|
||||
if (entry) {
|
||||
references.push({
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import Token = require('markdown-it/lib/token');
|
||||
import * as vscode from 'vscode';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContents, TocEntry } from '../tableOfContents';
|
||||
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
|
||||
interface MarkdownItTokenWithMap extends Token {
|
||||
|
@ -15,7 +15,8 @@ interface MarkdownItTokenWithMap extends Token {
|
|||
export class MdSmartSelect implements vscode.SelectionRangeProvider {
|
||||
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly tocProvider: MdTableOfContentsProvider,
|
||||
) { }
|
||||
|
||||
public async provideSelectionRanges(document: SkinnyTextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise<vscode.SelectionRange[] | undefined> {
|
||||
|
@ -54,7 +55,7 @@ export class MdSmartSelect implements vscode.SelectionRangeProvider {
|
|||
}
|
||||
|
||||
private async getHeaderSelectionRange(document: SkinnyTextDocument, position: vscode.Position): Promise<vscode.SelectionRange | undefined> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
const toc = await this.tocProvider.get(document.uri);
|
||||
|
||||
const headerInfo = getHeadersForPosition(toc.entries, position);
|
||||
|
||||
|
@ -253,6 +254,7 @@ function getFirstChildHeader(document: SkinnyTextDocument, header?: TocEntry, to
|
|||
export function registerSmartSelectSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
tocProvider: MdTableOfContentsProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(engine));
|
||||
return vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(engine, tocProvider));
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { MdDocumentInfoCache } from './languageFeatures/workspaceCache';
|
||||
import { MarkdownEngine } from './markdownEngine';
|
||||
import { githubSlugifier, Slug } from './slugify';
|
||||
import { Disposable } from './util/dispose';
|
||||
import { isMarkdownFile } from './util/file';
|
||||
import { SkinnyTextDocument } from './workspaceContents';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from './workspaceContents';
|
||||
|
||||
export interface TocEntry {
|
||||
readonly slug: Slug;
|
||||
|
@ -161,6 +163,8 @@ export class TableOfContents {
|
|||
return header.replace(/^\s*#+\s*(.*?)(\s+#+)?$/, (_, word) => word.trim());
|
||||
}
|
||||
|
||||
public static readonly empty = new TableOfContents([]);
|
||||
|
||||
private constructor(
|
||||
public readonly entries: readonly TocEntry[],
|
||||
) { }
|
||||
|
@ -170,3 +174,22 @@ export class TableOfContents {
|
|||
return this.entries.find(entry => entry.slug.equals(slug));
|
||||
}
|
||||
}
|
||||
|
||||
export class MdTableOfContentsProvider extends Disposable {
|
||||
|
||||
private readonly _cache: MdDocumentInfoCache<TableOfContents>;
|
||||
|
||||
constructor(
|
||||
engine: MarkdownEngine,
|
||||
workspaceContents: MdWorkspaceContents,
|
||||
) {
|
||||
super();
|
||||
this._cache = this._register(new MdDocumentInfoCache<TableOfContents>(workspaceContents, doc => {
|
||||
return TableOfContents.create(engine, doc);
|
||||
}));
|
||||
}
|
||||
|
||||
public async get(resource: vscode.Uri): Promise<TableOfContents> {
|
||||
return (await this._cache.get(resource)) ?? TableOfContents.empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'mocha';
|
|||
import * as vscode from 'vscode';
|
||||
import { MdDefinitionProvider } from '../languageFeatures/definitionProvider';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -18,7 +19,7 @@ import { joinLines, workspacePath } from './util';
|
|||
|
||||
function getDefinition(doc: InMemoryDocument, pos: vscode.Position, workspace: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace));
|
||||
const provider = new MdDefinitionProvider(referencesProvider);
|
||||
return provider.provideDefinition(doc, pos, noopToken);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as vscode from 'vscode';
|
|||
import { DiagnosticCollectionReporter, DiagnosticComputer, DiagnosticConfiguration, DiagnosticLevel, DiagnosticManager, DiagnosticOptions, DiagnosticReporter } from '../languageFeatures/diagnostics';
|
||||
import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { disposeAll } from '../util/dispose';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
@ -30,7 +31,8 @@ const defaultDiagnosticsOptions = Object.freeze<DiagnosticOptions>({
|
|||
async function getComputedDiagnostics(doc: InMemoryDocument, workspace: MdWorkspaceContents, options: Partial<DiagnosticOptions> = {}): Promise<vscode.Diagnostic[]> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const computer = new DiagnosticComputer(engine, workspace, linkProvider);
|
||||
const tocProvider = new MdTableOfContentsProvider(engine, workspace);
|
||||
const computer = new DiagnosticComputer(workspace, linkProvider, tocProvider);
|
||||
return (
|
||||
await computer.getDiagnostics(doc, { ...defaultDiagnosticsOptions, ...options, }, noopToken)
|
||||
).diagnostics;
|
||||
|
@ -430,11 +432,12 @@ suite('Markdown: Diagnostics manager', () => {
|
|||
) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const tocProvider = new MdTableOfContentsProvider(engine, workspace);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace, tocProvider);
|
||||
const manager = new DiagnosticManager(
|
||||
engine,
|
||||
workspace,
|
||||
new DiagnosticComputer(engine, workspace, linkProvider),
|
||||
new DiagnosticComputer(workspace, linkProvider, tocProvider),
|
||||
configuration,
|
||||
reporter,
|
||||
referencesProvider,
|
||||
|
|
|
@ -6,14 +6,18 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbolProvider';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { workspacePath } from './util';
|
||||
|
||||
|
||||
function getSymbolsForFile(fileContents: string) {
|
||||
const doc = new InMemoryDocument(workspacePath('test.md'), fileContents);
|
||||
const provider = new MdDocumentSymbolProvider(createNewMarkdownEngine());
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
const engine = createNewMarkdownEngine();
|
||||
const provider = new MdDocumentSymbolProvider(new MdTableOfContentsProvider(engine, workspace));
|
||||
return provider.provideDocumentSymbols(doc);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as assert from 'assert';
|
|||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdReference, MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -15,9 +16,9 @@ import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
|||
import { joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
function getFileReferences(resource: vscode.Uri, workspaceContents: MdWorkspaceContents) {
|
||||
function getFileReferences(resource: vscode.Uri, workspace: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const computer = new MdReferencesProvider(engine, workspaceContents);
|
||||
const computer = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace));
|
||||
return computer.getAllReferencesToFile(resource, noopToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,10 @@ import * as assert from 'assert';
|
|||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdFoldingProvider } from '../languageFeatures/foldingProvider';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { joinLines } from './util';
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
@ -218,6 +220,8 @@ suite('markdown.FoldingProvider', () => {
|
|||
|
||||
async function getFoldsForDocument(contents: string) {
|
||||
const doc = new InMemoryDocument(testFileName, contents);
|
||||
const provider = new MdFoldingProvider(createNewMarkdownEngine());
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
const engine = createNewMarkdownEngine();
|
||||
const provider = new MdFoldingProvider(engine, new MdTableOfContentsProvider(engine, workspace));
|
||||
return await provider.provideFoldingRanges(doc, {}, new vscode.CancellationTokenSource().token);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as assert from 'assert';
|
|||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdReferencesProvider, MdVsCodeReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -15,9 +16,9 @@ import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
|||
import { joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
function getReferences(doc: InMemoryDocument, pos: vscode.Position, workspaceContents: MdWorkspaceContents) {
|
||||
function getReferences(doc: InMemoryDocument, pos: vscode.Position, workspace: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const computer = new MdReferencesProvider(engine, workspaceContents);
|
||||
const computer = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace));
|
||||
const provider = new MdVsCodeReferencesProvider(computer);
|
||||
return provider.provideReferences(doc, pos, { includeDeclaration: true }, noopToken);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as vscode from 'vscode';
|
|||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdVsCodeRenameProvider, MdWorkspaceEdit } from '../languageFeatures/rename';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -22,7 +23,7 @@ import { assertRangeEqual, joinLines, workspacePath } from './util';
|
|||
*/
|
||||
function prepareRename(doc: InMemoryDocument, pos: vscode.Position, workspace: MdWorkspaceContents): Promise<undefined | { readonly range: vscode.Range; readonly placeholder: string }> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const referenceComputer = new MdReferencesProvider(engine, workspace);
|
||||
const referenceComputer = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace));
|
||||
const renameProvider = new MdVsCodeRenameProvider(workspace, referenceComputer, githubSlugifier);
|
||||
return renameProvider.prepareRename(doc, pos, noopToken);
|
||||
}
|
||||
|
@ -32,7 +33,7 @@ function prepareRename(doc: InMemoryDocument, pos: vscode.Position, workspace: M
|
|||
*/
|
||||
function getRenameEdits(doc: InMemoryDocument, pos: vscode.Position, newName: string, workspace: MdWorkspaceContents): Promise<MdWorkspaceEdit | undefined> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace));
|
||||
const renameProvider = new MdVsCodeRenameProvider(workspace, referencesProvider, githubSlugifier);
|
||||
return renameProvider.provideRenameEditsImpl(doc, pos, newName, noopToken);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import { MdSmartSelect } from '../languageFeatures/smartSelect';
|
|||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { CURSOR, getCursorPositions, joinLines } from './util';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
|
@ -720,7 +722,9 @@ function assertLineNumbersEqual(selectionRange: vscode.SelectionRange, startLine
|
|||
|
||||
function getSelectionRangesForDocument(contents: string, pos?: vscode.Position[]): Promise<vscode.SelectionRange[] | undefined> {
|
||||
const doc = new InMemoryDocument(testFileName, contents);
|
||||
const provider = new MdSmartSelect(createNewMarkdownEngine());
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
const engine = createNewMarkdownEngine();
|
||||
const provider = new MdSmartSelect(engine, new MdTableOfContentsProvider(engine, workspace));
|
||||
const positions = pos ? pos : getCursorPositions(contents, doc);
|
||||
return provider.provideSelectionRanges(doc, positions, new vscode.CancellationTokenSource().token);
|
||||
}
|
||||
|
|
|
@ -8,29 +8,31 @@ import 'mocha';
|
|||
import * as vscode from 'vscode';
|
||||
import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbolProvider';
|
||||
import { MdWorkspaceSymbolProvider } from '../languageFeatures/workspaceSymbolProvider';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { workspacePath } from './util';
|
||||
|
||||
|
||||
const symbolProvider = new MdDocumentSymbolProvider(createNewMarkdownEngine());
|
||||
function getWorkspaceSymbols(workspace: MdWorkspaceContents, query = ''): Promise<vscode.SymbolInformation[]> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const symbolProvider = new MdDocumentSymbolProvider(new MdTableOfContentsProvider(engine, workspace));
|
||||
return new MdWorkspaceSymbolProvider(symbolProvider, workspace).provideWorkspaceSymbols(query);
|
||||
}
|
||||
|
||||
suite('markdown.WorkspaceSymbolProvider', () => {
|
||||
test('Should not return anything for empty workspace', async () => {
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, new InMemoryWorkspaceMarkdownDocuments([]));
|
||||
|
||||
assert.deepStrictEqual(await provider.provideWorkspaceSymbols(''), []);
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([]);
|
||||
assert.deepStrictEqual(await getWorkspaceSymbols(workspace, ''), []);
|
||||
});
|
||||
|
||||
test('Should return symbols from workspace with one markdown file', async () => {
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([
|
||||
new InMemoryDocument(workspacePath('test.md'), `# header1\nabc\n## header2`)
|
||||
]);
|
||||
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, new InMemoryWorkspaceMarkdownDocuments([
|
||||
new InMemoryDocument(testFileName, `# header1\nabc\n## header2`)
|
||||
]));
|
||||
|
||||
const symbols = await provider.provideWorkspaceSymbols('');
|
||||
const symbols = await getWorkspaceSymbols(workspace, '');
|
||||
assert.strictEqual(symbols.length, 2);
|
||||
assert.strictEqual(symbols[0].name, '# header1');
|
||||
assert.strictEqual(symbols[1].name, '## header2');
|
||||
|
@ -40,64 +42,59 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
const fileNameCount = 10;
|
||||
const files: SkinnyTextDocument[] = [];
|
||||
for (let i = 0; i < fileNameCount; ++i) {
|
||||
const testFileName = vscode.Uri.file(`test${i}.md`);
|
||||
const testFileName = workspacePath(`test${i}.md`);
|
||||
files.push(new InMemoryDocument(testFileName, `# common\nabc\n## header${i}`));
|
||||
}
|
||||
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, new InMemoryWorkspaceMarkdownDocuments(files));
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments(files);
|
||||
|
||||
const symbols = await provider.provideWorkspaceSymbols('');
|
||||
const symbols = await getWorkspaceSymbols(workspace, '');
|
||||
assert.strictEqual(symbols.length, fileNameCount * 2);
|
||||
});
|
||||
|
||||
test('Should update results when markdown file changes symbols', async () => {
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocuments([
|
||||
const testFileName = workspacePath('test.md');
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([
|
||||
new InMemoryDocument(testFileName, `# header1`, 1 /* version */)
|
||||
]);
|
||||
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, workspaceFileProvider);
|
||||
|
||||
assert.strictEqual((await provider.provideWorkspaceSymbols('')).length, 1);
|
||||
assert.strictEqual((await getWorkspaceSymbols(workspace, '')).length, 1);
|
||||
|
||||
// Update file
|
||||
workspaceFileProvider.updateDocument(new InMemoryDocument(testFileName, `# new header\nabc\n## header2`, 2 /* version */));
|
||||
const newSymbols = await provider.provideWorkspaceSymbols('');
|
||||
workspace.updateDocument(new InMemoryDocument(testFileName, `# new header\nabc\n## header2`, 2 /* version */));
|
||||
const newSymbols = await getWorkspaceSymbols(workspace, '');
|
||||
assert.strictEqual(newSymbols.length, 2);
|
||||
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.file('test.md');
|
||||
const testFileName = workspacePath('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocuments([
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([
|
||||
new InMemoryDocument(testFileName, `# header1`)
|
||||
]);
|
||||
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, workspaceFileProvider);
|
||||
assert.strictEqual((await provider.provideWorkspaceSymbols('')).length, 1);
|
||||
assert.strictEqual((await getWorkspaceSymbols(workspace, '')).length, 1);
|
||||
|
||||
// delete file
|
||||
workspaceFileProvider.deleteDocument(testFileName);
|
||||
const newSymbols = await provider.provideWorkspaceSymbols('');
|
||||
workspace.deleteDocument(testFileName);
|
||||
const newSymbols = await getWorkspaceSymbols(workspace, '');
|
||||
assert.strictEqual(newSymbols.length, 0);
|
||||
});
|
||||
|
||||
test('Should update results when markdown file is created', async () => {
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
const testFileName = workspacePath('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocuments([
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([
|
||||
new InMemoryDocument(testFileName, `# header1`)
|
||||
]);
|
||||
|
||||
const provider = new MdWorkspaceSymbolProvider(symbolProvider, workspaceFileProvider);
|
||||
assert.strictEqual((await provider.provideWorkspaceSymbols('')).length, 1);
|
||||
assert.strictEqual((await getWorkspaceSymbols(workspace, '')).length, 1);
|
||||
|
||||
// Creat file
|
||||
workspaceFileProvider.createDocument(new InMemoryDocument(vscode.Uri.file('test2.md'), `# new header\nabc\n## header2`));
|
||||
const newSymbols = await provider.provideWorkspaceSymbols('');
|
||||
// Create file
|
||||
workspace.createDocument(new InMemoryDocument(workspacePath('test2.md'), `# new header\nabc\n## header2`));
|
||||
const newSymbols = await getWorkspaceSymbols(workspace, '');
|
||||
assert.strictEqual(newSymbols.length, 3);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue