nathanjcollins / zed-fsharp

F# support for Zed
11 stars 0 forks source link

Support running FsAutocomplete on other .NET Runtimes #3

Open baronfel opened 2 months ago

baronfel commented 2 months ago

The current distribution of F# for zed doesn't support running FsAutocomplete on .NET 9 preview SDKs, or any SDK that isn't explicitly supported by FSAC. When users try zed with projects that use the 9 SDK, they get errors like this in the LSP:

LSP errors ```terminal stderr: [18:19:34.770 ERR] [ProjectLoader] Generic error while loading project /Users/u/code/fsharp3/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/CS/MicroPerfCSharp.csproj stderr: Microsoft.Build.Exceptions.InvalidProjectFileException: SDK Resolver Failure: "The SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" failed while attempting to resolve the SDK "Microsoft.NET.SDK.WorkloadAutoImportPropsLocator". Exception: "System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. stderr: stderr: File name: 'System.Text.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' stderr: at Microsoft.NET.Sdk.WorkloadManifestReader.SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.GetWorkloadVersionFromGlobalJson(String globalJsonPath) stderr: at Microsoft.NET.Sdk.WorkloadManifestReader.SdkDirectoryWorkloadManifestProvider.RefreshWorkloadManifests() stderr: at Microsoft.NET.Sdk.WorkloadManifestReader.SdkDirectoryWorkloadManifestProvider..ctor(String sdkRootPath, String sdkVersion, Func`2 getEnvironmentVariable, String userProfileDir, String globalJsonPath, String workloadSetVersion) stderr: at Microsoft.NET.Sdk.WorkloadManifestReader.SdkDirectoryWorkloadManifestProvider..ctor(String sdkRootPath, String sdkVersion, String userProfileDir, String globalJsonPath) stderr: at Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.CachingWorkloadResolver.Resolve(String sdkReferenceName, String dotnetRootPath, String sdkVersion, String userProfileDir, String globalJsonPath) stderr: at Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver.WorkloadSdkResolver.Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory) stderr: at Microsoft.Build.BackEnd.SdkResolution.SdkResolverService.TryResolveSdkUsingSpecifiedResolvers(IReadOnlyList`1 resolvers, Int32 submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, String solutionPath, String projectPath, Boolean interactive, Boolean isRunningInVisualStudio, SdkResult& sdkResult, IEnumerable`1& errors, IEnumerable`1& warnings)"" /usr/local/share/dotnet/sdk/9.0.100-preview.6.24328.19/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.props stderr: at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args) stderr: at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject[T1](IElementLocation elementLocation, String resourceName, T1 arg0) stderr: at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpressionConditioned(String directoryOfImportingFile, ProjectImportElement importElement, List`1& projects, SdkResult& sdkResult) stderr: at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImports(String directoryOfImportingFile, ProjectImportElement importElement, SdkResult& sdkResult) stderr: at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) stderr: at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) stderr: at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) stderr: at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) stderr: at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) stderr: at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) stderr: at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) stderr: at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) stderr: at Microsoft.Build.Evaluation.Evaluator`4.Evaluate() stderr: at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(IEvaluatorData`4 data, Project project, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary`1 environmentProperties, ILoggingService loggingService, IItemFactory`2 itemFactory, IToolsetProvider toolsetProvider, IDirectoryCacheFactory directoryCacheFactory, ProjectRootElementCacheBase projectRootElementCache, BuildEventContext buildEventContext, ISdkResolverService sdkResolverService, Int32 submissionId, EvaluationContext evaluationContext, Boolean interactive) stderr: at Microsoft.Build.Evaluation.Project.ProjectImpl.Reevaluate(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext) stderr: at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext) stderr: at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation, EvaluationContext evaluationContext) stderr: at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(EvaluationContext evaluationContext) stderr: at Microsoft.Build.Evaluation.Project.ProjectImpl.Initialize(IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, Boolean interactive) stderr: at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory, Boolean interactive) stderr: at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings) stderr: at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings) stderr: at Ionide.ProjInfo.ProjectLoader.createNewProject@442(String path, ProjectCollection collection, IDictionary`2 properties) in /_//src/Ionide.ProjInfo/Library.fs:line 444 stderr: at Ionide.ProjInfo.ProjectLoader.findOrCreateMatchingProject(String path, ProjectCollection collection, IDictionary`2 globalProps) in /_//src/Ionide.ProjInfo/Library.fs:line 474 stderr: at Ionide.ProjInfo.ProjectLoader.loadProject(String path, BinaryLogGeneration binaryLogs, ProjectCollection projectCollection) in /_//src/Ionide.ProjInfo/Library.fs:line 626 ```

This is because FSAC needs to load the same DLLs as the SDK that's in use for the current workspace, and if the SDK in use is newer than the latest TFM that FSAC supports then FSAC needs to be launched with env vars to let it roll-forward more eagerly.

In Ionide, we've worked around this limitation with this logic - the purpose of which is to

I believe that same process should happen here so that Zed users can use more versions of the SDK and not be tightly bound to FSAC releases to bring support.

nathanjcollins commented 2 months ago

@baronfel thanks for the details, this is very helpful. Tested this locally and it seems like the neovim extension I use also has this issue.

When I get some time I'll see if I can implement something similar to the above in this plugin 🙂