Repository: microsoft/vscode (TypeScript) — Bug Fix

Issue:
Notification command links parsing broken when multiple links are present
<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠️ -->
<!-- Please read our Rules of Conduct: https://opensource.microsoft.com/codeofconduct/ -->
<!-- 🕮 Read our guide about submitting issues: https://github.com/microsoft/vscode/wiki/Submitting-Bugs-and-Suggestions -->
<!-- 🔎 Search existing issues to avoid creating duplicates. -->
<!-- 🧪 Test using the latest Insiders build to see if your issue has already been fixed: https://code.visualstudio.com/insiders/ -->
<!-- 💡 Instead of creating your report here, use 'Report Issue' from the 'Help' menu in VS Code to pre-fill useful information. -->
<!-- 🔧 Launch with `code --disable-extensions` to check. -->
Does this issue occur when all extensions are disabled?: Yes

<!-- 🪓 If you answered No above, use 'Help: Start Extension Bisect' from Command Palette to try to identify the cause. -->
<!-- 📣 Issues caused by an extension need to be reported directly to the extension publisher. The 'Help > Report Issue' dialog can assist with this. -->
- VS Code Version: 1.72.0
- OS Version: Windows 10 Pro, 21H2, build: 19044.2075

<br>

Command links inside notifications were implemented as described here, [v1.34](https://code.visualstudio.com/updates/v1_34#_command-links-in-notifications) or here #46571, i.e.

>This is now possible using the following syntax: `[link name](command:<command id> "Title")`

_Originally posted by @bpasero in https://github.com/microsoft/vscode/issues/46571#issuecomment-482485207_

The feature works great when a single command link is added to a notification but fails when two (or more) are present, see the sample code below (2).

<br>

Steps to Reproduce:

1. Create a new blank extension (JS/TS)
2. Add the following code to your extension's main entrypoint/command:

```js
vscode.window.showInformationMessage(
  'Lorem ipsum [Test A](command:ext.doSomething "First title") or [Test B](command:ext.doSomethingElse "Second title").'
)
```

Expected behavior is to see the notification with 2 command links and their titles but the following is rendered instead:

<p align="center">
 <img src="https://user-images.githubusercontent.com/20957750/194730379-0e04a0eb-d368-4257-b286-16023683489c.png" alt="notification-command">
</p>

Note: the provided commands `ext.doSomething` and `ext.doSomethingElse` should be valid and registered for the commands links to work when actually being clicked but that is irrelevant and out of scope for the issue.


Discussion:
This looks like a parsing bug to me when converting markdown to HTML.
Bug actually seems to be in `linkedText` since notifications don't use full markdown:

https://github.com/microsoft/vscode/blob/ce4aed5bf1917a86a6dfe1a71bdf51314bcc9afc/src/vs/workbench/common/notifications.ts#L496



Resolving patch:
diff --git a/src/vs/base/common/linkedText.ts b/src/vs/base/common/linkedText.ts
--- a/src/vs/base/common/linkedText.ts
+++ b/src/vs/base/common/linkedText.ts
@@ -23,7 +23,7 @@ export class LinkedText {
 	}
 }
 
-const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:|file:)[^\)\s]+)(?: ("|')([^\3]+)(\3))?\)/gi;
+const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:|file:)[^\)\s]+)(?: (["'])(.+?)(\3))?\)/gi;
 
 export function parseLinkedText(text: string): LinkedText {
 	const result: LinkedTextNode[] = [];


Test patch:
diff --git a/src/vs/base/test/common/linkedText.test.ts b/src/vs/base/test/common/linkedText.test.ts
--- a/src/vs/base/test/common/linkedText.test.ts
+++ b/src/vs/base/test/common/linkedText.test.ts
@@ -70,4 +70,14 @@ suite('LinkedText', () => {
 			'...'
 		]);
 	});
+
+	test('Should match non-greedily', () => {
+		assert.deepStrictEqual(parseLinkedText('a [link text 1](http://link.href "title1") b [link text 2](http://link.href "title2") c').nodes, [
+			'a ',
+			{ label: 'link text 1', href: 'http://link.href', title: 'title1' },
+			' b ',
+			{ label: 'link text 2', href: 'http://link.href', title: 'title2' },
+			' c',
+		]);
+	});
 });