Skip to content

Commit 8a6a300

Browse files
committed
Simplify code for dealing with link definitions
1 parent 57dffde commit 8a6a300

File tree

2 files changed

+53
-86
lines changed

2 files changed

+53
-86
lines changed

extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,29 @@ import { SkinnyTextDocument } from '../workspaceContents';
1414

1515
const localize = nls.loadMessageBundle();
1616

17-
export interface ExternalLinkTarget {
17+
export interface ExternalHref {
1818
readonly kind: 'external';
1919
readonly uri: vscode.Uri;
2020
}
2121

22-
export interface InternalLinkTarget {
22+
export interface InternalHref {
2323
readonly kind: 'internal';
2424
readonly path: vscode.Uri;
2525
readonly fragment: string;
2626
}
2727

28-
export interface ReferenceLinkTarget {
28+
export interface ReferenceHref {
2929
readonly kind: 'reference';
3030
readonly ref: string;
3131
}
3232

33-
export type LinkTarget = ExternalLinkTarget | InternalLinkTarget | ReferenceLinkTarget;
33+
export type LinkHref = ExternalHref | InternalHref | ReferenceHref;
3434

3535

3636
function parseLink(
3737
document: SkinnyTextDocument,
3838
link: string,
39-
): ExternalLinkTarget | InternalLinkTarget | undefined {
39+
): ExternalHref | InternalHref | undefined {
4040
const cleanLink = stripAngleBrackets(link);
4141
const externalSchemeUri = getUriForLinkWithKnownExternalScheme(cleanLink);
4242
if (externalSchemeUri) {
@@ -87,10 +87,10 @@ function getWorkspaceFolder(document: SkinnyTextDocument) {
8787
|| vscode.workspace.workspaceFolders?.[0]?.uri;
8888
}
8989

90-
interface MdInlineLink {
90+
export interface MdInlineLink {
9191
readonly kind: 'link';
9292

93-
readonly target: LinkTarget;
93+
readonly href: LinkHref;
9494

9595
readonly sourceText: string;
9696
readonly sourceResource: vscode.Uri;
@@ -105,7 +105,7 @@ export interface MdLinkDefinition {
105105
readonly sourceRange: vscode.Range;
106106

107107
readonly ref: string;
108-
readonly target: ExternalLinkTarget | InternalLinkTarget;
108+
readonly href: ExternalHref | InternalHref;
109109
}
110110

111111
export type MdLink = MdInlineLink | MdLinkDefinition;
@@ -126,7 +126,7 @@ function extractDocumentLink(
126126
}
127127
return {
128128
kind: 'link',
129-
target: linkTarget,
129+
href: linkTarget,
130130
sourceText: link,
131131
sourceResource: document.uri,
132132
sourceRange: new vscode.Range(linkStart, linkEnd)
@@ -215,28 +215,18 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
215215
}
216216

217217
private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined {
218-
if (link.kind === 'definition') {
219-
return this.toValidDocumentLink({
220-
kind: 'link',
221-
sourceText: link.sourceText,
222-
sourceRange: link.sourceRange,
223-
sourceResource: link.sourceResource,
224-
target: link.target
225-
}, definitionSet);
226-
}
227-
228-
switch (link.target.kind) {
218+
switch (link.href.kind) {
229219
case 'external': {
230-
return new vscode.DocumentLink(link.sourceRange, link.target.uri);
220+
return new vscode.DocumentLink(link.sourceRange, link.href.uri);
231221
}
232222
case 'internal': {
233-
const uri = OpenDocumentLinkCommand.createCommandUri(link.sourceResource, link.target.path, link.target.fragment);
223+
const uri = OpenDocumentLinkCommand.createCommandUri(link.sourceResource, link.href.path, link.href.fragment);
234224
const documentLink = new vscode.DocumentLink(link.sourceRange, uri);
235225
documentLink.tooltip = localize('documentLink.tooltip', 'Follow link');
236226
return documentLink;
237227
}
238228
case 'reference': {
239-
const def = definitionSet.lookup(link.target.ref);
229+
const def = definitionSet.lookup(link.href.ref);
240230
if (def) {
241231
return new vscode.DocumentLink(
242232
link.sourceRange,
@@ -299,7 +289,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
299289
sourceText: reference,
300290
sourceRange: new vscode.Range(linkStart, linkEnd),
301291
sourceResource: document.uri,
302-
target: {
292+
href: {
303293
kind: 'reference',
304294
ref: reference,
305295
}
@@ -326,9 +316,8 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
326316
sourceText: link,
327317
sourceResource: document.uri,
328318
sourceRange: new vscode.Range(linkStart, linkEnd),
329-
330319
ref: reference,
331-
target,
320+
href: target,
332321
};
333322
}
334323
} else {
@@ -342,7 +331,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
342331
sourceResource: document.uri,
343332
sourceRange: new vscode.Range(linkStart, linkEnd),
344333
ref: reference,
345-
target,
334+
href: target,
346335
};
347336
}
348337
}
@@ -351,7 +340,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
351340
}
352341

353342
export class LinkDefinitionSet {
354-
private readonly _map = new Map<string, MdLink>();
343+
private readonly _map = new Map<string, MdLinkDefinition>();
355344

356345
constructor(links: Iterable<MdLink>) {
357346
for (const link of links) {
@@ -361,7 +350,7 @@ export class LinkDefinitionSet {
361350
}
362351
}
363352

364-
public lookup(ref: string): MdLink | undefined {
353+
public lookup(ref: string): MdLinkDefinition | undefined {
365354
return this._map.get(ref);
366355
}
367356
}

extensions/markdown-language-features/src/languageFeatures/references.ts

Lines changed: 35 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import { Slugifier } from '../slugify';
99
import { TableOfContents, TocEntry } from '../tableOfContents';
1010
import { Disposable } from '../util/dispose';
1111
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
12-
import { InternalLinkTarget, MdLink, LinkTarget, MdLinkProvider, MdLinkDefinition } from './documentLinkProvider';
12+
import { InternalHref, LinkHref, MdLink, MdLinkProvider } from './documentLinkProvider';
1313
import { MdWorkspaceCache } from './workspaceCache';
1414

1515

16-
function isLinkToHeader(target: LinkTarget, header: TocEntry, headerDocument: vscode.Uri, slugifier: Slugifier): target is InternalLinkTarget {
16+
function isLinkToHeader(target: LinkHref, header: TocEntry, headerDocument: vscode.Uri, slugifier: Slugifier): target is InternalHref {
1717
return target.kind === 'internal'
1818
&& target.path.fsPath === headerDocument.fsPath
1919
&& slugifier.fromHeading(target.fragment).value === header.slug.value;
@@ -121,15 +121,15 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
121121
});
122122

123123
for (const link of links) {
124-
if (isLinkToHeader(link.target, header, document.uri, this.slugifier)) {
124+
if (isLinkToHeader(link.href, header, document.uri, this.slugifier)) {
125125
references.push({
126126
kind: 'link',
127127
isTriggerLocation: false,
128128
isDefinition: false,
129129
location: new vscode.Location(link.sourceResource, link.sourceRange),
130130
fragmentLocation: getFragmentLocation(link),
131131
});
132-
} else if (link.kind === 'definition' && isLinkToHeader(link.target, header, document.uri, this.slugifier)) {
132+
} else if (link.kind === 'definition' && isLinkToHeader(link.href, header, document.uri, this.slugifier)) {
133133
references.push({
134134
kind: 'link',
135135
isTriggerLocation: false,
@@ -150,25 +150,21 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
150150
}
151151

152152
private async getReferencesToLink(sourceLink: MdLink): Promise<MdReference[]> {
153-
if (sourceLink.kind === 'definition') {
154-
return this.getReferencesToLink(this.getInnerLink(sourceLink));
155-
}
156-
157153
const allLinksInWorkspace = (await this._linkCache.getAll()).flat();
158154

159-
if (sourceLink.target.kind === 'reference') {
155+
if (sourceLink.href.kind === 'reference') {
160156
return Array.from(this.getReferencesToReferenceLink(allLinksInWorkspace, sourceLink));
161157
}
162158

163-
if (sourceLink.target.kind !== 'internal') {
159+
if (sourceLink.href.kind !== 'internal') {
164160
return [];
165161
}
166162

167-
let targetDoc = await this.workspaceContents.getMarkdownDocument(sourceLink.target.path);
163+
let targetDoc = await this.workspaceContents.getMarkdownDocument(sourceLink.href.path);
168164
if (!targetDoc) {
169165
// We don't think the file exists. If it doesn't already have an extension, try tacking on a `.md` and using that instead
170-
if (uri.Utils.extname(sourceLink.target.path) === '') {
171-
const dotMdResource = sourceLink.target.path.with({ path: sourceLink.target.path.path + '.md' });
166+
if (uri.Utils.extname(sourceLink.href.path) === '') {
167+
const dotMdResource = sourceLink.href.path.with({ path: sourceLink.href.path.path + '.md' });
172168
targetDoc = await this.workspaceContents.getMarkdownDocument(dotMdResource);
173169
}
174170
}
@@ -179,9 +175,9 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
179175

180176
const references: MdReference[] = [];
181177

182-
if (sourceLink.target.fragment) {
178+
if (sourceLink.href.fragment) {
183179
const toc = await TableOfContents.create(this.engine, targetDoc);
184-
const entry = toc.lookup(sourceLink.target.fragment);
180+
const entry = toc.lookup(sourceLink.href.fragment);
185181
if (entry) {
186182
references.push({
187183
kind: 'header',
@@ -193,26 +189,22 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
193189
}
194190
}
195191

196-
for (let link of allLinksInWorkspace) {
197-
if (link.kind === 'definition') {
198-
link = this.getInnerLink(link);
199-
}
200-
201-
if (link.target.kind !== 'internal') {
192+
for (const link of allLinksInWorkspace) {
193+
if (link.href.kind !== 'internal') {
202194
continue;
203195
}
204196

205-
const matchesFilePart = link.target.path.fsPath === targetDoc.uri.fsPath
206-
|| uri.Utils.extname(link.target.path) === '' && link.target.path.with({ path: link.target.path.path + '.md' }).fsPath === targetDoc.uri.fsPath;
197+
const matchesFilePart = link.href.path.fsPath === targetDoc.uri.fsPath
198+
|| uri.Utils.extname(link.href.path) === '' && link.href.path.with({ path: link.href.path.path + '.md' }).fsPath === targetDoc.uri.fsPath;
207199

208200
if (!matchesFilePart) {
209201
continue;
210202
}
211203

212204
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
213205

214-
if (sourceLink.target.fragment) {
215-
if (this.slugifier.fromHeading(link.target.fragment).equals(this.slugifier.fromHeading(sourceLink.target.fragment))) {
206+
if (sourceLink.href.fragment) {
207+
if (this.slugifier.fromHeading(link.href.fragment).equals(this.slugifier.fromHeading(sourceLink.href.fragment))) {
216208
references.push({
217209
kind: 'link',
218210
isTriggerLocation,
@@ -239,44 +231,30 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
239231
return references;
240232
}
241233

242-
private getInnerLink(sourceLink: MdLinkDefinition): MdLink {
243-
return {
244-
kind: 'link',
245-
sourceText: sourceLink.sourceText, // This is not correct
246-
sourceResource: sourceLink.sourceResource,
247-
sourceRange: sourceLink.sourceRange,
248-
target: sourceLink.target,
249-
};
250-
}
251-
252234
private * getReferencesToReferenceLink(allLinks: Iterable<MdLink>, sourceLink: MdLink): Iterable<MdReference> {
253-
if (sourceLink.target.kind !== 'reference') {
235+
if (sourceLink.href.kind !== 'reference') {
254236
return;
255237
}
256238

257239
for (const link of allLinks) {
240+
let ref: string;
258241
if (link.kind === 'definition') {
259-
if (link.ref === sourceLink.target.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
260-
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
261-
yield {
262-
kind: 'link',
263-
isTriggerLocation,
264-
isDefinition: true,
265-
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
266-
fragmentLocation: getFragmentLocation(link),
267-
};
268-
}
269-
} else if (link.target.kind === 'reference') {
270-
if (link.target.ref === sourceLink.target.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
271-
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
272-
yield {
273-
kind: 'link',
274-
isTriggerLocation,
275-
isDefinition: false,
276-
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
277-
fragmentLocation: getFragmentLocation(link),
278-
};
279-
}
242+
ref = link.ref;
243+
} else if (link.href.kind === 'reference') {
244+
ref = link.href.ref;
245+
} else {
246+
continue;
247+
}
248+
249+
if (ref === sourceLink.href.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
250+
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
251+
yield {
252+
kind: 'link',
253+
isTriggerLocation,
254+
isDefinition: link.kind === 'definition',
255+
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange),
256+
fragmentLocation: getFragmentLocation(link),
257+
};
280258
}
281259
}
282260
}

0 commit comments

Comments
 (0)