From 8bcd40f152a99e64170172349584595819bef5fc Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 10 Feb 2017 17:29:42 +0100 Subject: [PATCH] First version to support keybindings for tasks --- .../taskConfiguration.ts} | 65 ++++++++++++++- .../parts/tasks/common/taskSystem.ts | 22 +++++ .../electron-browser/task.contribution.ts | 82 +++++++++++++------ .../parts/tasks/node/processRunnerDetector.ts | 26 +++--- .../parts/tasks/node/processRunnerSystem.ts | 8 +- .../tasks/test/node/configuration.test.ts | 2 +- 6 files changed, 159 insertions(+), 46 deletions(-) rename src/vs/workbench/parts/tasks/{node/processRunnerConfiguration.ts => common/taskConfiguration.ts} (94%) diff --git a/src/vs/workbench/parts/tasks/node/processRunnerConfiguration.ts b/src/vs/workbench/parts/tasks/common/taskConfiguration.ts similarity index 94% rename from src/vs/workbench/parts/tasks/node/processRunnerConfiguration.ts rename to src/vs/workbench/parts/tasks/common/taskConfiguration.ts index cc641c41945..f99b4e2f51b 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerConfiguration.ts +++ b/src/vs/workbench/parts/tasks/common/taskConfiguration.ts @@ -14,8 +14,12 @@ import * as UUID from 'vs/base/common/uuid'; import { Config as ProcessConfig } from 'vs/base/common/processes'; import { ValidationStatus, ValidationState, ILogger } from 'vs/base/common/parsers'; -import { NamedProblemMatcher, ProblemMatcher, ProblemMatcherParser, Config as ProblemMatcherConfig, registry as ProblemMatcherRegistry, isNamedProblemMatcher } from 'vs/platform/markers/common/problemMatcher'; -import * as TaskSystem from 'vs/workbench/parts/tasks/common/taskSystem'; +import { + NamedProblemMatcher, ProblemMatcher, ProblemMatcherParser, Config as ProblemMatcherConfig, + registry as ProblemMatcherRegistry, isNamedProblemMatcher +} from 'vs/platform/markers/common/problemMatcher'; + +import * as TaskSystem from './taskSystem'; /** * Defines the problem handling strategy @@ -55,6 +59,24 @@ export interface PlatformTaskDescription { args?: string[]; } +export interface CommandBinding { + /** + * The command Id the task is bound to. + */ + commandId?: string; + + /** + * The title to use + */ + title?: string; + + /** + * An optional category + */ + category?: string; +} + + /** * The description of a task. */ @@ -122,6 +144,11 @@ export interface TaskDescription extends PlatformTaskDescription { */ suppressTaskName?: boolean; + /** + * The command this task is bound to. + */ + bindTo?: CommandBinding; + /** * The problem matcher(s) to use to capture problems in the tasks * output. @@ -623,6 +650,37 @@ namespace ProblemMatcherConverter { } } +namespace CommandBinding { + export function isEmpty(value: TaskSystem.CommandBinding): boolean { + return !value || value.commandId === void 0 && value.title === void 0 && value.category === void 0; + } + + export function from(this: void, binding: CommandBinding, context: ParseContext): TaskSystem.CommandBinding { + if (!binding) { + return undefined; + } + + if (!Types.isString(binding.commandId)) { + context.validationStatus.state = ValidationState.Warning; + context.logger.log(nls.localize('noCommandId', 'Warning: a command binding must defined a commandId. Ignoring binding.')); + return undefined; + } + if (!Types.isString(binding.title)) { + context.validationStatus.state = ValidationState.Warning; + context.logger.log(nls.localize('noTitle', 'Warning: a command binding must defined a title. Ignoring binding.')); + return undefined; + } + let result: TaskSystem.CommandBinding = { + commandId: binding.commandId, + title: binding.title + }; + if (Types.isString(binding.category)) { + result.category = binding.category; + } + return result; + } +} + namespace TaskDescription { export interface TaskConfiguration { @@ -682,6 +740,9 @@ namespace TaskDescription { task.suppressTaskName = !!externalTask.suppressTaskName; } + if (externalTask.bindTo) { + task.bindTo = CommandBinding.from(externalTask.bindTo, context); + } if (problemMatchers) { task.problemMatchers = problemMatchers; } diff --git a/src/vs/workbench/parts/tasks/common/taskSystem.ts b/src/vs/workbench/parts/tasks/common/taskSystem.ts index 968878de578..60f6b31f02d 100644 --- a/src/vs/workbench/parts/tasks/common/taskSystem.ts +++ b/src/vs/workbench/parts/tasks/common/taskSystem.ts @@ -136,6 +136,23 @@ export interface CommandConfiguration { echo?: boolean; } +export interface CommandBinding { + /** + * The command Id the task is bound to. + */ + commandId: string; + + /** + * The title to use + */ + title: string; + + /** + * An optional category + */ + category?: string; +} + /** * A task description */ @@ -183,6 +200,11 @@ export interface TaskDescription { */ showOutput: ShowOutput; + /** + * The command this task is bound to. + */ + bindTo?: CommandBinding; + /** * The problem watchers to use for this task */ 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 78b03e8f017..a9dfddffd64 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -28,7 +28,7 @@ import * as strings from 'vs/base/common/strings'; import { Registry } from 'vs/platform/platform'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor, MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IEditor } from 'vs/platform/editor/common/editor'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -37,6 +37,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -65,7 +66,7 @@ import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskErr import { ITaskService, TaskServiceEvents } from 'vs/workbench/parts/tasks/common/taskService'; import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates'; -import * as FileConfig from 'vs/workbench/parts/tasks/node/processRunnerConfiguration'; +import * as TaskConfig from 'vs/workbench/parts/tasks/common/taskConfiguration'; import { ProcessRunnerSystem } from 'vs/workbench/parts/tasks/node/processRunnerSystem'; import { TerminalTaskSystem } from './terminalTaskSystem'; import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector'; @@ -73,6 +74,7 @@ import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunn import { IEnvironmentService } from 'vs/platform/environment/common/environment'; let $ = Builder.$; +let tasksCategory = nls.localize('tasksCategory', "Tasks"); class AbstractTaskAction extends Action { @@ -170,6 +172,20 @@ class CleanAction extends AbstractTaskAction { } } +class CommandAction extends AbstractTaskAction { + constructor(id: string, label: string, private taskId: string, @ITaskService taskService: ITaskService, @ITelemetryService telemetryService: ITelemetryService, + @IMessageService messageService: IMessageService, @IWorkspaceContextService contextService: IWorkspaceContextService) { + super(id, label, taskService, telemetryService, messageService, contextService); + } + + public run(): TPromise { + if (!this.canRun()) { + return TPromise.as(undefined); + } + return this.taskService.run(this.taskId); + } +} + abstract class OpenTaskConfigurationAction extends Action { private configurationService: IConfigurationService; @@ -196,6 +212,8 @@ abstract class OpenTaskConfigurationAction extends Action { this.outputService = outputService; this.messageService = messageService; this.quickOpenService = quickOpenService; + + } public run(event?: any): TPromise { @@ -421,7 +439,6 @@ class RunTaskAction extends AbstractTaskAction { } } - class StatusBarItem implements IStatusbarItem { private panelService: IPanelService; @@ -697,7 +714,7 @@ class TaskService extends EventEmitter implements ITaskService { } this.emit(TaskServiceEvents.ConfigChanged); if (this._inTerminal) { - this.readConfiguration().then((config) => { + this.createConfiguration().then((config) => { if (!config) { return; } @@ -720,6 +737,19 @@ class TaskService extends EventEmitter implements ITaskService { }); lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown())); + CommandsRegistry.registerCommand('workbench.action.tasks.runTask', (accessor, arg) => { + if (Types.isString(arg)) { + this.tasks().then(tasks => { + for (let task of tasks) { + if (task.name === arg) { + this.run(task.id); + } + } + }); + } else { + this.quickOpenService.show('task '); + } + }); } public log(value: string): void { @@ -747,7 +777,7 @@ class TaskService extends EventEmitter implements ITaskService { this._taskSystem = new NullTaskSystem(); this._taskSystemPromise = TPromise.as(this._taskSystem); } else { - let clearOutput = true; + let hasError = false; this._taskSystemPromise = TPromise.as(this.configurationService.getConfiguration('tasks')).then((config: TaskConfiguration) => { let parseErrors: string[] = config ? (config).$parseErrors : null; if (parseErrors) { @@ -766,16 +796,16 @@ class TaskService extends EventEmitter implements ITaskService { } let configPromise: TPromise; if (config) { - if (this.isRunnerConfig(config) && this.hasDetectorSupport(config)) { - let fileConfig = config; + if (this.isRunnerConfig(config) && this.hasDetectorSupport(config)) { + let fileConfig = config; configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, fileConfig).detect(true).then((value) => { - clearOutput = this.printStderr(value.stderr); + hasError = this.printStderr(value.stderr); let detectedConfig = value.config; if (!detectedConfig) { return config; } - let result: FileConfig.ExternalTaskRunnerConfiguration = Objects.clone(fileConfig); - let configuredTasks: IStringDictionary = Object.create(null); + let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(fileConfig); + let configuredTasks: IStringDictionary = Object.create(null); if (!result.tasks) { if (detectedConfig.tasks) { result.tasks = detectedConfig.tasks; @@ -795,7 +825,7 @@ class TaskService extends EventEmitter implements ITaskService { } } else { configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { - clearOutput = this.printStderr(value.stderr); + hasError = this.printStderr(value.stderr); return value.config; }); } @@ -805,16 +835,18 @@ class TaskService extends EventEmitter implements ITaskService { throw new TaskError(Severity.Info, nls.localize('TaskSystem.noConfiguration', 'No task runner configured.'), TaskErrors.NotConfigured); } let result: ITaskSystem = null; - let parseResult = FileConfig.parse(config, this); + let parseResult = TaskConfig.parse(config, this); if (!parseResult.validationStatus.isOK()) { this.outputChannel.show(true); + hasError = true; } if (parseResult.validationStatus.isFatal()) { throw new TaskError(Severity.Error, nls.localize('TaskSystem.fatalError', 'The provided task configuration has validation errors. See tasks output log for details.'), TaskErrors.ConfigValidationError); } if (this.isRunnerConfig(config)) { this._inTerminal = false; - result = new ProcessRunnerSystem(parseResult.configuration, this.markerService, this.modelService, this.telemetryService, this.outputService, this.configurationResolverService, TaskService.OutputChannelId, clearOutput); + result = new ProcessRunnerSystem(parseResult.configuration, this.markerService, this.modelService, + this.telemetryService, this.outputService, this.configurationResolverService, TaskService.OutputChannelId, hasError); } else if (this.isTerminalConfig(config)) { this._inTerminal = true; result = new TerminalTaskSystem( @@ -842,7 +874,7 @@ class TaskService extends EventEmitter implements ITaskService { return this._taskSystemPromise; } - private readConfiguration(): TPromise { + private createConfiguration(): TPromise { let config = this.configurationService.getConfiguration('tasks'); let parseErrors: string[] = config ? (config).$parseErrors : null; if (parseErrors) { @@ -861,16 +893,16 @@ class TaskService extends EventEmitter implements ITaskService { } let configPromise: TPromise; if (config) { - if (this.isRunnerConfig(config) && this.hasDetectorSupport(config)) { - let fileConfig = config; + if (this.isRunnerConfig(config) && this.hasDetectorSupport(config)) { + let fileConfig = config; configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, fileConfig).detect(true).then((value) => { this.printStderr(value.stderr); let detectedConfig = value.config; if (!detectedConfig) { return config; } - let result: FileConfig.ExternalTaskRunnerConfiguration = Objects.clone(fileConfig); - let configuredTasks: IStringDictionary = Object.create(null); + let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(fileConfig); + let configuredTasks: IStringDictionary = Object.create(null); if (!result.tasks) { if (detectedConfig.tasks) { result.tasks = detectedConfig.tasks; @@ -898,7 +930,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!config) { return undefined; } - let parseResult = FileConfig.parse(config, this); + let parseResult = TaskConfig.parse(config, this); if (!parseResult.validationStatus.isOK()) { this.showOutput(); } @@ -911,10 +943,10 @@ class TaskService extends EventEmitter implements ITaskService { } private printStderr(stderr: string[]): boolean { - let result = true; + let result = false; if (stderr && stderr.length > 0) { stderr.forEach((line) => { - result = false; + result = true; this.outputChannel.append(line + '\n'); }); this.outputChannel.show(true); @@ -934,7 +966,7 @@ class TaskService extends EventEmitter implements ITaskService { return this._inTerminal !== void 0 && this._inTerminal; } - private hasDetectorSupport(config: FileConfig.ExternalTaskRunnerConfiguration): boolean { + private hasDetectorSupport(config: TaskConfig.ExternalTaskRunnerConfiguration): boolean { if (!config.command) { return false; } @@ -1122,7 +1154,7 @@ class TaskService extends EventEmitter implements ITaskService { } } -let tasksCategory = nls.localize('tasksCategory', "Tasks"); + let workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureTaskRunnerAction, ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT), 'Tasks: Configure Task Runner', tasksCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(BuildAction, BuildAction.ID, BuildAction.TEXT, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_B }), 'Tasks: Run Build Task', tasksCategory); @@ -1131,7 +1163,9 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(TestAc // workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CleanAction, CleanAction.ID, CleanAction.TEXT), tasksCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminateAction, TerminateAction.ID, TerminateAction.TEXT), 'Tasks: Terminate Running Task', tasksCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowLogAction, ShowLogAction.ID, ShowLogAction.TEXT), 'Tasks: Show Task Log', tasksCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunTaskAction, RunTaskAction.ID, RunTaskAction.TEXT), 'Tasks: Run Task', tasksCategory); +// workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunTaskAction, RunTaskAction.ID, RunTaskAction.TEXT), 'Tasks: Run Task', tasksCategory); + +MenuRegistry.addCommand({ id: 'workbench.action.tasks.runTask', title: nls.localize('RunTaskAction.label', "Run Task"), category: tasksCategory }); // Task Service registerSingleton(ITaskService, TaskService); diff --git a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts index 1e61ccc1d2b..255df6ee251 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts +++ b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts @@ -20,7 +20,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import * as FileConfig from './processRunnerConfiguration'; +import * as TaskConfig from '../common/taskConfiguration'; let build: string = 'build'; let test: string = 'test'; @@ -109,7 +109,7 @@ class GruntTaskMatcher implements TaskDetectorMatcher { } export interface DetectorResult { - config: FileConfig.ExternalTaskRunnerConfiguration; + config: TaskConfig.ExternalTaskRunnerConfiguration; stdout: string[]; stderr: string[]; } @@ -143,12 +143,12 @@ export class ProcessRunnerDetector { private fileService: IFileService; private contextService: IWorkspaceContextService; private configurationResolverService: IConfigurationResolverService; - private taskConfiguration: FileConfig.ExternalTaskRunnerConfiguration; + private taskConfiguration: TaskConfig.ExternalTaskRunnerConfiguration; private _stderr: string[]; private _stdout: string[]; private _cwd: string; - constructor(fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: FileConfig.ExternalTaskRunnerConfiguration = null) { + constructor(fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: TaskConfig.ExternalTaskRunnerConfiguration = null) { this.fileService = fileService; this.contextService = contextService; this.configurationResolverService = configurationResolverService; @@ -225,27 +225,27 @@ export class ProcessRunnerDetector { return result; } - private tryDetectGulp(list: boolean): TPromise<{ config: FileConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { + private tryDetectGulp(list: boolean): TPromise<{ config: TaskConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { return this.fileService.resolveFile(this.contextService.toResource('gulpfile.js')).then((stat) => { let config = ProcessRunnerDetector.detectorConfig('gulp'); let process = new LineProcess('gulp', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'gulp', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); - }, (err: any): FileConfig.ExternalTaskRunnerConfiguration => { + }, (err: any): TaskConfig.ExternalTaskRunnerConfiguration => { return null; }); } - private tryDetectGrunt(list: boolean): TPromise<{ config: FileConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { + private tryDetectGrunt(list: boolean): TPromise<{ config: TaskConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { return this.fileService.resolveFile(this.contextService.toResource('Gruntfile.js')).then((stat) => { let config = ProcessRunnerDetector.detectorConfig('grunt'); let process = new LineProcess('grunt', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'grunt', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); - }, (err: any): FileConfig.ExternalTaskRunnerConfiguration => { + }, (err: any): TaskConfig.ExternalTaskRunnerConfiguration => { return null; }); } - private tryDetectJake(list: boolean): TPromise<{ config: FileConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { + private tryDetectJake(list: boolean): TPromise<{ config: TaskConfig.ExternalTaskRunnerConfiguration; stderr: string[]; }> { let run = () => { let config = ProcessRunnerDetector.detectorConfig('jake'); let process = new LineProcess('jake', [config.arg], true, { cwd: this._cwd }); @@ -256,7 +256,7 @@ export class ProcessRunnerDetector { }, (err: any) => { return this.fileService.resolveFile(this.contextService.toResource('Jakefile.js')).then((stat) => { return run(); - }, (err: any): FileConfig.ExternalTaskRunnerConfiguration => { + }, (err: any): TaskConfig.ExternalTaskRunnerConfiguration => { return null; }); }); @@ -276,7 +276,7 @@ export class ProcessRunnerDetector { } return { config: null, stdout: this._stdout, stderr: this._stderr }; } - let result: FileConfig.ExternalTaskRunnerConfiguration = { + let result: TaskConfig.ExternalTaskRunnerConfiguration = { version: ProcessRunnerDetector.Version, command: command, isShellCommand: isShellCommand @@ -314,8 +314,8 @@ export class ProcessRunnerDetector { }); } - private createTaskDescriptions(tasks: string[], problemMatchers: string[], list: boolean): FileConfig.TaskDescription[] { - let taskConfigs: FileConfig.TaskDescription[] = []; + private createTaskDescriptions(tasks: string[], problemMatchers: string[], list: boolean): TaskConfig.TaskDescription[] { + let taskConfigs: TaskConfig.TaskDescription[] = []; if (list) { tasks.forEach((task) => { taskConfigs.push({ diff --git a/src/vs/workbench/parts/tasks/node/processRunnerSystem.ts b/src/vs/workbench/parts/tasks/node/processRunnerSystem.ts index c76fb34e5a5..94ffda79681 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerSystem.ts +++ b/src/vs/workbench/parts/tasks/node/processRunnerSystem.ts @@ -53,7 +53,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem { private activeTaskPromise: TPromise; constructor(configuration: TaskRunnerConfiguration, markerService: IMarkerService, modelService: IModelService, telemetryService: ITelemetryService, - outputService: IOutputService, configurationResolverService: IConfigurationResolverService, outputChannelId: string, clearOutput: boolean = true) { + outputService: IOutputService, configurationResolverService: IConfigurationResolverService, outputChannelId: string, hasErrors: boolean) { super(); this.configuration = configuration; this.markerService = markerService; @@ -66,11 +66,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem { this.activeTaskIdentifier = null; this.activeTaskPromise = null; this.outputChannel = this.outputService.getChannel(outputChannelId); - - if (clearOutput) { - this.clearOutput(); - } - this.errorsShown = false; + this.errorsShown = !hasErrors; } diff --git a/src/vs/workbench/parts/tasks/test/node/configuration.test.ts b/src/vs/workbench/parts/tasks/test/node/configuration.test.ts index 5ca2adadf50..1aed4095f10 100644 --- a/src/vs/workbench/parts/tasks/test/node/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/node/configuration.test.ts @@ -12,7 +12,7 @@ import * as Platform from 'vs/base/common/platform'; import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/platform/markers/common/problemMatcher'; import * as TaskSystem from 'vs/workbench/parts/tasks/common/taskSystem'; -import { parse, ParseResult, ILogger, ExternalTaskRunnerConfiguration } from 'vs/workbench/parts/tasks/node/processRunnerConfiguration'; +import { parse, ParseResult, ILogger, ExternalTaskRunnerConfiguration } from 'vs/workbench/parts/tasks/common/taskConfiguration'; class Logger implements ILogger { public receivedMessage: boolean = false; -- GitLab