Fixes #23435: Proposed Task Api Feedback

This commit is contained in:
Dirk Baeumer
2017-05-18 21:53:22 +02:00
parent f1d0c1d884
commit f084c2a1e4
10 changed files with 688 additions and 629 deletions
@@ -552,7 +552,7 @@ export namespace Config {
/**
* A description to track the start and end of a watching task.
*/
export interface WatchingMatcher {
export interface BackgroundMonitor {
/**
* If set to true the watcher is in active mode when the task
@@ -648,7 +648,11 @@ export namespace Config {
*/
watchedTaskEndsRegExp?: string;
watching?: WatchingMatcher;
/**
* @deprecated Use background instead.
*/
watching?: BackgroundMonitor;
background?: BackgroundMonitor;
}
export type ProblemMatcherType = string | ProblemMatcher | (string | ProblemMatcher)[];
@@ -1264,15 +1268,15 @@ export class ProblemMatcherParser extends Parser {
};
return;
}
if (Types.isUndefinedOrNull(external.watching)) {
let backgroundMonitor = external.background || external.watching;
if (Types.isUndefinedOrNull(backgroundMonitor)) {
return;
}
let watching = external.watching;
let begins: WatchingPattern = this.createWatchingPattern(watching.beginsPattern);
let ends: WatchingPattern = this.createWatchingPattern(watching.endsPattern);
let begins: WatchingPattern = this.createWatchingPattern(backgroundMonitor.beginsPattern);
let ends: WatchingPattern = this.createWatchingPattern(backgroundMonitor.endsPattern);
if (begins && ends) {
internal.watching = {
activeOnStart: Types.isBoolean(watching.activeOnStart) ? watching.activeOnStart : false,
activeOnStart: Types.isBoolean(backgroundMonitor.activeOnStart) ? backgroundMonitor.activeOnStart : false,
beginsPattern: begins,
endsPattern: ends
};
@@ -1325,7 +1329,7 @@ export namespace Schemas {
properties: {
regexp: {
type: 'string',
description: localize('WatchingPatternSchema.regexp', 'The regular expression to detect the begin or end of a watching task.')
description: localize('WatchingPatternSchema.regexp', 'The regular expression to detect the begin or end of a background task.')
},
file: {
type: 'integer',
@@ -1385,9 +1389,40 @@ export namespace Schemas {
],
description: localize('ProblemMatcherSchema.fileLocation', 'Defines how file names reported in a problem pattern should be interpreted.')
},
background: {
type: 'object',
additionalProperties: false,
description: localize('ProblemMatcherSchema.background', 'Patterns to track the begin and end of a matcher active on a background task.'),
properties: {
activeOnStart: {
type: 'boolean',
description: localize('ProblemMatcherSchema.background.activeOnStart', 'If set to true the background monitor is in active mode when the task starts. This is equals of issuing a line that matches the beginPattern')
},
beginsPattern: {
oneOf: [
{
type: 'string'
},
Schemas.WatchingPattern
],
description: localize('ProblemMatcherSchema.background.beginsPattern', 'If matched in the output the start of a background task is signaled.')
},
endsPattern: {
oneOf: [
{
type: 'string'
},
Schemas.WatchingPattern
],
description: localize('ProblemMatcherSchema.background.endsPattern', 'If matched in the output the end of a background task is signaled.')
}
}
},
watching: {
type: 'object',
additionalProperties: false,
deprecationMessage: localize('ProblemMatcherSchema.watching.deprecated', 'The watching property is deprecated. Use background instead.'),
description: localize('ProblemMatcherSchema.watching', 'Patterns to track the begin and end of a watching matcher.'),
properties: {
activeOnStart: {
type: 'boolean',
@@ -1411,8 +1446,7 @@ export namespace Schemas {
],
description: localize('ProblemMatcherSchema.watching.endsPattern', 'If matched in the output the end of a watching task is signaled.')
}
},
description: localize('ProblemMatcherSchema.watching', 'Patterns to track the begin and end of a watching pattern.')
}
}
}
};
+520
View File
@@ -3489,6 +3489,526 @@ declare module 'vscode' {
update(key: string, value: any): Thenable<void>;
}
/**
* Defines a problem pattern
*/
export interface ProblemPattern {
/**
* The regular expression to find a problem in the console output of an
* executed task.
*/
regexp: RegExp;
/**
* The match group index of the filename.
*
* Defaults to 1 if omitted.
*/
file?: number;
/**
* The match group index of the problems's location. Valid location
* patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn).
* If omitted the line and colum properties are used.
*/
location?: number;
/**
* The match group index of the problem's line in the source file.
*
* Defaults to 2 if omitted.
*/
line?: number;
/**
* The match group index of the problem's character in the source file.
*
* Defaults to 3 if omitted.
*/
character?: number;
/**
* The match group index of the problem's end line in the source file.
*
* Defaults to undefined. No end line is captured.
*/
endLine?: number;
/**
* The match group index of the problem's end character in the source file.
*
* Defaults to undefined. No end column is captured.
*/
endCharacter?: number;
/**
* The match group index of the problem's severity.
*
* Defaults to undefined. In this case the problem matcher's severity
* is used.
*/
severity?: number;
/**
* The match group index of the problems's code.
*
* Defaults to undefined. No code is captured.
*/
code?: number;
/**
* The match group index of the message. If omitted it defaults
* to 4 if location is specified. Otherwise it defaults to 5.
*/
message?: number;
/**
* Specifies if the last pattern in a multi line problem matcher should
* loop as long as it does match a line consequently. Only valid on the
* last problem pattern in a multi line problem matcher.
*/
loop?: boolean;
}
/**
* A multi line problem pattern.
*/
export type MultiLineProblemPattern = ProblemPattern[];
/**
* The way how the file location is interpreted
*/
export enum FileLocationKind {
/**
* VS Code should decide based on whether the file path found in the
* output is absolute or relative. A relative file path will be treated
* relative to the workspace root.
*/
Auto = 1,
/**
* Always treat the file path relative.
*/
Relative = 2,
/**
* Always treat the file path absolute.
*/
Absolute = 3
}
/**
* Controls to which kind of documents problems are applied.
*/
export enum ApplyToKind {
/**
* Problems are applied to all documents.
*/
AllDocuments = 1,
/**
* Problems are applied to open documents only.
*/
OpenDocuments = 2,
/**
* Problems are applied to closed documents only.
*/
ClosedDocuments = 3
}
/**
* A background monitor pattern
*/
export interface BackgroundPattern {
/**
* The actual regular expression
*/
regexp: RegExp;
/**
* The match group index of the filename. If provided the expression
* is matched for that file only.
*/
file?: number;
}
/**
* A description to control the activity of a problem matcher
* watching a background task.
*/
export interface BackgroundMonitor {
/**
* If set to true the monitor is in active mode when the task
* starts. This is equals of issuing a line that matches the
* beginPattern.
*/
activeOnStart?: boolean;
/**
* If matched in the output the start of a background activity is signaled.
*/
beginsPattern: RegExp | BackgroundPattern;
/**
* If matched in the output the end of a background activity is signaled.
*/
endsPattern: RegExp | BackgroundPattern;
}
/**
* Defines a problem matcher
*/
export interface ProblemMatcher {
/**
* The owner of a problem. Defaults to a generated id
* if omitted.
*/
owner?: string;
/**
* The type of documents problems detected by this matcher
* apply to. Default to `ApplyToKind.AllDocuments` if omitted.
*/
applyTo?: ApplyToKind;
/**
* How a file location recognized by a matcher should be interpreted. If omitted the file location
* if `FileLocationKind.Auto`.
*/
fileLocation?: FileLocationKind | string;
/**
* The actual pattern used by the problem matcher.
*/
pattern: ProblemPattern | MultiLineProblemPattern;
/**
* The default severity of a detected problem in the output. Used
* if the `ProblemPattern` doesn't define a severity match group.
*/
severity?: DiagnosticSeverity;
/**
* A background monitor for tasks that are running in the background.
*/
backgound?: BackgroundMonitor;
}
/**
* Controls the behaviour of the terminal's visibility.
*/
export enum RevealKind {
/**
* Always brings the terminal to front if the task is executed.
*/
Always = 1,
/**
* Only brings the terminal to front if a problem is detected executing the task
* (e.g. the task couldn't be started because).
*/
Silent = 2,
/**
* The terminal never comes to front when the task is executed.
*/
Never = 3
}
/**
* Controls terminal specific behaviour.
*/
export interface TerminalBehaviour {
/**
* Controls whether the terminal executing a task is brought to front or not.
* Defaults to `RevealKind.Always`.
*/
reveal?: RevealKind;
/**
* Controls whether the command is echoed in the terminal or not.
*/
echo?: boolean;
}
export interface ProcessOptions {
/**
* The current working directory of the executed program or shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed program or shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
}
export namespace TaskGroup {
/**
* The clean task group
*/
export const Clean: 'clean';
/**
* The build task group
*/
export const Build: 'build';
/**
* The rebuild all task group
*/
export const RebuildAll: 'rebuildAll';
/**
* The test task group
*/
export const Test: 'test';
}
/**
* The supported task groups.
*/
export type TaskGroup = 'clean' | 'build' | 'rebuildAll' | 'test';
/**
* The ProblemMatchers type definition.
*/
export type ProblemMatchers = string | ProblemMatcher | (string | ProblemMatcher)[];
/**
* A task that starts an external process.
*/
export class ProcessTask {
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, problemMatchers?: ProblemMatchers);
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param args arguments to be passed to the process.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, args: string[], problemMatchers?: ProblemMatchers);
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param args arguments to be passed to the process.
* @param options additional options for the started process.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, args: string[], options: ProcessOptions, problemMatchers?: ProblemMatchers);
/**
* The task's name
*/
readonly name: string;
/**
* The task's identifier. If omitted the name is
* used as an identifier.
*/
identifier: string;
/**
* Whether the task is a background task or not.
*/
isBackground: boolean;
/**
* The process to be executed.
*/
readonly process: string;
/**
* The arguments passed to the process. Defaults to an empty array.
*/
args: string[];
/**
* The task group this tasks belongs to. Defaults to undefined meaning
* that the task doesn't belong to any special group.
*/
group?: TaskGroup;
/**
* The process options used when the process is executed.
* Defaults to an empty object literal.
*/
options: ProcessOptions;
/**
* The terminal options. Defaults to an empty object literal.
*/
terminal: TerminalBehaviour;
/**
* The problem matchers attached to the task. Defaults to an empty
* array.
*/
problemMatchers: (string | ProblemMatcher)[];
}
export type ShellOptions = {
/**
* The shell executable.
*/
executable: string;
/**
* The arguments to be passed to the shell executable used to run the task.
*/
shellArgs?: string[];
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env: { [key: string]: string };
};
/**
* A task that executes a shell command.
*/
export class ShellTask {
/**
* Creates a shell task.
*
* @param name the task's name. Is presented in the user interface.
* @param commandLine the command line to execute.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, commandLine: string, problemMatchers?: ProblemMatchers);
/**
* Creates a shell task.
*
* @param name the task's name. Is presented in the user interface.
* @param commandLine the command line to execute.
* @param options additional options used when creating the shell.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, commandLine: string, options: ShellOptions, problemMatchers?: ProblemMatchers);
/**
* The task's name
*/
readonly name: string;
/**
* The task's identifier. If omitted the name is
* used as an identifier.
*/
identifier: string;
/**
* Whether the task is a background task or not.
*/
isBackground: boolean;
/**
* The command line to execute.
*/
readonly commandLine: string;
/**
* The task group this tasks belongs to. Defaults to undefined meaning
* that the task doesn't belong to any special group.
*/
group?: TaskGroup;
/**
* The shell options used when the shell is executed. Defaults to an
* empty object literal.
*/
options: ShellOptions;
/**
* The terminal options. Defaults to an empty object literal.
*/
terminal: TerminalBehaviour;
/**
* The problem matchers attached to the task. Defaults to an empty
* array.
*/
problemMatchers: (string | ProblemMatcher)[];
}
export type Task = ProcessTask | ShellTask;
/**
* A task provider allows to add tasks to the task service.
* A task provider is registerd via #workspace.registerTaskProvider.
*/
export interface TaskProvider {
/**
* Provides additional tasks.
* @param token A cancellation token.
* @return a #TaskSet
*/
provideTasks(token: CancellationToken): ProviderResult<Task[]>;
}
export namespace workspace {
/**
* Register a task provider.
*
* @param provider A task provider.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerTaskProvider(provider: TaskProvider): Disposable;
}
/**
* Namespace describing the environment the editor runs in.
*/
-515
View File
@@ -7,521 +7,6 @@
declare module 'vscode' {
/**
* Defines a problem pattern
*/
export interface ProblemPattern {
/**
* The regular expression to find a problem in the console output of an
* executed task.
*/
regexp: RegExp;
/**
* The match group index of the filename.
*
* Defaults to 1 if omitted.
*/
file?: number;
/**
* The match group index of the problems's location. Valid location
* patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn).
* If omitted the line and colum properties are used.
*/
location?: number;
/**
* The match group index of the problem's line in the source file.
*
* Defaults to 2 if omitted.
*/
line?: number;
/**
* The match group index of the problem's character in the source file.
*
* Defaults to 3 if omitted.
*/
character?: number;
/**
* The match group index of the problem's end line in the source file.
*
* Defaults to undefined. No end line is captured.
*/
endLine?: number;
/**
* The match group index of the problem's end character in the source file.
*
* Defaults to undefined. No end column is captured.
*/
endCharacter?: number;
/**
* The match group index of the problem's severity.
*
* Defaults to undefined. In this case the problem matcher's severity
* is used.
*/
severity?: number;
/**
* The match group index of the problems's code.
*
* Defaults to undefined. No code is captured.
*/
code?: number;
/**
* The match group index of the message. If omitted it defaults
* to 4 if location is specified. Otherwise it defaults to 5.
*/
message?: number;
/**
* Specifies if the last pattern in a multi line problem matcher should
* loop as long as it does match a line consequently. Only valid on the
* last problem pattern in a multi line problem matcher.
*/
loop?: boolean;
}
/**
* A multi line problem pattern.
*/
export type MultiLineProblemPattern = ProblemPattern[];
/**
* The way how the file location is interpreted
*/
export enum FileLocationKind {
/**
* VS Code should decide based on whether the file path found in the
* output is absolute or relative. A relative file path will be treated
* relative to the workspace root.
*/
Auto = 1,
/**
* Always treat the file path relative.
*/
Relative = 2,
/**
* Always treat the file path absolute.
*/
Absolute = 3
}
/**
* Controls to which kind of documents problems are applied.
*/
export enum ApplyToKind {
/**
* Problems are applied to all documents.
*/
AllDocuments = 1,
/**
* Problems are applied to open documents only.
*/
OpenDocuments = 2,
/**
* Problems are applied to closed documents only.
*/
ClosedDocuments = 3
}
/**
* A background monitor pattern
*/
export interface BackgroundPattern {
/**
* The actual regular expression
*/
regexp: RegExp;
/**
* The match group index of the filename. If provided the expression
* is matched for that file only.
*/
file?: number;
}
/**
* A description to control the activity of a problem matcher
* watching a background task.
*/
export interface BackgroundMonitor {
/**
* If set to true the monitor is in active mode when the task
* starts. This is equals of issuing a line that matches the
* beginPattern.
*/
activeOnStart?: boolean;
/**
* If matched in the output the start of a background activity is signaled.
*/
beginsPattern: RegExp | BackgroundPattern;
/**
* If matched in the output the end of a background activity is signaled.
*/
endsPattern: RegExp | BackgroundPattern;
}
/**
* Defines a problem matcher
*/
export interface ProblemMatcher {
/**
* The owner of a problem. Defaults to a generated id
* if omitted.
*/
owner?: string;
/**
* The type of documents problems detected by this matcher
* apply to. Default to `ApplyToKind.AllDocuments` if omitted.
*/
applyTo?: ApplyToKind;
/**
* How a file location recognize by a matcher should be interpreted. If omitted the file location
* if `FileLocationKind.Auto`.
*/
fileLocation?: FileLocationKind | string;
/**
* The actual pattern used by the problem matcher.
*/
pattern: ProblemPattern | MultiLineProblemPattern;
/**
* The default severity of a detected problem in the output. Used
* if the `ProblemPattern` doesn't define a severity match group.
*/
severity?: DiagnosticSeverity;
/**
* A background monitor for tasks that are running in the background.
*/
backgound?: BackgroundMonitor;
}
/**
* Controls the behaviour of the terminal's visibility.
*/
export enum RevealKind {
/**
* Always brings the terminal to front if the task is executed.
*/
Always = 1,
/**
* Only brings the terminal to front if a problem is detected executing the task
* (e.g. the task couldn't be started because).
*/
Silent = 2,
/**
* The terminal never comes to front when the task is executed.
*/
Never = 3
}
/**
* Controls terminal specific behaviour.
*/
export interface TerminalBehaviour {
/**
* Controls whether the terminal executing a task is brought to front or not.
* Defaults to `RevealKind.Always`.
*/
reveal?: RevealKind;
/**
* Controls whether the command is echoed in the terminal or not.
*/
echo?: boolean;
}
export interface ProcessOptions {
/**
* The current working directory of the executed program or shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed program or shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
}
export namespace TaskGroup {
/**
* The clean task group
*/
export const Clean: 'clean';
/**
* The build task group
*/
export const Build: 'build';
/**
* The rebuild all task group
*/
export const RebuildAll: 'rebuildAll';
/**
* The test task group
*/
export const Test: 'test';
}
/**
* The supported task groups.
*/
export type TaskGroup = 'clean' | 'build' | 'rebuildAll' | 'test';
/**
* A task that starts an external process.
*/
export class ProcessTask {
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, ...problemMatchers: ProblemMatcher[]);
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param args arguments to be passed to the process.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, args: string[], ...problemMatchers: ProblemMatcher[]);
/**
* Creates a process task.
*
* @param name the task's name. Is presented in the user interface.
* @param process the process to start.
* @param args arguments to be passed to the process.
* @param options additional options for the started process.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, process: string, args: string[], options: ProcessOptions, ...problemMatchers: ProblemMatcher[]);
/**
* The task's name
*/
readonly name: string;
/**
* The task's identifier. If omitted the name is
* used as an identifier.
*/
identifier: string;
/**
* Whether the task is a background task or not.
*/
isBackground: boolean;
/**
* The process to be executed.
*/
readonly process: string;
/**
* The arguments passed to the process. Defaults to an empty array.
*/
args: string[];
/**
* The task group this tasks belongs to. Defaults to undefined meaning
* that the task doesn't belong to any special group.
*/
group?: TaskGroup;
/**
* The process options used when the process is executed.
* Defaults to an empty object literal.
*/
options: ProcessOptions;
/**
* The terminal options. Defaults to an empty object literal.
*/
terminal: TerminalBehaviour;
/**
* The problem matchers attached to the task. Defaults to an empty
* array.
*/
problemMatchers: ProblemMatcher[];
}
export type ShellOptions = {
/**
* The shell executable.
*/
executable: string;
/**
* The arguments to be passed to the shell executable used to run the task.
*/
shellArgs?: string[];
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env: { [key: string]: string };
};
/**
* A task that executes a shell command.
*/
export class ShellTask {
/**
* Creates a shell task.
*
* @param name the task's name. Is presented in the user interface.
* @param commandLine the command line to execute.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, commandLine: string, ...problemMatchers: ProblemMatcher[]);
/**
* Creates a shell task.
*
* @param name the task's name. Is presented in the user interface.
* @param commandLine the command line to execute.
* @param options additional options used when creating the shell.
* @param problemMatchers the problem matchers to use.
*/
constructor(name: string, commandLine: string, options: ShellOptions, ...problemMatchers: ProblemMatcher[]);
/**
* The task's name
*/
readonly name: string;
/**
* The task's identifier. If omitted the name is
* used as an identifier.
*/
identifier: string;
/**
* Whether the task is a background task or not.
*/
isBackground: boolean;
/**
* The command line to execute.
*/
readonly commandLine: string;
/**
* The task group this tasks belongs to. Defaults to undefined meaning
* that the task doesn't belong to any special group.
*/
group?: TaskGroup;
/**
* The shell options used when the shell is executed. Defaults to an
* empty object literal.
*/
options: ShellOptions;
/**
* The terminal options. Defaults to an empty object literal.
*/
terminal: TerminalBehaviour;
/**
* The problem matchers attached to the task. Defaults to an empty
* array.
*/
problemMatchers: ProblemMatcher[];
}
export type Task = ProcessTask | ShellTask;
/**
* A task provider allows to add tasks to the task service.
* A task provider is registerd via #workspace.registerTaskProvider.
*/
export interface TaskProvider {
/**
* Provides additional tasks.
* @param token A cancellation token.
* @return a #TaskSet
*/
provideTasks(token: CancellationToken): ProviderResult<Task[]>;
}
export namespace workspace {
/**
* Register a task provider.
*
* @param provider A task provider.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerTaskProvider(provider: TaskProvider): Disposable;
}
export namespace window {
export function sampleFunction(): Thenable<any>;
+3 -4
View File
@@ -159,13 +159,13 @@ namespace WathingMatcher {
}
namespace ProblemMatcher {
export function from(values: vscode.ProblemMatcher[]): Problems.ProblemMatcher[] {
export function from(values: (string | vscode.ProblemMatcher)[]): (string | Problems.ProblemMatcher)[] {
if (values === void 0 || values === null) {
return undefined;
}
let result: Problems.ProblemMatcher[];
let result: (string | Problems.ProblemMatcher)[];
for (let value of values) {
let converted = fromSingle(value);
let converted = typeof value === 'string' ? value : fromSingle(value);
if (converted) {
result.push(converted);
}
@@ -186,7 +186,6 @@ namespace ProblemMatcher {
filePrefix: location.prefix,
pattern: ProblemPattern.from(problemMatcher.pattern),
severity: fromDiagnosticSeverity(problemMatcher.severity),
};
return result;
}
+54 -60
View File
@@ -1018,12 +1018,12 @@ export enum RevealKind {
export class BaseTask {
private _name: string;
private _problemMatchers: vscode.ProblemMatcher[];
private _problemMatchers: (string | vscode.ProblemMatcher)[];
private _identifier: string;
private _isBackground: boolean;
private _terminal: vscode.TerminalBehaviour;
constructor(name: string, problemMatchers: vscode.ProblemMatcher[]) {
constructor(name: string, problemMatchers: (string | vscode.ProblemMatcher)[]) {
if (typeof name !== 'string') {
throw illegalArgument('name');
}
@@ -1074,11 +1074,11 @@ export class BaseTask {
this._terminal = value;
}
get problemMatchers(): vscode.ProblemMatcher[] {
get problemMatchers(): (string | vscode.ProblemMatcher)[] {
return this._problemMatchers;
}
set problemMatchers(value: vscode.ProblemMatcher[]) {
set problemMatchers(value: (string | vscode.ProblemMatcher)[]) {
if (!Array.isArray(value)) {
value = [];
}
@@ -1093,6 +1093,12 @@ namespace ProblemMatcher {
}
}
namespace ShellOptions {
export function is(value: any): value is vscode.ShellOptions {
return value && ((typeof value.executable === 'string') || (typeof value.cwd === 'string') || !!value.env);
}
}
export namespace TaskGroup {
/**
* The clean task group
@@ -1126,40 +1132,35 @@ export class ProcessTask extends BaseTask {
private _group: vscode.TaskGroup;
private _options: vscode.ProcessOptions;
private static parseArguments(restArgs: any[]): { args: string[]; options: vscode.ProcessOptions; problemMatchers: vscode.ProblemMatcher[] } {
let args: string[] = [];
let options: vscode.ProcessOptions = undefined;
let problemMatchers: vscode.ProblemMatcher[] = [];
if (!restArgs || restArgs.length === 0) {
return { args, options, problemMatchers };
}
let current: any = restArgs[0];
if (Array.isArray(current)) {
args = current;
restArgs.shift();
current = restArgs[0];
}
if (ProblemMatcher.is(current)) {
problemMatchers = restArgs;
} else if (current) {
options = current;
restArgs.shift();
if (restArgs.length > 0) {
problemMatchers = restArgs;
}
}
return { args, options, problemMatchers };
}
constructor(name: string, process: string, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, args: string[], ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, args: string[], options: vscode.ProcessOptions, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, ...rest: any[]) {
constructor(name: string, process: string, args?: string[], problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, process: string, args: string[] | undefined, options: vscode.ProcessOptions, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, process: string, arg3?: string[], arg4?: vscode.ProcessOptions | vscode.ProblemMatchers, arg5?: vscode.ProblemMatchers) {
if (typeof process !== 'string') {
throw illegalArgument('process');
}
let { args, options, problemMatchers } = ProcessTask.parseArguments(rest);
super(name, problemMatchers);
let args: string[];
let options: vscode.ProcessOptions;
let problemMatchers: vscode.ProblemMatchers;
args = arg3 || [];
if (arg4) {
if (Array.isArray(arg4) || typeof arg4 === 'string' || ProblemMatcher.is(arg4)) {
problemMatchers = arg4;
} else {
options = arg4;
}
}
if (arg5 && !problemMatchers) {
problemMatchers = arg5;
}
let pm: (string | vscode.ProblemMatcher)[];
if (problemMatchers && (typeof problemMatchers === 'string' || ProblemMatcher.is(problemMatchers))) {
pm = [problemMatchers];
} else if (Array.isArray(problemMatchers)) {
pm = problemMatchers;
}
pm = pm || [];
super(name, pm);
this._process = process;
this._args = args;
this._options = options || Object.create(null);
@@ -1203,39 +1204,32 @@ export class ProcessTask extends BaseTask {
}
}
export class ShellTask extends BaseTask {
export class ShellTask extends BaseTask implements vscode.ShellTask {
private _commandLine: string;
private _group: vscode.TaskGroup;
private _options: vscode.ShellOptions;
private static parseArguments(restArgs: any[]): { options: vscode.ShellOptions; problemMatchers: vscode.ProblemMatcher[] } {
let options: vscode.ShellOptions = undefined;
let problemMatchers: vscode.ProblemMatcher[] = [];
if (!restArgs || restArgs.length === 0) {
return { options, problemMatchers };
}
let current: any = restArgs[0];
if (current && !ProblemMatcher.is(current)) {
options = current;
restArgs.shift();
current = restArgs[0];
}
if (ProblemMatcher.is(current)) {
problemMatchers = restArgs;
}
return { options, problemMatchers };
}
constructor(name: string, commandLine: string, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, commandLine: string, options: vscode.ShellOptions, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, commandLine: string, ...rest: any[]) {
constructor(name: string, commandLine: string, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, commandLine: string, options: vscode.ShellOptions, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, commandLine: string, optionsOrProblemMatchers?: vscode.ShellOptions | vscode.ProblemMatchers, problemMatchers?: vscode.ProblemMatchers) {
if (typeof commandLine !== 'string') {
throw illegalArgument('commandLine');
}
let { options, problemMatchers } = ShellTask.parseArguments(rest);
super(name, problemMatchers);
let options: vscode.ShellOptions = undefined;
let pm: (string | vscode.ProblemMatcher)[];
if (ShellOptions.is(optionsOrProblemMatchers)) {
options = optionsOrProblemMatchers;
} else {
problemMatchers = optionsOrProblemMatchers;
}
if (problemMatchers && (typeof problemMatchers === 'string' || ProblemMatcher.is(problemMatchers))) {
pm = [problemMatchers];
} else if (Array.isArray(problemMatchers)) {
pm = problemMatchers;
}
pm = pm || [];
super(name, pm);
this._commandLine = commandLine;
this._options = options || Object.create(null);
}
+1 -1
View File
@@ -175,7 +175,7 @@ export interface Task {
/**
* The problem watchers to use for this task
*/
problemMatchers?: ProblemMatcher[];
problemMatchers?: (string | ProblemMatcher)[];
}
export enum ExecutionEngine {
@@ -791,17 +791,19 @@ class TaskService extends EventEmitter implements ITaskService {
}
private executeTask(task: Task, resolver: ITaskResolver): TPromise<ITaskSummary> {
return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved
let executeResult = this.getTaskSystem().run(task, resolver);
if (executeResult.kind === TaskExecuteKind.Active) {
let active = executeResult.active;
if (active.same && active.background) {
this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame', 'The task is already active and in watch mode. To terminate the task use `F1 > terminate task`'));
} else {
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is already a task running. Terminate it first before executing another task.'), TaskErrors.RunningTask);
return ProblemMatcherRegistry.onReady().then(() => {
return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved
let executeResult = this.getTaskSystem().run(task, resolver);
if (executeResult.kind === TaskExecuteKind.Active) {
let active = executeResult.active;
if (active.same && active.background) {
this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame', 'The task is already active and in watch mode. To terminate the task use `F1 > terminate task`'));
} else {
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is already a task running. Terminate it first before executing another task.'), TaskErrors.RunningTask);
}
}
}
return executeResult.promise;
return executeResult.promise;
});
});
}
@@ -24,7 +24,8 @@ import * as TPath from 'vs/base/common/paths';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ProblemMatcher /*, ProblemPattern, getResource */ } from 'vs/platform/markers/common/problemMatcher';
import { ProblemMatcher, ProblemMatcherRegistry /*, ProblemPattern, getResource */ } from 'vs/platform/markers/common/problemMatcher';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -553,15 +554,22 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
return value.map(s => this.resolveVariable(s));
}
private resolveMatchers<T extends ProblemMatcher>(values: T[]): T[] {
if (values === void 0 || values === null) {
private resolveMatchers(values: (string | ProblemMatcher)[]): ProblemMatcher[] {
if (values === void 0 || values === null || values.length === 0) {
return [];
}
if (values.length === 0) {
return values;
}
let result: T[] = [];
values.forEach((matcher) => {
let result: ProblemMatcher[] = [];
values.forEach((value) => {
let matcher: ProblemMatcher;
if (Types.isString(value)) {
matcher = ProblemMatcherRegistry.get(value);
} else {
matcher = value;
}
if (!matcher) {
this.outputChannel.append(nls.localize('unkownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored'));
return;
}
if (!matcher.filePrefix) {
result.push(matcher);
} else {
@@ -22,7 +22,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher';
import { ProblemMatcher, ProblemMatcherRegistry } from 'vs/platform/markers/common/problemMatcher';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEvents } from 'vs/workbench/parts/tasks/common/problemCollectors';
@@ -335,12 +335,22 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem {
return value.map(s => this.resolveVariable(s));
}
private resolveMatchers<T extends ProblemMatcher>(values: T[]): T[] {
if (values.length === 0) {
return values;
private resolveMatchers(values: (string | ProblemMatcher)[]): ProblemMatcher[] {
if (values === void 0 || values === null || values.length === 0) {
return [];
}
let result: T[] = [];
values.forEach((matcher) => {
let result: ProblemMatcher[] = [];
values.forEach((value) => {
let matcher: ProblemMatcher;
if (Types.isString(value)) {
matcher = ProblemMatcherRegistry.get(value);
} else {
matcher = value;
}
if (!matcher) {
this.outputChannel.append(nls.localize('unkownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored'));
return;
}
if (!matcher.filePrefix) {
result.push(matcher);
} else {
@@ -432,22 +432,29 @@ function assertCommandConfiguration(actual: Tasks.CommandConfiguration, expected
}
}
function assertProblemMatcher(actual: ProblemMatcher, expected: ProblemMatcher) {
if (expected.owner === ProblemMatcherBuilder.DEFAULT_UUID) {
try {
UUID.parse(actual.owner);
} catch (err) {
assert.fail(actual.owner, 'Owner must be a UUID');
}
} else {
assert.strictEqual(actual.owner, expected.owner);
function assertProblemMatcher(actual: string | ProblemMatcher, expected: string | ProblemMatcher) {
assert.strictEqual(typeof actual, typeof expected);
if (typeof actual === 'string' && typeof expected === 'string') {
assert.strictEqual(actual, expected, 'Problem matcher references are different');
return;
}
assert.strictEqual(actual.applyTo, expected.applyTo);
assert.strictEqual(actual.severity, expected.severity);
assert.strictEqual(actual.fileLocation, expected.fileLocation);
assert.strictEqual(actual.filePrefix, expected.filePrefix);
if (actual.pattern && expected.pattern) {
assertProblemPatterns(actual.pattern, expected.pattern);
if (typeof actual !== 'string' && typeof expected !== 'string') {
if (expected.owner === ProblemMatcherBuilder.DEFAULT_UUID) {
try {
UUID.parse(actual.owner);
} catch (err) {
assert.fail(actual.owner, 'Owner must be a UUID');
}
} else {
assert.strictEqual(actual.owner, expected.owner);
}
assert.strictEqual(actual.applyTo, expected.applyTo);
assert.strictEqual(actual.severity, expected.severity);
assert.strictEqual(actual.fileLocation, expected.fileLocation);
assert.strictEqual(actual.filePrefix, expected.filePrefix);
if (actual.pattern && expected.pattern) {
assertProblemPatterns(actual.pattern, expected.pattern);
}
}
}