Add support for reference to ref links in md

For #146277
This commit is contained in:
Matt Bierner 2022-03-30 14:13:31 -07:00
parent f25827e3cd
commit 17783a09e5
No known key found for this signature in database
GPG key ID: 099C331567E11888
3 changed files with 85 additions and 7 deletions

View file

@ -15,6 +15,7 @@ const localize = nls.loadMessageBundle();
export interface ExternalLinkTarget {
readonly kind: 'external';
readonly uri: vscode.Uri;
}
@ -30,12 +31,18 @@ export interface InternalLinkTarget {
export interface ReferenceLinkTarget {
readonly kind: 'reference';
readonly fromResource: vscode.Uri;
readonly ref: string;
readonly position: vscode.Position;
}
export interface DefinitionLinkTarget {
readonly kind: 'definition';
readonly fromResource: vscode.Uri;
readonly ref: string;
readonly target: ExternalLinkTarget | InternalLinkTarget;
}
@ -271,23 +278,26 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
sourceRange: new vscode.Range(linkStart, linkEnd),
target: {
kind: 'reference',
fromResource: document.uri,
ref: reference,
position: link.linkRange.start
}
};
}
}
}
public *getDefinitionLinks(document: SkinnyTextDocument): Iterable<LinkData> {
const definitions = this.getDefinitions(document);
for (const definition of definitions.values()) {
for (const [ref, definition] of definitions) {
try {
const target = parseLink(document, definition.link);
if (target) {
yield {
sourceRange: definition.linkRange,
target: {
fromResource: document.uri,
ref,
kind: 'definition',
target
}

View file

@ -68,16 +68,29 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
}
private async getReferencesToLink(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext): Promise<vscode.Location[] | undefined> {
const links = (await Promise.all(await this._linkCache.getAll())).flat();
const links = (await this._linkCache.getAll()).flat();
const docLinks = await this.linkProvider.getInlineLinks(document);
const docLinks = await this.linkProvider.getAllLinks(document);
const sourceLink = docLinks.find(link => link.sourceRange.contains(position));
if (sourceLink?.target.kind === 'reference') {
const references: vscode.Location[] = [];
for (const link of links) {
if (link.target.kind === 'reference' || link.target.kind === 'definition') {
if (link.target.ref === sourceLink.target.ref && link.target.fromResource.fsPath === document.uri.fsPath) {
references.push(new vscode.Location(document.uri, link.sourceRange));
}
}
}
return references;
}
if (sourceLink?.target.kind !== 'internal') {
return undefined;
}
let targetDoc = await this.workspaceContents.getMarkdownDocument(sourceLink.target.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

View file

@ -22,8 +22,8 @@ function getReferences(doc: InMemoryDocument, pos: vscode.Position, workspaceCon
return provider.provideReferences(doc, pos, { includeDeclaration: true }, noopToken);
}
suite('markdown references', () => {
test('Should not return references when not on header', async () => {
suite('markdown: find all references', () => {
test('Should not return references when not on header or link', async () => {
const doc = new InMemoryDocument(workspaceFile('doc.md'), joinLines(
`# abc`,
``,
@ -287,4 +287,59 @@ suite('markdown references', () => {
assert.deepStrictEqual(ref.range.start.line, 2);
}
});
suite('Reference links', () => {
test('Should find reference links within file', async () => {
const docUri = workspaceFile('doc.md');
const doc = new InMemoryDocument(docUri, joinLines(
`[link 1][abc]`,
``,
`[abc]: https://example.com`,
));
const refs = await getReferences(doc, new vscode.Position(0, 12), new InMemoryWorkspaceMarkdownDocuments([doc]));
assert.deepStrictEqual(refs!.length, 2);
{
const ref = refs![0];
assert.deepStrictEqual(ref.uri.toString(), docUri.toString());
assert.deepStrictEqual(ref.range.start.line, 0);
}
{
const ref = refs![1];
assert.deepStrictEqual(ref.uri.toString(), docUri.toString());
assert.deepStrictEqual(ref.range.start.line, 2);
}
});
test('Should not find reference links across files', async () => {
const docUri = workspaceFile('doc.md');
const doc = new InMemoryDocument(docUri, joinLines(
`[link 1][abc]`,
``,
`[abc]: https://example.com`,
));
const refs = await getReferences(doc, new vscode.Position(0, 12), new InMemoryWorkspaceMarkdownDocuments([
doc,
new InMemoryDocument(workspaceFile('other.md'), joinLines(
`[link 1][abc]`,
``,
`[abc]: https://example.com?bad`,
))
]));
assert.deepStrictEqual(refs!.length, 2);
{
const ref = refs![0];
assert.deepStrictEqual(ref.uri.toString(), docUri.toString());
assert.deepStrictEqual(ref.range.start.line, 0);
}
{
const ref = refs![1];
assert.deepStrictEqual(ref.uri.toString(), docUri.toString());
assert.deepStrictEqual(ref.range.start.line, 2);
}
});
});
});