Split out VS Code reference provider from markdown reference provider (#152369)

This change renames the main markdown reference provider class to `MdReferenceComputer` and then uses this to implement a `vscode.ReferenceProvider`

This more cleanly splits the VS Code part of the logic from the general reference calculation stuff other providers consume
This commit is contained in:
Matt Bierner
2022-06-16 12:47:48 -07:00
committed by GitHub
parent e8f28ac3ac
commit 3114ee690b
11 changed files with 73 additions and 55 deletions

View File

@@ -5,16 +5,18 @@
import * as vscode from 'vscode';
import { Disposable } from '../util/dispose';
import { SkinnyTextDocument } from '../workspaceContents';
import { MdReferencesProvider } from './references';
import { MdReferencesComputer } from './references';
export class MdDefinitionProvider extends Disposable implements vscode.DefinitionProvider {
constructor(private readonly referencesProvider: MdReferencesProvider) {
constructor(
private readonly referencesComputer: MdReferencesComputer
) {
super();
}
async provideDefinition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Definition | undefined> {
const allRefs = await this.referencesProvider.getAllReferencesAtPosition(document, position, token);
const allRefs = await this.referencesComputer.getReferencesAtPosition(document, position, token);
return allRefs.find(ref => ref.kind === 'link' && ref.isDefinition)?.location;
}

View File

@@ -18,7 +18,7 @@ import { ResourceMap } from '../util/resourceMap';
import { MdTableOfContentsWatcher } from '../test/tableOfContentsWatcher';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { InternalHref, LinkDefinitionSet, MdLink, MdLinkComputer, MdLinkSource } from './documentLinkProvider';
import { MdReferencesProvider, tryFindMdDocumentForLink } from './references';
import { MdReferencesComputer, tryFindMdDocumentForLink } from './references';
const localize = nls.loadMessageBundle();
@@ -311,7 +311,7 @@ export class DiagnosticManager extends Disposable {
private readonly computer: DiagnosticComputer,
private readonly configuration: DiagnosticConfiguration,
private readonly reporter: DiagnosticReporter,
private readonly referencesProvider: MdReferencesProvider,
private readonly referencesComputer: MdReferencesComputer,
delay = 300,
) {
super();
@@ -350,7 +350,7 @@ export class DiagnosticManager extends Disposable {
this._register(this.tableOfContentsWatcher.onTocChanged(async e => {
// When the toc of a document changes, revalidate every file that linked to it too
const triggered = new ResourceMap<void>();
for (const ref of await this.referencesProvider.getAllReferencesToFile(e.uri, noopToken)) {
for (const ref of await this.referencesComputer.getAllReferencesToFile(e.uri, noopToken)) {
const file = ref.location.uri;
if (!triggered.has(file)) {
this.triggerDiagnostics(file);
@@ -627,7 +627,7 @@ export function register(
workspaceContents: MdWorkspaceContents,
linkComputer: MdLinkComputer,
commandManager: CommandManager,
referenceProvider: MdReferencesProvider,
referenceComputer: MdReferencesComputer,
): vscode.Disposable {
const configuration = new VSCodeDiagnosticConfiguration();
const manager = new DiagnosticManager(
@@ -636,7 +636,7 @@ export function register(
new DiagnosticComputer(engine, workspaceContents, linkComputer),
configuration,
new DiagnosticCollectionReporter(),
referenceProvider);
referenceComputer);
return vscode.Disposable.from(
configuration,
manager,

View File

@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { Command, CommandManager } from '../commandManager';
import { MdReferencesProvider } from './references';
import { MdReferencesComputer } from './references';
const localize = nls.loadMessageBundle();
@@ -16,7 +16,7 @@ export class FindFileReferencesCommand implements Command {
public readonly id = 'markdown.findAllFileReferences';
constructor(
private readonly referencesProvider: MdReferencesProvider,
private readonly referencesComputer: MdReferencesComputer,
) { }
public async execute(resource?: vscode.Uri) {
@@ -33,7 +33,7 @@ export class FindFileReferencesCommand implements Command {
location: vscode.ProgressLocation.Window,
title: localize('progress.title', "Finding file references")
}, async (_progress, token) => {
const references = await this.referencesProvider.getAllReferencesToFile(resource!, token);
const references = await this.referencesComputer.getAllReferencesToFile(resource!, token);
const locations = references.map(ref => ref.location);
const config = vscode.workspace.getConfiguration('references');
@@ -49,6 +49,6 @@ export class FindFileReferencesCommand implements Command {
}
}
export function registerFindFileReferences(commandManager: CommandManager, referencesProvider: MdReferencesProvider): vscode.Disposable {
export function registerFindFileReferences(commandManager: CommandManager, referencesProvider: MdReferencesComputer): vscode.Disposable {
return commandManager.register(new FindFileReferencesCommand(referencesProvider));
}

View File

@@ -59,7 +59,7 @@ export interface MdHeaderReference {
export type MdReference = MdLinkReference | MdHeaderReference;
export class MdReferencesProvider extends Disposable implements vscode.ReferenceProvider {
export class MdReferencesComputer extends Disposable {
private readonly _linkCache: MdWorkspaceCache<readonly MdLink[]>;
@@ -74,15 +74,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
this._linkCache = this._register(new MdWorkspaceCache(workspaceContents, doc => linkComputer.getAllLinks(doc, noopToken)));
}
async provideReferences(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
const allRefs = await this.getAllReferencesAtPosition(document, position, token);
return allRefs
.filter(ref => context.includeDeclaration || !ref.isDefinition)
.map(ref => ref.location);
}
public async getAllReferencesAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
public async getReferencesAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
const toc = await TableOfContents.create(this.engine, document);
if (token.isCancellationRequested) {
return [];
@@ -96,6 +88,11 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
}
}
public async getAllReferencesToFile(resource: vscode.Uri, _token: vscode.CancellationToken): Promise<MdReference[]> {
const allLinksInWorkspace = (await this._linkCache.values()).flat();
return Array.from(this.findAllLinksToFile(resource, allLinksInWorkspace, undefined));
}
private async getReferencesToHeader(document: SkinnyTextDocument, header: TocEntry): Promise<MdReference[]> {
const links = (await this._linkCache.values()).flat();
@@ -226,12 +223,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|| uri.Utils.extname(href.path) === '' && href.path.with({ path: href.path.path + '.md' }).fsPath === targetDoc.fsPath;
}
public async getAllReferencesToFile(resource: vscode.Uri, _token: vscode.CancellationToken): Promise<MdReference[]> {
const allLinksInWorkspace = (await this._linkCache.values()).flat();
return Array.from(this.findAllLinksToFile(resource, allLinksInWorkspace, undefined));
}
private * findAllLinksToFile(resource: vscode.Uri, allLinksInWorkspace: readonly MdLink[], sourceLink: MdLink | undefined): Iterable<MdReference> {
private *findAllLinksToFile(resource: vscode.Uri, allLinksInWorkspace: readonly MdLink[], sourceLink: MdLink | undefined): Iterable<MdReference> {
for (const link of allLinksInWorkspace) {
if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, resource)) {
continue;
@@ -254,7 +246,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
}
}
private * getReferencesToLinkReference(allLinks: Iterable<MdLink>, refToFind: string, from: { resource: vscode.Uri; range: vscode.Range }): Iterable<MdReference> {
private *getReferencesToLinkReference(allLinks: Iterable<MdLink>, refToFind: string, from: { resource: vscode.Uri; range: vscode.Range }): Iterable<MdReference> {
for (const link of allLinks) {
let ref: string;
if (link.kind === 'definition') {
@@ -291,6 +283,30 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
}
}
/**
*
*/
export class MdVsCodeReferencesProvider implements vscode.ReferenceProvider {
public constructor(
private readonly referencesComputer: MdReferencesComputer
) { }
async provideReferences(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[]> {
const allRefs = await this.referencesComputer.getReferencesAtPosition(document, position, token);
return allRefs
.filter(ref => context.includeDeclaration || !ref.isDefinition)
.map(ref => ref.location);
}
}
export function registerReferencesProvider(
selector: vscode.DocumentSelector,
computer: MdReferencesComputer,
): vscode.Disposable {
return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(computer));
}
export async function tryFindMdDocumentForLink(href: InternalHref, workspaceContents: MdWorkspaceContents): Promise<SkinnyTextDocument | undefined> {
const targetDoc = await workspaceContents.getMarkdownDocument(href.path);
if (targetDoc) {
@@ -305,4 +321,3 @@ export async function tryFindMdDocumentForLink(href: InternalHref, workspaceCont
return undefined;
}

View File

@@ -11,7 +11,7 @@ import { Disposable } from '../util/dispose';
import { resolveDocumentLink } from '../util/openDocumentLink';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { InternalHref } from './documentLinkProvider';
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryFindMdDocumentForLink } from './references';
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesComputer, tryFindMdDocumentForLink } from './references';
const localize = nls.loadMessageBundle();
@@ -58,7 +58,7 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
private readonly renameNotSupportedText = localize('invalidRenameLocation', "Rename not supported at location");
public constructor(
private readonly referencesProvider: MdReferencesProvider,
private readonly referencesComputer: MdReferencesComputer,
private readonly workspaceContents: MdWorkspaceContents,
private readonly slugifier: Slugifier,
) {
@@ -253,7 +253,7 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
return this.cachedRefs;
}
const references = await this.referencesProvider.getAllReferencesAtPosition(document, position, token);
const references = await this.referencesComputer.getReferencesAtPosition(document, position, token);
const triggerRef = references.find(ref => ref.isTriggerLocation);
if (!triggerRef) {
return undefined;