From df8523e5509bf8cb2cdde0805c8d9cc87117c8d4 Mon Sep 17 00:00:00 2001 From: Elaheh Rashedi Date: Tue, 3 Nov 2020 14:39:48 -0800 Subject: [PATCH] "F5" using the correct build task (#6420) * shows details correctly * change default name * generating unique names * lint errors * lint errors * modify resolvetask * modify details --- .../src/Debugger/configurationProvider.ts | 42 ++++++++--- .../LanguageServer/cppBuildTaskProvider.ts | 73 +++++++++++++------ 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/Extension/src/Debugger/configurationProvider.ts b/Extension/src/Debugger/configurationProvider.ts index fbd130fa68..3142fe69da 100644 --- a/Extension/src/Debugger/configurationProvider.ts +++ b/Extension/src/Debugger/configurationProvider.ts @@ -7,7 +7,7 @@ import * as debugUtils from './utils'; import * as os from 'os'; import * as path from 'path'; import * as vscode from 'vscode'; -import { CppBuildTaskDefinition } from '../LanguageServer/cppBuildTaskProvider'; +import { CppBuildTask, CppBuildTaskDefinition } from '../LanguageServer/cppBuildTaskProvider'; import * as util from '../common'; import * as fs from 'fs'; import * as Telemetry from '../telemetry'; @@ -113,10 +113,6 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider { * Returns a list of initial debug configurations based on contextual information, e.g. package.json or folder. */ async provideDebugConfigurations(folder?: vscode.WorkspaceFolder, token?: vscode.CancellationToken): Promise { - let buildTasks: vscode.Task[] = await cppBuildTaskProvider.getTasks(true); - if (buildTasks.length === 0) { - return Promise.resolve(this.provider.getInitialConfigurations(this.type)); - } const defaultConfig: vscode.DebugConfiguration = this.provider.getInitialConfigurations(this.type).find((config: any) => isDebugLaunchStr(config.name) && config.request === "launch"); console.assert(defaultConfig, "Could not find default debug configuration."); @@ -124,14 +120,42 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider { const platformInfo: PlatformInformation = await PlatformInformation.GetPlatformInformation(); const platform: string = platformInfo.platform; + // Import the tasks from tasks.json file. + const buildTasksJson: CppBuildTask[] = await cppBuildTaskProvider.getJsonTasks(); + + // Provide detected tasks by cppBuildTaskProvider. + const buildTasksDetected: CppBuildTask[] = await cppBuildTaskProvider.getTasks(true); + + // Rename the provided tasks that has same name as tasks in tasks.json. + const buildTasksDetectedRename: CppBuildTask[] = buildTasksDetected.map(taskDetected => { + for (const taskJson of buildTasksJson) { + if ((taskDetected.definition.label as string) === (taskJson.definition.label as string)) { + taskDetected.name = cppBuildTaskProvider.provideUniqueTaskLabel(taskJson.definition.label, buildTasksJson); + taskDetected.definition.label = taskDetected.name; + break; + } + } + return taskDetected; + }); + + let buildTasks: CppBuildTask[] = []; + buildTasks = buildTasks.concat(buildTasksJson, buildTasksDetectedRename); + + if (buildTasks.length === 0) { + return Promise.resolve(this.provider.getInitialConfigurations(this.type)); + } + + if (buildTasks.length === 0) { + return Promise.resolve(this.provider.getInitialConfigurations(this.type)); + } // Filter out build tasks that don't match the currently selected debug configuration type. - buildTasks = buildTasks.filter((task: vscode.Task) => { + buildTasks = buildTasks.filter((task: CppBuildTask) => { if (defaultConfig.name.startsWith("(Windows) ")) { - if (task.name.startsWith("C/C++: cl.exe")) { + if ((task.definition.command as string).includes("cl.exe")) { return true; } } else { - if (!task.name.startsWith("C/C++: cl.exe")) { + if (!(task.definition.command as string).includes("cl.exe")) { return true; } } @@ -153,7 +177,7 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider { newConfig.program = platform === "win32" ? exeName + ".exe" : exeName; // Add the "detail" property to show the compiler path in QuickPickItem. // This property will be removed before writing the DebugConfiguration in launch.json. - newConfig.detail = definition.command; + newConfig.detail = task.detail ? task.detail : definition.command; return new Promise(resolve => { if (platform === "darwin") { diff --git a/Extension/src/LanguageServer/cppBuildTaskProvider.ts b/Extension/src/LanguageServer/cppBuildTaskProvider.ts index 1923b4f4f9..f31c729b54 100644 --- a/Extension/src/LanguageServer/cppBuildTaskProvider.ts +++ b/Extension/src/LanguageServer/cppBuildTaskProvider.ts @@ -31,14 +31,10 @@ export class CppBuildTask extends Task { export class CppBuildTaskProvider implements TaskProvider { static CppBuildScriptType: string = 'cppbuild'; static CppBuildSourceStr: string = "C/C++"; - private tasks: CppBuildTask[] | undefined; constructor() { } public async provideTasks(): Promise { - if (this.tasks) { - return this.tasks; - } return this.getTasks(false); } @@ -47,7 +43,7 @@ export class CppBuildTaskProvider implements TaskProvider { const execution: ProcessExecution | ShellExecution | CustomExecution | undefined = _task.execution; if (!execution) { const definition: CppBuildTaskDefinition = _task.definition; - _task = this.getTask(definition.command, false, definition.args ? definition.args : [], definition); + _task = this.getTask(definition.command, false, definition.args ? definition.args : [], definition, _task.detail); return _task; } return undefined; @@ -55,9 +51,6 @@ export class CppBuildTaskProvider implements TaskProvider { // Generate tasks to build the current file based on the user's detected compilers, the user's compilerPath setting, and the current file's extension. public async getTasks(appendSourceToName: boolean): Promise { - if (this.tasks !== undefined) { - return this.tasks; - } const editor: TextEditor | undefined = window.activeTextEditor; const emptyTasks: CppBuildTask[] = []; if (!editor) { @@ -149,14 +142,11 @@ export class CppBuildTaskProvider implements TaskProvider { if (userCompilerPath) { result.push(this.getTask(userCompilerPath, appendSourceToName, userCompilerPathAndArgs?.additionalArgs)); } - return result; } - private getTask: (compilerPath: string, appendSourceToName: boolean, compilerArgs?: string[], definition?: CppBuildTaskDefinition) => Task = (compilerPath: string, appendSourceToName: boolean, compilerArgs?: string[], definition?: CppBuildTaskDefinition) => { + private getTask: (compilerPath: string, appendSourceToName: boolean, compilerArgs?: string[], definition?: CppBuildTaskDefinition, detail?: string) => Task = (compilerPath: string, appendSourceToName: boolean, compilerArgs?: string[], definition?: CppBuildTaskDefinition, detail?: string) => { const compilerPathBase: string = path.basename(compilerPath); - const taskLabel: string = ((appendSourceToName && !compilerPathBase.startsWith(CppBuildTaskProvider.CppBuildSourceStr)) ? - CppBuildTaskProvider.CppBuildSourceStr + ": " : "") + compilerPathBase + " build active file"; const isCl: boolean = compilerPathBase === "cl.exe"; // Double-quote the command if it is not already double-quoted. let resolvedcompilerPath: string = isCl ? compilerPathBase : compilerPath; @@ -165,6 +155,8 @@ export class CppBuildTaskProvider implements TaskProvider { } if (!definition) { + const taskLabel: string = ((appendSourceToName && !compilerPathBase.startsWith(CppBuildTaskProvider.CppBuildSourceStr)) ? + CppBuildTaskProvider.CppBuildSourceStr + ": " : "") + compilerPathBase + " build active file"; const filePath: string = path.join('${fileDirname}', '${fileBasenameNoExtension}'); const isWindows: boolean = os.platform() === 'win32'; let args: string[] = isCl ? ['/Zi', '/EHsc', '/Fe:', filePath + '.exe', '${file}'] : ['-g', '${file}', '-o', filePath + (isWindows ? '.exe' : '')]; @@ -192,38 +184,58 @@ export class CppBuildTaskProvider implements TaskProvider { } const scope: TaskScope = TaskScope.Workspace; - const task: CppBuildTask = new Task(definition, scope, taskLabel, CppBuildTaskProvider.CppBuildSourceStr, + const task: CppBuildTask = new Task(definition, scope, definition.label, CppBuildTaskProvider.CppBuildSourceStr, new CustomExecution(async (): Promise => // When the task is executed, this callback will run. Here, we setup for running the task. new CustomBuildTaskTerminal(resolvedcompilerPath, definition ? definition.args : [], definition ? definition.options : undefined) ), isCl ? '$msCompile' : '$gcc'); task.group = TaskGroup.Build; - task.detail = "compiler: " + resolvedcompilerPath; + task.detail = detail ? detail : "compiler: " + resolvedcompilerPath; return task; }; + public async getJsonTasks(): Promise { + const rawJson: any = await this.getRawTasksJson(); + const rawTasksJson: any = (!rawJson.tasks) ? new Array() : rawJson.tasks; + const buildTasksJson: CppBuildTask[] = rawTasksJson.map((task: any) => { + const definition: CppBuildTaskDefinition = { + type: task.type, + label: task.label, + command: task.command, + args: task.args, + options: task.options + }; + const cppBuildTask: CppBuildTask = new Task(definition, TaskScope.Workspace, task.label, "C/C++"); + cppBuildTask.detail = task.detail; + return cppBuildTask; + }); + return buildTasksJson; + } + public async ensureBuildTaskExists(taskLabel: string): Promise { const rawTasksJson: any = await this.getRawTasksJson(); - - // Ensure that the task exists in the user's task.json. Task will not be found otherwise. if (!rawTasksJson.tasks) { rawTasksJson.tasks = new Array(); } - // Find or create the task which should be created based on the selected "debug configuration". - let selectedTask: CppBuildTask | undefined = rawTasksJson.tasks.find((task: any) => task.label && task.label === taskLabel); + // Ensure that the task exists in the user's task.json. Task will not be found otherwise. + let selectedTask: any = rawTasksJson.tasks.find((task: any) => task.label && task.label === taskLabel); if (selectedTask) { return; } + // Create the task which should be created based on the selected "debug configuration". const buildTasks: CppBuildTask[] = await this.getTasks(true); - selectedTask = buildTasks.find(task => task.name === taskLabel); + const normalizedLabel: string = (taskLabel.indexOf("ver(") !== -1) ? taskLabel.slice(0, taskLabel.indexOf("ver(")).trim() : taskLabel; + selectedTask = buildTasks.find(task => task.name === normalizedLabel); console.assert(selectedTask); if (!selectedTask) { throw new Error("Failed to get selectedTask in ensureBuildTaskExists()"); + } else { + selectedTask.definition.label = taskLabel; + selectedTask.name = taskLabel; } - rawTasksJson.version = "2.0.0"; // Modify the current default task @@ -272,6 +284,23 @@ export class CppBuildTaskProvider implements TaskProvider { return; } + // Provide a unique name for a newly defined tasks, which is different from tasks' names in tasks.json. + public provideUniqueTaskLabel(label: string, buildTasksJson: CppBuildTask[]): string { + const taskNameDictionary: {[key: string]: any} = {}; + buildTasksJson.forEach(task => { + taskNameDictionary[task.definition.label] = {}; + }); + let newLabel: string = label; + let version: number = 0; + do { + version = version + 1; + newLabel = label + ` ver(${version})`; + + } while (taskNameDictionary[newLabel]); + + return newLabel; + } + private getLaunchJsonPath(): string | undefined { return util.getJsonPath("launch.json"); } @@ -280,12 +309,12 @@ export class CppBuildTaskProvider implements TaskProvider { return util.getJsonPath("tasks.json"); } - private getRawLaunchJson(): Promise { + public getRawLaunchJson(): Promise { const path: string | undefined = this.getLaunchJsonPath(); return util.getRawJson(path); } - private getRawTasksJson(): Promise { + public getRawTasksJson(): Promise { const path: string | undefined = this.getTasksJsonPath(); return util.getRawJson(path); }