diff options
author | Matt Bierner <matb@microsoft.com> | 2022-06-07 23:58:29 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-07 23:58:29 +0300 |
commit | 9545af80f69becea056b57f1fd846f7e764f018c (patch) | |
tree | 45ddc06b4c12864963d616bf4e408e30cdde328f | |
parent | 677d79a4cd2e7091e5bd9882146f67f31d097063 (diff) |
Fix markdown link detection for links with titles (#151459)
Fixes #151458
3 files changed, 62 insertions, 13 deletions
diff --git a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts index 92e0e6d1164..d1457dd3e2a 100644 --- a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts @@ -185,12 +185,12 @@ function stripAngleBrackets(link: string) { /** * Matches `[text](link)` */ -const linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\([^\s\(\)]*?\))+)\s*(".*?")?\)/g; +const linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\([^\s\(\)]*?\))+)\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; /** * Matches `[text](<link>)` */ -const linkPatternAngle = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*<)(([^<>]|\([^\s\(\)]*?\))+)>\s*(".*?")?\)/g; +const linkPatternAngle = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*<)(([^<>]|\([^\s\(\)]*?\))+)>\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; /** diff --git a/extensions/markdown-language-features/src/test/diagnostic.test.ts b/extensions/markdown-language-features/src/test/diagnostic.test.ts index 1c6ae3dd6e8..d84a69dd20c 100644 --- a/extensions/markdown-language-features/src/test/diagnostic.test.ts +++ b/extensions/markdown-language-features/src/test/diagnostic.test.ts @@ -37,6 +37,14 @@ function createDiagnosticsManager(workspaceContents: MdWorkspaceContents, config return new DiagnosticManager(new DiagnosticComputer(engine, workspaceContents, linkProvider), configuration); } +function assertDiagnosticsEqual(actual: readonly vscode.Diagnostic[], expectedRanges: readonly vscode.Range[]) { + assert.strictEqual(actual.length, expectedRanges.length); + + for (let i = 0; i < actual.length; ++i) { + assertRangeEqual(actual[i].range, expectedRanges[i], `Range ${i} to be equal`); + } +} + class MemoryDiagnosticConfiguration implements DiagnosticConfiguration { private readonly _onDidChange = new vscode.EventEmitter<void>(); @@ -87,9 +95,10 @@ suite('markdown: Diagnostics', () => { )); const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc])); - assert.deepStrictEqual(diagnostics.length, 2); - assertRangeEqual(new vscode.Range(0, 6, 0, 22), diagnostics[0].range); - assertRangeEqual(new vscode.Range(3, 11, 3, 27), diagnostics[1].range); + assertDiagnosticsEqual(diagnostics, [ + new vscode.Range(0, 6, 0, 22), + new vscode.Range(3, 11, 3, 27), + ]); }); test('Should generate diagnostics for links to header that does not exist in current file', async () => { @@ -103,9 +112,10 @@ suite('markdown: Diagnostics', () => { )); const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc])); - assert.deepStrictEqual(diagnostics.length, 2); - assertRangeEqual(new vscode.Range(2, 6, 2, 21), diagnostics[0].range); - assertRangeEqual(new vscode.Range(5, 11, 5, 26), diagnostics[1].range); + assertDiagnosticsEqual(diagnostics, [ + new vscode.Range(2, 6, 2, 21), + new vscode.Range(5, 11, 5, 26), + ]); }); test('Should generate diagnostics for links to non-existent headers in other files', async () => { @@ -123,8 +133,9 @@ suite('markdown: Diagnostics', () => { )); const diagnostics = await getComputedDiagnostics(doc1, new InMemoryWorkspaceMarkdownDocuments([doc1, doc2])); - assert.deepStrictEqual(diagnostics.length, 1); - assertRangeEqual(new vscode.Range(5, 6, 5, 35), diagnostics[0].range); + assertDiagnosticsEqual(diagnostics, [ + new vscode.Range(5, 6, 5, 35), + ]); }); test('Should support links both with and without .md file extension', async () => { @@ -150,8 +161,9 @@ suite('markdown: Diagnostics', () => { )); const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc])); - assert.deepStrictEqual(diagnostics.length, 1); - assertRangeEqual(new vscode.Range(1, 11, 1, 18), diagnostics[0].range); + assertDiagnosticsEqual(diagnostics, [ + new vscode.Range(1, 11, 1, 18), + ]); }); test('Should not generate diagnostics when validate is disabled', async () => { @@ -281,4 +293,24 @@ suite('markdown: Diagnostics', () => { const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken); assert.deepStrictEqual(diagnostics.length, 0); }); + + test('Should detect invalid links with titles', async () => { + const doc = new InMemoryDocument(workspacePath('doc1.md'), joinLines( + `[link](<no such.md> "text")`, + `[link](<no such.md> 'text')`, + `[link](<no such.md> (text))`, + `[link](no-such.md "text")`, + `[link](no-such.md 'text')`, + `[link](no-such.md (text))`, + )); + const diagnostics = await getComputedDiagnostics(doc, new InMemoryWorkspaceMarkdownDocuments([doc])); + assertDiagnosticsEqual(diagnostics, [ + new vscode.Range(0, 8, 0, 18), + new vscode.Range(1, 8, 1, 18), + new vscode.Range(2, 8, 2, 18), + new vscode.Range(3, 7, 3, 17), + new vscode.Range(4, 7, 4, 17), + new vscode.Range(5, 7, 5, 17), + ]); + }); }); diff --git a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts index 29793b2a5d8..37d9330d357 100644 --- a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts @@ -408,5 +408,22 @@ suite('markdown.DocumentLinkProvider', () => { assertLinksEqual(links, [new vscode.Range(0, 8, 0, 13)]); }); - + test('Should find links with titles', async () => { + const links = await getLinksForFile(joinLines( + `[link](<no such.md> "text")`, + `[link](<no such.md> 'text')`, + `[link](<no such.md> (text))`, + `[link](no-such.md "text")`, + `[link](no-such.md 'text')`, + `[link](no-such.md (text))`, + )); + assertLinksEqual(links, [ + new vscode.Range(0, 8, 0, 18), + new vscode.Range(1, 8, 1, 18), + new vscode.Range(2, 8, 2, 18), + new vscode.Range(3, 7, 3, 17), + new vscode.Range(4, 7, 4, 17), + new vscode.Range(5, 7, 5, 17), + ]); + }); }); |