@@ -193,9 +193,13 @@ type SyntheticSourceFile =
193193:  string 
194194        ExtraSource:  string 
195195        EntryPoint:  bool 
196+         /// Indicates whether this is an existing F# file on disk. 
197+ :  bool 
196198    } 
197199
198-     member  this.FileName  =  $" File{this.Id}.fs" 
200+     member  this.FileName  = 
201+         if  this.IsPhysicalFile then  $" %s " else  $" File%s " 
202+ 
199203    member  this.SignatureFileName  =  $" {this.FileName}i" 
200204    member  this.TypeName  =  $" T{this.Id}V_{this.PublicVersion}" 
201205    member  this.ModuleName  =  $" Module{this.Id}" 
@@ -216,7 +220,8 @@ let sourceFile fileId deps =
216220      HasErrors =  false 
217221      Source =  " " 
218222      ExtraSource =  " " 
219-       EntryPoint =  false  } 
223+       EntryPoint =  false 
224+       IsPhysicalFile =  false  } 
220225
221226
222227let  OptionsCache  =  ConcurrentDictionary() 
@@ -468,6 +473,76 @@ let private writeFile (p: SyntheticProject) (f: SyntheticSourceFile) =
468473    let  content  =  renderSourceFile p f
469474    writeFileIfChanged fileName content
470475
476+ /// Creates a SyntheticProject from the compiler arguments found in the response file. 
477+ let  mkSyntheticProjectForResponseFile   ( responseFile :  FileInfo )  :  SyntheticProject  = 
478+     if  not  responseFile.Exists then 
479+         failwith $" %s " 
480+     
481+     let  compilerArgs  =  File.ReadAllLines responseFile.FullName
482+ 
483+     let  fsharpFileExtensions  =  set [|  " .fs" ;  " .fsi" ;  " .fsx" |] 
484+ 
485+     let  isFSharpFile   ( file  :  string )  = 
486+         Set.exists ( fun   ( ext  :  string )  -> ( ext,  StringComparison.Ordinal))  fsharpFileExtensions
487+           
488+     let  fsharpFiles  = 
489+         compilerArgs
490+         |>  Array.choose ( fun   ( line  :  string )  -> 
491+             if  not  ( isFSharpFile line)  then 
492+                 None
493+             else 
494+ 
495+             let  fullPath  =  Path.Combine ( responseFile.DirectoryName,  line) 
496+             if  not  ( File.Exists fullPath)  then 
497+                 None
498+             else 
499+                 Some fullPath
500+         ) 
501+         |>  Array.toList
502+ 
503+     let  signatureFiles ,  implementationFiles  = 
504+         fsharpFiles |>  List.partition ( fun  path  ->  path.EndsWith " .fsi" ) 
505+ 
506+     let  signatureFiles  =  set signatureFiles
507+ 
508+     let  sourceFiles  = 
509+         implementationFiles
510+         |>  List.map ( fun  implPath  -> 
511+             let  id  = 
512+                 let  fileNameWithoutExtension  =  Path.GetFileNameWithoutExtension implPath 
513+                 let  directoryOfFile  =  FileInfo( implPath) .DirectoryName
514+                 let  relativeUri  =  Uri( responseFile.FullName) .MakeRelativeUri( Uri( directoryOfFile)) 
515+                 let  relativeFolderPath  =  Uri.UnescapeDataString( relativeUri.ToString()) .Replace( '/' ,  Path.DirectorySeparatorChar) 
516+                 Path.Combine( relativeFolderPath,  fileNameWithoutExtension) 
517+ 
518+             { 
519+                   Id =  id
520+                   PublicVersion =  1 
521+                   InternalVersion =  1 
522+                   DependsOn =  [] 
523+                   FunctionName =  " f" 
524+                   SignatureFile = 
525+                       let  sigPath  =  $" %s " in 
526+                       if  signatureFiles.Contains sigPath then  Custom( File.ReadAllText sigPath)  else  No
527+                   HasErrors =  false 
528+                   Source =  File.ReadAllText implPath
529+                   ExtraSource =  " " 
530+                   EntryPoint =  false 
531+                   IsPhysicalFile =  true  
532+             } 
533+         ) 
534+     
535+     let  otherOptions  = 
536+         compilerArgs
537+         |>  Array.filter ( fun  line  ->  not  ( isFSharpFile line)) 
538+         |>  Array.toList
539+ 
540+     {  SyntheticProject.Create( Path.GetFileNameWithoutExtension responseFile.Name)  with 
541+         ProjectDir =  responseFile.DirectoryName
542+         SourceFiles =  sourceFiles
543+         OtherOptions =  otherOptions
544+         AutoAddModules =  false 
545+     } 
471546
472547[<AutoOpen>] 
473548module  ProjectOperations  = 
@@ -792,12 +867,14 @@ type WorkflowContext =
792867      Signatures:  Map < string ,  string > 
793868      Cursor:  FSharpSymbolUse option  } 
794869
795- let  SaveAndCheckProject  project checker  = 
870+ let  SaveAndCheckProject  project checker isExistingProject   = 
796871    async  { 
797872        use  _ = 
798873            Activity.start " SaveAndCheckProject" [  Activity.Tags.project,  project.Name ] 
799874
800-         do !  saveProject project true  checker
875+         // Don't save the project if it is a real world project that exists on disk. 
876+         if  not  isExistingProject then 
877+             do !  saveProject project true  checker
801878
802879        let  options  =  project.GetProjectOptions checker
803880        let!  snapshot  =  FSharpProjectSnapshot.FromOptions( options,  getFileSnapshot project) 
@@ -834,13 +911,15 @@ type ProjectWorkflowBuilder
834911        ?useSyntaxTreeCache, 
835912        ?useTransparentCompiler, 
836913        ?runTimeout, 
837-         ?autoStart
914+         ?autoStart, 
915+         ?isExistingProject
838916    )  = 
839917
840918    let  useTransparentCompiler  =  defaultArg useTransparentCompiler FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically
841919    let  useGetSource  =  not  useTransparentCompiler &&  defaultArg useGetSource false 
842920    let  useChangeNotifications  =  not  useTransparentCompiler &&  defaultArg useChangeNotifications false 
843921    let  autoStart  =  defaultArg autoStart true 
922+     let  isExistingProject  =  defaultArg isExistingProject false 
844923
845924    let mutable  latestProject  =  initialProject
846925    let mutable  activity  =  None
@@ -874,7 +953,7 @@ type ProjectWorkflowBuilder
874953    let  getInitialContext ()  = 
875954        match  initialContext with 
876955        |  Some ctx ->  async.Return ctx
877-         |  None ->  SaveAndCheckProject initialProject checker
956+         |  None ->  SaveAndCheckProject initialProject checker isExistingProject 
878957
879958    /// Creates a ProjectWorkflowBuilder which will already have the project 
880959/// saved and checked so time won't be spent on that. 
@@ -915,7 +994,7 @@ type ProjectWorkflowBuilder
915994        try 
916995            Async.RunSynchronously( workflow,  timeout =  defaultArg runTimeout 600_000 ) 
917996        finally 
918-             if  initialContext.IsNone then 
997+             if  initialContext.IsNone &&   not  isExistingProject  then 
919998                this.DeleteProjectDir() 
920999            activity |>  Option.iter ( fun  x  ->  x.Dispose()) 
9211000            tracerProvider |>  Option.iter ( fun  x  -> 
@@ -1021,10 +1100,13 @@ type ProjectWorkflowBuilder
10211100        async  { 
10221101            let!  ctx  =  workflow
10231102
1024-             use  _  = 
1103+             use  activity  = 
10251104                Activity.start " ProjectWorkflowBuilder.CheckFile" [  Activity.Tags.project,  initialProject.Name;  " fileId" ,  fileId ] 
10261105
1027-             let!  results  =  checkFile fileId ctx.Project checker
1106+             let!  results  = 
1107+                 checkFile fileId ctx.Project checker
1108+ 
1109+             activity.Dispose() 
10281110
10291111            let  oldSignature  =  ctx.Signatures[ fileId] 
10301112            let  newSignature  =  getSignature results
0 commit comments