From 586fff5df2a69ae09b65e99b557286dec8dddc42 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Fri, 15 Mar 2024 12:52:50 +0100 Subject: [PATCH 1/2] Add minimal solution file --- VSFSharpExtension.sln | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 VSFSharpExtension.sln diff --git a/VSFSharpExtension.sln b/VSFSharpExtension.sln new file mode 100644 index 00000000000..ea65dc0c6f4 --- /dev/null +++ b/VSFSharpExtension.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B4A1E626-4A48-4977-B291-219882DB3413}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service", "src\Compiler\FSharp.Compiler.Service.fsproj", "{0F25FA8C-3A2A-4908-BDB6-23D90946502C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSharp.VisualStudio.Extension", "src\FSharp.VisualStudio.Extension\FSharp.VisualStudio.Extension.csproj", "{14B9AB0E-2FC0-43F1-9775-20C262202D12}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Release|Any CPU.Build.0 = Release|Any CPU + {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0F25FA8C-3A2A-4908-BDB6-23D90946502C} = {B4A1E626-4A48-4977-B291-219882DB3413} + {14B9AB0E-2FC0-43F1-9775-20C262202D12} = {B4A1E626-4A48-4977-B291-219882DB3413} + EndGlobalSection +EndGlobal From 524c1c25c6a7cd8b70522b6771d1c17483a184a4 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Tue, 26 Mar 2024 14:07:12 +0100 Subject: [PATCH 2/2] Get compiler cmdline args via ProjectQuery --- VSFSharpExtension.sln | 19 +++--- src/Compiler/Service/FSharpProjectSnapshot.fs | 5 +- .../FSharp.VisualStudio.Extension.csproj | 8 ++- .../FSharpLanguageServerProvider.cs | 59 +++++++++++++++---- 4 files changed, 65 insertions(+), 26 deletions(-) diff --git a/VSFSharpExtension.sln b/VSFSharpExtension.sln index ea65dc0c6f4..0c3c7d1a184 100644 --- a/VSFSharpExtension.sln +++ b/VSFSharpExtension.sln @@ -5,30 +5,29 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B4A1E626-4A48-4977-B291-219882DB3413}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service", "src\Compiler\FSharp.Compiler.Service.fsproj", "{0F25FA8C-3A2A-4908-BDB6-23D90946502C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.VisualStudio.Extension", "src\FSharp.VisualStudio.Extension\FSharp.VisualStudio.Extension.csproj", "{14B9AB0E-2FC0-43F1-9775-20C262202D12}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSharp.VisualStudio.Extension", "src\FSharp.VisualStudio.Extension\FSharp.VisualStudio.Extension.csproj", "{14B9AB0E-2FC0-43F1-9775-20C262202D12}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer", "src\FSharp.Compiler.LanguageServer\FSharp.Compiler.LanguageServer.fsproj", "{7EDDFB35-2428-4433-8ABF-47233480B746}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0F25FA8C-3A2A-4908-BDB6-23D90946502C}.Release|Any CPU.Build.0 = Release|Any CPU {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Debug|Any CPU.Build.0 = Debug|Any CPU {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Release|Any CPU.ActiveCfg = Release|Any CPU {14B9AB0E-2FC0-43F1-9775-20C262202D12}.Release|Any CPU.Build.0 = Release|Any CPU + {7EDDFB35-2428-4433-8ABF-47233480B746}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EDDFB35-2428-4433-8ABF-47233480B746}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7EDDFB35-2428-4433-8ABF-47233480B746}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EDDFB35-2428-4433-8ABF-47233480B746}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {0F25FA8C-3A2A-4908-BDB6-23D90946502C} = {B4A1E626-4A48-4977-B291-219882DB3413} {14B9AB0E-2FC0-43F1-9775-20C262202D12} = {B4A1E626-4A48-4977-B291-219882DB3413} EndGlobalSection EndGlobal diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 38d62f974f8..14fca7148b9 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -679,6 +679,9 @@ and [] FSha let compilerArgs = File.ReadAllLines responseFile.FullName + FSharpProjectSnapshot.FromCommandLineArgs(compilerArgs, responseFile.DirectoryName, projectFileName) + + static member FromCommandLineArgs(compilerArgs: string array, directoryPath: string, projectFileName) = let fsharpFileExtensions = set [| ".fs"; ".fsi"; ".fsx" |] let isFSharpFile (file: string) = @@ -693,7 +696,7 @@ and [] FSha None else - let fullPath = Path.Combine(responseFile.DirectoryName, line) + let fullPath = Path.Combine(directoryPath, line) if not (File.Exists fullPath) then None else Some fullPath) |> Array.toList diff --git a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj index bbcbdb6e3af..bef467713a0 100644 --- a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj +++ b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj @@ -9,10 +9,12 @@ - - + + - + + + diff --git a/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs b/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs index d8880e08835..3a282fe12d3 100644 --- a/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs +++ b/src/FSharp.VisualStudio.Extension/FSharpLanguageServerProvider.cs @@ -157,13 +157,46 @@ internal class FSharpLanguageServerProvider : LanguageServerProvider public override async Task CreateServerConnectionAsync(CancellationToken cancellationToken) { var ws = this.Extensibility.Workspaces(); - //var result = what.QueryProjectsAsync(project => project.With(p => p.Kind == "6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705"), cancellationToken).Result; - IQueryResults? result = await ws.QueryProjectsAsync(project => project.With(p => new { p.ActiveConfigurations, p.Id, p.Guid }), cancellationToken); - var x = await ws.QuerySolutionAsync(solution => solution.With(s => new { s.Path, s.Guid, s.ActiveConfiguration, s.ActivePlatform }), cancellationToken); + IQueryResults? result = await ws.QueryProjectsAsync(project => project + .With(p => p.ActiveConfigurations + .With(c => c.RuleResultsByRuleName("CompilerCommandLineArgs") + .With(r => r.RuleName) + .With(r => r.Items))) + .With(p => new { p.ActiveConfigurations, p.Id, p.Guid }), cancellationToken); + + List<(string, string)> projectsAndCommandLineArgs = []; foreach (var project in result) { + project.Id.TryGetValue("ProjectPath", out var projectPath); + + List commandLineArgs = []; + if (projectPath != null) + { + // There can be multiple Active Configurations, e.g. one for net8.0 and one for net472 + // TODO For now taking any single one of them, but we might actually want to pick specific one + var config = project.ActiveConfigurations.FirstOrDefault(); + if (config != null) + { + foreach (var ruleResults in config.RuleResults) + { + // XXX Idk why `.Where` does not work with these IAsyncQuerable type + if (ruleResults?.RuleName == "CompilerCommandLineArguments") + { + // XXX Not sure why there would be more than one item for this rule result + // Taking first one, ignoring the rest + var args = ruleResults?.Items?.FirstOrDefault()?.Name; + if (args != null) commandLineArgs.Add(args); + } + } + } + if (commandLineArgs.Count > 0) + { + projectsAndCommandLineArgs.Add((projectPath, commandLineArgs[0])); + } + } + try { this.ProcessProject(project); @@ -178,15 +211,17 @@ internal class FSharpLanguageServerProvider : LanguageServerProvider try { - // Some hardcoded projects before we create them from the ProjectQuery - var projectsRoot = @"D:\code"; - var giraffe = FSharpProjectSnapshot.FromResponseFile( - new FileInfo(Path.Combine(projectsRoot, @"Giraffe\src\Giraffe\Giraffe.rsp")), - Path.Combine(projectsRoot, @"Giraffe\src\Giraffe\Giraffe.fsproj")); - var giraffeTests = FSharpProjectSnapshot.FromResponseFile( - new FileInfo(Path.Combine(projectsRoot, @"Giraffe\tests\Giraffe.Tests\Giraffe.Tests.rsp")), - Path.Combine(projectsRoot, @"Giraffe\tests\Giraffe.Tests\Giraffe.Tests.fsproj")); - workspace = FSharpWorkspace.Create([giraffe, giraffeTests]); + List snapshots = []; + foreach(var args in projectsAndCommandLineArgs) + { + var lines = args.Item2.Split(';'); // XXX Probably not robust enough + var path = args.Item1; + + var snapshot = FSharpProjectSnapshot.FromCommandLineArgs( + lines, Path.GetDirectoryName(path), Path.GetFileName(path)); + snapshots.Add(snapshot); + } + workspace = FSharpWorkspace.Create(snapshots); } catch {