Skip to content

Commit

Permalink
support presentation.reveal and presentation.focus in task config
Browse files Browse the repository at this point in the history
- show the terminal if presentation.reveal = "always",
- do not show the terminal if presentation.reveal = "never",
- when presentation.reveal = "silent", show the terminal only if errors are found from the task output by the parser

- when users start a task that is already active, put focus on the terminal if presentation.focus = true, or reveal the terminal if presentation.reveal = "always"

Signed-off-by: Liang Huang <liang.huang@ericsson.com>
  • Loading branch information
Liang Huang authored and elaihau committed Jan 9, 2020
1 parent 62d13b4 commit c8b8854
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 29 deletions.
58 changes: 36 additions & 22 deletions packages/task/src/browser/task-configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@

import * as Ajv from 'ajv';
import { inject, injectable, postConstruct } from 'inversify';
import { ContributedTaskConfiguration, TaskConfiguration, TaskCustomization, TaskDefinition } from '../common';
import {
ContributedTaskConfiguration,
TaskConfiguration,
TaskCustomization,
TaskDefinition,
TaskOutputPresentation
} from '../common';
import { TaskDefinitionRegistry } from './task-definition-registry';
import { ProvidedTaskConfigurations } from './provided-task-configurations';
import { TaskConfigurationManager } from './task-configuration-manager';
Expand Down Expand Up @@ -266,27 +272,12 @@ export class TaskConfigurations implements Disposable {

/** parses a config file and extracts the tasks launch configurations */
protected async readTasks(rootFolderUri: string): Promise<(TaskCustomization | TaskConfiguration)[] | undefined> {
const configArray = this.taskConfigurationManager.getTasks(rootFolderUri);
const rawConfigArray = this.taskConfigurationManager.getTasks(rootFolderUri);
if (this.rawTaskConfigurations.has(rootFolderUri)) {
this.rawTaskConfigurations.delete(rootFolderUri);
}
const tasks = configArray.map(config => {
if (this.isDetectedTask(config)) {
const def = this.getTaskDefinition(config);
return {
...config,
_source: def!.source,
_scope: rootFolderUri
};
}
return {
...config,
_source: rootFolderUri,
_scope: rootFolderUri
};
});
this.rawTaskConfigurations.set(rootFolderUri, tasks);
return tasks;
this.rawTaskConfigurations.set(rootFolderUri, rawConfigArray);
return rawConfigArray;
}

/** Adds given task to a config file and opens the file to provide ability to edit task configuration. */
Expand Down Expand Up @@ -386,10 +377,11 @@ export class TaskConfigurations implements Disposable {
if (!isValid) {
continue;
}
if (this.isDetectedTask(taskConfig)) {
addCustomization(rootFolder, taskConfig);
const transformedTask = this.getTransformedRawTask(taskConfig, rootFolder);
if (this.isDetectedTask(transformedTask)) {
addCustomization(rootFolder, transformedTask);
} else {
addConfiguredTask(rootFolder, taskConfig['label'] as string, taskConfig);
addConfiguredTask(rootFolder, transformedTask['label'] as string, transformedTask);
}
}
}
Expand All @@ -398,6 +390,28 @@ export class TaskConfigurations implements Disposable {
this.tasksMap = newTaskMap;
}

private getTransformedRawTask(rawTask: TaskCustomization | TaskConfiguration, rootFolderUri: string): TaskCustomization | TaskConfiguration {
let taskConfig: TaskCustomization | TaskConfiguration;
if (this.isDetectedTask(rawTask)) {
const def = this.getTaskDefinition(rawTask);
taskConfig = {
...rawTask,
_source: def!.source,
_scope: rootFolderUri
};
} else {
taskConfig = {
...rawTask,
_source: rootFolderUri,
_scope: rootFolderUri
};
}
return {
...taskConfig,
presentation: TaskOutputPresentation.fromJson(rawTask)
};
}

/**
* Returns `true` if the given task configuration is valid as per the task schema defined in Theia
* or contributed by Theia extensions and plugins, `false` otherwise.
Expand Down
31 changes: 30 additions & 1 deletion packages/task/src/browser/task-schema-updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,34 @@ const problemMatcher = {
]
};

const presentation: IJSONSchema = {
type: 'object',
default: {
reveal: 'always',
focus: false
},
description: 'Configures the panel that is used to present the task\'s output and reads its input.',
additionalProperties: true,
properties: {
focus: {
type: 'boolean',
default: false,
description: 'Controls whether the panel takes focus. Default is false. If set to true the panel is revealed as well.'
},
reveal: {
type: 'string',
enum: ['always', 'silent', 'never'],
enumDescriptions: [
'Always reveals the terminal when this task is executed.',
'Only reveals the terminal if the task exits with an error or the problem matcher finds an error.',
'Never reveals the terminal when this task is executed.'
],
default: 'always',
description: 'Controls whether the terminal running the task is revealed or not. May be overridden by option \"revealProblems\". Default is \"always\".'
}
}
};

const taskIdentifier: IJSONSchema = {
type: 'object',
additionalProperties: true,
Expand Down Expand Up @@ -603,7 +631,8 @@ const processTaskConfigurationSchema: IJSONSchema = {
properties: commandAndArgs
},
group,
problemMatcher
problemMatcher,
presentation
},
additionalProperties: true
};
Expand Down
58 changes: 52 additions & 6 deletions packages/task/src/browser/task-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { TerminalWidgetFactoryOptions, TERMINAL_WIDGET_FACTORY_ID } from '@theia
import { VariableResolverService } from '@theia/variable-resolver/lib/browser';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { inject, injectable, named, postConstruct } from 'inversify';
import { Range } from 'vscode-languageserver-types';
import { DiagnosticSeverity, Range } from 'vscode-languageserver-types';
import {
NamedProblemMatcher,
ProblemMatchData,
Expand All @@ -45,7 +45,8 @@ import {
TaskDefinition,
TaskServer,
TaskIdentifier,
DependsOrder
DependsOrder,
RevealKind
} from '../common';
import { TaskWatcher } from '../common/task-watcher';
import { ProvidedTaskConfigurations } from './provided-task-configurations';
Expand Down Expand Up @@ -201,16 +202,39 @@ export class TaskService implements TaskConfigurationClient {
this.messageService.info(`Task '${taskIdentifier}' has been started.`);
});

this.taskWatcher.onOutputProcessed((event: TaskOutputProcessedEvent) => {
this.taskWatcher.onOutputProcessed(async (event: TaskOutputProcessedEvent) => {
if (!this.isEventForThisClient(event.ctx)) {
return;
}
if (event.problems) {
const runningTasksInfo: TaskInfo[] = await this.getRunningTasks();
// check if the task is active
const matchedRunningTaskInfo = runningTasksInfo.find(taskInfo => {
const taskConfig = taskInfo.config;
return this.taskDefinitionRegistry.compareTasks(taskConfig, event.config);
});
const isTaskActiveAndOutputSilent = matchedRunningTaskInfo &&
matchedRunningTaskInfo.config.presentation && matchedRunningTaskInfo.config.presentation.reveal === RevealKind.Silent;
event.problems.forEach(problem => {
const existingMarkers = this.problemManager.findMarkers({ owner: problem.description.owner });
const uris = new Set<string>();
existingMarkers.forEach(marker => uris.add(marker.uri));
if (ProblemMatchData.is(problem) && problem.resource) {
// When task.presentation.reveal === RevealKind.Silent, put focus on the terminal only if it is an error
if (isTaskActiveAndOutputSilent && problem.marker.severity === DiagnosticSeverity.Error) {
const terminalId = matchedRunningTaskInfo!.terminalId;
if (terminalId) {
const terminal = this.terminalService.getById(this.getTerminalWidgetId(terminalId));
if (terminal) {
const focus = !!matchedRunningTaskInfo!.config.presentation!.focus;
if (focus) { // assign focus to the terminal if presentation.focus is true
this.shell.activateWidget(terminal.id);
} else { // show the terminal but not assign focus
this.shell.revealWidget(terminal.id);
}
}
}
}
const uri = new URI(problem.resource.path).withScheme(problem.resource.scheme);
if (uris.has(uri.toString())) {
const newData = [
Expand Down Expand Up @@ -268,6 +292,18 @@ export class TaskService implements TaskConfigurationClient {
if (event.code === 0) {
this.messageService.info(message);
} else {
const eventTaskConfig = event.config;
if (eventTaskConfig && eventTaskConfig.presentation && eventTaskConfig.presentation.reveal === RevealKind.Silent && event.terminalId) {
const terminal = this.terminalService.getById(this.getTerminalWidgetId(event.terminalId));
const focus = !!eventTaskConfig.presentation.focus;
if (terminal) {
if (focus) { // assign focus to the terminal if presentation.focus is true
this.shell.activateWidget(terminal.id);
} else { // show the terminal but not assign focus
this.shell.revealWidget(terminal.id);
}
}
}
this.messageService.error(message);
}
} else if (event.signal !== undefined) {
Expand Down Expand Up @@ -655,8 +691,12 @@ export class TaskService implements TaskConfigurationClient {
const terminalId = matchedRunningTaskInfo.terminalId;
if (terminalId) {
const terminal = this.terminalService.getById(this.getTerminalWidgetId(terminalId));
if (terminal) {
this.shell.activateWidget(terminal.id); // make the terminal visible and assign focus
if (terminal && task.presentation) {
if (task.presentation.focus) { // assign focus to the terminal if presentation.focus is true
this.shell.activateWidget(terminal.id);
} else if (task.presentation.reveal === RevealKind.Always) { // show the terminal but not assign focus
this.shell.revealWidget(terminal.id);
}
}
}
const selectedAction = await this.messageService.info(`The task '${taskName}' is already active`, 'Terminate Task', 'Restart Task');
Expand Down Expand Up @@ -947,7 +987,13 @@ export class TaskService implements TaskConfigurationClient {
}
);
this.shell.addWidget(widget, { area: 'bottom' });
this.shell.activateWidget(widget.id);
if (taskInfo && taskInfo.config.presentation && taskInfo.config.presentation.reveal === RevealKind.Always) {
if (taskInfo.config.presentation.focus) { // assign focus to the terminal if presentation.focus is true
this.shell.activateWidget(widget.id);
} else { // show the terminal but not assign focus
this.shell.revealWidget(widget.id);
}
}
widget.start(processId);
}

Expand Down
36 changes: 36 additions & 0 deletions packages/task/src/common/task-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,45 @@ export enum DependsOrder {
Parallel = 'parallel',
}

export enum RevealKind {
Always,
Silent,
Never
}

export interface TaskOutputPresentation {
focus?: boolean;
reveal?: RevealKind;
// tslint:disable-next-line:no-any
[name: string]: any;
}
export namespace TaskOutputPresentation {
// tslint:disable-next-line:no-any
export function fromJson(task: any): TaskOutputPresentation {
if (task && task.presentation) {
let reveal = RevealKind.Always;
if (task.presentation.reveal === 'silent') {
reveal = RevealKind.Silent;
} else if (task.presentation.reveal === 'never') {
reveal = RevealKind.Never;
}
return {
reveal,
focus: !!task.presentation.focus
};
}
return {
reveal: RevealKind.Always,
focus: false
};
}
}

export interface TaskCustomization {
type: string;
group?: 'build' | 'test' | 'none' | { kind: 'build' | 'test' | 'none', isDefault: true };
problemMatcher?: string | ProblemMatcherContribution | (string | ProblemMatcherContribution)[];
presentation?: TaskOutputPresentation;

/** Whether the task is a background task or not. */
isBackground?: boolean;
Expand Down Expand Up @@ -157,6 +192,7 @@ export interface TaskOutputEvent {

export interface TaskOutputProcessedEvent {
readonly taskId: number;
readonly config: TaskConfiguration;
readonly ctx?: string;
readonly problems?: ProblemMatch[];
}
Expand Down
1 change: 1 addition & 0 deletions packages/task/src/node/task-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class TaskServerImpl implements TaskServer, Disposable {
if (problems.length > 0) {
this.fireTaskOutputProcessedEvent({
taskId: event.taskId,
config: taskConfiguration,
ctx: event.ctx,
problems
});
Expand Down

0 comments on commit c8b8854

Please sign in to comment.