mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-28 13:46:17 +00:00
Fixes #29913: Action to show and navigate to running tasks
This commit is contained in:
@@ -913,9 +913,10 @@ export class CodeMenu {
|
||||
|
||||
private setTaskMenu(taskMenu: Electron.Menu): void {
|
||||
const runTask = this.createMenuItem(nls.localize({ key: 'miRunTask', comment: ['&& denotes a mnemonic'] }, "&&Run Task..."), 'workbench.action.tasks.runTask');
|
||||
const buildTask = this.createMenuItem(nls.localize({ key: 'miBuildTask', comment: ['&& denotes a mnemonic'] }, "Run &&Build Task..."), 'workbench.action.tasks.build');
|
||||
const showTasks = this.createMenuItem(nls.localize({ key: 'miRunningTask', comment: ['&& denotes a mnemonic'] }, "Show Runnin&&g Tasks..."), 'workbench.action.tasks.showTasks');
|
||||
const restartTask = this.createMenuItem(nls.localize({ key: 'miRestartTask', comment: ['&& denotes a mnemonic'] }, "R&&estart Running Task..."), 'workbench.action.tasks.restartTask');
|
||||
const terminateTask = this.createMenuItem(nls.localize({ key: 'miTerminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task..."), 'workbench.action.tasks.terminate');
|
||||
const buildTask = this.createMenuItem(nls.localize({ key: 'miBuildTask', comment: ['&& denotes a mnemonic'] }, "Run &&Build Task..."), 'workbench.action.tasks.build');
|
||||
// const testTask = this.createMenuItem(nls.localize({ key: 'miTestTask', comment: ['&& denotes a mnemonic'] }, "Run Test T&&ask..."), 'workbench.action.tasks.test');
|
||||
// const showTaskLog = this.createMenuItem(nls.localize({ key: 'miShowTaskLog', comment: ['&& denotes a mnemonic'] }, "&&Show Task Log"), 'workbench.action.tasks.showLog');
|
||||
const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks"), 'workbench.action.tasks.configureTaskRunner');
|
||||
@@ -930,6 +931,7 @@ export class CodeMenu {
|
||||
__separator__(),
|
||||
terminateTask,
|
||||
restartTask,
|
||||
showTasks,
|
||||
__separator__(),
|
||||
//showTaskLog,
|
||||
configureTask,
|
||||
|
||||
@@ -21,6 +21,7 @@ export namespace TaskServiceEvents {
|
||||
export let Inactive: string = 'inactive';
|
||||
export let ConfigChanged: string = 'configChanged';
|
||||
export let Terminated: string = 'terminated';
|
||||
export let Changed: string = 'changed';
|
||||
}
|
||||
|
||||
export interface ITaskProvider {
|
||||
|
||||
@@ -82,6 +82,7 @@ export namespace TaskSystemEvents {
|
||||
export let Active: string = 'active';
|
||||
export let Inactive: string = 'inactive';
|
||||
export let Terminated: string = 'terminated';
|
||||
export let Changed: string = 'changed';
|
||||
}
|
||||
|
||||
export enum TaskType {
|
||||
@@ -113,4 +114,5 @@ export interface ITaskSystem extends IEventEmitter {
|
||||
canAutoTerminate(): boolean;
|
||||
terminate(id: string): TPromise<TaskTerminateResponse>;
|
||||
terminateAll(): TPromise<TaskTerminateResponse[]>;
|
||||
revealTask(task: Task): boolean;
|
||||
}
|
||||
@@ -3,6 +3,16 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.task-statusbar-runningItem {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.task-statusbar-runningItem-label {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
.task-statusbar-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ class ViewTerminalAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
class StatusBarItem extends Themable implements IStatusbarItem {
|
||||
class BuildStatusBarItem extends Themable implements IStatusbarItem {
|
||||
private intervalToken: any;
|
||||
private activeCount: number;
|
||||
private static progressChars: string = '|/-\\';
|
||||
@@ -309,7 +309,7 @@ class StatusBarItem extends Themable implements IStatusbarItem {
|
||||
|
||||
Dom.addClass(progress, 'task-statusbar-item-progress');
|
||||
element.appendChild(progress);
|
||||
progress.innerHTML = StatusBarItem.progressChars[0];
|
||||
progress.innerHTML = BuildStatusBarItem.progressChars[0];
|
||||
$(progress).hide();
|
||||
|
||||
Dom.addClass(label, 'task-statusbar-item-label');
|
||||
@@ -384,7 +384,7 @@ class StatusBarItem extends Themable implements IStatusbarItem {
|
||||
this.activeCount++;
|
||||
if (this.activeCount === 1) {
|
||||
let index = 1;
|
||||
let chars = StatusBarItem.progressChars;
|
||||
let chars = BuildStatusBarItem.progressChars;
|
||||
progress.innerHTML = chars[0];
|
||||
this.intervalToken = setInterval(() => {
|
||||
progress.innerHTML = chars[index];
|
||||
@@ -454,6 +454,69 @@ class StatusBarItem extends Themable implements IStatusbarItem {
|
||||
}
|
||||
}
|
||||
|
||||
class TaskStatusBarItem extends Themable implements IStatusbarItem {
|
||||
|
||||
constructor(
|
||||
@IPanelService private panelService: IPanelService,
|
||||
@IMarkerService private markerService: IMarkerService,
|
||||
@IOutputService private outputService: IOutputService,
|
||||
@ITaskService private taskService: ITaskService,
|
||||
@IPartService private partService: IPartService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
) {
|
||||
super(themeService);
|
||||
}
|
||||
|
||||
protected updateStyles(): void {
|
||||
super.updateStyles();
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): IDisposable {
|
||||
let callOnDispose: IDisposable[] = [];
|
||||
|
||||
const element = document.createElement('div');
|
||||
const label = document.createElement('a');
|
||||
|
||||
Dom.addClass(element, 'task-statusbar-runningItem');
|
||||
|
||||
Dom.addClass(label, 'task-statusbar-runningItem-label');
|
||||
element.appendChild(label);
|
||||
element.title = nls.localize('runningTasks', "Show Running Tasks");
|
||||
|
||||
callOnDispose.push(Dom.addDisposableListener(label, 'click', (e: MouseEvent) => {
|
||||
(this.taskService as TaskService).runShowTasks();
|
||||
}));
|
||||
|
||||
let updateStatus = (): void => {
|
||||
this.taskService.getActiveTasks().then(tasks => {
|
||||
if (tasks.length === 0) {
|
||||
label.innerHTML = nls.localize('nothingRunner', 'Running Tasks: 0');
|
||||
} else if (tasks.length === 1) {
|
||||
label.innerHTML = nls.localize('oneTasksRunnering', 'Running Tasks: 1');
|
||||
} else {
|
||||
label.innerHTML = nls.localize('nTasksRunnering', 'Running Tasks: {0}', tasks.length);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
callOnDispose.push(this.taskService.addListener(TaskServiceEvents.Changed, (event: TaskEvent) => {
|
||||
updateStatus();
|
||||
}));
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
this.updateStyles();
|
||||
updateStatus();
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
callOnDispose = dispose(callOnDispose);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface TaskServiceEventData {
|
||||
error?: any;
|
||||
}
|
||||
@@ -465,6 +528,9 @@ class NullTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
promise: TPromise.as<ITaskSummary>({})
|
||||
};
|
||||
}
|
||||
public revealTask(task: Task): boolean {
|
||||
return false;
|
||||
}
|
||||
public isActive(): TPromise<boolean> {
|
||||
return TPromise.as(false);
|
||||
}
|
||||
@@ -686,6 +752,10 @@ class TaskService extends EventEmitter implements ITaskService {
|
||||
CommandsRegistry.registerCommand('workbench.action.tasks.configureDefaultTestTask', () => {
|
||||
this.runConfigureDefaultTestTask();
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('workbench.action.tasks.showTasks', () => {
|
||||
this.runShowTasks();
|
||||
});
|
||||
}
|
||||
|
||||
private showOutput(): void {
|
||||
@@ -1189,6 +1259,7 @@ class TaskService extends EventEmitter implements ITaskService {
|
||||
this._taskSystemListeners.push(this._taskSystem.addListener(TaskSystemEvents.Active, (event) => this.emit(TaskServiceEvents.Active, event)));
|
||||
this._taskSystemListeners.push(this._taskSystem.addListener(TaskSystemEvents.Inactive, (event) => this.emit(TaskServiceEvents.Inactive, event)));
|
||||
this._taskSystemListeners.push(this._taskSystem.addListener(TaskSystemEvents.Terminated, (event) => this.emit(TaskServiceEvents.Terminated, event)));
|
||||
this._taskSystemListeners.push(this._taskSystem.addListener(TaskSystemEvents.Changed, () => this.emit(TaskServiceEvents.Changed)));
|
||||
return this._taskSystem;
|
||||
}
|
||||
|
||||
@@ -1874,6 +1945,24 @@ class TaskService extends EventEmitter implements ITaskService {
|
||||
this.configureAction().run();
|
||||
}
|
||||
}
|
||||
|
||||
public runShowTasks(): void {
|
||||
if (!this.canRunCommand()) {
|
||||
return;
|
||||
}
|
||||
if (!this._taskSystem) {
|
||||
this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskIsRunning', 'No task is running.'));
|
||||
return;
|
||||
}
|
||||
this.getActiveTasks().then((tasks) => {
|
||||
this.showQuickPick(tasks, nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), false, true).then((task) => {
|
||||
if (!task || !this._taskSystem) {
|
||||
return;
|
||||
}
|
||||
this._taskSystem.revealTask(task);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1883,6 +1972,7 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Config
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.showLog', title: { value: nls.localize('ShowLogAction.label', "Show Task Log"), original: 'Show Task Log' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.runTask', title: { value: nls.localize('RunTaskAction.label', "Run Task"), original: 'Run Task' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.restartTask', title: { value: nls.localize('RestartTaskAction.label', "Restart Running Task"), original: 'Restart Running Task' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.showTasks', title: { value: nls.localize('ShowTasksAction.label', "Show Running Tasks"), original: 'Show Running Tasks' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.terminate', title: { value: nls.localize('TerminateAction.label', "Terminate Task"), original: 'Terminate Task' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.build', title: { value: nls.localize('BuildAction.label', "Run Build Task"), original: 'Run Build Task' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
MenuRegistry.addCommand({ id: 'workbench.action.tasks.test', title: { value: nls.localize('TestAction.label', "Run Test Task"), original: 'Run Test Task' }, category: { value: tasksCategory, original: 'Tasks' } });
|
||||
@@ -1913,7 +2003,8 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionCont
|
||||
|
||||
// Status bar
|
||||
let statusbarRegistry = <IStatusbarRegistry>Registry.as(StatusbarExtensions.Statusbar);
|
||||
statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(StatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */));
|
||||
statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(BuildStatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */));
|
||||
statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(TaskStatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */));
|
||||
|
||||
// Output channel
|
||||
let outputChannelRegistry = <IOutputChannelRegistry>Registry.as(OutputExt.OutputChannels);
|
||||
|
||||
@@ -162,6 +162,17 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public revealTask(task: Task): boolean {
|
||||
let terminalData = this.activeTasks[task._id];
|
||||
if (!terminalData) {
|
||||
return false;
|
||||
}
|
||||
this.terminalService.setActiveInstance(terminalData.terminal);
|
||||
this.terminalService.showPanel(task.command.presentation.focus);
|
||||
return true;
|
||||
}
|
||||
|
||||
public isActive(): TPromise<boolean> {
|
||||
return TPromise.as(this.isActiveSync());
|
||||
}
|
||||
@@ -301,6 +312,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
onData.dispose();
|
||||
onExit.dispose();
|
||||
delete this.activeTasks[task._id];
|
||||
this.emit(TaskSystemEvents.Changed);
|
||||
switch (task.command.presentation.panel) {
|
||||
case PanelKind.Dedicated:
|
||||
this.sameTaskTerminals[task._id] = terminal.id.toString();
|
||||
@@ -347,6 +359,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
onData.dispose();
|
||||
onExit.dispose();
|
||||
delete this.activeTasks[task._id];
|
||||
this.emit(TaskSystemEvents.Changed);
|
||||
switch (task.command.presentation.panel) {
|
||||
case PanelKind.Dedicated:
|
||||
this.sameTaskTerminals[task._id] = terminal.id.toString();
|
||||
@@ -372,6 +385,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
this.terminalService.showPanel(task.command.presentation.focus);
|
||||
}
|
||||
this.activeTasks[task._id] = { terminal, task, promise };
|
||||
this.emit(TaskSystemEvents.Changed);
|
||||
return promise.then((summary) => {
|
||||
try {
|
||||
let telemetryEvent: TelemetryEvent = {
|
||||
|
||||
@@ -90,6 +90,11 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem {
|
||||
return this.executeTask(task);
|
||||
}
|
||||
|
||||
public revealTask(task: Task): boolean {
|
||||
this.showOutput();
|
||||
return true;
|
||||
}
|
||||
|
||||
public hasErrors(value: boolean): void {
|
||||
this.errorsShown = !value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user