diff --git a/src/vs/workbench/parts/tasks/browser/quickOpen.ts b/src/vs/workbench/parts/tasks/browser/quickOpen.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc2df2f1c4044a7b7bf38ff6066b639809cae917 --- /dev/null +++ b/src/vs/workbench/parts/tasks/browser/quickOpen.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import nls = require('vs/nls'); +import Filters = require('vs/base/common/filters'); +import { TPromise } from 'vs/base/common/winjs.base'; +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'); +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; + +import { Task } from 'vs/workbench/parts/tasks/common/tasks'; +import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; + +export class TaskEntry extends Model.QuickOpenEntry { + + constructor(protected taskService: ITaskService, protected task: Task, highlights: Model.IHighlight[] = []) { + super(highlights); + this.task = task; + } + + public getLabel(): string { + return this.task.name; + } + + public getAriaLabel(): string { + return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel()); + } +} + +export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { + + constructor( + @IQuickOpenService protected quickOpenService: IQuickOpenService, + @ITaskService protected taskService: ITaskService + ) { + super(); + + this.quickOpenService = quickOpenService; + this.taskService = taskService; + } + + public getResults(input: string): TPromise { + return this.getTasks().then(tasks => tasks + .sort((a, b) => a.name.localeCompare(b.name)) + .map(task => ({ task: task, highlights: Filters.matchesContiguousSubString(input, task.name) })) + .filter(({ highlights }) => !!highlights) + .map(({ task, highlights }) => this.createEntry(this.taskService, task, highlights)) + , _ => []).then(e => new Model.QuickOpenModel(e)); + } + + protected abstract getTasks(): TPromise; + + protected abstract createEntry(taskService: ITaskService, task: Task, highlights: Model.IHighlight[]): TaskEntry; + + public getClass(): string { + return null; + } + + public canRun(): boolean { + return true; + } + + public getAutoFocus(input: string): QuickOpen.IAutoFocus { + return { + autoFocusFirstEntry: !!input + }; + } + + public onClose(canceled: boolean): void { + return; + } + + public getGroupLabel(): string { + return null; + } +} \ 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 new file mode 100644 index 0000000000000000000000000000000000000000..9a8ee28964a28eac2a1b8f70b14e9f7b64eb7f3d --- /dev/null +++ b/src/vs/workbench/parts/tasks/browser/restartQuickOpen.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import nls = require('vs/nls'); +import { TPromise } from 'vs/base/common/winjs.base'; +import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen'); +import Model = require('vs/base/parts/quickopen/browser/quickOpenModel'); +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; + +import { Task } from 'vs/workbench/parts/tasks/common/tasks'; +import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; + +import * as base from './quickOpen'; + +class TaskEntry extends base.TaskEntry { + constructor(taskService: ITaskService, task: Task, highlights: Model.IHighlight[] = []) { + super(taskService, task, highlights); + } + + public getAriaLabel(): string { + return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel()); + } + + public run(mode: QuickOpen.Mode, context: Model.IContext): boolean { + if (mode === QuickOpen.Mode.PREVIEW) { + return false; + } + this.taskService.restart(this.task._id); + return true; + } +} + +export class QuickOpenHandler extends base.QuickOpenHandler { + constructor( + @IQuickOpenService quickOpenService: IQuickOpenService, + @ITaskService taskService: ITaskService + ) { + super(quickOpenService, taskService); + } + + public getAriaLabel(): string { + return nls.localize('tasksAriaLabel', "Type the name of a task to restart"); + } + + protected getTasks(): TPromise { + return this.taskService.getActiveTasks(); + } + + protected createEntry(taskService: ITaskService, task: Task, highlights: Model.IHighlight[]): base.TaskEntry { + return new TaskEntry(taskService, task, highlights); + } + + public getEmptyLabel(searchString: string): string { + if (searchString.length > 0) { + return nls.localize('noTasksMatching', "No tasks matching"); + } + return nls.localize('noTasksFound', "No tasks to restart found"); + } +} diff --git a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts index 7ee2cec474b875c2d75215fd1cf874b32bc00c1b..80d951b898d486837b6eb29c70eb54654073be86 100644 --- a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts @@ -5,9 +5,7 @@ 'use strict'; import nls = require('vs/nls'); -import Filters = require('vs/base/common/filters'); import { TPromise } from 'vs/base/common/winjs.base'; -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'); import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -15,19 +13,11 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Task } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; -class TaskEntry extends Model.QuickOpenEntry { - - private taskService: ITaskService; - private task: Task; +import * as base from './quickOpen'; +class TaskEntry extends base.TaskEntry { constructor(taskService: ITaskService, task: Task, highlights: Model.IHighlight[] = []) { - super(highlights); - this.taskService = taskService; - this.task = task; - } - - public getLabel(): string { - return this.task.name; + super(taskService, task, highlights); } public getAriaLabel(): string { @@ -43,54 +33,24 @@ class TaskEntry extends Model.QuickOpenEntry { } } -export class QuickOpenHandler extends Quickopen.QuickOpenHandler { - - private quickOpenService: IQuickOpenService; - private taskService: ITaskService; - +export class QuickOpenHandler extends base.QuickOpenHandler { constructor( @IQuickOpenService quickOpenService: IQuickOpenService, @ITaskService taskService: ITaskService ) { - super(); - - this.quickOpenService = quickOpenService; - this.taskService = taskService; + super(quickOpenService, taskService); } public getAriaLabel(): string { return nls.localize('tasksAriaLabel', "Type the name of a task to run"); } - public getResults(input: string): TPromise { - return this.taskService.tasks().then(tasks => tasks - .sort((a, b) => a.name.localeCompare(b.name)) - .map(task => ({ task: task, highlights: Filters.matchesContiguousSubString(input, task.name) })) - .filter(({ highlights }) => !!highlights) - .map(({ task, highlights }) => new TaskEntry(this.taskService, task, highlights)) - , _ => []).then(e => new Model.QuickOpenModel(e)); - } - - public getClass(): string { - return null; + protected getTasks(): TPromise { + return this.taskService.tasks(); } - public canRun(): boolean { - return true; - } - - public getAutoFocus(input: string): QuickOpen.IAutoFocus { - return { - autoFocusFirstEntry: !!input - }; - } - - public onClose(canceled: boolean): void { - return; - } - - public getGroupLabel(): string { - return null; + protected createEntry(taskService: ITaskService, task: Task, highlights: Model.IHighlight[]): base.TaskEntry { + return new TaskEntry(taskService, task, highlights); } public getEmptyLabel(searchString: string): string { @@ -99,4 +59,4 @@ export class QuickOpenHandler extends Quickopen.QuickOpenHandler { } return nls.localize('noTasksFound', "No tasks found"); } -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts index af80138ff2b0dd86c7ec1006bd02adc93c6cdcb2..767e872a446fb3a133ecf2d71d670a4ab90c1fba 100644 --- a/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/terminateQuickOpen.ts @@ -5,9 +5,7 @@ 'use strict'; import nls = require('vs/nls'); -import Filters = require('vs/base/common/filters'); import { TPromise } from 'vs/base/common/winjs.base'; -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'); import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -15,23 +13,11 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Task } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; -class TaskEntry extends Model.QuickOpenEntry { - - private taskService: ITaskService; - private task: Task; +import * as base from './quickOpen'; +class TaskEntry extends base.TaskEntry { constructor(taskService: ITaskService, task: Task, highlights: Model.IHighlight[] = []) { - super(highlights); - this.taskService = taskService; - this.task = task; - } - - public getLabel(): string { - return this.task.name; - } - - public getAriaLabel(): string { - return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel()); + super(taskService, task, highlights); } public run(mode: QuickOpen.Mode, context: Model.IContext): boolean { @@ -43,54 +29,24 @@ class TaskEntry extends Model.QuickOpenEntry { } } -export class QuickOpenHandler extends Quickopen.QuickOpenHandler { - - private quickOpenService: IQuickOpenService; - private taskService: ITaskService; - +export class QuickOpenHandler extends base.QuickOpenHandler { constructor( @IQuickOpenService quickOpenService: IQuickOpenService, @ITaskService taskService: ITaskService ) { - super(); - - this.quickOpenService = quickOpenService; - this.taskService = taskService; + super(quickOpenService, taskService); } public getAriaLabel(): string { return nls.localize('tasksAriaLabel', "Type the name of a task to terminate"); } - public getResults(input: string): TPromise { - return this.taskService.getActiveTasks().then(tasks => tasks - .sort((a, b) => a.name.localeCompare(b.name)) - .map(task => ({ task: task, highlights: Filters.matchesContiguousSubString(input, task.name) })) - .filter(({ highlights }) => !!highlights) - .map(({ task, highlights }) => new TaskEntry(this.taskService, task, highlights)) - , _ => []).then(e => new Model.QuickOpenModel(e)); - } - - public getClass(): string { - return null; - } - - public canRun(): boolean { - return true; - } - - public getAutoFocus(input: string): QuickOpen.IAutoFocus { - return { - autoFocusFirstEntry: !!input - }; - } - - public onClose(canceled: boolean): void { - return; + protected getTasks(): TPromise { + return this.taskService.getActiveTasks(); } - public getGroupLabel(): string { - return null; + protected createEntry(taskService: ITaskService, task: Task, highlights: Model.IHighlight[]): base.TaskEntry { + return new TaskEntry(taskService, task, highlights); } public getEmptyLabel(searchString: string): string { diff --git a/src/vs/workbench/parts/tasks/common/taskService.ts b/src/vs/workbench/parts/tasks/common/taskService.ts index 2dd95e1c0c52f468465635e6fe8a21a8984e9ffd..53f92ee18ee8b4a47f124a4657a207f491469bcb 100644 --- a/src/vs/workbench/parts/tasks/common/taskService.ts +++ b/src/vs/workbench/parts/tasks/common/taskService.ts @@ -38,7 +38,8 @@ export interface ITaskService extends IEventEmitter { inTerminal(): boolean; isActive(): TPromise; getActiveTasks(): TPromise; - terminate(id: string): TPromise; + restart(task: string | Task): void; + terminate(task: string | Task): TPromise; terminateAll(): TPromise; tasks(): TPromise; 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 89159e2459fc872f7ac8a2d228d43c0b5321f930..0cade174be6859c38c8ebcbd5fd0ebd31ce3a7a5 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -11,7 +11,7 @@ import 'vs/workbench/parts/tasks/browser/terminateQuickOpen'; import * as nls from 'vs/nls'; -import { TPromise, Promise } from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import Severity from 'vs/base/common/severity'; import * as Objects from 'vs/base/common/objects'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -562,6 +562,10 @@ class TaskService extends EventEmitter implements ITaskService { this.runTaskCommand(accessor, arg); }); + CommandsRegistry.registerCommand('workbench.action.tasks.restartTask', (accessor, arg) => { + this.runRestartTaskCommand(accessor, arg); + }); + CommandsRegistry.registerCommand('workbench.action.tasks.terminate', (accessor, arg) => { this.runTerminateCommand(); }); @@ -775,13 +779,31 @@ class TaskService extends EventEmitter implements ITaskService { }); } + public restart(task: string | Task): void { + if (!this._taskSystem) { + return; + } + const id: string = Types.isString(task) ? task : task._id; + this._taskSystem.terminate(id).then((response) => { + if (response.success) { + this.emit(TaskServiceEvents.Terminated, {}); + this.run(task); + } else { + this.messageService.show(Severity.Warning, nls.localize('TaskSystem.restartFailed', 'Failed to terminate and restart task {0}', Types.isString(task) ? task : task.name)); + } + return response; + }); + } + public terminate(task: string | Task): TPromise { if (!this._taskSystem) { return TPromise.as({ success: true }); } const id: string = Types.isString(task) ? task : task._id; return this._taskSystem.terminate(id).then((response) => { - this.emit(TaskServiceEvents.Terminated, {}); + if (response.success) { + this.emit(TaskServiceEvents.Terminated, {}); + } return response; }); } @@ -1095,35 +1117,59 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (this.inTerminal()) { - if (!this._taskSystem) { - return; - } - let activeTasks = this._taskSystem.getActiveTasks(); - if (activeTasks.length === 0) { - return; - } - if (activeTasks.length === 1) { - this._taskSystem.terminate(activeTasks[0]._id); - } else { - this.quickOpenService.show('terminate task '); - } + this.getActiveTasks().then((activeTasks) => { + if (activeTasks.length === 0) { + return; + } + if (activeTasks.length === 1) { + this.terminate(activeTasks[0]); + } else { + this.quickOpenService.show('terminate task '); + } + }); } else { this.isActive().then((active) => { if (active) { this.terminateAll().then((response) => { if (response.success) { - return undefined; - } else if (response.code && response.code === TerminateResponseCode.ProcessNotFound) { + return; + } + if (response.code && response.code === TerminateResponseCode.ProcessNotFound) { this.messageService.show(Severity.Error, nls.localize('TerminateAction.noProcess', 'The launched process doesn\'t exist anymore. If the task spawned background tasks exiting VS Code might result in orphaned processes.')); - return undefined; } else { - return Promise.wrapError(nls.localize('TerminateAction.failed', 'Failed to terminate running task')); + this.messageService.show(Severity.Error, nls.localize('TerminateAction.failed', 'Failed to terminate running task')); } }); } }); } } + + private runRestartTaskCommand(accessor: ServicesAccessor, arg: any): void { + if (!this.canRunCommand()) { + return; + } + if (this.inTerminal()) { + this.getActiveTasks().then((activeTasks) => { + if (activeTasks.length === 0) { + return; + } + if (activeTasks.length === 1) { + this.restart(activeTasks[0]); + } else { + this.quickOpenService.show('restart task '); + } + }); + } else { + this.getActiveTasks().then((activeTasks) => { + if (activeTasks.length === 0) { + return; + } + let task = activeTasks[0]; + this.restart(task); + }); + } + } } @@ -1132,6 +1178,7 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Config MenuRegistry.addCommand({ id: 'workbench.action.tasks.showLog', title: nls.localize('ShowLogAction.label', "Show Task Log"), alias: 'Tasks: Show Task Log', category: tasksCategory }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.runTask', title: nls.localize('RunTaskAction.label', "Run Task"), alias: 'Tasks: Run Task', category: tasksCategory }); +MenuRegistry.addCommand({ id: 'workbench.action.tasks.restartTask', title: nls.localize('RestartTaskAction.label', "Restart Task"), alias: 'Tasks: Restart Task', category: tasksCategory }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.terminate', title: nls.localize('TerminateAction.label', "Terminate Running Task"), alias: 'Tasks: Terminate Running Task', category: tasksCategory }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.build', title: nls.localize('BuildAction.label', "Run Build Task"), alias: 'Tasks: Run Build Task', category: tasksCategory }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.test', title: nls.localize('TestAction.label', "Run Test Task"), alias: 'Tasks: Run Test Task', category: tasksCategory }); @@ -1162,6 +1209,15 @@ quickOpenRegistry.registerQuickOpenHandler( ) ); +quickOpenRegistry.registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/tasks/browser/restartQuickOpen', + 'QuickOpenHandler', + 'restart task ', + nls.localize('quickOpen.restartTask', "Restart Task") + ) +); + // Status bar let statusbarRegistry = Registry.as(StatusbarExtensions.Statusbar); statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(StatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */));