@@ -131,27 +131,48 @@ function promptToAddAssets() {
131131 } ) ;
132132}
133133
134- function createLaunchConfiguration ( targetFramework : string , executableName : string ) : ConsoleLaunchConfiguration {
134+ function computeProgramPath ( projectData : TargetProjectData ) {
135+ if ( ! projectData ) {
136+ // If there's no target project data, use a placeholder for the path.
137+ return '${workspaceRoot}/bin/Debug/<target-framework>/<project-name.dll>'
138+ }
139+
140+ let result = '${workspaceRoot}' ;
141+
142+ if ( projectData . projectPath ) {
143+ result += vscode . workspace . asRelativePath ( projectData . projectPath ) ;
144+ }
145+
146+ if ( ! result . endsWith ( '/' ) ) {
147+ result += '/' ;
148+ }
149+
150+ result += `bin/${ projectData . configurationName } /${ projectData . targetFramework } /${ projectData . executableName } ` ;
151+
152+ return result ;
153+ }
154+
155+ function createLaunchConfiguration ( projectData : TargetProjectData ) : ConsoleLaunchConfiguration {
135156 return {
136157 name : '.NET Core Launch (console)' ,
137158 type : 'coreclr' ,
138159 request : 'launch' ,
139160 preLaunchTask : 'build' ,
140- program : '${workspaceRoot}/bin/Debug/' + targetFramework + '/' + executableName ,
161+ program : computeProgramPath ( projectData ) ,
141162 args : [ ] ,
142163 cwd : '${workspaceRoot}' ,
143164 externalConsole : false ,
144165 stopAtEntry : false
145166 }
146167}
147168
148- function createWebLaunchConfiguration ( targetFramework : string , executableName : string ) : WebLaunchConfiguration {
169+ function createWebLaunchConfiguration ( projectData : TargetProjectData ) : WebLaunchConfiguration {
149170 return {
150171 name : '.NET Core Launch (web)' ,
151172 type : 'coreclr' ,
152173 request : 'launch' ,
153174 preLaunchTask : 'build' ,
154- program : '${workspaceRoot}/bin/Debug/' + targetFramework + '/' + executableName ,
175+ program : computeProgramPath ( projectData ) ,
155176 args : [ ] ,
156177 cwd : '${workspaceRoot}' ,
157178 stopAtEntry : false ,
@@ -187,13 +208,13 @@ function createAttachConfiguration(): AttachConfiguration {
187208 }
188209}
189210
190- function createLaunchJson ( targetFramework : string , executableName : string , isWebProject : boolean ) : any {
211+ function createLaunchJson ( projectData : TargetProjectData , isWebProject : boolean ) : any {
191212 let version = '0.2.0' ;
192213 if ( ! isWebProject ) {
193214 return {
194215 version : version ,
195216 configurations : [
196- createLaunchConfiguration ( targetFramework , executableName ) ,
217+ createLaunchConfiguration ( projectData ) ,
197218 createAttachConfiguration ( )
198219 ]
199220 }
@@ -202,49 +223,123 @@ function createLaunchJson(targetFramework: string, executableName: string, isWeb
202223 return {
203224 version : version ,
204225 configurations : [
205- createWebLaunchConfiguration ( targetFramework , executableName ) ,
226+ createWebLaunchConfiguration ( projectData ) ,
206227 createAttachConfiguration ( )
207228 ]
208229 }
209230 }
210231}
211232
212- function createBuildTaskDescription ( ) : tasks . TaskDescription {
233+ function createBuildTaskDescription ( projectData : TargetProjectData ) : tasks . TaskDescription {
234+ let buildPath = '' ;
235+ if ( projectData ) {
236+ buildPath = '${workspaceRoot}' ;
237+ buildPath += vscode . workspace . asRelativePath ( projectData . projectJsonPath ) ;
238+ }
239+
213240 return {
214241 taskName : 'build' ,
215- args : [ ] ,
242+ args : [ buildPath ] ,
216243 isBuildCommand : true ,
217244 problemMatcher : '$msCompile'
218245 } ;
219246}
220247
221- function createTasksConfiguration ( ) : tasks . TaskConfiguration {
248+ function createTasksConfiguration ( projectData : TargetProjectData ) : tasks . TaskConfiguration {
222249 return {
223250 version : '0.1.0' ,
224251 command : 'dotnet' ,
225252 isShellCommand : true ,
226253 args : [ ] ,
227- tasks : [ createBuildTaskDescription ( ) ]
254+ tasks : [ createBuildTaskDescription ( projectData ) ]
228255 } ;
229256}
230257
231- function addTasksJsonIfNecessary ( info : protocol . DotNetWorkspaceInformation , paths : Paths , operations : Operations ) {
258+ function addTasksJsonIfNecessary ( projectData : TargetProjectData , paths : Paths , operations : Operations ) {
232259 return new Promise < void > ( ( resolve , reject ) => {
233260 if ( ! operations . addTasksJson ) {
234261 return resolve ( ) ;
235262 }
236263
237- const tasksJson = createTasksConfiguration ( ) ;
264+ const tasksJson = createTasksConfiguration ( projectData ) ;
238265 const tasksJsonText = JSON . stringify ( tasksJson , null , ' ' ) ;
239266
240267 return fs . writeFileAsync ( paths . tasksJsonPath , tasksJsonText ) ;
241268 } ) ;
242269}
243270
244- function hasWebServerDependency ( projectJsonPath : string ) {
245- let projectJson = fs . readFileSync ( projectJsonPath , 'utf8' ) ;
246- let projectJsonObject = JSON . parse ( projectJson . replace ( / ^ \uFEFF / , '' ) ) ;
247-
271+ interface TargetProjectData {
272+ projectPath : string ;
273+ projectJsonPath : string ;
274+ targetFramework : string ;
275+ executableName : string ;
276+ configurationName : string ;
277+ }
278+
279+ function findTargetProjectData ( projects : protocol . DotNetProject [ ] ) : TargetProjectData {
280+ // TODO: For now, assume the Debug configuration. Eventually, we'll need to revisit
281+ // this when we allow selecting configurations.
282+ const configurationName = 'Debug' ;
283+
284+ const executableProjects = findExecutableProjects ( projects , configurationName ) ;
285+
286+ // TODO: We arbitrarily pick the first executable projec that we find. This will need
287+ // revisiting when we project a "start up project" selector.
288+ const targetProject = executableProjects . length > 0
289+ ? executableProjects [ 0 ]
290+ : undefined ;
291+
292+ if ( targetProject && targetProject . Frameworks . length > 0 ) {
293+ const config = targetProject . Configurations . find ( c => c . Name === configurationName ) ;
294+ if ( config ) {
295+ return {
296+ projectPath : targetProject . Path ,
297+ projectJsonPath : path . join ( targetProject . Path , 'project.json' ) ,
298+ targetFramework : targetProject . Frameworks [ 0 ] . ShortName ,
299+ executableName : path . basename ( config . CompilationOutputAssemblyFile ) ,
300+ configurationName
301+ } ;
302+ }
303+ }
304+
305+ return undefined ;
306+ }
307+
308+ function findExecutableProjects ( projects : protocol . DotNetProject [ ] , configName : string ) {
309+ let result : protocol . DotNetProject [ ] = [ ] ;
310+
311+ projects . forEach ( project => {
312+ project . Configurations . forEach ( configuration => {
313+ if ( configuration . Name === configName && configuration . EmitEntryPoint === true ) {
314+ if ( project . Frameworks . length > 0 ) {
315+ result . push ( project ) ;
316+ }
317+ }
318+ } ) ;
319+ } ) ;
320+
321+ return result ;
322+ }
323+
324+ function hasWebServerDependency ( targetProjectData : TargetProjectData ) : boolean {
325+ if ( ! targetProjectData || ! targetProjectData . projectJsonPath ) {
326+ return false ;
327+ }
328+
329+ let projectJson = fs . readFileSync ( targetProjectData . projectJsonPath , 'utf8' ) ;
330+ projectJson = projectJson . replace ( / ^ \uFEFF / , '' ) ;
331+
332+ let projectJsonObject : any ;
333+
334+ try {
335+ // TODO: This error should be surfaced to the user. If the JSON can't be parsed
336+ // (maybe due to a syntax error like an extra comma), the user should be notified
337+ // to fix up their project.json.
338+ projectJsonObject = JSON . parse ( projectJson ) ;
339+ } catch ( error ) {
340+ projectJsonObject = null ;
341+ }
342+
248343 if ( projectJsonObject == null ) {
249344 return false ;
250345 }
@@ -255,38 +350,17 @@ function hasWebServerDependency(projectJsonPath: string) {
255350 }
256351 }
257352
258- return false ;
353+ return false ;
259354}
260355
261- function addLaunchJsonIfNecessary ( info : protocol . DotNetWorkspaceInformation , paths : Paths , operations : Operations , projectJsonPath : string ) {
356+ function addLaunchJsonIfNecessary ( projectData : TargetProjectData , paths : Paths , operations : Operations ) {
262357 return new Promise < void > ( ( resolve , reject ) => {
263358 if ( ! operations . addLaunchJson ) {
264359 return resolve ( ) ;
265360 }
266-
267- let targetFramework = '<target-framework>' ;
268- let executableName = '<project-name.dll>' ;
269-
270- let done = false ;
271- for ( var project of info . Projects ) {
272- for ( var configuration of project . Configurations ) {
273- if ( configuration . Name === "Debug" && configuration . EmitEntryPoint === true ) {
274- if ( project . Frameworks . length > 0 ) {
275- targetFramework = project . Frameworks [ 0 ] . ShortName ;
276- executableName = path . basename ( configuration . CompilationOutputAssemblyFile )
277- }
278-
279- done = true ;
280- break ;
281- }
282- }
283-
284- if ( done ) {
285- break ;
286- }
287- }
288-
289- const launchJson = createLaunchJson ( targetFramework , executableName , hasWebServerDependency ( projectJsonPath ) ) ;
361+
362+ const isWebProject = hasWebServerDependency ( projectData ) ;
363+ const launchJson = createLaunchJson ( projectData , isWebProject ) ;
290364 const launchJsonText = JSON . stringify ( launchJson , null , ' ' ) ;
291365
292366 return fs . writeFileAsync ( paths . launchJsonPath , launchJsonText ) ;
@@ -298,12 +372,6 @@ export function addAssetsIfNecessary(server: OmnisharpServer) {
298372 return ;
299373 }
300374
301- // If there is no project.json, we won't bother to prompt the user for tasks.json.
302- const projectJsonPath = path . join ( vscode . workspace . rootPath , 'project.json' ) ;
303- if ( ! fs . existsSync ( projectJsonPath ) ) {
304- return ;
305- }
306-
307375 return serverUtils . requestWorkspaceInformation ( server ) . then ( info => {
308376 // If there are no .NET Core projects, we won't bother offering to add assets.
309377 if ( 'DotNet' in info && info . DotNet . Projects . length > 0 ) {
@@ -317,12 +385,13 @@ export function addAssetsIfNecessary(server: OmnisharpServer) {
317385 return ;
318386 }
319387
388+ const data = findTargetProjectData ( info . DotNet . Projects ) ;
320389 const paths = getPaths ( ) ;
321390
322391 return fs . ensureDirAsync ( paths . vscodeFolder ) . then ( ( ) => {
323392 return Promise . all ( [
324- addTasksJsonIfNecessary ( info . DotNet , paths , operations ) ,
325- addLaunchJsonIfNecessary ( info . DotNet , paths , operations , projectJsonPath )
393+ addTasksJsonIfNecessary ( data , paths , operations ) ,
394+ addLaunchJsonIfNecessary ( data , paths , operations )
326395 ] ) ;
327396 } ) ;
328397 } ) ;
0 commit comments