From 3ea2c216aa42cffa2549301eff73b52f760d9315 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Wed, 24 May 2017 12:29:51 +0200 Subject: [PATCH] More work to make v2 the default --- src/vs/workbench/api/node/extHostTask.ts | 23 ++- .../parts/tasks/browser/quickOpen.ts | 61 +++++++- .../parts/tasks/browser/restartQuickOpen.ts | 2 +- .../parts/tasks/browser/taskQuickOpen.ts | 2 +- .../parts/tasks/browser/terminateQuickOpen.ts | 2 +- .../parts/tasks/common/taskConfiguration.ts | 144 +++++++++++++----- .../parts/tasks/common/taskTemplates.ts | 9 +- src/vs/workbench/parts/tasks/common/tasks.ts | 77 ++++++---- .../electron-browser/task.contribution.ts | 59 +++---- .../electron-browser/terminalTaskSystem.ts | 16 +- .../parts/tasks/node/processTaskSystem.ts | 11 +- .../tasks/test/node/configuration.test.ts | 82 ++++++---- 12 files changed, 332 insertions(+), 156 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index f1c5a8065b8..5f23efc8f80 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -192,26 +192,26 @@ namespace ProblemMatcher { } namespace RevealKind { - export function from(value: vscode.RevealKind): TaskSystem.ShowOutput { + export function from(value: vscode.RevealKind): TaskSystem.RevealKind { if (value === void 0 || value === null) { - return TaskSystem.ShowOutput.Always; + return TaskSystem.RevealKind.Always; } switch (value) { case types.RevealKind.Silent: - return TaskSystem.ShowOutput.Silent; + return TaskSystem.RevealKind.Silent; case types.RevealKind.Never: - return TaskSystem.ShowOutput.Never; + return TaskSystem.RevealKind.Never; } - return TaskSystem.ShowOutput.Always; + return TaskSystem.RevealKind.Always; } } namespace TerminalBehaviour { - export function from(value: vscode.TerminalBehaviour): { showOutput: TaskSystem.ShowOutput, echo: boolean } { + export function from(value: vscode.TerminalBehaviour): TaskSystem.TerminalBehavior { if (value === void 0 || value === null) { - return { showOutput: TaskSystem.ShowOutput.Always, echo: false }; + return { reveal: TaskSystem.RevealKind.Always, echo: false }; } - return { showOutput: RevealKind.from(value.reveal), echo: !!value.echo }; + return { reveal: RevealKind.from(value.reveal), echo: !!value.echo }; } } @@ -302,8 +302,6 @@ namespace Tasks { if (command === void 0) { return undefined; } - let behaviour = TerminalBehaviour.from(task.terminal); - command.echo = behaviour.echo; let result: TaskSystem.Task = { _id: uuidMap.getUUID(task.identifier), _source: { kind: TaskSystem.TaskSourceKind.Extension, detail: extension.id }, @@ -311,7 +309,6 @@ namespace Tasks { identifier: task.identifier, group: types.TaskGroup.is(task.group) ? task.group : undefined, command: command, - showOutput: behaviour.showOutput, isBackground: !!task.isBackground, suppressTaskName: true, problemMatchers: ProblemMatcher.from(task.problemMatchers) @@ -327,7 +324,7 @@ namespace Tasks { name: value.process, args: Strings.from(value.args), isShellCommand: false, - echo: false, + terminal: TerminalBehaviour.from(value.terminal) }; if (value.options) { result.options = CommandOptions.from(value.options); @@ -342,7 +339,7 @@ namespace Tasks { let result: TaskSystem.CommandConfiguration = { name: value.commandLine, isShellCommand: ShellConfiguration.from(value.options), - echo: false + terminal: TerminalBehaviour.from(value.terminal) }; if (value.options) { result.options = CommandOptions.from(value.options); diff --git a/src/vs/workbench/parts/tasks/browser/quickOpen.ts b/src/vs/workbench/parts/tasks/browser/quickOpen.ts index 743413653aa..754d5756a22 100644 --- a/src/vs/workbench/parts/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/quickOpen.ts @@ -7,6 +7,7 @@ import nls = require('vs/nls'); import Filters = require('vs/base/common/filters'); import { TPromise } from 'vs/base/common/winjs.base'; +import { Action, IAction } from 'vs/base/common/actions'; import Quickopen = require('vs/workbench/browser/quickopen'); import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen'); import Model = require('vs/base/parts/quickopen/browser/quickOpenModel'); @@ -14,21 +15,26 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Task, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; +import { ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; export class TaskEntry extends Model.QuickOpenEntry { - constructor(protected taskService: ITaskService, protected task: Task, highlights: Model.IHighlight[] = []) { + constructor(protected taskService: ITaskService, protected _task: Task, highlights: Model.IHighlight[] = []) { super(highlights); - this.task = task; + this._task = _task; } public getLabel(): string { - return this.task.name; + return this._task.name; } public getAriaLabel(): string { return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel()); } + + public get task(): Task { + return this._task; + } } export class TaskGroupEntry extends Model.QuickOpenEntryGroup { @@ -112,4 +118,53 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { autoFocusFirstEntry: !!input }; } +} + +class CustomizeTaskAction extends Action { + + private static ID = 'workbench.action.tasks.customizeTask'; + private static LABEL = nls.localize('customizeTask', "Customize Task"); + + constructor() { + super(CustomizeTaskAction.ID, CustomizeTaskAction.LABEL); + this.updateClass(); + } + + public updateClass(): void { + this.class = 'quick-open-sidebyside-vertical'; + } + + public run(context: any): TPromise { + return TPromise.as(false); + } +} + +export class QuickOpenActionContributor extends ActionBarContributor { + + constructor() { + super(); + } + + public hasActions(context: any): boolean { + const entry = this.getEntry(context); + + return !!entry; + } + + public getActions(context: any): IAction[] { + const actions: Action[] = []; + + const entry = this.getEntry(context); + if (entry && entry.task._source.kind === TaskSourceKind.Extension) { + actions.push(new CustomizeTaskAction()); + } + return actions; + } + + private getEntry(context: any): TaskEntry { + if (!context || !(context.element instanceof TaskEntry)) { + return undefined; + } + return context.element as TaskEntry; + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/browser/restartQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/restartQuickOpen.ts index 2c78bdac7e8..95d4d2bd5dd 100644 --- a/src/vs/workbench/parts/tasks/browser/restartQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/restartQuickOpen.ts @@ -24,7 +24,7 @@ class TaskEntry extends base.TaskEntry { if (mode === QuickOpen.Mode.PREVIEW) { return false; } - this.taskService.restart(this.task._id); + this.taskService.restart(this._task._id); return true; } } diff --git a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts index f32f5d199f9..b6939d7a77c 100644 --- a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts @@ -26,7 +26,7 @@ class TaskEntry extends base.TaskEntry { if (mode === QuickOpen.Mode.PREVIEW) { return false; } - this.taskService.run(this.task); + this.taskService.run(this._task); return true; } } diff --git a/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts index 767e872a446..80fc424f5d0 100644 --- a/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts @@ -24,7 +24,7 @@ class TaskEntry extends base.TaskEntry { if (mode === QuickOpen.Mode.PREVIEW) { return false; } - this.taskService.terminate(this.task._id); + this.taskService.terminate(this._task._id); return true; } } diff --git a/src/vs/workbench/parts/tasks/common/taskConfiguration.ts b/src/vs/workbench/parts/tasks/common/taskConfiguration.ts index 87feaedfd38..b06f6c15bf3 100644 --- a/src/vs/workbench/parts/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/parts/tasks/common/taskConfiguration.ts @@ -189,6 +189,21 @@ export interface BaseTaskRunnerConfiguration { */ echoCommand?: boolean; + /** + * Controls the behavior of the used terminal + */ + terminal?: { + /** + * The terminal should echo the run command. + */ + echo?: boolean; + /** + * Controls whether or not the terminal is reveal if a task + * is executed. + */ + reveal?: string; + }; + /** * If set to false the task name is added as an additional argument to the * command when executed. If set to true the task name is suppressed. If @@ -402,12 +417,19 @@ namespace ShellConfiguration { } namespace CommandConfiguration { + interface TerminalBehavior { + echo?: boolean; + reveal?: string; + } + interface BaseCommandConfiguationShape { command?: string; isShellCommand?: boolean | ShellConfiguration; args?: string[]; options?: ProcessConfig.CommandOptions; echoCommand?: boolean; + showOutput?: string; + terminal?: TerminalBehavior; taskSelector?: string; } @@ -417,6 +439,70 @@ namespace CommandConfiguration { linux?: BaseCommandConfiguationShape; } + export namespace TerminalBehavior { + export function from(this: void, config: BaseCommandConfiguationShape, context: ParseContext): Tasks.TerminalBehavior { + let echo: boolean = undefined; + let reveal: Tasks.RevealKind = undefined; + if (Types.isBoolean(config.echoCommand)) { + echo = config.echoCommand; + } + if (Types.isString(config.showOutput)) { + reveal = Tasks.RevealKind.fromString(config.showOutput); + } + if (config.terminal) { + if (Types.isBoolean(config.terminal.echo)) { + echo = config.terminal.echo; + } + if (Types.isString(config.terminal.reveal)) { + reveal = Tasks.RevealKind.fromString(config.terminal.reveal); + } + } + if (echo === void 0 && reveal === void 0) { + return undefined; + } + return { echo, reveal }; + } + + export function merge(target: Tasks.TerminalBehavior, source: Tasks.TerminalBehavior): Tasks.TerminalBehavior { + if (isEmpty(source)) { + return target; + } + if (isEmpty(target)) { + return source; + } + mergeProperty(target, source, 'echo'); + mergeProperty(target, source, 'reveal'); + return target; + } + + export function fillDefault(value: Tasks.TerminalBehavior): Tasks.TerminalBehavior { + if (value && Object.isFrozen(value)) { + return value; + } + if (value === void 0) { + return { echo: false, reveal: Tasks.RevealKind.Always }; + } + if (value.echo === void 0) { + value.echo = false; + } + if (value.reveal === void 0) { + value.reveal = Tasks.RevealKind.Always; + } + return value; + } + + export function freeze(value: Tasks.TerminalBehavior): void { + if (value === void 0) { + return; + } + Object.freeze(value); + } + + function isEmpty(this: void, value: Tasks.TerminalBehavior): boolean { + return !value || value.echo === void 0 && value.reveal === void 0; + } + } + export function from(this: void, config: CommandConfiguationShape, context: ParseContext): Tasks.CommandConfiguration { let result: Tasks.CommandConfiguration = fromBase(config, context); @@ -439,7 +525,7 @@ namespace CommandConfiguration { let result: Tasks.CommandConfiguration = { name: undefined, isShellCommand: undefined, - echo: undefined + terminal: undefined }; if (Types.isString(config.command)) { result.name = config.command; @@ -464,8 +550,9 @@ namespace CommandConfiguration { if (config.options !== void 0) { result.options = CommandOptions.from(config.options, context); } - if (Types.isBoolean(config.echoCommand)) { - result.echo = config.echoCommand; + let terminal = TerminalBehavior.from(config, context); + if (terminal) { + result.terminal = terminal; } if (Types.isString(config.taskSelector)) { result.taskSelector = config.taskSelector; @@ -474,11 +561,13 @@ namespace CommandConfiguration { } export function isEmpty(value: Tasks.CommandConfiguration): boolean { - return !value || value.name === void 0 && value.isShellCommand === void 0 && value.args === void 0 && CommandOptions.isEmpty(value.options) && value.echo === void 0; + return !value || value.name === void 0 && value.isShellCommand === void 0 && value.args === void 0 && CommandOptions.isEmpty(value.options) && value.terminal === void 0; } - export function onlyEcho(value: Tasks.CommandConfiguration): boolean { - return value && value.echo !== void 0 && value.name === void 0 && value.isShellCommand === void 0 && value.args === void 0 && CommandOptions.isEmpty(value.options); + export function onlyTerminalBehaviour(value: Tasks.CommandConfiguration): boolean { + return value && + value.terminal && (value.terminal.echo !== void 0 || value.terminal.reveal === void 0) && + value.name === void 0 && value.isShellCommand === void 0 && value.args === void 0 && CommandOptions.isEmpty(value.options); } export function merge(target: Tasks.CommandConfiguration, source: Tasks.CommandConfiguration): Tasks.CommandConfiguration { @@ -500,7 +589,7 @@ namespace CommandConfiguration { target.isShellCommand = source.isShellCommand; } - mergeProperty(target, source, 'echo'); + target.terminal = TerminalBehavior.merge(target.terminal, source.terminal); mergeProperty(target, source, 'taskSelector'); if (source.args !== void 0) { if (target.args === void 0) { @@ -520,9 +609,7 @@ namespace CommandConfiguration { if (value.name !== void 0 && value.isShellCommand === void 0) { value.isShellCommand = false; } - if (value.echo === void 0) { - value.echo = false; - } + value.terminal = TerminalBehavior.fillDefault(value.terminal); if (value.args === void 0) { value.args = EMPTY_ARRAY; } @@ -539,6 +626,9 @@ namespace CommandConfiguration { if (value.options) { CommandOptions.freeze(value.options); } + if (value.terminal) { + TerminalBehavior.freeze(value.terminal); + } if (ShellConfiguration.is(value.isShellCommand)) { ShellConfiguration.freeze(value.isShellCommand); } @@ -660,15 +750,16 @@ namespace TaskDescription { let problemMatchers = ProblemMatcherConverter.from(externalTask.problemMatcher, context); let command: Tasks.CommandConfiguration = externalTask.command !== void 0 ? CommandConfiguration.from(externalTask, context) - : externalTask.echoCommand !== void 0 ? { name: undefined, isShellCommand: undefined, echo: !!externalTask.echoCommand } : undefined; + : externalTask.echoCommand !== void 0 + ? { name: undefined, isShellCommand: undefined, terminal: CommandConfiguration.TerminalBehavior.from(externalTask, context) } + : undefined; let identifer = Types.isString(externalTask.identifier) ? externalTask.identifier : taskName; let task: Tasks.Task = { _id: UUID.generateUuid(), _source: source, name: taskName, identifier: identifer, - command, - showOutput: undefined + command }; if (externalTask.command === void 0 && Types.isStringArray(externalTask.args)) { task.args = externalTask.args.slice(); @@ -682,9 +773,6 @@ namespace TaskDescription { if (externalTask.promptOnClose !== void 0) { task.promptOnClose = !!externalTask.promptOnClose; } - if (Types.isString(externalTask.showOutput)) { - task.showOutput = Tasks.ShowOutput.fromString(externalTask.showOutput); - } if (externalTask.command !== void 0) { // if the task has its own command then we suppress the // task name by default. @@ -793,13 +881,13 @@ namespace TaskDescription { if (CommandConfiguration.isEmpty(task.command) && !CommandConfiguration.isEmpty(globals.command) && globals.command.name !== void 0) { task.command = globals.command; } - if (CommandConfiguration.onlyEcho(task.command)) { + if (CommandConfiguration.onlyTerminalBehaviour(task.command)) { // The globals can have a echo set which would override the local echo // Saves the need of a additional fill method. But might be necessary // at some point. - let oldEcho = task.command.echo; + let oldTerminal = Objects.clone(task.command.terminal); CommandConfiguration.merge(task.command, globals.command); - task.command.echo = oldEcho; + task.command.terminal = oldTerminal; } } // promptOnClose is inferred from isBackground if available @@ -809,9 +897,6 @@ namespace TaskDescription { if (task.suppressTaskName === void 0 && globals.suppressTaskName !== void 0) { task.suppressTaskName = globals.suppressTaskName; } - if (task.showOutput === void 0 && globals.showOutput !== void 0) { - task.showOutput = globals.showOutput; - } } export function fillDefaults(task: Tasks.Task): void { @@ -828,9 +913,6 @@ namespace TaskDescription { if (task.isBackground === void 0) { task.isBackground = false; } - if (task.showOutput === void 0) { - task.showOutput = Tasks.ShowOutput.Always; - } if (task.problemMatchers === void 0) { task.problemMatchers = EMPTY_ARRAY; } @@ -876,7 +958,6 @@ namespace TaskDescription { mergeProperty(target, source, 'args'); mergeProperty(target, source, 'isBackground'); mergeProperty(target, source, 'promptOnClose'); - mergeProperty(target, source, 'showOutput'); mergeProperty(target, source, 'dependsOn'); mergeProperty(target, source, 'problemMatchers'); return target; @@ -887,7 +968,6 @@ interface Globals { command?: Tasks.CommandConfiguration; promptOnClose?: boolean; suppressTaskName?: boolean; - showOutput?: Tasks.ShowOutput; } namespace Globals { @@ -916,9 +996,6 @@ namespace Globals { export function fromBase(this: void, config: BaseTaskRunnerConfiguration, context: ParseContext): Globals { let result: Globals = {}; - if (Types.isString(config.showOutput)) { - result.showOutput = Tasks.ShowOutput.fromString(config.showOutput); - } if (config.suppressTaskName !== void 0) { result.suppressTaskName = !!config.suppressTaskName; } @@ -929,7 +1006,7 @@ namespace Globals { } export function isEmpty(value: Globals): boolean { - return !value || value.command === void 0 && value.promptOnClose === void 0 && value.showOutput === void 0 && value.suppressTaskName === void 0; + return !value || value.command === void 0 && value.promptOnClose === void 0 && value.suppressTaskName === void 0; } export function merge(target: Globals, source: Globals): Globals { @@ -941,7 +1018,6 @@ namespace Globals { } mergeProperty(target, source, 'promptOnClose'); mergeProperty(target, source, 'suppressTaskName'); - mergeProperty(target, source, 'showOutput'); return target; } @@ -952,9 +1028,6 @@ namespace Globals { if (value.suppressTaskName === void 0) { value.suppressTaskName = false; } - if (value.showOutput === void 0) { - value.showOutput = Tasks.ShowOutput.Always; - } if (value.promptOnClose === void 0) { value.promptOnClose = true; } @@ -1059,7 +1132,6 @@ class ConfigurationParser { group: Tasks.TaskGroup.Build, command: undefined, isBackground: isBackground, - showOutput: undefined, suppressTaskName: true, // this must be true since we infer the task from the global data. problemMatchers: matchers }; diff --git a/src/vs/workbench/parts/tasks/common/taskTemplates.ts b/src/vs/workbench/parts/tasks/common/taskTemplates.ts index d153e784935..0d7253582b8 100644 --- a/src/vs/workbench/parts/tasks/common/taskTemplates.ts +++ b/src/vs/workbench/parts/tasks/common/taskTemplates.ts @@ -179,8 +179,13 @@ const command: TaskEntry = { '\t// See https://go.microsoft.com/fwlink/?LinkId=733558', '\t// for the documentation about the tasks.json format', '\t"version": "2.0.0",', - '\t"command": "echo \"Hello World\"",', - '\t"isShellCommand": true,', + '\t"tasks": [', + '\t\t{', + '\t\t\t"taskName": "echo",', + '\t\t\t"command": "echo Hello",', + '\t\t\t"isShellCommand": true', + '\t\t}', + '\t]', '}' ].join('\n') }; diff --git a/src/vs/workbench/parts/tasks/common/tasks.ts b/src/vs/workbench/parts/tasks/common/tasks.ts index c7b3d4ebf9b..4b3031da91f 100644 --- a/src/vs/workbench/parts/tasks/common/tasks.ts +++ b/src/vs/workbench/parts/tasks/common/tasks.ts @@ -41,6 +41,52 @@ export namespace ShellConfiguration { } } +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 +} + +export namespace RevealKind { + export function fromString(value: string): RevealKind { + switch (value.toLowerCase()) { + case 'always': + return RevealKind.Always; + case 'silent': + return RevealKind.Silent; + case 'never': + return RevealKind.Never; + default: + return RevealKind.Always; + } + } +} + +export interface TerminalBehavior { + /** + * Controls whether the terminal executing a task is brought to front or not. + * Defaults to `RevealKind.Always`. + */ + reveal: RevealKind; + + /** + * Controls whether the executed command is printed to the output window or terminal as well. + */ + echo: boolean; +} + export interface CommandConfiguration { /** * The command to execute @@ -68,30 +114,9 @@ export interface CommandConfiguration { taskSelector?: string; /** - * Controls whether the executed command is printed to the output windows as well. + * Describes how the terminal is supposed to behave. */ - echo: boolean; -} - -export enum ShowOutput { - Always = 1, - Silent = 2, - Never = 3 -} - -export namespace ShowOutput { - export function fromString(value: string): ShowOutput { - value = value.toLowerCase(); - if (value === 'always') { - return ShowOutput.Always; - } else if (value === 'silent') { - return ShowOutput.Silent; - } else if (value === 'never') { - return ShowOutput.Never; - } else { - return undefined; - } - } + terminal: TerminalBehavior; } export namespace TaskGroup { @@ -177,12 +202,6 @@ export interface Task { */ promptOnClose?: boolean; - /** - * Controls whether the output of the running tasks is shown or not. Default - * value is "always". - */ - showOutput: ShowOutput; - /** * The other tasks this task depends on. */ diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index ac6c9429c55..98b390f2f21 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -65,11 +65,12 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output'; +import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; import { ITaskSystem, ITaskResolver, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem'; -import { Task, TaskSet, TaskGroup, ExecutionEngine, ShowOutput, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks'; +import { Task, TaskSet, TaskGroup, ExecutionEngine, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService, TaskServiceEvents, ITaskProvider } from 'vs/workbench/parts/tasks/common/taskService'; import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates'; @@ -77,6 +78,7 @@ import * as TaskConfig from 'vs/workbench/parts/tasks/common/taskConfiguration'; import { ProcessTaskSystem } from 'vs/workbench/parts/tasks/node/processTaskSystem'; import { TerminalTaskSystem } from './terminalTaskSystem'; import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector'; +import { QuickOpenActionContributor } from '../browser/quickOpen'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -758,7 +760,6 @@ class TaskService extends EventEmitter implements ITaskService { identifier: id, dependsOn: primaryTasks.map(task => task._id), command: undefined, - showOutput: ShowOutput.Never }; return { task, resolver }; } @@ -867,30 +868,32 @@ class TaskService extends EventEmitter implements ITaskService { } private getTaskSets(): TPromise { - return new TPromise((resolve, reject) => { - let result: TaskSet[] = []; - let counter: number = 0; - let done = (value: TaskSet) => { - if (value) { - result.push(value); - } - if (--counter === 0) { + return this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask').then(() => { + return new TPromise((resolve, reject) => { + let result: TaskSet[] = []; + let counter: number = 0; + let done = (value: TaskSet) => { + if (value) { + result.push(value); + } + if (--counter === 0) { + resolve(result); + } + }; + let error = () => { + if (--counter === 0) { + resolve(result); + } + }; + if (this.getExecutionEngine() === ExecutionEngine.Terminal && this._providers.size > 0) { + this._providers.forEach((provider) => { + counter++; + provider.provideTasks().done(done, error); + }); + } else { resolve(result); } - }; - let error = () => { - if (--counter === 0) { - resolve(result); - } - }; - if (this.getExecutionEngine() === ExecutionEngine.Terminal && this._providers.size > 0) { - this._providers.forEach((provider) => { - counter++; - provider.provideTasks().done(done, error); - }); - } else { - resolve(result); - } + }); }).then((result) => { return this.getWorkspaceTasks().then((workspaceTaskResult) => { let workspaceTasksToDelete: Task[] = []; @@ -1018,10 +1021,7 @@ class TaskService extends EventEmitter implements ITaskService { configPromise = TPromise.as({ config, hasErrors: false }); } } else { - configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { - let hasErrors = this.printStderr(value.stderr); - return { config: value.config, hasErrors }; - }); + configPromise = TPromise.as({ config, hasErrors: false }); } } return configPromise.then((resolved) => { @@ -1326,6 +1326,9 @@ quickOpenRegistry.registerQuickOpenHandler( ) ); +const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); +actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor); + // Status bar let statusbarRegistry = Registry.as(StatusbarExtensions.Statusbar); statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(StatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */)); diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index 00b2950731f..504d0114385 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -33,7 +33,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { ITerminalService, ITerminalInstance, IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal'; import { IOutputService, IOutputChannel } from 'vs/workbench/parts/output/common/output'; import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEvents } from 'vs/workbench/parts/tasks/common/problemCollectors'; -import { Task, ShowOutput, CommandOptions, ShellConfiguration } from 'vs/workbench/parts/tasks/common/tasks'; +import { Task, RevealKind, CommandOptions, ShellConfiguration } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, ITaskResolver, TelemetryEvent, Triggers, TaskSystemEvents, TaskEvent, TaskType @@ -134,7 +134,8 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { public run(task: Task, resolver: ITaskResolver, trigger: string = Triggers.command): ITaskExecuteResult { let terminalData = this.activeTasks[task._id]; if (terminalData && terminalData.promise) { - if (task.showOutput === ShowOutput.Always) { + let reveal = task.command.terminal.reveal; + if (reveal === RevealKind.Always) { terminalData.terminal.setVisible(true); } return { kind: TaskExecuteKind.Active, active: { same: true, background: task.isBackground }, promise: terminalData.promise }; @@ -288,7 +289,8 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { this.emit(TaskSystemEvents.Inactive, event); } eventCounter = 0; - if (exitCode && exitCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) { + let reveal = task.command.terminal.reveal; + if (exitCode && exitCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && reveal !== RevealKind.Never) { this.terminalService.setActiveInstance(terminal); this.terminalService.showPanel(false); } @@ -330,7 +332,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { }); } this.terminalService.setActiveInstance(terminal); - if (task.showOutput === ShowOutput.Always) { + if (task.command.terminal.reveal === RevealKind.Always) { this.terminalService.showPanel(false); } this.activeTasks[task._id] = { terminal, task, promise }; @@ -364,7 +366,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { let options = this.resolveOptions(task.command.options); let { command, args } = this.resolveCommandAndArgs(task); let terminalName = nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', task.name); - let waitOnExit = task.showOutput !== ShowOutput.Never || !task.isBackground; + let waitOnExit = task.command.terminal.reveal !== RevealKind.Never || !task.isBackground; let shellLaunchConfig: IShellLaunchConfig = undefined; if (task.command.isShellCommand) { if (Platform.isWindows && ((options.cwd && TPath.isUNC(options.cwd)) || (!options.cwd && TPath.isUNC(process.cwd())))) { @@ -413,7 +415,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { }); shellArgs.push(commandLine); shellLaunchConfig.args = Platform.isWindows ? shellArgs.join(' ') : shellArgs; - if (task.command.echo) { + if (task.command.terminal.echo) { shellLaunchConfig.initialText = `> ${commandLine}`; } } else { @@ -427,7 +429,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { args, waitOnExit }; - if (task.command.echo) { + if (task.command.terminal.echo) { let getArgsToEcho = (args: string | string[]): string => { if (!args || args.length === 0) { return ''; diff --git a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts index 9cc26f22205..848368e6dc4 100644 --- a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts @@ -29,7 +29,7 @@ import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEv import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TelemetryEvent, Triggers, TaskSystemEvents, TaskEvent, TaskType } from 'vs/workbench/parts/tasks/common/taskSystem'; -import { Task, CommandOptions, ShowOutput, CommandConfiguration } from 'vs/workbench/parts/tasks/common/tasks'; +import { Task, CommandOptions, RevealKind, CommandConfiguration } from 'vs/workbench/parts/tasks/common/tasks'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -178,11 +178,12 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { this.childProcess = new LineProcess(command, args, !!commandConfig.isShellCommand, this.resolveOptions(commandConfig.options)); telemetryEvent.command = this.childProcess.getSanitizedCommand(); // we have no problem matchers defined. So show the output log - if (task.showOutput === ShowOutput.Always || (task.showOutput === ShowOutput.Silent && task.problemMatchers.length === 0)) { + let reveal = task.command.terminal.reveal; + if (reveal === RevealKind.Always || (reveal === RevealKind.Silent && task.problemMatchers.length === 0)) { this.showOutput(); } - if (commandConfig.echo) { + if (commandConfig.terminal.echo) { let prompt: string = Platform.isWindows ? '>' : '$'; this.log(`running command${prompt} ${command} ${args.join(' ')}`); } @@ -214,7 +215,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { if (!this.checkTerminated(task, success)) { this.log(nls.localize('TaskRunnerSystem.watchingBuildTaskFinished', '\nWatching build tasks has finished.')); } - if (success.cmdCode && success.cmdCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) { + if (success.cmdCode && success.cmdCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && reveal !== RevealKind.Never) { this.showOutput(); } taskSummary.exitCode = success.cmdCode; @@ -258,7 +259,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { startStopProblemMatcher.dispose(); this.checkTerminated(task, success); this.emit(TaskSystemEvents.Inactive, event); - if (success.cmdCode && success.cmdCode === 1 && startStopProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) { + if (success.cmdCode && success.cmdCode === 1 && startStopProblemMatcher.numberOfMatches === 0 && reveal !== RevealKind.Never) { this.showOutput(); } taskSummary.exitCode = success.cmdCode; diff --git a/src/vs/workbench/parts/tasks/test/node/configuration.test.ts b/src/vs/workbench/parts/tasks/test/node/configuration.test.ts index 40ef9ddda1d..091899e941a 100644 --- a/src/vs/workbench/parts/tasks/test/node/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/node/configuration.test.ts @@ -68,10 +68,32 @@ class ConfiguationBuilder { } } +class TerminalBehaviorBuilder { + + public result: Tasks.TerminalBehavior; + + constructor(public parent: CommandConfigurationBuilder) { + this.result = { echo: false, reveal: Tasks.RevealKind.Always }; + } + + public echo(value: boolean): TerminalBehaviorBuilder { + this.result.echo = value; + return this; + } + + public reveal(value: Tasks.RevealKind): TerminalBehaviorBuilder { + this.result.reveal = value; + return this; + } +} + class CommandConfigurationBuilder { public result: Tasks.CommandConfiguration; + private terminalBuilder: TerminalBehaviorBuilder; + constructor(public parent: TaskBuilder, command: string) { + this.terminalBuilder = new TerminalBehaviorBuilder(this); this.result = { name: command, isShellCommand: false, @@ -79,7 +101,7 @@ class CommandConfigurationBuilder { options: { cwd: '${workspaceRoot}' }, - echo: false + terminal: this.terminalBuilder.result }; } @@ -103,15 +125,14 @@ class CommandConfigurationBuilder { return this; } - public echo(value: boolean): CommandConfigurationBuilder { - this.result.echo = value; - return this; - } - public taskSelector(value: string): CommandConfigurationBuilder { this.result.taskSelector = value; return this; } + + public terminal(): TerminalBehaviorBuilder { + return this.terminalBuilder; + } } class TaskBuilder { @@ -127,7 +148,6 @@ class TaskBuilder { identifier: name, name: name, command: this.commandBuilder.result, - showOutput: Tasks.ShowOutput.Always, suppressTaskName: false, isBackground: false, promptOnClose: true, @@ -150,11 +170,6 @@ class TaskBuilder { return this; } - public showOutput(value: Tasks.ShowOutput): TaskBuilder { - this.result.showOutput = value; - return this; - } - public suppressTaskName(value: boolean): TaskBuilder { this.result.suppressTaskName = value; return this; @@ -401,7 +416,6 @@ function assertTask(actual: Tasks.Task, expected: Tasks.Task) { assert.ok(actual._id); assert.strictEqual(actual.name, expected.name, 'name'); assertCommandConfiguration(actual.command, expected.command); - assert.strictEqual(actual.showOutput, expected.showOutput, 'showOutput'); assert.strictEqual(actual.suppressTaskName, expected.suppressTaskName, 'suppressTaskName'); assert.strictEqual(actual.isBackground, expected.isBackground, 'isBackground'); assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose'); @@ -417,6 +431,7 @@ function assertTask(actual: Tasks.Task, expected: Tasks.Task) { function assertCommandConfiguration(actual: Tasks.CommandConfiguration, expected: Tasks.CommandConfiguration) { assert.strictEqual(typeof actual, typeof expected); if (actual && expected) { + assertTerminalBehavior(actual.terminal, expected.terminal); assert.strictEqual(actual.name, expected.name, 'name'); assert.strictEqual(actual.isShellCommand, expected.isShellCommand, 'isShellCommand'); assert.deepEqual(actual.args, expected.args, 'args'); @@ -428,11 +443,18 @@ function assertCommandConfiguration(actual: Tasks.CommandConfiguration, expected assert.deepEqual(actual.options.env, expected.options.env, 'env'); } } - assert.strictEqual(actual.echo, expected.echo, 'echo'); assert.strictEqual(actual.taskSelector, expected.taskSelector, 'taskSelector'); } } +function assertTerminalBehavior(actual: Tasks.TerminalBehavior, expected: Tasks.TerminalBehavior) { + assert.strictEqual(typeof actual, typeof expected); + if (actual && expected) { + assert.strictEqual(actual.echo, expected.echo); + assert.strictEqual(actual.reveal, expected.reveal); + } +} + function assertProblemMatcher(actual: string | ProblemMatcher, expected: string | ProblemMatcher) { assert.strictEqual(typeof actual, typeof expected); if (typeof actual === 'string' && typeof expected === 'string') { @@ -525,7 +547,7 @@ suite('Tasks Configuration parsing tests', () => { task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). suppressTaskName(true). - showOutput(Tasks.ShowOutput.Silent); + command().terminal().reveal(Tasks.RevealKind.Silent); testConfiguration( { version: '0.1.0', @@ -590,7 +612,7 @@ suite('Tasks Configuration parsing tests', () => { task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). suppressTaskName(true). - showOutput(Tasks.ShowOutput.Never); + command().terminal().reveal(Tasks.RevealKind.Never); testConfiguration( { version: '0.1.0', @@ -607,7 +629,7 @@ suite('Tasks Configuration parsing tests', () => { task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). suppressTaskName(true). - command(). + command().terminal(). echo(true); testConfiguration( { @@ -759,8 +781,8 @@ suite('Tasks Configuration parsing tests', () => { builder. task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). - showOutput(Platform.isWindows ? Tasks.ShowOutput.Always : Tasks.ShowOutput.Never). - suppressTaskName(true); + suppressTaskName(true). + command().terminal().reveal(Platform.isWindows ? Tasks.RevealKind.Always : Tasks.RevealKind.Never); let external: ExternalTaskRunnerConfiguration = { version: '0.1.0', command: 'tsc', @@ -778,7 +800,7 @@ suite('Tasks Configuration parsing tests', () => { task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). suppressTaskName(true). - command(). + command().terminal(). echo(Platform.isWindows ? false : true); let external: ExternalTaskRunnerConfiguration = { version: '0.1.0', @@ -903,12 +925,11 @@ suite('Tasks Configuration parsing tests', () => { let builder = new ConfiguationBuilder(); builder.task('test', 'tsc'). group(Tasks.TaskGroup.Test). - showOutput(Tasks.ShowOutput.Never). args(['--p']). isBackground(true). promptOnClose(false). - command(). - echo(true); + command().terminal(). + echo(true).reveal(Tasks.RevealKind.Never); testConfiguration(external, builder); }); @@ -928,9 +949,8 @@ suite('Tasks Configuration parsing tests', () => { let builder = new ConfiguationBuilder(); builder.task('test', 'tsc'). group(Tasks.TaskGroup.Test). - showOutput(Tasks.ShowOutput.Never). - command(). - echo(true); + command().terminal(). + echo(true).reveal(Tasks.RevealKind.Never); testConfiguration(external, builder); }); @@ -1392,15 +1412,17 @@ suite('Bugs / regression tests', () => { let builder = new ConfiguationBuilder(); if (Platform.isWindows) { builder.task('composeForDebug', 'powershell'). - suppressTaskName(true).showOutput(Tasks.ShowOutput.Always). + suppressTaskName(true). args(['-ExecutionPolicy', 'RemoteSigned', '.\\dockerTask.ps1', '-ComposeForDebug', '-Environment', 'debug']). - command().echo(true).options({ cwd: '${workspaceRoot}' }); + command().options({ cwd: '${workspaceRoot}' }). + terminal().echo(true).reveal(Tasks.RevealKind.Always); testConfiguration(external, builder); } else if (Platform.isMacintosh) { builder.task('composeForDebug', '/bin/bash'). - suppressTaskName(true).showOutput(Tasks.ShowOutput.Always). + suppressTaskName(true). args(['-c', './dockerTask.sh composeForDebug debug']). - command().options({ cwd: '${workspaceRoot}' }); + command().options({ cwd: '${workspaceRoot}' }). + terminal().reveal(Tasks.RevealKind.Always); testConfiguration(external, builder); } });