Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support presentation.reveal and presentation.focus in task config #6814

Merged
merged 1 commit into from
Jan 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
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) {
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
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
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
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