quick fix API polish (#168688)

* fix #167649

* Update src/vs/platform/terminal/common/xterm/terminalQuickFix.ts

* fix #167652

* add builtin everywhere for consistency

* fix  #167621 and fix #167646

* get rid of type in api

* fix  #167584

* fix #167587

* fix #167587

* fix #167590 and fix #167557

* Revert "fix #167652"

This reverts commit cf4cc72790.

* Update src/vs/workbench/contrib/terminal/common/terminal.ts

Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com>

* Update src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts

Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com>

* use const enum + more

* use classes

* update npm package.json

* add example for outputMatcher

* improve description

Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com>
This commit is contained in:
Megan Rogge 2022-12-13 12:32:54 -06:00 committed by GitHub
parent f99a293cef
commit 3e9bfdddc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 122 additions and 98 deletions

View file

@ -346,13 +346,12 @@
{ {
"id": "ms-vscode.npm-command", "id": "ms-vscode.npm-command",
"commandLineMatcher": "npm", "commandLineMatcher": "npm",
"exitStatus": false, "commandExitResult": "error",
"outputMatcher": { "outputMatcher": {
"anchor": "bottom", "anchor": "bottom",
"length": 8, "length": 8,
"lineMatcher": "Did you mean (?:this|one of these)\\?((?:\\n.+?npm .+ #.+)+)", "lineMatcher": "Did you mean (?:this|one of these)\\?((?:\\n.+?npm .+ #.+)+)",
"offset": 2, "offset": 2
"multipleMatches": true
} }
} }
] ]

View file

@ -78,7 +78,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
} }
const lines = outputMatch.regexMatch[1]; const lines = outputMatch.regexMatch[1];
const fixes: vscode.TerminalQuickFixCommandAction[] = []; const fixes: vscode.TerminalQuickFixCommand[] = [];
for (const line of lines.split('\n')) { for (const line of lines.split('\n')) {
// search from the second char, since the lines might be prefixed with // search from the second char, since the lines might be prefixed with
// "npm ERR!" which comes before the actual command suggestion. // "npm ERR!" which comes before the actual command suggestion.
@ -88,10 +88,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
} }
const end = line.lastIndexOf('#'); const end = line.lastIndexOf('#');
fixes.push({ fixes.push({ terminalCommand: line.slice(begin, end === -1 ? undefined : end - 1) });
type: vscode.TerminalQuickFixType.command,
terminalCommand: line.slice(begin, end === -1 ? undefined : end - 1)
});
} }
return fixes; return fixes;

View file

@ -674,9 +674,6 @@ function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker
} }
if (!match) { if (!match) {
match = lines.join('\n').match(matcher); match = lines.join('\n').match(matcher);
if (!outputMatcher.multipleMatches && match) {
return { regexMatch: match };
}
} }
} }
} else { } else {
@ -693,9 +690,6 @@ function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker
} }
if (!match) { if (!match) {
match = lines.join('\n').match(matcher); match = lines.join('\n').match(matcher);
if (!outputMatcher.multipleMatches && match) {
return { regexMatch: match };
}
} }
} }
} }

View file

