Repository: microsoft/vscode (TypeScript)
Date: 2022-01-18 21:00:50+00:00
Task type: Bug Fix

Issue:
Terminal link validation interferes with codespace connection for very long wrapped lines
Repro:

Echo a really long wrapped line, this whole line will get split up via regex and each word that looks like a path will be validated, requiring a round trip to the remote.

Solution:

We should catch this case and restrict the amount of characters we search back/forward for long wrapped lines.


Issue discussion:

Solution patch:
diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider.ts
--- a/src/vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider.ts
+++ b/src/vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider.ts
@@ -49,6 +49,11 @@ export class TerminalProtocolLinkProvider extends TerminalBaseLinkProvider {
 		}
 
 		while (endLine < this._xterm.buffer.active.length && this._xterm.buffer.active.getLine(endLine + 1)?.isWrapped) {
+			if (endLine - startLine > this._xterm.rows) {
+				// This keeps the search space reasonable to prevent issues
+				// like #139593 from happening
+				break;
+			}
 			lines.push(this._xterm.buffer.active.getLine(endLine + 1)!);
 			endLine++;
 		}
diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider.ts
--- a/src/vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider.ts
+++ b/src/vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider.ts
@@ -157,7 +157,7 @@ export class TerminalWordLinkProvider extends TerminalBaseLinkProvider {
 		});
 		let matchLink = link;
 		if (this._capabilities.has(TerminalCapability.CwdDetection)) {
-			matchLink = this._updateLinkWithRelativeCwd(y, link, pathSeparator);
+			matchLink = this._updateLinkWithRelativeCwd(y, link, pathSeparator) || link;
 		}
 		const sanitizedLink = matchLink.replace(/:\d+(:\d+)?$/, '');
 		try {
@@ -192,9 +192,12 @@ export class TerminalWordLinkProvider extends TerminalBaseLinkProvider {
 	* For shells with the CwdDetection capability, the cwd relative to the line
 	* of the particular link is used to narrow down the result for an exact file match, if possible.
 	*/
-	private _updateLinkWithRelativeCwd(y: number, link: string, pathSeparator: string): string {
+	private _updateLinkWithRelativeCwd(y: number, link: string, pathSeparator: string): string | undefined {
 		const cwd = this._xterm.commandTracker.getCwdForLine(y);
-		if (cwd && !link.includes(pathSeparator)) {
+		if (!cwd) {
+			return undefined;
+		}
+		if (!link.includes(pathSeparator)) {
 			link = cwd + pathSeparator + link;
 		} else {
 			let commonDirs = 0;


Test patch:
diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalProtocolLinkProvider.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalProtocolLinkProvider.test.ts
--- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalProtocolLinkProvider.test.ts
+++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalProtocolLinkProvider.test.ts
@@ -86,4 +86,20 @@ suite('Workbench - TerminalProtocolLinkProvider', () => {
 			{ range: [[16, 1], [29, 1]], text: 'http://bar.foo' }
 		]);
 	});
+	test('should cap link size', async () => {
+		await assertLink([
+			'https://foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar',
+			'/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar'.repeat(69)]
+			.join(''),
+			[{
+				range: [[1, 1], [80, 26]],
+				text:
+					[
+						'https://foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar',
+						'/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar/foo.bar'.repeat(31),
+						'/'
+					].join('')
+			}]
+		);
+	});
 });