diff --git a/extensions/markdown-language-features/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts index a51df3686b1..1f80e7d5f72 100644 --- a/extensions/markdown-language-features/src/features/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/features/documentLinkProvider.ts @@ -47,7 +47,7 @@ function matchAll( } export default class LinkProvider implements vscode.DocumentLinkProvider { - private readonly linkPattern = /(\[[^\]]*\]\(\s*?)(((((?=.*\)\)+)|(?=.*\)\]+))[^\s\)]+?)|([^\s]+?)))\)/g; + private readonly linkPattern = /(\[[^\]]*\]\(\s*)((([^\s\(\)]|\(\S*?\))+))\)/g; private readonly referenceLinkPattern = /(\[([^\]]+)\]\[\s*?)([^\s\]]*?)\]/g; private readonly definitionPattern = /^([\t ]*\[([^\]]+)\]:\s*)(\S+)/gm; diff --git a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts index dcaf30ec94d..416ac421766 100644 --- a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts @@ -25,21 +25,67 @@ function getLinksForFile(fileContents: string) { return provider.provideDocumentLinks(doc, noopToken); } +function assertRangeEqual(expected: vscode.Range, actual: vscode.Range) { + assert.strictEqual(expected.start.line, actual.start.line); + assert.strictEqual(expected.start.character, actual.start.character); + assert.strictEqual(expected.end.line, actual.end.line); + assert.strictEqual(expected.end.character, actual.end.character); +} suite('markdown.DocumentLinkProvider', () => { - test('Should not return anything for empty document', async () => { + test('Should not return anything for empty document', () => { const links = getLinksForFile(''); assert.strictEqual(links.length, 0); }); - test('Should not return anything for simple document without links', async () => { + test('Should not return anything for simple document without links', () => { const links = getLinksForFile('# a\nfdasfdfsafsa'); assert.strictEqual(links.length, 0); }); - test('Should should detect basic http link', async () => { + test('Should detect basic http links', () => { const links = getLinksForFile('a [b](https://example.com) c'); assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 25)); + }); + + test('Should detect basic workspace links', () => { + { + const links = getLinksForFile('a [b](./file) c'); + assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 12)); + } + { + const links = getLinksForFile('a [b](file.png) c'); + assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 14)); + } + }); + + test('Should handle links with balanced parens', () => { + { + const links = getLinksForFile('a [b](https://example.com/a()c) c'); + assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 30)); + } + { + const links = getLinksForFile('a [b](https://example.com/a(b)c) c'); + assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 31)); + } + }); + + test('Should handle two links without space', () => { + const links = getLinksForFile('a ([test](test)[test2](test2)) c'); + assert.strictEqual(links.length, 2); + const [link1, link2] = links; + assertRangeEqual(link1.range, new vscode.Range(0, 10, 0, 14)); + assertRangeEqual(link2.range, new vscode.Range(0, 23, 0, 28)); }); });