@ -9,6 +9,12 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
export enum TerminalQuickFixType {
Command = 0,
Opener = 1,
Port = 2
}
export interface ITerminalCommandSelector { export interface ITerminalCommandSelector {
id: string; id: string;
commandLineMatcher: string | RegExp; commandLineMatcher: string | RegExp;
@ -26,19 +32,19 @@ export interface ITerminalQuickFixOptions {
} }
export interface ITerminalQuickFix { export interface ITerminalQuickFix {
type: 'command' | 'opener'; type: TerminalQuickFixType;
id: string; id: string;
source: string; source: string;
} }
export interface ITerminalQuickFixCommandAction extends ITerminalQuickFix { export interface ITerminalQuickFixCommandAction extends ITerminalQuickFix {
type: 'command'; type: TerminalQuickFixType.Command;
terminalCommand: string; terminalCommand: string;
// TODO: Should this depend on whether alt is held? // TODO: Should this depend on whether alt is held?
addNewLine?: boolean; addNewLine?: boolean;
} }
export interface ITerminalQuickFixOpenerAction extends ITerminalQuickFix { export interface ITerminalQuickFixOpenerAction extends ITerminalQuickFix {
type: 'opener'; type: TerminalQuickFixType.Opener;
uri: URI; uri: URI;
} }
@ -69,7 +75,7 @@ export interface ITerminalCommandMatchResult {
export interface ITerminalOutputMatch { export interface ITerminalOutputMatch {
regexMatch: RegExpMatchArray; regexMatch: RegExpMatchArray;
outputLines?: string[]; outputLines: string[];
} }
export interface IInternalOptions extends ITerminalQuickFixOptions { export interface IInternalOptions extends ITerminalQuickFixOptions {

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, TerminalLaunchConfig, ITerminalDimensionsDto, ExtHostTerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, TerminalLaunchConfig, ITerminalDimensionsDto, ExtHostTerminalIdentifier, TerminalQuickFix } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch'; import { StopWatch } from 'vs/base/common/stopwatch';
@ -20,13 +20,14 @@ import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminal
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { withNullAsUndefined } from 'vs/base/common/types'; import { withNullAsUndefined } from 'vs/base/common/types';
import { OperatingSystem, OS } from 'vs/base/common/platform'; import { OperatingSystem, OS } from 'vs/base/common/platform';
import { TerminalEditorLocationOptions, TerminalQuickFix, TerminalQuickFixOpenerAction } from 'vscode'; import { TerminalEditorLocationOptions } from 'vscode';
import { Promises } from 'vs/base/common/async'; import { Promises } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ITerminalOutputMatch, ITerminalOutputMatcher, ITerminalQuickFix, ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix'; import { ITerminalOutputMatch, ITerminalOutputMatcher, ITerminalQuickFix, ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { TerminalQuickFixType } from 'vs/workbench/api/common/extHostTypes'; import { TerminalQuickFixType } from 'vs/workbench/api/common/extHostTypes';
@extHostNamedCustomer(MainContext.MainThreadTerminalService) @extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape { export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@ -456,12 +457,14 @@ class ExtensionTerminalLinkProvider implements ITerminalExternalLinkProvider {
export function getOutputMatchForLines(lines: string[], outputMatcher: ITerminalOutputMatcher): ITerminalOutputMatch | undefined { export function getOutputMatchForLines(lines: string[], outputMatcher: ITerminalOutputMatcher): ITerminalOutputMatch | undefined {
const match: RegExpMatchArray | null | undefined = lines.join('\n').match(outputMatcher.lineMatcher); const match: RegExpMatchArray | null | undefined = lines.join('\n').match(outputMatcher.lineMatcher);
return match ? { regexMatch: match, outputLines: outputMatcher.multipleMatches ? lines : undefined } : undefined; return match ? { regexMatch: match, outputLines: lines } : undefined;
} }
function parseQuickFix(id: string, source: string, fix: TerminalQuickFix): ITerminalQuickFix { function parseQuickFix(id: string, source: string, fix: TerminalQuickFix): ITerminalQuickFix {
if (fix.type === TerminalQuickFixType.opener) { let type = TerminalQuickFixType.Command;
(fix as TerminalQuickFixOpenerAction).uri = URI.revive((fix as TerminalQuickFixOpenerAction).uri); if ('uri' in fix) {
fix.uri = URI.revive(fix.uri);
type = TerminalQuickFixType.Opener;
} }
return { id, source, ...fix }; return { id, type, source, ...fix };
} }

View file

@ -1315,6 +1315,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
TaskRevealKind: extHostTypes.TaskRevealKind, TaskRevealKind: extHostTypes.TaskRevealKind,
TaskScope: extHostTypes.TaskScope, TaskScope: extHostTypes.TaskScope,
TerminalLink: extHostTypes.TerminalLink, TerminalLink: extHostTypes.TerminalLink,
TerminalQuickFixCommand: extHostTypes.TerminalQuickFixCommand,
TerminalQuickFixOpener: extHostTypes.TerminalQuickFixOpener,
TerminalLocation: extHostTypes.TerminalLocation, TerminalLocation: extHostTypes.TerminalLocation,
TerminalProfile: extHostTypes.TerminalProfile, TerminalProfile: extHostTypes.TerminalProfile,
TerminalExitReason: extHostTypes.TerminalExitReason, TerminalExitReason: extHostTypes.TerminalExitReason,

View file

@ -70,7 +70,10 @@ import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplore
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder'; import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
import * as search from 'vs/workbench/services/search/common/search'; import * as search from 'vs/workbench/services/search/common/search';
import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions'; import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions';
import { TerminalCommandMatchResult, TerminalQuickFix } from 'vscode'; import { TerminalCommandMatchResult, TerminalQuickFixCommand, TerminalQuickFixOpener } from 'vscode';
export type TerminalQuickFix = TerminalQuickFixCommand | TerminalQuickFixOpener;
export interface IWorkspaceData extends IStaticWorkspaceData { export interface IWorkspaceData extends IStaticWorkspaceData {
folders: { uri: UriComponents; name: string; index: number }[]; folders: { uri: UriComponents; name: string; index: number }[];

View file

@ -679,7 +679,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
}); });
} }
public async $provideTerminalQuickFixes(id: string, matchResult: vscode.TerminalCommandMatchResult): Promise<vscode.TerminalQuickFix[] | vscode.TerminalQuickFix | undefined> { public async $provideTerminalQuickFixes(id: string, matchResult: vscode.TerminalCommandMatchResult): Promise<(vscode.TerminalQuickFixOpener | vscode.TerminalQuickFixCommand)[] | vscode.TerminalQuickFixOpener | vscode.TerminalQuickFixCommand | undefined> {
const token = new CancellationTokenSource().token; const token = new CancellationTokenSource().token;
if (token.isCancellationRequested) { if (token.isCancellationRequested) {
return; return;
@ -688,7 +688,12 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
if (!provider) { if (!provider) {
return; return;
} }
return provider.provideTerminalQuickFixes(matchResult, token); const quickFixes = await provider.provideTerminalQuickFixes(matchResult, token);
if (quickFixes === null) {
return undefined;
} else {
return quickFixes;
}
} }
public async $createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void> { public async $createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void> {

View file

@ -46,13 +46,13 @@ function es5ClassCompat(target: Function): any {
} }
export enum TerminalOutputAnchor { export enum TerminalOutputAnchor {
top = 'top', Top = 0,
bottom = 'bottom' Bottom = 1
} }
export enum TerminalQuickFixType { export enum TerminalQuickFixType {
command = 'command', Command = 0,
opener = 'opener' Opener = 1
} }
@es5ClassCompat @es5ClassCompat
@ -1926,6 +1926,20 @@ export class TerminalLink implements vscode.TerminalLink {
} }
} }
export class TerminalQuickFixOpener {
uri: vscode.Uri;
constructor(uri: vscode.Uri) {
this.uri = uri;
}
}
export class TerminalQuickFixCommand {
terminalCommand: string;
constructor(terminalCommand: string) {
this.terminalCommand = terminalCommand;
}
}
export enum TerminalLocation { export enum TerminalLocation {
Panel = 1, Panel = 1,
Editor = 2, Editor = 2,

View file

@ -5,9 +5,8 @@
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { IInternalOptions, ITerminalCommandMatchResult, TerminalQuickFixActionInternal } from 'vs/platform/terminal/common/xterm/terminalQuickFix'; import { IInternalOptions, ITerminalCommandMatchResult, TerminalQuickFixActionInternal, TerminalQuickFixType } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalQuickFixType } from 'vs/workbench/contrib/terminal/browser/widgets/terminalQuickFixMenuItems';
export const GitCommandLineRegex = /git/; export const GitCommandLineRegex = /git/;
export const GitPushCommandLineRegex = /git\s+push/; export const GitPushCommandLineRegex = /git\s+push/;
@ -20,6 +19,10 @@ export const GitPushOutputRegex = /git push --set-upstream origin (?<branchName>
// it's safe to assume it's a github pull request if the URL includes `/pull/` // it's safe to assume it's a github pull request if the URL includes `/pull/`
export const GitCreatePrOutputRegex = /remote:\s*(?<link>https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/; export const GitCreatePrOutputRegex = /remote:\s*(?<link>https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/;
export const enum QuickFixSource {
Builtin = 'builtin'
}
export function gitSimilar(): IInternalOptions { export function gitSimilar(): IInternalOptions {
return { return {
id: 'Git Similar', id: 'Git Similar',
@ -46,7 +49,7 @@ export function gitSimilar(): IInternalOptions {
type: TerminalQuickFixType.Command, type: TerminalQuickFixType.Command,
terminalCommand: matchResult.commandLine.replace(/git\s+[^\s]+/, () => `git ${fixedCommand}`), terminalCommand: matchResult.commandLine.replace(/git\s+[^\s]+/, () => `git ${fixedCommand}`),
addNewLine: true, addNewLine: true,
source: 'builtin' source: QuickFixSource.Builtin
}); });
} }
} }
@ -77,7 +80,7 @@ export function gitTwoDashes(): IInternalOptions {
id: 'Git Two Dashes', id: 'Git Two Dashes',
terminalCommand: matchResult.commandLine.replace(` -${problemArg}`, () => ` --${problemArg}`), terminalCommand: matchResult.commandLine.replace(` -${problemArg}`, () => ` --${problemArg}`),
addNewLine: true, addNewLine: true,
source: 'builtin' source: QuickFixSource.Builtin
}; };
} }
}; };
@ -101,11 +104,13 @@ export function freePort(terminalInstance?: Partial<ITerminalInstance>): IIntern
} }
const label = localize("terminal.freePort", "Free port {0}", port); const label = localize("terminal.freePort", "Free port {0}", port);
return { return {
class: TerminalQuickFixType.Port, type: TerminalQuickFixType.Port,
class: undefined,
tooltip: label, tooltip: label,
id: 'Free Port', id: 'Free Port',
label, label,
enabled: true, enabled: true,
source: QuickFixSource.Builtin,
run: async () => { run: async () => {
await terminalInstance?.freePortKillProcess?.(port, matchResult.commandLine); await terminalInstance?.freePortKillProcess?.(port, matchResult.commandLine);
} }
@ -147,11 +152,11 @@ export function gitPushSetUpstream(): IInternalOptions {
} }
if (fixedCommand) { if (fixedCommand) {
actions.push({ actions.push({
type: 'command', type: TerminalQuickFixType.Command,
id: 'Git Push Set Upstream', id: 'Git Push Set Upstream',
terminalCommand: fixedCommand, terminalCommand: fixedCommand,
addNewLine: true, addNewLine: true,
source: 'builtin' source: QuickFixSource.Builtin
}); });
return actions; return actions;
} }
@ -179,14 +184,12 @@ export function gitCreatePr(): IInternalOptions {
} }
const label = localize("terminal.createPR", "Create PR {0}", link); const label = localize("terminal.createPR", "Create PR {0}", link);
return { return {
class: undefined,
tooltip: label,
id: 'Git Create Pr', id: 'Git Create Pr',
label, label,
enabled: true, enabled: true,
type: 'opener', type: TerminalQuickFixType.Opener,
uri: URI.parse(link), uri: URI.parse(link),
run: () => { } source: QuickFixSource.Builtin
}; };
} }
}; };

