From 11fcf6e204572a781d8e6bc81382cbaaeb1118f8 Mon Sep 17 00:00:00 2001 From: Jimmy Byrd Date: Sat, 25 Feb 2023 07:50:07 -0500 Subject: [PATCH 1/2] Initial msbuild properties support --- src/FsAutoComplete.Core/Consts.fs | 7 +++--- src/FsAutoComplete/LspHelpers.fs | 25 +++++++++++++++++++ .../LspServers/AdaptiveFSharpLspServer.fs | 19 ++++++++++++-- .../LspServers/FsAutoComplete.Lsp.fs | 2 +- src/FsAutoComplete/Parser.fs | 8 +++--- test/FsAutoComplete.Tests.Lsp/Helpers.fs | 1 + test/FsAutoComplete.Tests.Lsp/Program.fs | 11 +++++--- 7 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/FsAutoComplete.Core/Consts.fs b/src/FsAutoComplete.Core/Consts.fs index 423dfffd7..78d58fbc2 100644 --- a/src/FsAutoComplete.Core/Consts.fs +++ b/src/FsAutoComplete.Core/Consts.fs @@ -5,6 +5,7 @@ module ProjectLoader = let ProduceReferenceAssembly = "ProduceReferenceAssembly" let globalProperties = - [ - // For tooling we don't want to use Reference Assemblies as this doesn't play well with type checking across projects - ProduceReferenceAssembly, "false" ] + Map.ofList + [ + // For tooling we don't want to use Reference Assemblies as this doesn't play well with type checking across projects + ProduceReferenceAssembly, "false" ] diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 824dae84e..6f4a04158 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -609,6 +609,9 @@ type NotificationsDto = { Trace: bool option TraceNamespaces: string array option } +type BuildOptionsDto = + { MsBuildProperties: string array option } + type DebugDto = { DontCheckRelatedFiles: bool option CheckFileDebouncerTimeout: int option @@ -662,6 +665,7 @@ type FSharpConfigDto = InlayHints: InlayHintDto option Fsac: FSACDto option Notifications: NotificationsDto option + BuildOptions: BuildOptionsDto option Debug: DebugDto option } type FSharpConfigRequest = { FSharp: FSharpConfigDto option } @@ -725,6 +729,17 @@ type FSACConfig = member this.AddDto(dto: FSACDto) = { CachedTypeCheckCount = defaultArg dto.CachedTypeCheckCount this.CachedTypeCheckCount } +type BuildOptions = + { MsBuildProperties: string array } + + static member Default = { MsBuildProperties = [||] } + + static member FromDto(dto: BuildOptionsDto) : BuildOptions = + { MsBuildProperties = defaultArg dto.MsBuildProperties BuildOptions.Default.MsBuildProperties } + + + member this.AddDto(dto: BuildOptionsDto) : BuildOptions = + { MsBuildProperties = defaultArg dto.MsBuildProperties this.MsBuildProperties } type DebugConfig = { DontCheckRelatedFiles: bool @@ -778,6 +793,7 @@ type FSharpConfig = InlineValues: InlineValuesConfig Notifications: NotificationsConfig Fsac: FSACConfig + BuildOptions: BuildOptions Debug: DebugConfig } static member Default: FSharpConfig = @@ -820,6 +836,7 @@ type FSharpConfig = InlineValues = InlineValuesConfig.Default Notifications = NotificationsConfig.Default Fsac = FSACConfig.Default + BuildOptions = BuildOptions.Default Debug = DebugConfig.Default } static member FromDto(dto: FSharpConfigDto) : FSharpConfig = @@ -893,6 +910,10 @@ type FSharpConfig = dto.Fsac |> Option.map FSACConfig.FromDto |> Option.defaultValue FSACConfig.Default + BuildOptions = + dto.BuildOptions + |> Option.map BuildOptions.FromDto + |> Option.defaultValue BuildOptions.Default Debug = match dto.Debug with | None -> DebugConfig.Default @@ -981,6 +1002,10 @@ type FSharpConfig = |> Option.map x.Notifications.AddDto |> Option.defaultValue NotificationsConfig.Default Fsac = dto.Fsac |> Option.map x.Fsac.AddDto |> Option.defaultValue FSACConfig.Default + BuildOptions = + dto.BuildOptions + |> Option.map x.BuildOptions.AddDto + |> Option.defaultValue BuildOptions.Default Debug = match dto.Debug with | None -> DebugConfig.Default diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index 7ca88b328..21700485d 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -54,7 +54,7 @@ type AdaptiveWorkspaceChosen = | Projs of amap, DateTime> | NotChosen -type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FSharpLspClient) = +type AdaptiveFSharpLspServer(workspaceLoader: Map -> IWorkspaceLoader, lspClient: FSharpLspClient) = let thisType = typeof @@ -509,8 +509,23 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar file |> addAValLogging logMsg - let loader = cval workspaceLoader + let loaderFactory = cval -> Ionide.ProjInfo.IWorkspaceLoader> workspaceLoader + let loader = + aval { + let! loaderFactory = loaderFactory + and! config = config + + let props = + config.BuildOptions.MsBuildProperties + |> Array.choose(fun s -> + match s.Split("=") |> Array.toList with + | head::shoulders::_ -> Some(head,shoulders) + | _ -> None + ) + |> Map.ofArray + return loaderFactory props + } let binlogConfig = diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index cda183565..03f1a0d69 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -2953,7 +2953,7 @@ module FSharpLspServer = |> Map.add "fsproj/removeFile" (serverRequestHandling (fun s p -> s.FsProjRemoveFile(p))) let regularServer lspClient = - let state = State.Initial toolsPath stateStorageDir workspaceLoaderFactory + let state = State.Initial toolsPath stateStorageDir (fun toolsPath -> workspaceLoaderFactory toolsPath Map.empty) let originalFs = FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem <- FsAutoComplete.FileSystem(originalFs, state.Files.TryFind) new FSharpLspServer(state, lspClient) :> IFSharpLspServer diff --git a/src/FsAutoComplete/Parser.fs b/src/FsAutoComplete/Parser.fs index 655a3a466..da9993887 100644 --- a/src/FsAutoComplete/Parser.fs +++ b/src/FsAutoComplete/Parser.fs @@ -130,11 +130,12 @@ module Parser = rootCommand.SetHandler( Func<_, _, _, Task>(fun projectGraphEnabled stateDirectory adaptiveLspEnabled -> let workspaceLoaderFactory = - fun toolsPath -> + fun toolsPath props -> + let props = Map.merge ProjectLoader.globalProperties props |> Map.toList if projectGraphEnabled then - Ionide.ProjInfo.WorkspaceLoaderViaProjectGraph.Create(toolsPath, ProjectLoader.globalProperties) + Ionide.ProjInfo.WorkspaceLoaderViaProjectGraph.Create(toolsPath, props) else - Ionide.ProjInfo.WorkspaceLoader.Create(toolsPath, ProjectLoader.globalProperties) + Ionide.ProjInfo.WorkspaceLoader.Create(toolsPath, props) let dotnetPath = if @@ -191,7 +192,6 @@ module Parser = if ctx.ParseResult.GetValueForOption otelTracingOption then let serviceName = FsAutoComplete.Utils.Tracing.serviceName let version = FsAutoComplete.Utils.Version.info().Version - tracerProvider <- Sdk .CreateTracerProviderBuilder() diff --git a/test/FsAutoComplete.Tests.Lsp/Helpers.fs b/test/FsAutoComplete.Tests.Lsp/Helpers.fs index 2ad51f8bd..4004711db 100644 --- a/test/FsAutoComplete.Tests.Lsp/Helpers.fs +++ b/test/FsAutoComplete.Tests.Lsp/Helpers.fs @@ -272,6 +272,7 @@ let defaultConfigDto: FSharpConfigDto = Prefix = Some "//" } Notifications = None Fsac = None + BuildOptions = None Debug = None } let clientCaps: ClientCapabilities = diff --git a/test/FsAutoComplete.Tests.Lsp/Program.fs b/test/FsAutoComplete.Tests.Lsp/Program.fs index 1f25dcf6c..20b230e53 100644 --- a/test/FsAutoComplete.Tests.Lsp/Program.fs +++ b/test/FsAutoComplete.Tests.Lsp/Program.fs @@ -32,7 +32,9 @@ Environment.SetEnvironmentVariable("FSAC_WORKSPACELOAD_DELAY", "250") let loaders = [ - "Ionide WorkspaceLoader", (fun toolpath -> WorkspaceLoader.Create(toolpath, FsAutoComplete.Core.ProjectLoader.globalProperties)) + "Ionide WorkspaceLoader", (fun toolpath props -> + let props = FsAutoComplete.Utils.Map.merge FsAutoComplete.Core.ProjectLoader.globalProperties props |> Map.toList + WorkspaceLoader.Create(toolpath, props)) // "MSBuild Project Graph WorkspaceLoader", (fun toolpath -> WorkspaceLoaderViaProjectGraph.Create(toolpath, FsAutoComplete.Core.ProjectLoader.globalProperties)) ] @@ -195,9 +197,12 @@ let main args = args |> Array.windowed 2 |> Array.tryPick (function - | [| "--loader"; "ionide" |] as args -> Some(args, [ "Ionide WorkspaceLoader", WorkspaceLoader.Create ]) + | [| "--loader"; "ionide" |] as args -> + let (name, factory) = loaders |> Seq.find(fun (k,v) -> k = "Ionide WorkspaceLoader") + Some(args, [ name, factory ]) | [| "--loader"; "graph" |] as args -> - Some(args, [ "MSBuild Project Graph WorkspaceLoader", WorkspaceLoaderViaProjectGraph.Create ]) + let (name, factory) = loaders |> Seq.find(fun (k,v) -> k = "MSBuild Project Graph WorkspaceLoader") + Some(args, [ name, factory ]) | _ -> None) |> Option.defaultValue ([||], loaders) From 585848139dc4efcd4118d94bec2cfb569a82d91b Mon Sep 17 00:00:00 2001 From: Jimmy Byrd Date: Sat, 25 Feb 2023 13:50:26 -0500 Subject: [PATCH 2/2] Using simple dictionary for msbuild props --- src/FsAutoComplete/LspHelpers.fs | 15 ++++++++++----- .../LspServers/AdaptiveFSharpLspServer.fs | 15 ++++----------- .../LspServers/FsAutoComplete.Lsp.fs | 4 +++- src/FsAutoComplete/Parser.fs | 2 ++ 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 6f4a04158..c59bb338e 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -610,7 +610,7 @@ type NotificationsDto = TraceNamespaces: string array option } type BuildOptionsDto = - { MsBuildProperties: string array option } + { MsBuildProperties: Dictionary option } type DebugDto = { DontCheckRelatedFiles: bool option @@ -729,17 +729,22 @@ type FSACConfig = member this.AddDto(dto: FSACDto) = { CachedTypeCheckCount = defaultArg dto.CachedTypeCheckCount this.CachedTypeCheckCount } + type BuildOptions = - { MsBuildProperties: string array } + { MsBuildProperties: Map } - static member Default = { MsBuildProperties = [||] } + static member Default = { MsBuildProperties = Map.empty } static member FromDto(dto: BuildOptionsDto) : BuildOptions = - { MsBuildProperties = defaultArg dto.MsBuildProperties BuildOptions.Default.MsBuildProperties } + let props = dto.MsBuildProperties |> Option.map (Seq.map (|KeyValue|) >> Map.ofSeq) + + { MsBuildProperties = defaultArg props BuildOptions.Default.MsBuildProperties } member this.AddDto(dto: BuildOptionsDto) : BuildOptions = - { MsBuildProperties = defaultArg dto.MsBuildProperties this.MsBuildProperties } + let props = dto.MsBuildProperties |> Option.map (Seq.map (|KeyValue|) >> Map.ofSeq) + + { MsBuildProperties = defaultArg props this.MsBuildProperties } type DebugConfig = { DontCheckRelatedFiles: bool diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index 21700485d..ef250025b 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -509,22 +509,15 @@ type AdaptiveFSharpLspServer(workspaceLoader: Map -> IWorkspaceL file |> addAValLogging logMsg - let loaderFactory = cval -> Ionide.ProjInfo.IWorkspaceLoader> workspaceLoader + let loaderFactory = + cval -> Ionide.ProjInfo.IWorkspaceLoader> workspaceLoader + let loader = aval { let! loaderFactory = loaderFactory and! config = config - let props = - config.BuildOptions.MsBuildProperties - |> Array.choose(fun s -> - match s.Split("=") |> Array.toList with - | head::shoulders::_ -> Some(head,shoulders) - | _ -> None - ) - |> Map.ofArray - - return loaderFactory props + return loaderFactory config.BuildOptions.MsBuildProperties } diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index 03f1a0d69..aa71f5a1b 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -2953,7 +2953,9 @@ module FSharpLspServer = |> Map.add "fsproj/removeFile" (serverRequestHandling (fun s p -> s.FsProjRemoveFile(p))) let regularServer lspClient = - let state = State.Initial toolsPath stateStorageDir (fun toolsPath -> workspaceLoaderFactory toolsPath Map.empty) + let state = + State.Initial toolsPath stateStorageDir (fun toolsPath -> workspaceLoaderFactory toolsPath Map.empty) + let originalFs = FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem <- FsAutoComplete.FileSystem(originalFs, state.Files.TryFind) new FSharpLspServer(state, lspClient) :> IFSharpLspServer diff --git a/src/FsAutoComplete/Parser.fs b/src/FsAutoComplete/Parser.fs index da9993887..e777255e5 100644 --- a/src/FsAutoComplete/Parser.fs +++ b/src/FsAutoComplete/Parser.fs @@ -132,6 +132,7 @@ module Parser = let workspaceLoaderFactory = fun toolsPath props -> let props = Map.merge ProjectLoader.globalProperties props |> Map.toList + if projectGraphEnabled then Ionide.ProjInfo.WorkspaceLoaderViaProjectGraph.Create(toolsPath, props) else @@ -192,6 +193,7 @@ module Parser = if ctx.ParseResult.GetValueForOption otelTracingOption then let serviceName = FsAutoComplete.Utils.Tracing.serviceName let version = FsAutoComplete.Utils.Version.info().Version + tracerProvider <- Sdk .CreateTracerProviderBuilder()