Split markdown linkComputer from linkProvider (#152124)

Instead of passing around a full `vscode.DocumentLinkProvider`, we should pass just the more minimal interface that consumers need
This commit is contained in:
Matt Bierner
2022-06-14 15:34:05 -07:00
committed by GitHub
parent 43d8a326fa
commit 00273730e8
12 changed files with 105 additions and 90 deletions

View File

@@ -242,53 +242,12 @@ class NoLinkRanges {
}
}
export class MdLinkProvider implements vscode.DocumentLinkProvider {
export class MdLinkComputer {
constructor(
private readonly engine: MarkdownEngine
) { }
public async provideDocumentLinks(
document: SkinnyTextDocument,
token: vscode.CancellationToken
): Promise<vscode.DocumentLink[]> {
const allLinks = await this.getAllLinks(document, token);
if (token.isCancellationRequested) {
return [];
}
const definitionSet = new LinkDefinitionSet(allLinks);
return coalesce(allLinks
.map(data => this.toValidDocumentLink(data, definitionSet)));
}
private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined {
switch (link.href.kind) {
case 'external': {
return new vscode.DocumentLink(link.source.hrefRange, link.href.uri);
}
case 'internal': {
const uri = OpenDocumentLinkCommand.createCommandUri(link.source.resource, link.href.path, link.href.fragment);
const documentLink = new vscode.DocumentLink(link.source.hrefRange, uri);
documentLink.tooltip = localize('documentLink.tooltip', 'Follow link');
return documentLink;
}
case 'reference': {
const def = definitionSet.lookup(link.href.ref);
if (def) {
const documentLink = new vscode.DocumentLink(
link.source.hrefRange,
vscode.Uri.parse(`command:_markdown.moveCursorToPosition?${encodeURIComponent(JSON.stringify([def.source.hrefRange.start.line, def.source.hrefRange.start.character]))}`));
documentLink.tooltip = localize('documentLink.referenceTooltip', 'Go to link definition');
return documentLink;
} else {
return undefined;
}
}
}
}
public async getAllLinks(document: SkinnyTextDocument, token: vscode.CancellationToken): Promise<MdLink[]> {
const noLinkRanges = await NoLinkRanges.compute(document, this.engine);
if (token.isCancellationRequested) {
@@ -475,3 +434,57 @@ export class LinkDefinitionSet {
return this._map.get(ref);
}
}
export class MdLinkProvider implements vscode.DocumentLinkProvider {
constructor(
private readonly _linkComputer: MdLinkComputer,
) { }
public async provideDocumentLinks(
document: SkinnyTextDocument,
token: vscode.CancellationToken
): Promise<vscode.DocumentLink[]> {
const allLinks = (await this._linkComputer.getAllLinks(document, token)) ?? [];
if (token.isCancellationRequested) {
return [];
}
const definitionSet = new LinkDefinitionSet(allLinks);
return coalesce(allLinks
.map(data => this.toValidDocumentLink(data, definitionSet)));
}
private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined {
switch (link.href.kind) {
case 'external': {
return new vscode.DocumentLink(link.source.hrefRange, link.href.uri);
}
case 'internal': {
const uri = OpenDocumentLinkCommand.createCommandUri(link.source.resource, link.href.path, link.href.fragment);
const documentLink = new vscode.DocumentLink(link.source.hrefRange, uri);
documentLink.tooltip = localize('documentLink.tooltip', 'Follow link');
return documentLink;
}
case 'reference': {
const def = definitionSet.lookup(link.href.ref);
if (def) {
const documentLink = new vscode.DocumentLink(
link.source.hrefRange,
vscode.Uri.parse(`command:_markdown.moveCursorToPosition?${encodeURIComponent(JSON.stringify([def.source.hrefRange.start.line, def.source.hrefRange.start.character]))}`));
documentLink.tooltip = localize('documentLink.referenceTooltip', 'Go to link definition');
return documentLink;
} else {
return undefined;
}
}
}
}
}
export function registerDocumentLinkProvider(
selector: vscode.DocumentSelector,
linkComputer: MdLinkComputer,
): vscode.Disposable {
return vscode.languages.registerDocumentLinkProvider(selector, new MdLinkProvider(linkComputer));
}