View file

@ -9,21 +9,16 @@ import { CodeActionKind } from 'vs/editor/contrib/codeAction/common/types';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { ActionListItemKind, IListMenuItem } from 'vs/platform/actionWidget/browser/actionList'; import { ActionListItemKind, IListMenuItem } from 'vs/platform/actionWidget/browser/actionList';
import { IActionItem } from 'vs/platform/actionWidget/common/actionWidget'; import { IActionItem } from 'vs/platform/actionWidget/common/actionWidget';
import { TerminalQuickFixType } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { ITerminalAction } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { ITerminalAction } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon';
export const enum TerminalQuickFixType {
Command = 'command',
Opener = 'opener',
Port = 'port'
}
export class TerminalQuickFix implements IActionItem { export class TerminalQuickFix implements IActionItem {
action: ITerminalAction; action: ITerminalAction;
type: string; type: TerminalQuickFixType;
disabled?: boolean; disabled?: boolean;
title?: string; title?: string;
source: string; source: string;
constructor(action: ITerminalAction, type: string, source: string, title?: string, disabled?: boolean) { constructor(action: ITerminalAction, type: TerminalQuickFixType, source: string, title?: string, disabled?: boolean) {
this.action = action; this.action = action;
this.disabled = disabled; this.disabled = disabled;
this.title = title; this.title = title;
@ -72,5 +67,4 @@ function getQuickFixIcon(quickFix: TerminalQuickFix): { codicon: Codicon } {
case TerminalQuickFixType.Port: case TerminalQuickFixType.Port:
return { codicon: Codicon.debugDisconnect }; return { codicon: Codicon.debugDisconnect };
} }
return { codicon: Codicon.lightBulb };
} }

View file

@ -23,9 +23,9 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
import { IActionWidgetService } from 'vs/platform/actionWidget/browser/actionWidget'; import { IActionWidgetService } from 'vs/platform/actionWidget/browser/actionWidget';
import { ActionSet } from 'vs/platform/actionWidget/common/actionWidget'; import { ActionSet } from 'vs/platform/actionWidget/common/actionWidget';
import { TerminalQuickFix, TerminalQuickFixType, toMenuItems } from 'vs/workbench/contrib/terminal/browser/widgets/terminalQuickFixMenuItems'; import { TerminalQuickFix, toMenuItems } from 'vs/workbench/contrib/terminal/browser/widgets/terminalQuickFixMenuItems';
import { ITerminalQuickFixProviderSelector, ITerminalQuickFixService } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITerminalQuickFixProviderSelector, ITerminalQuickFixService } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalQuickFixOptions, IResolvedExtensionOptions, IUnresolvedExtensionOptions, ITerminalCommandSelector, ITerminalQuickFix, IInternalOptions, ITerminalQuickFixCommandAction, ITerminalQuickFixOpenerAction } from 'vs/platform/terminal/common/xterm/terminalQuickFix'; import { ITerminalQuickFixOptions, IResolvedExtensionOptions, IUnresolvedExtensionOptions, ITerminalCommandSelector, ITerminalQuickFix, IInternalOptions, ITerminalQuickFixCommandAction, ITerminalQuickFixOpenerAction, TerminalQuickFixType } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { getLinesForCommand } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { getLinesForCommand } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
import { ILabelService } from 'vs/platform/label/common/label'; import { ILabelService } from 'vs/platform/label/common/label';
@ -117,7 +117,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
} }
// TODO: What's documentation do? Need a vscode command? // TODO: What's documentation do? Need a vscode command?
const actions = this._currentRenderContext.quickFixes.map(f => new TerminalQuickFix(f, f.class || TerminalQuickFixType.Command, f.source, f.label)); const actions = this._currentRenderContext.quickFixes.map(f => new TerminalQuickFix(f, f.type, f.source, f.label));
const documentation = this._currentRenderContext.quickFixes.map(f => { return { id: f.source, title: f.label, tooltip: f.source }; }); const documentation = this._currentRenderContext.quickFixes.map(f => { return { id: f.source, title: f.label, tooltip: f.source }; });
const actionSet = { const actionSet = {
// TODO: Documentation and actions are separate? // TODO: Documentation and actions are separate?
@ -280,6 +280,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
} }
export interface ITerminalAction extends IAction { export interface ITerminalAction extends IAction {
type: TerminalQuickFixType;
source: string; source: string;
uri?: URI; uri?: URI;
command?: string; command?: string;
@ -336,10 +337,11 @@ export async function getQuickFixesForCommand(
const fix = quickFix as ITerminalQuickFixCommandAction; const fix = quickFix as ITerminalQuickFixCommandAction;
const label = localize('quickFix.command', 'Run: {0}', fix.terminalCommand); const label = localize('quickFix.command', 'Run: {0}', fix.terminalCommand);
action = { action = {
type: TerminalQuickFixType.Command,
class: undefined,
source: quickFix.source, source: quickFix.source,
id: quickFix.id, id: quickFix.id,
label, label,
class: quickFix.type,
enabled: true, enabled: true,
run: () => { run: () => {
onDidRequestRerunCommand?.fire({ onDidRequestRerunCommand?.fire({
@ -364,7 +366,8 @@ export async function getQuickFixesForCommand(
source: quickFix.source, source: quickFix.source,
id: quickFix.id, id: quickFix.id,
label, label,
class: quickFix.type, type: TerminalQuickFixType.Opener,
class: undefined,
enabled: true, enabled: true,
run: () => openerService.open(fix.uri), run: () => openerService.open(fix.uri),
tooltip: label, tooltip: label,
@ -372,23 +375,26 @@ export async function getQuickFixesForCommand(
}; };
break; break;
} }
case TerminalQuickFixType.Port: {
const fix = quickFix as ITerminalAction;
action = {
source: 'builtin',
type: fix.type,
id: fix.id,
label: fix.label,
class: fix.class,
enabled: fix.enabled,
run: () => {
fix.run();
},
tooltip: fix.tooltip
};
break;
}
}
if (action) {
fixes.push(action);
} }
} else {
const fix = quickFix as ITerminalAction;
action = {
source: 'builtin',
id: fix.id,
label: fix.label,
class: fix.class,
enabled: fix.enabled,
run: () => {
fix.run();
},
tooltip: fix.tooltip
};
}
if (action) {
fixes.push(action);
} }
} }
} }

View file

@ -741,7 +741,8 @@ export const terminalContributionsDescriptor: IExtensionPointDescriptor<ITermina
description: nls.localize('vscode.extension.contributes.terminal.quickFixes', "Defines quick fixes for terminals with shell integration enabled."), description: nls.localize('vscode.extension.contributes.terminal.quickFixes', "Defines quick fixes for terminals with shell integration enabled."),
items: { items: {
type: 'object', type: 'object',
required: ['id', 'commandLineMatcher', 'outputMatcher', 'exitStatus'], additionalProperties: false,
required: ['id', 'commandLineMatcher', 'outputMatcher', 'commandExitResult'],
defaultSnippets: [{ defaultSnippets: [{
body: { body: {
id: '$1', id: '$1',
@ -752,15 +753,15 @@ export const terminalContributionsDescriptor: IExtensionPointDescriptor<ITermina
}], }],
properties: { properties: {
id: { id: {
description: nls.localize('vscode.extension.contributes.terminal.quickFixes.id', "The ID of the quick fix."), description: nls.localize('vscode.extension.contributes.terminal.quickFixes.id', "The ID of the quick fix provider."),
type: 'string', type: 'string',
}, },
commandLineMatcher: { commandLineMatcher: {
description: nls.localize('vscode.extension.contributes.terminal.quickFixes.commandLineMatcher', "The command line to match."), description: nls.localize('vscode.extension.contributes.terminal.quickFixes.commandLineMatcher', "The regular expression to test the command line against."),
type: 'string', type: 'string',
}, },
outputMatcher: { outputMatcher: {
description: nls.localize('vscode.extension.contributes.terminal.quickFixes.outputMatcher', "The output to match, which provides groups of the form <group_name> to be referenced via ${group:group_name} in commandToRun and linkToOpen."), markdownDescription: nls.localize('vscode.extension.contributes.terminal.quickFixes.outputMatcher', "The regular expression to test the output against, which provides groups to be referenced in terminalCommand and uri.\n\nFor example:\n\n `lineMatcher: /git push --set-upstream origin (?<branchName>[^\s]+)/;`\n\n`terminalCommand: 'git push --set-upstream origin ${group:branchName}';`\n"),
type: 'object', type: 'object',
required: ['lineMatcher', 'anchor', 'offset', 'length'], required: ['lineMatcher', 'anchor', 'offset', 'length'],
properties: { properties: {
@ -769,11 +770,11 @@ export const terminalContributionsDescriptor: IExtensionPointDescriptor<ITermina
type: 'string' type: 'string'
}, },
anchor: { anchor: {
description: 'Which side of the output to anchor the offset and length against', description: 'Where the search should begin in the buffer',
enum: ['top', 'bottom'] enum: ['top', 'bottom']
}, },
offset: { offset: {
description: 'How far from either the top or the bottom of the butter to start matching against.', description: 'The number of lines vertically from the anchor in the buffer to start matching against',
type: 'number' type: 'number'
}, },
length: { length: {
@ -783,7 +784,7 @@ export const terminalContributionsDescriptor: IExtensionPointDescriptor<ITermina
} }
}, },
commandExitResult: { commandExitResult: {
description: nls.localize('vscode.extension.contributes.terminal.quickFixes.commandExitResult', "The command result to match on"), description: nls.localize('vscode.extension.contributes.terminal.quickFixes.commandExitResult', "The command exit result to match on"),
enum: ['success', 'error'], enum: ['success', 'error'],
enumDescriptions: [ enumDescriptions: [
'The command exited with an exit code of zero.', 'The command exited with an exit code of zero.',

View file

@ -12,19 +12,16 @@ declare module 'vscode' {
* @param token A cancellation token indicating the result is no longer needed * @param token A cancellation token indicating the result is no longer needed
* @return Terminal quick fix(es) if any * @return Terminal quick fix(es) if any
*/ */
provideTerminalQuickFixes(commandMatchResult: TerminalCommandMatchResult, token: CancellationToken): TerminalQuickFix[] | TerminalQuickFix | undefined; provideTerminalQuickFixes(commandMatchResult: TerminalCommandMatchResult, token: CancellationToken): ProviderResult<(TerminalQuickFixCommand | TerminalQuickFixOpener)[] | TerminalQuickFixCommand | TerminalQuickFixOpener>;
} }
interface TerminalQuickFix {
type: TerminalQuickFixType;
}
export interface TerminalCommandMatchResult { export interface TerminalCommandMatchResult {
commandLine: string; commandLine: string;
commandLineMatch: RegExpMatchArray; commandLineMatch: RegExpMatchArray;
outputMatch?: { outputMatch?: {
regexMatch: RegExpMatchArray; regexMatch: RegExpMatchArray;
outputLines?: string[]; outputLines: string[];
}; };
} }
@ -36,13 +33,19 @@ declare module 'vscode' {
export function registerTerminalQuickFixProvider(id: string, provider: TerminalQuickFixProvider): Disposable; export function registerTerminalQuickFixProvider(id: string, provider: TerminalQuickFixProvider): Disposable;
} }
export interface TerminalQuickFixCommandAction extends TerminalQuickFix { export class TerminalQuickFixCommand {
type: TerminalQuickFixType.command; /**
* The terminal command to run
*/
terminalCommand: string; terminalCommand: string;
constructor(terminalCommand: string);
} }
export interface TerminalQuickFixOpenerAction extends TerminalQuickFix { export class TerminalQuickFixOpener {
type: TerminalQuickFixType.opener; /**
* The uri to open
*/
uri: Uri; uri: Uri;
constructor(uri: Uri);
} }
/** /**
@ -67,21 +70,15 @@ declare module 'vscode' {
* reasons. This is capped at 40. * reasons. This is capped at 40.
*/ */
length: number; length: number;
/**
* If multiple matches are expected - this will result in {@link outputLines} being returned
* when there's a {@link regexMatch} from {@link offset} to {@link length}
*/
multipleMatches?: boolean;
} }
enum TerminalOutputAnchor { enum TerminalOutputAnchor {
top = 'top', Top = 0,
bottom = 'bottom' Bottom = 1
} }
enum TerminalQuickFixType { enum TerminalQuickFixType {
command = 'command', Command = 0,
opener = 'opener' Opener = 1
} }
} }