From 511de908d79830878eb6367bed2cabee1bb016c3 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Wed, 18 Dec 2024 18:15:40 +0100 Subject: [PATCH 1/4] wip --- .../Common/CapabilitiesManager.fs | 38 ++++++++----- .../FSharp.Compiler.LanguageServer.fsproj | 1 + .../FSharpLanguageServer.fs | 10 +++- .../FSharpLanguageServerConfig.fs | 14 +++++ .../ExtensionEntrypoint.cs | 2 + .../FSharp.VisualStudio.Extension.csproj | 8 +-- .../FSharpExtensionSettings.cs | 55 +++++++++++++++++++ .../FSharpLanguageServerProvider.cs | 54 +++++++++++++++--- .../Classification/ClassificationService.fs | 13 +++++ .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 7 ++- .../LanguageService/WorkspaceExtensions.fs | 42 ++++++++++++++ 11 files changed, 213 insertions(+), 31 deletions(-) create mode 100644 src/FSharp.Compiler.LanguageServer/FSharpLanguageServerConfig.fs create mode 100644 src/FSharp.VisualStudio.Extension/FSharpExtensionSettings.cs diff --git a/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs b/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs index b8b50e95f33..00b5e9c2bb3 100644 --- a/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs +++ b/src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs @@ -2,43 +2,53 @@ open Microsoft.VisualStudio.LanguageServer.Protocol open Microsoft.CommonLanguageServerProtocol.Framework +open FSharp.Compiler.LanguageServer type IServerCapabilitiesOverride = - abstract member OverrideServerCapabilities: ServerCapabilities -> ServerCapabilities + abstract member OverrideServerCapabilities: FSharpLanguageServerConfig * ServerCapabilities * ClientCapabilities -> ServerCapabilities -type CapabilitiesManager(scOverrides: IServerCapabilitiesOverride seq) = +type CapabilitiesManager(config: FSharpLanguageServerConfig, scOverrides: IServerCapabilitiesOverride seq) = let mutable initializeParams = None - let defaultCapabilities = + let getInitializeParams() = + match initializeParams with + | Some params' -> params' + | None -> failwith "InitializeParams is null" + + let addIf (enabled: bool) (capability: 'a) = + if enabled then capability |> withNull else null + + let defaultCapabilities (clientCapabilities: ClientCapabilities) = + // TODO: don't register if dynamic registraion is supported ServerCapabilities( TextDocumentSync = TextDocumentSyncOptions(OpenClose = true, Change = TextDocumentSyncKind.Full), DiagnosticOptions = - DiagnosticOptions(WorkDoneProgress = true, InterFileDependencies = true, Identifier = "potato", WorkspaceDiagnostics = true), + addIf config.EnabledFeatures.Diagnostics (DiagnosticOptions(WorkDoneProgress = true, InterFileDependencies = true, Identifier = "potato", WorkspaceDiagnostics = true)), //CompletionProvider = CompletionOptions(TriggerCharacters = [| "."; " " |], ResolveProvider = true, WorkDoneProgress = true), //HoverProvider = SumType(HoverOptions(WorkDoneProgress = true)) SemanticTokensOptions = - SemanticTokensOptions( + addIf config.EnabledFeatures.SemanticHighlighting + + (SemanticTokensOptions( Legend = SemanticTokensLegend( TokenTypes = (SemanticTokenTypes.AllTypes |> Seq.toArray), // XXX should be extended TokenModifiers = (SemanticTokenModifiers.AllModifiers |> Seq.toArray) ), Range = false - ) + )) ) interface IInitializeManager with member this.SetInitializeParams(request) = initializeParams <- Some request + member this.GetInitializeParams() = getInitializeParams() + member this.GetInitializeResult() = + let clientCapabilities = getInitializeParams().Capabilities let serverCapabilities = - (defaultCapabilities, scOverrides) - ||> Seq.fold (fun acc (x: IServerCapabilitiesOverride) -> x.OverrideServerCapabilities acc) - - InitializeResult(Capabilities = serverCapabilities) + (defaultCapabilities clientCapabilities, scOverrides) + ||> Seq.fold (fun acc (x: IServerCapabilitiesOverride) -> x.OverrideServerCapabilities(config, acc, clientCapabilities)) - member this.GetInitializeParams() = - match initializeParams with - | Some params' -> params' - | None -> failwith "InitializeParams is null" + InitializeResult(Capabilities = serverCapabilities) \ No newline at end of file diff --git a/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj b/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj index 1b5f7c99122..d6ebfc1c6f6 100644 --- a/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj +++ b/src/FSharp.Compiler.LanguageServer/FSharp.Compiler.LanguageServer.fsproj @@ -34,6 +34,7 @@ + diff --git a/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs index 9d0d3ec4412..d5e234526bf 100644 --- a/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs +++ b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs @@ -30,11 +30,12 @@ type Extensions = Async.StartAsTask(this, cancellationToken = ct) type FSharpLanguageServer - (jsonRpc: JsonRpc, logger: ILspLogger, ?initialWorkspace: FSharpWorkspace, ?addExtraHandlers: Action) = + (jsonRpc: JsonRpc, logger: ILspLogger, ?initialWorkspace: FSharpWorkspace, ?addExtraHandlers: Action, ?config: FSharpLanguageServerConfig) = // TODO: Switch to SystemTextJsonLanguageServer inherit NewtonsoftLanguageServer(jsonRpc, Newtonsoft.Json.JsonSerializer.CreateDefault(), logger) + let config = defaultArg config FSharpLanguageServerConfig.Default let initialWorkspace = defaultArg initialWorkspace (FSharpWorkspace()) do @@ -77,7 +78,10 @@ type FSharpLanguageServer static member Create(initialWorkspace, addExtraHandlers: Action) = FSharpLanguageServer.Create(LspLogger System.Diagnostics.Trace.TraceInformation, initialWorkspace, addExtraHandlers) - static member Create(logger: ILspLogger, initialWorkspace, ?addExtraHandlers: Action) = + static member Create(initialWorkspace, config: FSharpLanguageServerConfig, addExtraHandlers: Action) = + FSharpLanguageServer.Create(LspLogger System.Diagnostics.Trace.TraceInformation, initialWorkspace, addExtraHandlers, config) + + static member Create(logger: ILspLogger, initialWorkspace, ?addExtraHandlers: Action, ?config: FSharpLanguageServerConfig) = let struct (clientStream, serverStream) = FullDuplexStream.CreatePair() @@ -96,7 +100,7 @@ type FSharpLanguageServer jsonRpc.TraceSource.Switch.Level <- SourceLevels.All let server = - new FSharpLanguageServer(jsonRpc, logger, initialWorkspace, ?addExtraHandlers = addExtraHandlers) + new FSharpLanguageServer(jsonRpc, logger, initialWorkspace, ?addExtraHandlers = addExtraHandlers, ?config = config) jsonRpc.StartListening() diff --git a/src/FSharp.Compiler.LanguageServer/FSharpLanguageServerConfig.fs b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServerConfig.fs new file mode 100644 index 00000000000..15e8466b0ed --- /dev/null +++ b/src/FSharp.Compiler.LanguageServer/FSharpLanguageServerConfig.fs @@ -0,0 +1,14 @@ +namespace FSharp.Compiler.LanguageServer + +type FSharpLanguageServerFeatures = + { + Diagnostics: bool + SemanticHighlighting: bool + } + static member Default = { Diagnostics = true; SemanticHighlighting = true } + +type FSharpLanguageServerConfig = + { + EnabledFeatures: FSharpLanguageServerFeatures + } + static member Default = { EnabledFeatures = FSharpLanguageServerFeatures.Default } diff --git a/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs b/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs index 8fbaf39dc70..ba47320b925 100644 --- a/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs +++ b/src/FSharp.VisualStudio.Extension/ExtensionEntrypoint.cs @@ -2,6 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.Extensibility; +using System.Threading; +using System; using Extension = Microsoft.VisualStudio.Extensibility.Extension; /// diff --git a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj index db3a0a846f3..fae776deb73 100644 --- a/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj +++ b/src/FSharp.VisualStudio.Extension/FSharp.VisualStudio.Extension.csproj @@ -9,10 +9,10 @@ - - - - + + + +