Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions VisualFSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,15 @@ EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MicroPerf", "tests\benchmarks\CompiledCodeBenchmarks\MicroPerf\MicroPerf.fsproj", "{601CD5C1-EAFA-4AE3-8FB9-F667B5728213}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroPerfCSharp", "tests\benchmarks\CompiledCodeBenchmarks\MicroPerf\CS\MicroPerfCSharp.csproj", "{9F9DD315-37DA-4413-928E-1CFC6924B64F}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer", "src\FSharp.Compiler.LanguageServer\FSharp.Compiler.LanguageServer.fsproj", "{D72F6593-DB2D-47AC-8E15-8DCE8527972E}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer.Tests", "tests\FSharp.Compiler.LanguageServer.Tests\FSharp.Compiler.LanguageServer.Tests.fsproj", "{1E83A6C8-FA4D-42BD-B4A5-B7F9AAD1B388}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.VisualStudio.Extension", "src\FSharp.VisualStudio.Extension\FSharp.VisualStudio.Extension.csproj", "{E1013576-6257-47BA-AAFB-F95B68DAB1FF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CommonLanguageServerProtocol.Framework.Proxy", "src\Microsoft.CommonLanguageServerProtocol.Framework.Proxy\Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj", "{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1060,6 +1063,18 @@ Global
{E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|Any CPU.Build.0 = Release|Any CPU
{E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|x86.ActiveCfg = Release|Any CPU
{E1013576-6257-47BA-AAFB-F95B68DAB1FF}.Release|x86.Build.0 = Release|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|x86.ActiveCfg = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Debug|x86.Build.0 = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|Any CPU.Build.0 = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|x86.ActiveCfg = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Proto|x86.Build.0 = Debug|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|Any CPU.Build.0 = Release|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|x86.ActiveCfg = Release|Any CPU
{FAFF15B5-F7C4-1CE5-9A18-2F6DC93E03ED}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 2 additions & 1 deletion buildtools/AssemblyCheck/SkipVerifyEmbeddedPdb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ FSharp.Benchmarks.Common.dll
FSharp.Compiler.Benchmarks.dll
FSharp.Compiler.ComponentTests.dll
FSharp.Test.Utilities.dll
FSharp.Compiler.LanguageServer.Tests.dll
FSharp.Compiler.Private.Scripting.UnitTests.dll
FSharp.Compiler.Service.Tests.dll
FSharp.Core.UnitTests.dll
FSharpSuite.Tests.dll
FSharpSuite.Tests.dll
1 change: 1 addition & 0 deletions src/Compiler/Service/FSharpProjectSnapshot.fs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ and [<Experimental("This FCS API is experimental and subject to change.")>] FSha
member _.OriginalLoadReferences = projectSnapshot.OriginalLoadReferences
member _.Stamp = projectSnapshot.Stamp
member _.OutputFileName = projectSnapshot.OutputFileName
member _.ProjectConfig = projectSnapshot.ProjectConfig

static member Create
(
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Service/FSharpWorkspace.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ open FSharpWorkspaceQuery
/// Project references are discovered automatically as projects are added or updated.
///
/// Updates to file contents are signaled through the `Files.Open`, `Files.Edit`, and `Files.Close` methods.
[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpWorkspace(checker: FSharpChecker) =

let depGraph = LockOperatedDependencyGraph() :> IThreadSafeDependencyGraph<_, _>
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Service/FSharpWorkspaceQuery.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ open FSharpWorkspaceState

#nowarn "57"

[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpDiagnosticReport internal (diagnostics, resultId: int) =

member _.Diagnostics = diagnostics

/// The result ID of the diagnostics. This needs to be unique for each version of the document in order to be able to clear old diagnostics.
member _.ResultId = resultId.ToString()

[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpWorkspaceQuery internal (depGraph: IThreadSafeDependencyGraph<_, _>, checker: FSharpChecker) =

let mutable resultIdCounter = 0
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Service/FSharpWorkspaceState.fs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ module internal WorkspaceDependencyGraphExtensions =
|> _.Unpack(WorkspaceNode.sourceFile)

/// Interface for managing files in an F# workspace.
[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpWorkspaceFiles internal (depGraph: IThreadSafeDependencyGraph<_, _>) =

/// Open files in the editor.
Expand Down Expand Up @@ -255,6 +256,7 @@ type FSharpWorkspaceFiles internal (depGraph: IThreadSafeDependencyGraph<_, _>)
| false, _ -> None

/// Interface for managing with projects in an F# workspace.
[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpWorkspaceProjects internal (depGraph: IThreadSafeDependencyGraph<_, _>, files: FSharpWorkspaceFiles) =

/// A map from project output path to project identifier.
Expand Down
13 changes: 11 additions & 2 deletions src/FSharp.Compiler.LanguageServer/Common/CapabilitiesManager.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ type CapabilitiesManager(scOverrides: IServerCapabilitiesOverride seq) =
TextDocumentSync = TextDocumentSyncOptions(OpenClose = true, Change = TextDocumentSyncKind.Full),
DiagnosticOptions =
DiagnosticOptions(WorkDoneProgress = true, InterFileDependencies = true, Identifier = "potato", WorkspaceDiagnostics = true),
CompletionProvider = CompletionOptions(TriggerCharacters = [| "."; " " |], ResolveProvider = true, WorkDoneProgress = true),
HoverProvider = SumType<bool, HoverOptions>(HoverOptions(WorkDoneProgress = true))
//CompletionProvider = CompletionOptions(TriggerCharacters = [| "."; " " |], ResolveProvider = true, WorkDoneProgress = true),
//HoverProvider = SumType<bool, HoverOptions>(HoverOptions(WorkDoneProgress = true))
SemanticTokensOptions =
SemanticTokensOptions(
Legend =
SemanticTokensLegend(
TokenTypes = (SemanticTokenTypes.AllTypes |> Seq.toArray), // XXX should be extended
TokenModifiers = (SemanticTokenModifiers.AllModifiers |> Seq.toArray)
),
Range = false
)
)

interface IInitializeManager<InitializeParams, InitializeResult> with
Expand Down
23 changes: 12 additions & 11 deletions src/FSharp.Compiler.LanguageServer/Common/FSharpRequestContext.fs
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,15 @@ type ContextHolder(workspace, lspServices: ILspServices) =

type FShapRequestContextFactory(lspServices: ILspServices) =

interface IRequestContextFactory<FSharpRequestContext> with

member _.CreateRequestContextAsync<'TRequestParam>
(
queueItem: IQueueItem<FSharpRequestContext>,
requestParam: 'TRequestParam,
cancellationToken: CancellationToken
) =
lspServices.GetRequiredService<ContextHolder>()
|> _.GetContext()
|> Task.FromResult
inherit AbstractRequestContextFactory<FSharpRequestContext>()

override _.CreateRequestContextAsync<'TRequestParam>
(
queueItem: IQueueItem<FSharpRequestContext>,
methodHandler: IMethodHandler,
requestParam: 'TRequestParam,
cancellationToken: CancellationToken
) =
lspServices.GetRequiredService<ContextHolder>()
|> _.GetContext()
|> Task.FromResult
24 changes: 14 additions & 10 deletions src/FSharp.Compiler.LanguageServer/Common/LifecycleManager.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ open StreamJsonRpc
open System.Threading.Tasks
open Microsoft.Extensions.DependencyInjection

#nowarn "3261"

type LspServiceLifeCycleManager() =

interface ILifeCycleManager with
member this.ShutdownAsync(message: string) =
member _.ShutdownAsync(message: string) =
task {
try
printfn "Shutting down"
Expand All @@ -18,7 +20,7 @@ type LspServiceLifeCycleManager() =
| :? ConnectionLostException -> ()
}

member this.ExitAsync() = Task.CompletedTask
member _.ExitAsync() = Task.CompletedTask

type FSharpLspServices(serviceCollection: IServiceCollection) as this =

Expand All @@ -27,15 +29,17 @@ type FSharpLspServices(serviceCollection: IServiceCollection) as this =
let serviceProvider = serviceCollection.BuildServiceProvider()

interface ILspServices with
member this.GetRequiredService<'T when 'T: not null>() : 'T =
serviceProvider.GetRequiredService<'T>()

member this.TryGetService(t) = serviceProvider.GetService(t)
member _.GetRequiredService() = serviceProvider.GetRequiredService()

member this.GetRequiredServices() = serviceProvider.GetServices()
member _.GetService() = serviceProvider.GetService()

member this.GetRegisteredServices() = failwith "Not implemented"
member _.GetRequiredServices() = serviceProvider.GetServices()

member this.SupportsGetRegisteredServices() = false
member _.Dispose() = serviceProvider.Dispose()

member this.Dispose() = ()
member _.TryGetService(``type``, service) =
match serviceProvider.GetService(``type``) with
| NonNull x ->
service <- x
true
| Null -> false
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<CheckNulls>true</CheckNulls>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup Label="Package References">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.CommonLanguageServerProtocol.Framework" Version="4.10.0-2.24105.6" />
<!--<PackageReference Include="Microsoft.CodeAnalysis.LanguageServer.Protocol" Version="4.10.0-1.24067.1" />-->
<PackageReference Include="Microsoft.VisualStudio.LanguageServer.Protocol" Version="17.10.13-preview" />
<PackageReference Include="StreamJsonRpc" Version="2.17.13" />
<PackageReference Include="Microsoft.VisualStudio.LanguageServer.Protocol" Version="17.13.6-preview" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.12.21" />
<PackageReference Include="StreamJsonRpc" Version="2.21.3-preview" />
</ItemGroup>

<ItemGroup>
Expand All @@ -32,20 +32,20 @@
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\vsintegration\src\FSharp.Editor\Common\CancellableTasks.fs" />
<Compile Include="Utils.fs" />
<Compile Include="Common\LifecycleManager.fs" />
<Compile Include="Common\CapabilitiesManager.fs" />
<Compile Include="Common\FSharpRequestContext.fs" />
<Compile Include="Handlers\LanguageFeaturesHandler.fs" />
<Compile Include="Handlers\DocumentStateHandler.fs" />
<Compile Include="Utils.fs" />
<Compile Include="FSharpLanguageServer.fs" />
<Compile Include="Executable.fs" />
</ItemGroup>

<ItemGroup>
<!--<ProjectReference Include="..\..\..\roslyn\src\Features\LanguageServer\Microsoft.CommonLanguageServerProtocol.Framework\Microsoft.CommonLanguageServerProtocol.Framework.csproj" />-->
<ProjectReference Include="..\Compiler\FSharp.Compiler.Service.fsproj" />
<ProjectReference Include="..\Compiler\FSharp.Compiler.Service.fsproj" />
<ProjectReference Include="..\Microsoft.CommonLanguageServerProtocol.Framework.Proxy\Microsoft.CommonLanguageServerProtocol.Framework.Proxy.csproj" />
</ItemGroup>

</Project>

18 changes: 11 additions & 7 deletions src/FSharp.Compiler.LanguageServer/FSharpLanguageServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ open Nerdbank.Streams
open System.Diagnostics
open FSharp.Compiler.CodeAnalysis.Workspace

#nowarn "57"

[<AutoOpen>]
module Stuff =
[<Literal>]
Expand All @@ -29,7 +31,9 @@ type Extensions =

type FSharpLanguageServer
(jsonRpc: JsonRpc, logger: ILspLogger, ?initialWorkspace: FSharpWorkspace, ?addExtraHandlers: Action<IServiceCollection>) =
inherit AbstractLanguageServer<FSharpRequestContext>(jsonRpc, logger)

// TODO: Switch to SystemTextJsonLanguageServer
inherit NewtonsoftLanguageServer<FSharpRequestContext>(jsonRpc, Newtonsoft.Json.JsonSerializer.CreateDefault(), logger)

let initialWorkspace = defaultArg initialWorkspace (FSharpWorkspace())

Expand All @@ -39,8 +43,6 @@ type FSharpLanguageServer

member _.JsonRpc: JsonRpc = jsonRpc

member private this.GetBaseHandlerProvider() = base.GetHandlerProvider()

override this.ConstructLspServices() =
let serviceCollection = new ServiceCollection()

Expand All @@ -53,8 +55,7 @@ type FSharpLanguageServer
.AddSingleton<IMethodHandler, DocumentStateHandler>()
.AddSingleton<IMethodHandler, LanguageFeaturesHandler>()
.AddSingleton<ILspLogger>(logger)
.AddSingleton<IRequestContextFactory<FSharpRequestContext>, FShapRequestContextFactory>()
.AddSingleton<IHandlerProvider>(fun _ -> this.GetBaseHandlerProvider())
.AddSingleton<AbstractRequestContextFactory<FSharpRequestContext>, FShapRequestContextFactory>()
.AddSingleton<IInitializeManager<InitializeParams, InitializeResult>, CapabilitiesManager>()
.AddSingleton(this)
.AddSingleton<ILifeCycleManager>(new LspServiceLifeCycleManager())
Expand All @@ -68,7 +69,10 @@ type FSharpLanguageServer
lspServices :> ILspServices

static member Create() =
FSharpLanguageServer.Create(FSharpWorkspace(), (fun _ -> ()))
FSharpLanguageServer.Create(FSharpWorkspace())

static member Create(initialWorkspace) =
FSharpLanguageServer.Create(initialWorkspace, (fun _ -> ()))

static member Create(initialWorkspace, addExtraHandlers: Action<IServiceCollection>) =
FSharpLanguageServer.Create(LspLogger System.Diagnostics.Trace.TraceInformation, initialWorkspace, addExtraHandlers)
Expand All @@ -89,7 +93,7 @@ type FSharpLanguageServer

jsonRpc.TraceSource.Listeners.Add(listener) |> ignore

jsonRpc.TraceSource.Switch.Level <- SourceLevels.Information
jsonRpc.TraceSource.Switch.Level <- SourceLevels.All

let server =
new FSharpLanguageServer(jsonRpc, logger, initialWorkspace, ?addExtraHandlers = addExtraHandlers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ open FSharp.Compiler.LanguageServer.Common
open System.Threading
open System.Threading.Tasks

#nowarn "57"

type DocumentStateHandler() =
interface IMethodHandler with
member _.MutatesSolutionState = true

interface IRequestHandler<DidOpenTextDocumentParams, SemanticTokensDeltaPartialResult, FSharpRequestContext> with
[<LanguageServerEndpoint(Methods.TextDocumentDidOpenName)>]
[<LanguageServerEndpoint(Methods.TextDocumentDidOpenName, LanguageServerConstants.DefaultLanguageName)>]
member _.HandleRequestAsync
(
request: DidOpenTextDocumentParams,
Expand All @@ -26,7 +28,7 @@ type DocumentStateHandler() =
Task.FromResult(SemanticTokensDeltaPartialResult())

interface IRequestHandler<DidChangeTextDocumentParams, SemanticTokensDeltaPartialResult, FSharpRequestContext> with
[<LanguageServerEndpoint(Methods.TextDocumentDidChangeName)>]
[<LanguageServerEndpoint(Methods.TextDocumentDidChangeName, LanguageServerConstants.DefaultLanguageName)>]
member _.HandleRequestAsync
(
request: DidChangeTextDocumentParams,
Expand All @@ -40,7 +42,7 @@ type DocumentStateHandler() =
Task.FromResult(SemanticTokensDeltaPartialResult())

interface INotificationHandler<DidCloseTextDocumentParams, FSharpRequestContext> with
[<LanguageServerEndpoint(Methods.TextDocumentDidCloseName)>]
[<LanguageServerEndpoint(Methods.TextDocumentDidCloseName, LanguageServerConstants.DefaultLanguageName)>]
member _.HandleNotificationAsync
(
request: DidCloseTextDocumentParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,57 @@

open Microsoft.CommonLanguageServerProtocol.Framework
open Microsoft.VisualStudio.LanguageServer.Protocol
open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks
open FSharp.Compiler.LanguageServer.Common
open FSharp.Compiler.LanguageServer
open System.Threading.Tasks
open System.Threading
open System.Collections.Generic
open Microsoft.VisualStudio.FSharp.Editor

#nowarn "57"

type LanguageFeaturesHandler() =
interface IMethodHandler with
member _.MutatesSolutionState = false

// TODO: this is not getting called
interface IRequestHandler<DocumentDiagnosticParams, SumType<RelatedFullDocumentDiagnosticReport, RelatedUnchangedDocumentDiagnosticReport>, FSharpRequestContext> with
[<LanguageServerEndpoint(Methods.TextDocumentDiagnosticName)>]
[<LanguageServerEndpoint(Methods.TextDocumentDiagnosticName, LanguageServerConstants.DefaultLanguageName)>]
member _.HandleRequestAsync
(
request: DocumentDiagnosticParams,
context: FSharpRequestContext,
cancellationToken: CancellationToken
) =
Task.FromResult(new RelatedUnchangedDocumentDiagnosticReport())
cancellableTask {

let! fsharpDiagnosticReport = context.Workspace.Query.GetDiagnosticsForFile request.TextDocument.Uri

let report =
FullDocumentDiagnosticReport(
Items = (fsharpDiagnosticReport.Diagnostics |> Array.map (_.ToLspDiagnostic())),
ResultId = fsharpDiagnosticReport.ResultId
)

let relatedDocuments = Dictionary()

relatedDocuments.Add(
request.TextDocument.Uri,
SumType<FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport> report
)

return
SumType<RelatedFullDocumentDiagnosticReport, RelatedUnchangedDocumentDiagnosticReport>(
RelatedFullDocumentDiagnosticReport(RelatedDocuments = relatedDocuments)
)
}
|> CancellableTask.start cancellationToken

interface IRequestHandler<SemanticTokensParams, SemanticTokens, FSharpRequestContext> with
[<LanguageServerEndpoint(Methods.TextDocumentSemanticTokensFullName, LanguageServerConstants.DefaultLanguageName)>]
member _.HandleRequestAsync(request: SemanticTokensParams, context: FSharpRequestContext, cancellationToken: CancellationToken) =
cancellableTask {
let! tokens = context.GetSemanticTokensForFile(request.TextDocument.Uri)
return SemanticTokens(Data = tokens)
}
|> CancellableTask.start cancellationToken
Loading