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.echo in task config #7503

Merged
merged 1 commit into from
Apr 17, 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
6 changes: 6 additions & 0 deletions packages/task/src/browser/task-schema-updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ const problemMatcher = {
const presentation: IJSONSchema = {
type: 'object',
default: {
echo: true,
reveal: 'always',
focus: false,
panel: 'shared',
Expand All @@ -548,6 +549,11 @@ const presentation: IJSONSchema = {
description: 'Configures the panel that is used to present the task\'s output and reads its input.',
additionalProperties: true,
properties: {
echo: {
type: 'boolean',
default: true,
description: 'Controls whether the executed command is echoed to the panel. Default is true.'
},
focus: {
type: 'boolean',
default: false,
Expand Down
3 changes: 1 addition & 2 deletions packages/task/src/browser/task-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,6 @@ export class TaskService implements TaskConfigurationClient {
}
}
}

// Create / find a terminal widget to display an execution output of a task that was launched as a command inside a shell.
const widget = await this.taskTerminalWidgetManager.open({
created: new Date().toString(),
Expand All @@ -1013,7 +1012,7 @@ export class TaskService implements TaskConfigurationClient {
taskId,
widgetOptions: { area: 'bottom' },
mode: widgetOpenMode,
taskConfig: taskInfo ? taskInfo.config : undefined
taskInfo
});
widget.start(terminalId);
}
Expand Down
38 changes: 26 additions & 12 deletions packages/task/src/browser/task-terminal-widget-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { ApplicationShell, WidgetOpenerOptions } from '@theia/core/lib/browser';
import { TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
import { TerminalWidgetFactoryOptions } from '@theia/terminal/lib/browser/terminal-widget-impl';
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
import { PanelKind, TaskConfiguration, TaskWatcher, TaskExitedEvent, TaskServer, TaskOutputPresentation } from '../common';
import { PanelKind, TaskConfiguration, TaskWatcher, TaskExitedEvent, TaskServer, TaskOutputPresentation, TaskInfo } from '../common';
import { ProcessTaskInfo } from '../common/process/task-protocol';
import { TaskDefinitionRegistry } from './task-definition-registry';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';

Expand All @@ -38,20 +39,27 @@ export namespace TaskTerminalWidget {

export interface TaskTerminalWidgetOpenerOptions extends WidgetOpenerOptions {
taskId: number;
taskConfig?: TaskConfiguration;
taskInfo?: TaskInfo;
}
export namespace TaskTerminalWidgetOpenerOptions {
export function isDedicatedTerminal(options: TaskTerminalWidgetOpenerOptions): boolean {
return !!options.taskConfig && !!options.taskConfig.presentation && options.taskConfig.presentation.panel === PanelKind.Dedicated;
const taskConfig = options.taskInfo ? options.taskInfo.config : undefined;
return !!taskConfig && !!taskConfig.presentation && taskConfig.presentation.panel === PanelKind.Dedicated;
}

export function isNewTerminal(options: TaskTerminalWidgetOpenerOptions): boolean {
return !!options.taskConfig && !!options.taskConfig.presentation && options.taskConfig.presentation.panel === PanelKind.New;
const taskConfig = options.taskInfo ? options.taskInfo.config : undefined;
return !!taskConfig && !!taskConfig.presentation && taskConfig.presentation.panel === PanelKind.New;
}

export function isSharedTerminal(options: TaskTerminalWidgetOpenerOptions): boolean {
return !!options.taskConfig &&
(options.taskConfig.presentation === undefined || options.taskConfig.presentation.panel === undefined || options.taskConfig.presentation.panel === PanelKind.Shared);
const taskConfig = options.taskInfo ? options.taskInfo.config : undefined;
return !!taskConfig && (taskConfig.presentation === undefined || taskConfig.presentation.panel === undefined || taskConfig.presentation.panel === PanelKind.Shared);
}

export function echoExecutedCommand(options: TaskTerminalWidgetOpenerOptions): boolean {
const taskConfig = options.taskInfo ? options.taskInfo.config : undefined;
return !!taskConfig && (taskConfig.presentation === undefined || taskConfig.presentation.echo === undefined || taskConfig.presentation.echo);
}
}

Expand Down Expand Up @@ -120,8 +128,8 @@ export class TaskTerminalWidgetManager {

async open(factoryOptions: TerminalWidgetFactoryOptions, openerOptions: TaskTerminalWidgetOpenerOptions): Promise<TerminalWidget> {
const dedicated = TaskTerminalWidgetOpenerOptions.isDedicatedTerminal(openerOptions);
if (dedicated && !openerOptions.taskConfig) {
throw new Error('"taskConfig" must be included as part of the "option" if "isDedicated" is true');
if (dedicated && (!openerOptions.taskInfo || !openerOptions.taskInfo.config)) {
throw new Error('"taskConfig" must be included as part of the "option.taskInfo" if "isDedicated" is true');
}

const { isNew, widget } = await this.getWidgetToRunTask(factoryOptions, openerOptions);
Expand All @@ -132,12 +140,18 @@ export class TaskTerminalWidgetManager {
if (factoryOptions.title) {
widget.setTitle(factoryOptions.title);
}
if (openerOptions.taskConfig && TaskOutputPresentation.shouldClearTerminalBeforeRun(openerOptions.taskConfig)) {
const taskConfig = openerOptions.taskInfo ? openerOptions.taskInfo.config : undefined;
if (taskConfig && TaskOutputPresentation.shouldClearTerminalBeforeRun(taskConfig)) {
widget.clearOutput();
}
}
this.terminalService.open(widget, openerOptions);

const taskInfo = openerOptions.taskInfo;
if (TaskTerminalWidgetOpenerOptions.echoExecutedCommand(openerOptions) &&
taskInfo && ProcessTaskInfo.is(taskInfo) && taskInfo.command && taskInfo.command.length > 0
) {
widget.writeLine(`\x1b[1m> Executing task: ${taskInfo.command} <\x1b[0m\n`);
}
return widget;
}

Expand All @@ -151,8 +165,8 @@ export class TaskTerminalWidgetManager {
// 1) dedicated, 2) idle, 3) the one that ran the same task
if (widget.dedicated &&
!widget.busy &&
widget.taskConfig && openerOptions.taskConfig &&
this.taskDefinitionRegistry.compareTasks(openerOptions.taskConfig, widget.taskConfig)) {
widget.taskConfig && openerOptions.taskInfo &&
this.taskDefinitionRegistry.compareTasks(openerOptions.taskInfo.taskConfig, widget.taskConfig)) {

reusableTerminalWidget = widget;
break;
Expand Down
6 changes: 3 additions & 3 deletions packages/task/src/common/process/task-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ export interface ProcessTaskConfiguration extends TaskConfiguration, CommandProp
}

export interface ProcessTaskInfo extends TaskInfo {
/** terminal id. Defined if task is run as a terminal process */
readonly terminalId?: number;
paul-marechal marked this conversation as resolved.
Show resolved Hide resolved
/** process id. Defined if task is run as a process */
readonly processId?: number;
/** process task command */
readonly command?: string;
}
export namespace ProcessTaskInfo {
export function is(info: TaskInfo): info is ProcessTaskInfo {
return info['terminalId'] !== undefined || info['processId'] !== undefined;
return info['processId'] !== undefined;
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/task/src/common/task-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export enum PanelKind {
}

export interface TaskOutputPresentation {
echo?: boolean;
focus?: boolean;
reveal?: RevealKind;
panel?: PanelKind;
Expand All @@ -51,6 +52,7 @@ export interface TaskOutputPresentation {
export namespace TaskOutputPresentation {
export function getDefault(): TaskOutputPresentation {
return {
echo: true,
reveal: RevealKind.Always,
focus: false,
panel: PanelKind.Shared,
Expand Down Expand Up @@ -83,6 +85,7 @@ export namespace TaskOutputPresentation {
}
outputPresentation = {
...outputPresentation,
echo: task.presentation.echo === undefined || task.presentation.echo,
focus: shouldSetFocusToTerminal(task),
showReuseMessage: shouldShowReuseMessage(task),
clear: shouldClearTerminalBeforeRun(task)
Expand Down
19 changes: 16 additions & 3 deletions packages/task/src/node/process/process-task-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ export class ProcessTaskRunner implements TaskRunner {
// way the command is passed:
// - process: directly look for an executable and pass a specific set of arguments/options.
// - shell: defer the spawning to a shell that will evaluate a command line with our executable.
const terminal: Process = this.terminalProcessFactory(this.getResolvedCommand(taskConfig));
const terminalProcessOptions = this.getResolvedCommand(taskConfig);
const terminal: Process = this.terminalProcessFactory(terminalProcessOptions);

// Wait for the confirmation that the process is successfully started, or has failed to start.
await new Promise((resolve, reject) => {
Expand All @@ -82,12 +83,14 @@ export class ProcessTaskRunner implements TaskRunner {
});
});

const processType = taskConfig.type as 'process' | 'shell';
return this.taskFactory({
label: taskConfig.label,
process: terminal,
processType: taskConfig.type as 'process' | 'shell',
processType,
context: ctx,
config: taskConfig
config: taskConfig,
command: this.getCommand(processType, terminalProcessOptions)
});
} catch (error) {
this.logger.error(`Error occurred while creating task: ${error}`);
Expand Down Expand Up @@ -249,6 +252,16 @@ export class ProcessTaskRunner implements TaskRunner {
return { command, args, commandLine, options };
}

private getCommand(processType: 'process' | 'shell', terminalProcessOptions: TerminalProcessOptions): string | undefined {
if (terminalProcessOptions.args) {
if (processType === 'shell') {
return terminalProcessOptions.args[terminalProcessOptions.args.length - 1];
} else if (processType === 'process') {
return `${terminalProcessOptions.command} ${terminalProcessOptions.args.join(' ')}`;
}
}
}

/**
* This is task specific, to align with VS Code's behavior.
*
Expand Down
6 changes: 6 additions & 0 deletions packages/task/src/node/process/process-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const TaskProcessOptions = Symbol('TaskProcessOptions');
export interface TaskProcessOptions extends TaskOptions {
process: Process;
processType: ProcessType;
command?: string;
}

export const TaskFactory = Symbol('TaskFactory');
Expand All @@ -57,6 +58,8 @@ export type TaskFactory = (options: TaskProcessOptions) => ProcessTask;
@injectable()
export class ProcessTask extends Task {

protected command: string | undefined;

constructor(
@inject(TaskManager) protected readonly taskManager: TaskManager,
@inject(ILogger) @named('task') protected readonly logger: ILogger,
Expand Down Expand Up @@ -92,6 +95,8 @@ export class ProcessTask extends Task {
});
}
});

this.command = this.options.command;
this.logger.info(`Created new task, id: ${this.id}, process id: ${this.options.process.id}, OS PID: ${this.process.pid}, context: ${this.context}`);
}

Expand Down Expand Up @@ -128,6 +133,7 @@ export class ProcessTask extends Task {
config: this.options.config,
terminalId: this.process.id,
processId: this.process.id,
command: this.command
};
}

Expand Down