Repository: microsoft/vscode (TypeScript)
Date: 2022-09-27 22:38:14+00:00
Task type: Bug Fix

Issue:
Terminal quick fix title should show the command that should be run
Testing #161846

1. `git checkout -b lalala`
2. `git push`
3. Notice quick fix title is "git push lalala". Title should be what will actually be run `git push --set-upstream origin lalala`

Right now the user does not know what will be run, so it is surprising and does not give confidence.

![Screenshot 2022-09-27 at 10 20 01](https://user-images.githubusercontent.com/1926584/192472878-90950f03-e398-41fa-bf0d-12db1d7d6506.png)



Issue discussion:
Not sure if we want to show all of those details - maybe we could on hover of the action?
If you do not want to render all the details then I suggest to render the first n characters and render `...` at the end. That way the user can understand that we only took the beginning

And :+1: for on hover to show the whole thing
https://github.com/microsoft/vscode/issues/161599 is is about coding convenience, plus this issue. For simple commands like this we should always show the full thing without hover imo (hovering also can't happen on native dropdowns). This will increase the user's trust in the feature
Agreed. We could have a long command cutoff limit - 50 characters for example. After that we can render elipses `...`
Commands that long are probably too complicated anyway, such as how we free the port which is a little different as it's handled outside of the terminal
I think we should also show the URL we're navigating to

https://github.com/microsoft/vscode/blob/08578603ee434e8d6574a26f1f83cda98335b2dc/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts#L131

A good example of why this trust is important is because this:

![image](https://user-images.githubusercontent.com/2193314/192646552-2a63b6e2-0ac1-4b65-88e7-8daffe9fe96b.png)

Was navigating to `https://github.com/microsoft/vscode/compare/tyriar/wording%20%20%20%20%20%20%20%20remote:To%20https:/github.com/microsoft/vscode%20*%20%5Bnew%20branch%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20tyriar/wording%20-%3E%20tyriar/wordingBranch%20'tyriar/wording'%20set%20up%20to%20track%20remote%20branch%20'tyriar/wording'%20from%20'origin'.?expand=1` due to a bug (https://github.com/microsoft/vscode/issues/162074). If a user clicked "Create PR" and they go there, they may never use the feature again 

Solution patch:
diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts
--- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts
+++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts
@@ -660,13 +660,11 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en
 	if (outputMatcher?.length && (endLine - startLine) < outputMatcher.length) {
 		return undefined;
 	}
-	let output = '';
 	let line: string | undefined;
 	if (outputMatcher?.anchor === 'bottom') {
 		for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) {
 			line = getXtermLineContent(buffer, i, i, cols);
-			output = line + output;
-			const match = output.match(outputMatcher.lineMatcher);
+			const match = line.match(outputMatcher.lineMatcher);
 			if (match) {
 				return match;
 			}
@@ -674,9 +672,8 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en
 	} else {
 		for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) {
 			line = getXtermLineContent(buffer, i, i, cols);
-			output += line;
 			if (outputMatcher) {
-				const match = output.match(outputMatcher.lineMatcher);
+				const match = line.match(outputMatcher.lineMatcher);
 				if (match) {
 					return match;
 				}
diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts
--- a/src/vs/workbench/contrib/terminal/browser/terminal.ts
+++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts
@@ -920,14 +920,12 @@ export interface ITerminalInstance {
 }
 
 export interface ITerminalQuickFixOptions {
-	quickFixLabel: string | DynamicQuickFixLabel;
 	commandLineMatcher: string | RegExp;
 	outputMatcher?: ITerminalOutputMatcher;
 	getQuickFixes: QuickFixCallback;
 	exitStatus?: boolean;
 }
 export type QuickFixMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null };
-export type DynamicQuickFixLabel = (matchResult: QuickFixMatchResult) => string;
 export type QuickFixCallback = (matchResult: QuickFixMatchResult, command: ITerminalCommand) => ITerminalQuickFixAction[] | undefined;
 
 export interface ITerminalQuickFixAction extends IAction {
diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts
--- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts
+++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts
@@ -16,12 +16,13 @@ export const AnyCommandLineRegex = /.+/;
 export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/;
 export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/;
 export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/;
-export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*remote:\s*(https:.+pull.+)/;
+// The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*",
+// it's safe to assume it's a github pull request if the URL includes `/pull/`
+export const GitCreatePrOutputRegex = /remote:\s*(https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/;
 
 export function gitSimilarCommand(): ITerminalQuickFixOptions {
 	return {
 		commandLineMatcher: GitCommandLineRegex,
-		quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Run git ${matchResult.outputMatch[1]}` : ``,
 		outputMatcher: {
 			lineMatcher: GitSimilarOutputRegex,
 			anchor: 'bottom',
@@ -35,10 +36,11 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions {
 			if (!fixedCommand) {
 				return;
 			}
-			const label = localize("terminal.gitSimilarCommand", "Run git {0}", fixedCommand);
+			const commandToRunInTerminal = `git ${fixedCommand}`;
+			const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal);
 			actions.push({
 				class: undefined, tooltip: label, id: 'terminal.gitSimilarCommand', label, enabled: true,
-				commandToRunInTerminal: `git ${fixedCommand}`,
+				commandToRunInTerminal,
 				addNewLine: true,
 				run: () => { }
 			});
@@ -48,7 +50,6 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions {
 }
 export function freePort(terminalInstance?: Partial<ITerminalInstance>): ITerminalQuickFixOptions {
 	return {
-		quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '',
 		commandLineMatcher: AnyCommandLineRegex,
 		// TODO: Support free port on Windows https://github.com/microsoft/vscode/issues/161775
 		outputMatcher: isWindows ? undefined : {
@@ -79,7 +80,6 @@ export function freePort(terminalInstance?: Partial<ITerminalInstance>): ITermin
 }
 export function gitPushSetUpstream(): ITerminalQuickFixOptions {
 	return {
-		quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Git push ${matchResult.outputMatch[1]}` : '',
 		commandLineMatcher: GitPushCommandLineRegex,
 		outputMatcher: {
 			lineMatcher: GitPushOutputRegex,
@@ -94,11 +94,11 @@ export function gitPushSetUpstream(): ITerminalQuickFixOptions {
 				return;
 			}
 			const actions: ITerminalQuickFixAction[] = [];
-			const label = localize("terminal.gitPush", "Git push {0}", branch);
-			command.command = `git push --set-upstream origin ${branch}`;
+			const commandToRunInTerminal = `git push --set-upstream origin ${branch}`;
+			const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal);
 			actions.push({
 				class: undefined, tooltip: label, id: 'terminal.gitPush', label, enabled: true,
-				commandToRunInTerminal: command.command,
+				commandToRunInTerminal,
 				addNewLine: true,
 				run: () => { }
 			});
@@ -109,7 +109,6 @@ export function gitPushSetUpstream(): ITerminalQuickFixOptions {
 
 export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOptions {
 	return {
-		quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Create PR for ${matchResult.outputMatch[1]}` : '',
 		commandLineMatcher: GitPushCommandLineRegex,
 		outputMatcher: {
 			lineMatcher: GitCreatePrOutputRegex,
@@ -122,13 +121,12 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOpt
 			if (!command) {
 				return;
 			}
-			const branch = matchResult?.outputMatch?.[1];
-			const link = matchResult?.outputMatch?.[2];
-			if (!branch || !link) {
+			const link = matchResult?.outputMatch?.[1];
+			if (!link) {
 				return;
 			}
 			const actions: IAction[] = [];
-			const label = localize("terminal.gitCreatePr", "Create PR");
+			const label = localize("terminal.openLink", "Open link: {0}", link);
 			actions.push({
 				class: undefined, tooltip: label, id: 'terminal.gitCreatePr', label, enabled: true,
 				run: () => openerService.open(link)


Test patch:
diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts
--- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts
+++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts
@@ -56,9 +56,9 @@ suite('QuickFixAddon', () => {
 			const actions = [
 				{
 					id: 'terminal.gitSimilarCommand',
-					label: 'Run git status',
+					label: 'Run: git status',
 					run: true,
-					tooltip: 'Run git status',
+					tooltip: 'Run: git status',
 					enabled: true
 				}
 			];
@@ -136,9 +136,9 @@ suite('QuickFixAddon', () => {
 			const actions = [
 				{
 					id: 'terminal.gitPush',
-					label: 'Git push test22',
+					label: 'Run: git push --set-upstream origin test22',
 					run: true,
-					tooltip: 'Git push test22',
+					tooltip: 'Run: git push --set-upstream origin test22',
 					enabled: true
 				}
 			];
@@ -179,9 +179,9 @@ suite('QuickFixAddon', () => {
 			const actions = [
 				{
 					id: 'terminal.gitCreatePr',
-					label: 'Create PR',
+					label: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22',
 					run: true,
-					tooltip: 'Create PR',
+					tooltip: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22',
 					enabled: true
 				}
 			];
@@ -219,9 +219,9 @@ suite('QuickFixAddon', () => {
 		const actions = [
 			{
 				id: 'terminal.gitPush',
-				label: 'Git push test22',
+				label: 'Run: git push --set-upstream origin test22',
 				run: true,
-				tooltip: 'Git push test22',
+				tooltip: 'Run: git push --set-upstream origin test22',
 				enabled: true
 			}
 		];