From bfcb0f1d453f4a4d0341e29f944ce142762f49a2 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Sat, 23 Jul 2022 14:07:59 -0500 Subject: [PATCH] add a way to efficiently map many project options to FCS options at once --- src/Ionide.ProjInfo.FCS/Library.fs | 71 ++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/Ionide.ProjInfo.FCS/Library.fs b/src/Ionide.ProjInfo.FCS/Library.fs index 0725f994..5be973cc 100644 --- a/src/Ionide.ProjInfo.FCS/Library.fs +++ b/src/Ionide.ProjInfo.FCS/Library.fs @@ -18,32 +18,57 @@ module FCS = FSharpReferencedProject.CreatePortableExecutable(p.TargetPath, getStamp, getStream) - let rec mapToFSharpProjectOptions (projectOptions: ProjectOptions) (allKnownProjects: ProjectOptions seq) : FSharpProjectOptions = + let private makeFCSOptions mapProjectToReference (project: ProjectOptions) = { ProjectId = None - ProjectFileName = projectOptions.ProjectFileName - SourceFiles = List.toArray projectOptions.SourceFiles - OtherOptions = List.toArray projectOptions.OtherOptions - ReferencedProjects = - projectOptions.ReferencedProjects - |> List.toArray - |> Array.choose (fun d -> - let knownProject = allKnownProjects |> Seq.tryFind (fun n -> n.ProjectFileName = d.ProjectFileName) - - let isDotnetProject (knownProject: ProjectOptions option) = - match knownProject with - | Some p -> (p.ProjectFileName.EndsWith(".csproj") || p.ProjectFileName.EndsWith(".vbproj")) && File.Exists p.TargetPath - | None -> false - - if d.ProjectFileName.EndsWith ".fsproj" then - knownProject - |> Option.map (fun p -> FSharpReferencedProject.CreateFSharp(p.TargetPath, mapToFSharpProjectOptions p allKnownProjects)) - elif isDotnetProject knownProject then - knownProject |> Option.map loadFromDotnetDll - else - None) + ProjectFileName = project.ProjectFileName + SourceFiles = List.toArray project.SourceFiles + OtherOptions = List.toArray project.OtherOptions + ReferencedProjects = project.ReferencedProjects |> List.toArray |> Array.choose mapProjectToReference IsIncompleteTypeCheckEnvironment = false UseScriptResolutionRules = false - LoadTime = projectOptions.LoadTime + LoadTime = project.LoadTime UnresolvedReferences = None // it's always None OriginalLoadReferences = [] // it's always empty list Stamp = None } + + let rec private makeProjectReference isKnownProject makeFSharpProjectReference (p: ProjectReference) : FSharpReferencedProject option = + let knownProject = isKnownProject p + + let isDotnetProject (knownProject: ProjectOptions option) = + match knownProject with + | Some p -> (p.ProjectFileName.EndsWith(".csproj") || p.ProjectFileName.EndsWith(".vbproj")) && File.Exists p.TargetPath + | None -> false + + if p.ProjectFileName.EndsWith ".fsproj" then + knownProject + |> Option.map (fun p -> + let theseOptions = makeFSharpProjectReference p + FSharpReferencedProject.CreateFSharp(p.TargetPath, theseOptions)) + elif isDotnetProject knownProject then + knownProject |> Option.map loadFromDotnetDll + else + None + + let mapManyOptions (allKnownProjects: ProjectOptions seq) : FSharpProjectOptions seq = + seq { + let dict = System.Collections.Concurrent.ConcurrentDictionary() + + let isKnownProject (p: ProjectReference) = + allKnownProjects |> Seq.tryFind (fun kp -> kp.ProjectFileName = p.ProjectFileName) + + let rec makeFSharpProjectReference (p: ProjectOptions) = + let factory = makeProjectReference isKnownProject makeFSharpProjectReference + dict.GetOrAdd(p, (fun p -> makeFCSOptions factory p)) + + for project in allKnownProjects do + let thisProject = + dict.GetOrAdd(project, (fun p -> makeFCSOptions (makeProjectReference isKnownProject makeFSharpProjectReference) p)) + + yield thisProject + } + + let rec mapToFSharpProjectOptions (projectOptions: ProjectOptions) (allKnownProjects: ProjectOptions seq) : FSharpProjectOptions = + let isKnownProject (d: ProjectReference) = + allKnownProjects |> Seq.tryFind (fun n -> n.ProjectFileName = d.ProjectFileName) + + makeFCSOptions (makeProjectReference isKnownProject (fun p -> mapToFSharpProjectOptions p allKnownProjects)) projectOptions