mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Simplify code for dealing with link definitions
This commit is contained in:
parent
57dffde3d4
commit
8a6a300216
|
@ -14,29 +14,29 @@ import { SkinnyTextDocument } from '../workspaceContents';
|
|||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export interface ExternalLinkTarget {
|
||||
export interface ExternalHref {
|
||||
readonly kind: 'external';
|
||||
readonly uri: vscode.Uri;
|
||||
}
|
||||
|
||||
export interface InternalLinkTarget {
|
||||
export interface InternalHref {
|
||||
readonly kind: 'internal';
|
||||
readonly path: vscode.Uri;
|
||||
readonly fragment: string;
|
||||
}
|
||||
|
||||
export interface ReferenceLinkTarget {
|
||||
export interface ReferenceHref {
|
||||
readonly kind: 'reference';
|
||||
readonly ref: string;
|
||||
}
|
||||
|
||||
export type LinkTarget = ExternalLinkTarget | InternalLinkTarget | ReferenceLinkTarget;
|
||||
export type LinkHref = ExternalHref | InternalHref | ReferenceHref;
|
||||
|
||||
|
||||
function parseLink(
|
||||
document: SkinnyTextDocument,
|
||||
link: string,
|
||||
): ExternalLinkTarget | InternalLinkTarget | undefined {
|
||||
): ExternalHref | InternalHref | undefined {
|
||||
const cleanLink = stripAngleBrackets(link);
|
||||
const externalSchemeUri = getUriForLinkWithKnownExternalScheme(cleanLink);
|
||||
if (externalSchemeUri) {
|
||||
|
@ -87,10 +87,10 @@ function getWorkspaceFolder(document: SkinnyTextDocument) {
|
|||
|| vscode.workspace.workspaceFolders?.[0]?.uri;
|
||||
}
|
||||
|
||||
interface MdInlineLink {
|
||||
export interface MdInlineLink {
|
||||
readonly kind: 'link';
|
||||
|
||||
readonly target: LinkTarget;
|
||||
readonly href: LinkHref;
|
||||
|
||||
readonly sourceText: string;
|
||||
readonly sourceResource: vscode.Uri;
|
||||
|
@ -105,7 +105,7 @@ export interface MdLinkDefinition {
|
|||
readonly sourceRange: vscode.Range;
|
||||
|
||||
readonly ref: string;
|
||||
readonly target: ExternalLinkTarget | InternalLinkTarget;
|
||||
readonly href: ExternalHref | InternalHref;
|
||||
}
|
||||
|
||||
export type MdLink = MdInlineLink | MdLinkDefinition;
|
||||
|
@ -126,7 +126,7 @@ function extractDocumentLink(
|
|||
}
|
||||
return {
|
||||
kind: 'link',
|
||||
target: linkTarget,
|
||||
href: linkTarget,
|
||||
sourceText: link,
|
||||
sourceResource: document.uri,
|
||||
sourceRange: new vscode.Range(linkStart, linkEnd)
|
||||
|
@ -215,28 +215,18 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
}
|
||||
|
||||
private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined {
|
||||
if (link.kind === 'definition') {
|
||||
return this.toValidDocumentLink({
|
||||
kind: 'link',
|
||||
sourceText: link.sourceText,
|
||||
sourceRange: link.sourceRange,
|
||||
sourceResource: link.sourceResource,
|
||||
target: link.target
|
||||
}, definitionSet);
|
||||
}
|
||||
|
||||
switch (link.target.kind) {
|
||||
switch (link.href.kind) {
|
||||
case 'external': {
|
||||
return new vscode.DocumentLink(link.sourceRange, link.target.uri);
|
||||
return new vscode.DocumentLink(link.sourceRange, link.href.uri);
|
||||
}
|
||||
case 'internal': {
|
||||
const uri = OpenDocumentLinkCommand.createCommandUri(link.sourceResource, link.target.path, link.target.fragment);
|
||||
const uri = OpenDocumentLinkCommand.createCommandUri(link.sourceResource, link.href.path, link.href.fragment);
|
||||
const documentLink = new vscode.DocumentLink(link.sourceRange, uri);
|
||||
documentLink.tooltip = localize('documentLink.tooltip', 'Follow link');
|
||||
return documentLink;
|
||||
}
|
||||
case 'reference': {
|
||||
const def = definitionSet.lookup(link.target.ref);
|
||||
const def = definitionSet.lookup(link.href.ref);
|
||||
if (def) {
|
||||
return new vscode.DocumentLink(
|
||||
link.sourceRange,
|
||||
|
@ -299,7 +289,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
sourceText: reference,
|
||||
sourceRange: new vscode.Range(linkStart, linkEnd),
|
||||
sourceResource: document.uri,
|
||||
target: {
|
||||
href: {
|
||||
kind: 'reference',
|
||||
ref: reference,
|
||||
}
|
||||
|
@ -326,9 +316,8 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
sourceText: link,
|
||||
sourceResource: document.uri,
|
||||
sourceRange: new vscode.Range(linkStart, linkEnd),
|
||||
|
||||
ref: reference,
|
||||
target,
|
||||
href: target,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
@ -342,7 +331,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
sourceResource: document.uri,
|
||||
sourceRange: new vscode.Range(linkStart, linkEnd),
|
||||
ref: reference,
|
||||
target,
|
||||
href: target,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -351,7 +340,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
}
|
||||
|
||||
export class LinkDefinitionSet {
|
||||
private readonly _map = new Map<string, MdLink>();
|
||||
private readonly _map = new Map<string, MdLinkDefinition>();
|
||||
|
||||
constructor(links: Iterable<MdLink>) {
|
||||
for (const link of links) {
|
||||
|
@ -361,7 +350,7 @@ export class LinkDefinitionSet {
|
|||
}
|
||||
}
|
||||
|
||||
public lookup(ref: string): MdLink | undefined {
|
||||
public lookup(ref: string): MdLinkDefinition | undefined {
|
||||
return this._map.get(ref);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import { Slugifier } from '../slugify';
|
|||
import { TableOfContents, TocEntry } from '../tableOfContents';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalLinkTarget, MdLink, LinkTarget, MdLinkProvider, MdLinkDefinition } from './documentLinkProvider';
|
||||
import { InternalHref, LinkHref, MdLink, MdLinkProvider } from './documentLinkProvider';
|
||||
import { MdWorkspaceCache } from './workspaceCache';
|
||||
|
||||
|
||||
function isLinkToHeader(target: LinkTarget, header: TocEntry, headerDocument: vscode.Uri, slugifier: Slugifier): target is InternalLinkTarget {
|
||||
function isLinkToHeader(target: LinkHref, header: TocEntry, headerDocument: vscode.Uri, slugifier: Slugifier): target is InternalHref {
|
||||
return target.kind === 'internal'
|
||||
&& target.path.fsPath === headerDocument.fsPath
|
||||
&& slugifier.fromHeading(target.fragment).value === header.slug.value;
|
||||
|
@ -121,7 +121,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
});
|
||||
|
||||
for (const link of links) {
|
||||
if (isLinkToHeader(link.target, header, document.uri, this.slugifier)) {
|
||||
if (isLinkToHeader(link.href, header, document.uri, this.slugifier)) {
|
||||
references.push({
|
||||
kind: 'link',
|
||||
isTriggerLocation: false,
|
||||
|
@ -129,7 +129,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
location: new vscode.Location(link.sourceResource, link.sourceRange),
|
||||
fragmentLocation: getFragmentLocation(link),
|
||||
});
|
||||
} else if (link.kind === 'definition' && isLinkToHeader(link.target, header, document.uri, this.slugifier)) {
|
||||
} else if (link.kind === 'definition' && isLinkToHeader(link.href, header, document.uri, this.slugifier)) {
|
||||
references.push({
|
||||
kind: 'link',
|
||||
isTriggerLocation: false,
|
||||
|
@ -150,25 +150,21 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
}
|
||||
|
||||
private async getReferencesToLink(sourceLink: MdLink): Promise<MdReference[]> {
|
||||
if (sourceLink.kind === 'definition') {
|
||||
return this.getReferencesToLink(this.getInnerLink(sourceLink));
|
||||
}
|
||||
|
||||
const allLinksInWorkspace = (await this._linkCache.getAll()).flat();
|
||||
|
||||
if (sourceLink.target.kind === 'reference') {
|
||||
if (sourceLink.href.kind === 'reference') {
|
||||
return Array.from(this.getReferencesToReferenceLink(allLinksInWorkspace, sourceLink));
|
||||
}
|
||||
|
||||
if (sourceLink.target.kind !== 'internal') {
|
||||
if (sourceLink.href.kind !== 'internal') {
|
||||
return [];
|
||||
}
|
||||
|
||||
let targetDoc = await this.workspaceContents.getMarkdownDocument(sourceLink.target.path);
|
||||
let targetDoc = await this.workspaceContents.getMarkdownDocument(sourceLink.href.path);
|
||||
if (!targetDoc) {
|
||||
// We don't think the file exists. If it doesn't already have an extension, try tacking on a `.md` and using that instead
|
||||
if (uri.Utils.extname(sourceLink.target.path) === '') {
|
||||
const dotMdResource = sourceLink.target.path.with({ path: sourceLink.target.path.path + '.md' });
|
||||
if (uri.Utils.extname(sourceLink.href.path) === '') {
|
||||
const dotMdResource = sourceLink.href.path.with({ path: sourceLink.href.path.path + '.md' });
|
||||
targetDoc = await this.workspaceContents.getMarkdownDocument(dotMdResource);
|
||||
}
|
||||
}
|
||||
|
@ -179,9 +175,9 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
|
||||
const references: MdReference[] = [];
|
||||
|
||||
if (sourceLink.target.fragment) {
|
||||
if (sourceLink.href.fragment) {
|
||||
const toc = await TableOfContents.create(this.engine, targetDoc);
|
||||
const entry = toc.lookup(sourceLink.target.fragment);
|
||||
const entry = toc.lookup(sourceLink.href.fragment);
|
||||
if (entry) {
|
||||
references.push({
|
||||
kind: 'header',
|
||||
|
@ -193,17 +189,13 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
}
|
||||
}
|
||||
|
||||
for (let link of allLinksInWorkspace) {
|
||||
if (link.kind === 'definition') {
|
||||
link = this.getInnerLink(link);
|
||||
}
|
||||
|
||||
if (link.target.kind !== 'internal') {
|
||||
for (const link of allLinksInWorkspace) {
|
||||
if (link.href.kind !== 'internal') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchesFilePart = link.target.path.fsPath === targetDoc.uri.fsPath
|
||||
|| uri.Utils.extname(link.target.path) === '' && link.target.path.with({ path: link.target.path.path + '.md' }).fsPath === targetDoc.uri.fsPath;
|
||||
const matchesFilePart = link.href.path.fsPath === targetDoc.uri.fsPath
|
||||
|| uri.Utils.extname(link.href.path) === '' && link.href.path.with({ path: link.href.path.path + '.md' }).fsPath === targetDoc.uri.fsPath;
|
||||
|
||||
if (!matchesFilePart) {
|
||||
continue;
|
||||
|
@ -211,8 +203,8 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
|
||||
if (sourceLink.target.fragment) {
|
||||
if (this.slugifier.fromHeading(link.target.fragment).equals(this.slugifier.fromHeading(sourceLink.target.fragment))) {
|
||||
if (sourceLink.href.fragment) {
|
||||
if (this.slugifier.fromHeading(link.href.fragment).equals(this.slugifier.fromHeading(sourceLink.href.fragment))) {
|
||||
references.push({
|
||||
kind: 'link',
|
||||
isTriggerLocation,
|
||||
|
@ -239,44 +231,30 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
return references;
|
||||
}
|
||||
|
||||
private getInnerLink(sourceLink: MdLinkDefinition): MdLink {
|
||||
return {
|
||||
kind: 'link',
|
||||
sourceText: sourceLink.sourceText, // This is not correct
|
||||
sourceResource: sourceLink.sourceResource,
|
||||
sourceRange: sourceLink.sourceRange,
|
||||
target: sourceLink.target,
|
||||
};
|
||||
}
|
||||
|
||||
private * getReferencesToReferenceLink(allLinks: Iterable<MdLink>, sourceLink: MdLink): Iterable<MdReference> {
|
||||
if (sourceLink.target.kind !== 'reference') {
|
||||
if (sourceLink.href.kind !== 'reference') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const link of allLinks) {
|
||||
let ref: string;
|
||||
if (link.kind === 'definition') {
|
||||
if (link.ref === sourceLink.target.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
yield {
|
||||
kind: 'link',
|
||||
isTriggerLocation,
|
||||
isDefinition: true,
|
||||
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
|
||||
fragmentLocation: getFragmentLocation(link),
|
||||
};
|
||||
}
|
||||
} else if (link.target.kind === 'reference') {
|
||||
if (link.target.ref === sourceLink.target.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
yield {
|
||||
kind: 'link',
|
||||
isTriggerLocation,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
|
||||
fragmentLocation: getFragmentLocation(link),
|
||||
};
|
||||
}
|
||||
ref = link.ref;
|
||||
} else if (link.href.kind === 'reference') {
|
||||
ref = link.href.ref;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ref === sourceLink.href.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
yield {
|
||||
kind: 'link',
|
||||
isTriggerLocation,
|
||||
isDefinition: link.kind === 'definition',
|
||||
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
|
||||
fragmentLocation: getFragmentLocation(link),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue