@@ -31,14 +31,10 @@ export class CppBuildTask extends Task {
3131export class CppBuildTaskProvider implements TaskProvider {
3232static CppBuildScriptType :string = 'cppbuild' ;
3333static CppBuildSourceStr :string = "C/C++" ;
34- private tasks :CppBuildTask [ ] | undefined ;
3534
3635constructor ( ) { }
3736
3837public async provideTasks ( ) :Promise < CppBuildTask [ ] > {
39- if ( this . tasks ) {
40- return this . tasks ;
41- }
4238return this . getTasks ( false ) ;
4339}
4440
@@ -47,17 +43,14 @@ export class CppBuildTaskProvider implements TaskProvider {
4743const execution :ProcessExecution | ShellExecution | CustomExecution | undefined = _task . execution ;
4844if ( ! execution ) {
4945const definition :CppBuildTaskDefinition = < any > _task . definition ;
50- _task = this . getTask ( definition . command , false , definition . args ?definition . args :[ ] , definition ) ;
46+ _task = this . getTask ( definition . command , false , definition . args ?definition . args :[ ] , definition , _task . detail ) ;
5147return _task ;
5248}
5349return undefined ;
5450}
5551
5652// 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.
5753public async getTasks ( appendSourceToName :boolean ) :Promise < CppBuildTask [ ] > {
58- if ( this . tasks !== undefined ) {
59- return this . tasks ;
60- }
6154const editor :TextEditor | undefined = window . activeTextEditor ;
6255const emptyTasks :CppBuildTask [ ] = [ ] ;
6356if ( ! editor ) {
@@ -149,14 +142,11 @@ export class CppBuildTaskProvider implements TaskProvider {
149142if ( userCompilerPath ) {
150143result . push ( this . getTask ( userCompilerPath , appendSourceToName , userCompilerPathAndArgs ?. additionalArgs ) ) ;
151144}
152-
153145return result ;
154146}
155147
156- private getTask :( compilerPath :string , appendSourceToName :boolean , compilerArgs ?:string [ ] , definition ?:CppBuildTaskDefinition ) => Task = ( compilerPath :string , appendSourceToName :boolean , compilerArgs ?:string [ ] , definition ?:CppBuildTaskDefinition ) => {
148+ private getTask :( compilerPath :string , appendSourceToName :boolean , compilerArgs ?:string [ ] , definition ?:CppBuildTaskDefinition , detail ?: string ) => Task = ( compilerPath :string , appendSourceToName :boolean , compilerArgs ?:string [ ] , definition ?:CppBuildTaskDefinition , detail ?: string ) => {
157149const compilerPathBase :string = path . basename ( compilerPath ) ;
158- const taskLabel :string = ( ( appendSourceToName && ! compilerPathBase . startsWith ( CppBuildTaskProvider . CppBuildSourceStr ) ) ?
159- CppBuildTaskProvider . CppBuildSourceStr + ": " :"" ) + compilerPathBase + " build active file" ;
160150const isCl :boolean = compilerPathBase === "cl.exe" ;
161151// Double-quote the command if it is not already double-quoted.
162152let resolvedcompilerPath :string = isCl ?compilerPathBase :compilerPath ;
@@ -165,6 +155,8 @@ export class CppBuildTaskProvider implements TaskProvider {
165155}
166156
167157if ( ! definition ) {
158+ const taskLabel :string = ( ( appendSourceToName && ! compilerPathBase . startsWith ( CppBuildTaskProvider . CppBuildSourceStr ) ) ?
159+ CppBuildTaskProvider . CppBuildSourceStr + ": " :"" ) + compilerPathBase + " build active file" ;
168160const filePath :string = path . join ( '${fileDirname}' , '${fileBasenameNoExtension}' ) ;
169161const isWindows :boolean = os . platform ( ) === 'win32' ;
170162let args :string [ ] = isCl ?[ '/Zi' , '/EHsc' , '/Fe:' , filePath + '.exe' , '${file}' ] :[ '-g' , '${file}' , '-o' , filePath + ( isWindows ?'.exe' :'' ) ] ;
@@ -192,38 +184,58 @@ export class CppBuildTaskProvider implements TaskProvider {
192184}
193185
194186const scope :TaskScope = TaskScope . Workspace ;
195- const task :CppBuildTask = new Task ( definition , scope , taskLabel , CppBuildTaskProvider . CppBuildSourceStr ,
187+ const task :CppBuildTask = new Task ( definition , scope , definition . label , CppBuildTaskProvider . CppBuildSourceStr ,
196188new CustomExecution ( async ( ) :Promise < Pseudoterminal > =>
197189// When the task is executed, this callback will run. Here, we setup for running the task.
198190new CustomBuildTaskTerminal ( resolvedcompilerPath , definition ?definition . args :[ ] , definition ?definition . options :undefined )
199191) , isCl ?'$msCompile' :'$gcc' ) ;
200192
201193task . group = TaskGroup . Build ;
202- task . detail = "compiler: " + resolvedcompilerPath ;
194+ task . detail = detail ? detail : "compiler: " + resolvedcompilerPath ;
203195
204196return task ;
205197} ;
206198
199+ public async getJsonTasks ( ) :Promise < CppBuildTask [ ] > {
200+ const rawJson :any = await this . getRawTasksJson ( ) ;
201+ const rawTasksJson :any = ( ! rawJson . tasks ) ?new Array ( ) :rawJson . tasks ;
202+ const buildTasksJson :CppBuildTask [ ] = rawTasksJson . map ( ( task :any ) => {
203+ const definition :CppBuildTaskDefinition = {
204+ type :task . type ,
205+ label :task . label ,
206+ command :task . command ,
207+ args :task . args ,
208+ options :task . options
209+ } ;
210+ const cppBuildTask :CppBuildTask = new Task ( definition , TaskScope . Workspace , task . label , "C/C++" ) ;
211+ cppBuildTask . detail = task . detail ;
212+ return cppBuildTask ;
213+ } ) ;
214+ return buildTasksJson ;
215+ }
216+
207217public async ensureBuildTaskExists ( taskLabel :string ) :Promise < void > {
208218const rawTasksJson :any = await this . getRawTasksJson ( ) ;
209-
210- // Ensure that the task exists in the user's task.json. Task will not be found otherwise.
211219if ( ! rawTasksJson . tasks ) {
212220rawTasksJson . tasks = new Array ( ) ;
213221}
214- //Find or create the taskwhich should be created based on the selected "debug configuration" .
215- let selectedTask :CppBuildTask | undefined = rawTasksJson . tasks . find ( ( task :any ) => task . label && task . label === taskLabel ) ;
222+ //Ensure that the taskexists in the user's task.json. Task will not be found otherwise .
223+ let selectedTask :any = rawTasksJson . tasks . find ( ( task :any ) => task . label && task . label === taskLabel ) ;
216224if ( selectedTask ) {
217225return ;
218226}
219227
228+ // Create the task which should be created based on the selected "debug configuration".
220229const buildTasks :CppBuildTask [ ] = await this . getTasks ( true ) ;
221- selectedTask = buildTasks . find ( task => task . name === taskLabel ) ;
230+ const normalizedLabel :string = ( taskLabel . indexOf ( "ver(" ) !== - 1 ) ?taskLabel . slice ( 0 , taskLabel . indexOf ( "ver(" ) ) . trim ( ) :taskLabel ;
231+ selectedTask = buildTasks . find ( task => task . name === normalizedLabel ) ;
222232console . assert ( selectedTask ) ;
223233if ( ! selectedTask ) {
224234throw new Error ( "Failed to get selectedTask in ensureBuildTaskExists()" ) ;
235+ } else {
236+ selectedTask . definition . label = taskLabel ;
237+ selectedTask . name = taskLabel ;
225238}
226-
227239rawTasksJson . version = "2.0.0" ;
228240
229241// Modify the current default task
@@ -272,6 +284,23 @@ export class CppBuildTaskProvider implements TaskProvider {
272284return ;
273285}
274286
287+ // Provide a unique name for a newly defined tasks, which is different from tasks' names in tasks.json.
288+ public provideUniqueTaskLabel ( label :string , buildTasksJson :CppBuildTask [ ] ) :string {
289+ const taskNameDictionary :{ [ key :string ] :any } = { } ;
290+ buildTasksJson . forEach ( task => {
291+ taskNameDictionary [ task . definition . label ] = { } ;
292+ } ) ;
293+ let newLabel :string = label ;
294+ let version :number = 0 ;
295+ do {
296+ version = version + 1 ;
297+ newLabel = label + ` ver(${ version } )` ;
298+
299+ } while ( taskNameDictionary [ newLabel ] ) ;
300+
301+ return newLabel ;
302+ }
303+
275304private getLaunchJsonPath ( ) :string | undefined {
276305return util . getJsonPath ( "launch.json" ) ;
277306}
@@ -280,12 +309,12 @@ export class CppBuildTaskProvider implements TaskProvider {
280309return util . getJsonPath ( "tasks.json" ) ;
281310}
282311
283- private getRawLaunchJson ( ) :Promise < any > {
312+ public getRawLaunchJson ( ) :Promise < any > {
284313const path :string | undefined = this . getLaunchJsonPath ( ) ;
285314return util . getRawJson ( path ) ;
286315}
287316
288- private getRawTasksJson ( ) :Promise < any > {
317+ public getRawTasksJson ( ) :Promise < any > {
289318const path :string | undefined = this . getTasksJsonPath ( ) ;
290319return util . getRawJson ( path ) ;
291320}