@@ -193,9 +193,13 @@ type SyntheticSourceFile =
193
193
Source: string
194
194
ExtraSource: string
195
195
EntryPoint: bool
196
+ /// Indicates whether this is an existing F# file on disk.
197
+ IsPhysicalFile: bool
196
198
}
197
199
198
- member this.FileName = $" File{this.Id}.fs"
200
+ member this.FileName =
201
+ if this.IsPhysicalFile then $" %s {this.Id}.fs" else $" File%s {this.Id}.fs"
202
+
199
203
member this.SignatureFileName = $" {this.FileName}i"
200
204
member this.TypeName = $" T{this.Id}V_{this.PublicVersion}"
201
205
member this.ModuleName = $" Module{this.Id}"
@@ -216,7 +220,8 @@ let sourceFile fileId deps =
216
220
HasErrors = false
217
221
Source = " "
218
222
ExtraSource = " "
219
- EntryPoint = false }
223
+ EntryPoint = false
224
+ IsPhysicalFile = false }
220
225
221
226
222
227
let OptionsCache = ConcurrentDictionary()
@@ -468,6 +473,76 @@ let private writeFile (p: SyntheticProject) (f: SyntheticSourceFile) =
468
473
let content = renderSourceFile p f
469
474
writeFileIfChanged fileName content
470
475
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 {responseFile.FullName} does not exist"
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 ) -> file.EndsWith ( 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 {implPath}i" 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
+ }
471
546
472
547
[<AutoOpen>]
473
548
module ProjectOperations =
@@ -792,12 +867,14 @@ type WorkflowContext =
792
867
Signatures: Map < string , string >
793
868
Cursor: FSharpSymbolUse option }
794
869
795
- let SaveAndCheckProject project checker =
870
+ let SaveAndCheckProject project checker isExistingProject =
796
871
async {
797
872
use _ =
798
873
Activity.start " SaveAndCheckProject" [ Activity.Tags.project, project.Name ]
799
874
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
801
878
802
879
let options = project.GetProjectOptions checker
803
880
let! snapshot = FSharpProjectSnapshot.FromOptions( options, getFileSnapshot project)
@@ -834,13 +911,15 @@ type ProjectWorkflowBuilder
834
911
?useSyntaxTreeCache,
835
912
?useTransparentCompiler,
836
913
?runTimeout,
837
- ?autoStart
914
+ ?autoStart,
915
+ ?isExistingProject
838
916
) =
839
917
840
918
let useTransparentCompiler = defaultArg useTransparentCompiler FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically
841
919
let useGetSource = not useTransparentCompiler && defaultArg useGetSource false
842
920
let useChangeNotifications = not useTransparentCompiler && defaultArg useChangeNotifications false
843
921
let autoStart = defaultArg autoStart true
922
+ let isExistingProject = defaultArg isExistingProject false
844
923
845
924
let mutable latestProject = initialProject
846
925
let mutable activity = None
@@ -874,7 +953,7 @@ type ProjectWorkflowBuilder
874
953
let getInitialContext () =
875
954
match initialContext with
876
955
| Some ctx -> async.Return ctx
877
- | None -> SaveAndCheckProject initialProject checker
956
+ | None -> SaveAndCheckProject initialProject checker isExistingProject
878
957
879
958
/// Creates a ProjectWorkflowBuilder which will already have the project
880
959
/// saved and checked so time won't be spent on that.
@@ -915,7 +994,7 @@ type ProjectWorkflowBuilder
915
994
try
916
995
Async.RunSynchronously( workflow, timeout = defaultArg runTimeout 600_000 )
917
996
finally
918
- if initialContext.IsNone then
997
+ if initialContext.IsNone && not isExistingProject then
919
998
this.DeleteProjectDir()
920
999
activity |> Option.iter ( fun x -> x.Dispose())
921
1000
tracerProvider |> Option.iter ( fun x ->
@@ -1021,10 +1100,13 @@ type ProjectWorkflowBuilder
1021
1100
async {
1022
1101
let! ctx = workflow
1023
1102
1024
- use _ =
1103
+ use activity =
1025
1104
Activity.start " ProjectWorkflowBuilder.CheckFile" [ Activity.Tags.project, initialProject.Name; " fileId" , fileId ]
1026
1105
1027
- let! results = checkFile fileId ctx.Project checker
1106
+ let! results =
1107
+ checkFile fileId ctx.Project checker
1108
+
1109
+ activity.Dispose()
1028
1110
1029
1111
let oldSignature = ctx.Signatures[ fileId]
1030
1112
let newSignature = getSignature results
0 commit comments