Skip to content

Commit 9f5f49f

Browse files
Breaking: Registration Options require Client Capability during creation (#440)
* Breaking: LSP ISerializer interface is now deprecated, and marked obsolete. * LSP Serializer renamed to LSPSerializer * Added serialization rules for client * Ensure code actions are provided properly. * Updated serialization rules for server * Started on documentation, fixed ICanHaveData not generating * Updated DAP to use new source generation as well, next is to source generate 'AllowDerivedRequests' * Added support for generation with AllowDerivedRequests * Added source generator caching... yes I know we're not supposed to do this but 3 second intellisense times are unbearable * Some caching changes and fixes for working in rider * Added full client capabilities to registration options delegate
1 parent 31f44bf commit 9f5f49f

File tree

747 files changed

+22491
-20644
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

747 files changed

+22491
-20644
lines changed

Directory.Build.props

+5-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
2323
<AllowedReferenceRelatedFileExtensions>$(AllowedReferenceRelatedFileExtensions);.pdb</AllowedReferenceRelatedFileExtensions>
2424
</PropertyGroup>
25+
<PropertyGroup>
26+
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
27+
</PropertyGroup>
2528
<ItemGroup>
26-
<None Include="$(MSBuildThisFileDirectory)/.tmp/packageicon.png" Condition="Exists('$(MSBuildThisFileDirectory)/.tmp/packageicon.png')" Pack="true" PackagePath="/images/"
27-
Visible="false"/>
28-
<None Include="$(MSBuildThisFileDirectory)/LICENSE" Pack="true" PackagePath="/" Visible="false"/>
29+
<None Include="$(MSBuildThisFileDirectory)/.tmp/packageicon.png" Condition="Exists('$(MSBuildThisFileDirectory)/.tmp/packageicon.png')" Pack="true" PackagePath="/images/" Visible="false" />
30+
<None Include="$(MSBuildThisFileDirectory)/LICENSE" Pack="true" PackagePath="/" Visible="false" />
2931
</ItemGroup>
3032
</Project>

Directory.Build.targets

-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project>
33
<PropertyGroup>
4-
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
54
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
65
</PropertyGroup>
7-
<ItemGroup>
8-
<Compile Condition="'$(DesignTimeBuild)' == 'true' and '$(IDEA_INITIAL_DIRECTORY)' != ''" Include="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
9-
</ItemGroup>
106
<ItemGroup>
117
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
128
<PackageReference Include="Rocket.Surgery.MSBuild.CI" Version="1.1.0" PrivateAssets="All" />

benchmarks/Pipeline/Pipeline.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net472;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
4+
<TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
55
<OutputType>Exe</OutputType>
66
<IsPackable>false</IsPackable>
77
</PropertyGroup>

docs/lsp.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,19 @@ The goal of this library is to implement [Language Server Protocol](https://micr
44

55
Included in this library is a full-fidelity `LanguageServer` but also full `LanguageClient` implementation that could be implemented in an editor, but mainly it is used to help make Unit Testing easier, more consistent (and maybe even fun!).
66

7-
# Creating a JsonRpcServer
7+
# Concepts
8+
The language server is built oin a few concepts. At it's core is the [MediatR](https://github.com/jbogard/MediatR) library that you will build language specific handlers around. Around that core is a bunch of knowledge of the LSP protocol
9+
with the goal of making it more ".NET" like and less protocol centric.
10+
11+
LSP revolves around features ( eg Completion, Hover, etc ) that define the inputs (request object) the outputs (response object) as well as Client Capabilities and Server Registration Options.
12+
13+
## Client Capabilities
14+
These determine what features are supported by the client, and each has a different set of capabilities. The [specification](https://microsoft.github.io/language-server-protocol/) explains each feature and the requirements of each.
15+
16+
## Server Registration Options
17+
The protocol defines two kinds of registration, static and dynamic. Dynamic registration, when it's supported, allows you to register features with the client on demand. Static registration is returned to the client during the initialization phase that explains what features the server supports. Dynamic and Static registration cannot be mixed. If you register something statically, you cannot register the same thing dynamically, otherwise the client will register both features twice.
18+
19+
# Creating a Language Server or Client
820
`LanguageServer` or `LanguageClient` can be created through two methods.
921

1022
## Standalone

docs/source-generation.md

+824
Large diffs are not rendered by default.

sample/SampleServer/DidChangeWatchedFilesHandler.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ internal class DidChangeWatchedFilesHandler : IDidChangeWatchedFilesHandler
1313

1414
public Task<Unit> Handle(DidChangeWatchedFilesParams request, CancellationToken cancellationToken) => Unit.Task;
1515

16-
public void SetCapability(DidChangeWatchedFilesCapability capability)
17-
{
18-
}
16+
public DidChangeWatchedFilesRegistrationOptions GetRegistrationOptions(DidChangeWatchedFilesCapability capability, ClientCapabilities clientCapabilities) => new DidChangeWatchedFilesRegistrationOptions();
1917
}
2018
}

sample/SampleServer/FoldingRangeHandler.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ CancellationToken cancellationToken
2929
)
3030
);
3131

32-
public void SetCapability(FoldingRangeCapability capability)
33-
{
34-
}
32+
public FoldingRangeRegistrationOptions GetRegistrationOptions(FoldingRangeCapability capability, ClientCapabilities clientCapabilities) => new FoldingRangeRegistrationOptions {
33+
DocumentSelector = DocumentSelector.ForLanguage("csharp")
34+
};
3535
}
3636
}

sample/SampleServer/SemanticTokensHandler.cs

+14-11
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,7 @@ public class SemanticTokensHandler : SemanticTokensHandlerBase
1818
{
1919
private readonly ILogger _logger;
2020

21-
public SemanticTokensHandler(ILogger<SemanticTokensHandler> logger) : base(
22-
new SemanticTokensRegistrationOptions {
23-
DocumentSelector = DocumentSelector.ForLanguage("csharp"),
24-
Legend = new SemanticTokensLegend(),
25-
Full = new SemanticTokensCapabilityRequestFull {
26-
Delta = true
27-
},
28-
Range = true
29-
}
30-
) =>
21+
public SemanticTokensHandler(ILogger<SemanticTokensHandler> logger) =>
3122
_logger = logger;
3223

3324
public override async Task<SemanticTokens?> Handle(
@@ -83,7 +74,7 @@ CancellationToken cancellationToken
8374

8475
protected override Task<SemanticTokensDocument>
8576
GetSemanticTokensDocument(ITextDocumentIdentifierParams @params, CancellationToken cancellationToken) =>
86-
Task.FromResult(new SemanticTokensDocument(GetRegistrationOptions().Legend));
77+
Task.FromResult(new SemanticTokensDocument(RegistrationOptions.Legend));
8778

8879

8980
private IEnumerable<T> RotateEnum<T>(IEnumerable<T> values)
@@ -94,6 +85,18 @@ private IEnumerable<T> RotateEnum<T>(IEnumerable<T> values)
9485
yield return item;
9586
}
9687
}
88+
89+
protected override SemanticTokensRegistrationOptions CreateRegistrationOptions(SemanticTokensCapability capability, ClientCapabilities clientCapabilities) => new SemanticTokensRegistrationOptions {
90+
DocumentSelector = DocumentSelector.ForLanguage("csharp"),
91+
Legend = new SemanticTokensLegend() {
92+
TokenModifiers = capability.TokenModifiers,
93+
TokenTypes = capability.TokenTypes
94+
},
95+
Full = new SemanticTokensCapabilityRequestFull {
96+
Delta = true
97+
},
98+
Range = true
99+
};
97100
}
98101
#pragma warning restore 618
99102
}

sample/SampleServer/TextDocumentHandler.cs

+24-45
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities;
1414
using OmniSharp.Extensions.LanguageServer.Protocol.Server.WorkDone;
1515
using OmniSharp.Extensions.LanguageServer.Protocol.Workspace;
16+
1617
#pragma warning disable CS0618
1718

1819
namespace SampleServer
1920
{
20-
internal class TextDocumentHandler : ITextDocumentSyncHandler
21+
internal class TextDocumentHandler : TextDocumentSyncHandlerBase
2122
{
2223
private readonly ILogger<TextDocumentHandler> _logger;
2324
private readonly ILanguageServerConfiguration _configuration;
@@ -28,12 +29,7 @@ internal class TextDocumentHandler : ITextDocumentSyncHandler
2829
}
2930
);
3031

31-
private SynchronizationCapability _capability;
32-
33-
public TextDocumentHandler(
34-
ILogger<TextDocumentHandler> logger, Foo foo,
35-
ILanguageServerConfiguration configuration
36-
)
32+
public TextDocumentHandler(ILogger<TextDocumentHandler> logger, Foo foo, ILanguageServerConfiguration configuration)
3733
{
3834
_logger = logger;
3935
_configuration = configuration;
@@ -42,7 +38,7 @@ ILanguageServerConfiguration configuration
4238

4339
public TextDocumentSyncKind Change { get; } = TextDocumentSyncKind.Full;
4440

45-
public Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
41+
public override Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
4642
{
4743
_logger.LogCritical("Critical");
4844
_logger.LogDebug("Debug");
@@ -51,29 +47,15 @@ public Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationT
5147
return Unit.Task;
5248
}
5349

54-
TextDocumentChangeRegistrationOptions IRegistration<TextDocumentChangeRegistrationOptions>.
55-
GetRegistrationOptions() =>
56-
new TextDocumentChangeRegistrationOptions {
57-
DocumentSelector = _documentSelector,
58-
SyncKind = Change
59-
};
60-
61-
public void SetCapability(SynchronizationCapability capability) => _capability = capability;
62-
63-
public async Task<Unit> Handle(DidOpenTextDocumentParams notification, CancellationToken token)
50+
public override async Task<Unit> Handle(DidOpenTextDocumentParams notification, CancellationToken token)
6451
{
6552
await Task.Yield();
6653
_logger.LogInformation("Hello world!");
6754
await _configuration.GetScopedConfiguration(notification.TextDocument.Uri, token);
6855
return Unit.Value;
6956
}
7057

71-
TextDocumentRegistrationOptions IRegistration<TextDocumentRegistrationOptions>.GetRegistrationOptions() =>
72-
new TextDocumentRegistrationOptions {
73-
DocumentSelector = _documentSelector,
74-
};
75-
76-
public Task<Unit> Handle(DidCloseTextDocumentParams notification, CancellationToken token)
58+
public override Task<Unit> Handle(DidCloseTextDocumentParams notification, CancellationToken token)
7759
{
7860
if (_configuration.TryGetScopedConfiguration(notification.TextDocument.Uri, out var disposable))
7961
{
@@ -83,28 +65,20 @@ public Task<Unit> Handle(DidCloseTextDocumentParams notification, CancellationTo
8365
return Unit.Task;
8466
}
8567

86-
public Task<Unit> Handle(DidSaveTextDocumentParams notification, CancellationToken token) => Unit.Task;
68+
public override Task<Unit> Handle(DidSaveTextDocumentParams notification, CancellationToken token) => Unit.Task;
8769

88-
TextDocumentSaveRegistrationOptions IRegistration<TextDocumentSaveRegistrationOptions>.GetRegistrationOptions() =>
89-
new TextDocumentSaveRegistrationOptions {
90-
DocumentSelector = _documentSelector,
91-
IncludeText = true
92-
};
70+
protected override TextDocumentSyncRegistrationOptions CreateRegistrationOptions(SynchronizationCapability capability, ClientCapabilities clientCapabilities) => new TextDocumentSyncRegistrationOptions() {
71+
DocumentSelector = _documentSelector,
72+
SyncKind = Change,
73+
IncludeText = true
74+
};
9375

94-
public TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri) => new TextDocumentAttributes(uri, "csharp");
76+
public override TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri) => new TextDocumentAttributes(uri, "csharp");
9577
}
9678

97-
internal class MyDocumentSymbolHandler : DocumentSymbolHandler
79+
internal class MyDocumentSymbolHandler : IDocumentSymbolHandler
9880
{
99-
public MyDocumentSymbolHandler() : base(
100-
new DocumentSymbolRegistrationOptions {
101-
DocumentSelector = DocumentSelector.ForLanguage("csharp")
102-
}
103-
)
104-
{
105-
}
106-
107-
public override async Task<SymbolInformationOrDocumentSymbolContainer> Handle(
81+
public async Task<SymbolInformationOrDocumentSymbolContainer> Handle(
10882
DocumentSymbolParams request,
10983
CancellationToken cancellationToken
11084
)
@@ -151,23 +125,26 @@ CancellationToken cancellationToken
151125
// await Task.Delay(2000, cancellationToken);
152126
return symbols;
153127
}
128+
129+
public DocumentSymbolRegistrationOptions GetRegistrationOptions(DocumentSymbolCapability capability, ClientCapabilities clientCapabilities) => new DocumentSymbolRegistrationOptions {
130+
DocumentSelector = DocumentSelector.ForLanguage("csharp")
131+
};
154132
}
155133

156-
internal class MyWorkspaceSymbolsHandler : WorkspaceSymbolsHandler
134+
internal class MyWorkspaceSymbolsHandler : IWorkspaceSymbolsHandler
157135
{
158136
private readonly IServerWorkDoneManager _serverWorkDoneManager;
159137
private readonly IProgressManager _progressManager;
160138
private readonly ILogger<MyWorkspaceSymbolsHandler> _logger;
161139

162-
public MyWorkspaceSymbolsHandler(IServerWorkDoneManager serverWorkDoneManager, IProgressManager progressManager, ILogger<MyWorkspaceSymbolsHandler> logger) :
163-
base(new WorkspaceSymbolRegistrationOptions())
140+
public MyWorkspaceSymbolsHandler(IServerWorkDoneManager serverWorkDoneManager, IProgressManager progressManager, ILogger<MyWorkspaceSymbolsHandler> logger)
164141
{
165142
_serverWorkDoneManager = serverWorkDoneManager;
166143
_progressManager = progressManager;
167144
_logger = logger;
168145
}
169146

170-
public override async Task<Container<SymbolInformation>> Handle(
147+
public async Task<Container<SymbolInformation>> Handle(
171148
WorkspaceSymbolParams request,
172149
CancellationToken cancellationToken
173150
)
@@ -272,5 +249,7 @@ CancellationToken cancellationToken
272249
);
273250
}
274251
}
252+
253+
public WorkspaceSymbolRegistrationOptions GetRegistrationOptions(WorkspaceSymbolCapability capability, ClientCapabilities clientCapabilities) => new WorkspaceSymbolRegistrationOptions();
275254
}
276255
}

src/Client/LanguageClient.cs

+11-7
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@
2828

2929
namespace OmniSharp.Extensions.LanguageServer.Client
3030
{
31+
[BuiltIn]
3132
public class LanguageClient : JsonRpcServerBase, ILanguageClient
3233
{
3334
private readonly Connection _connection;
3435
private readonly ClientInfo _clientInfo;
3536
private readonly ILspClientReceiver _receiver;
3637
private readonly TextDocumentIdentifiers _textDocumentIdentifiers;
3738

38-
private readonly IHandlerCollection _collection;
39+
private readonly SharedHandlerCollection _collection;
3940

4041
// private readonly IEnumerable<InitializeDelegate> _initializeDelegates;
4142
// private readonly IEnumerable<InitializedDelegate> _initializedDelegates;
@@ -143,8 +144,10 @@ internal LanguageClient(
143144
IProgressManager progressManager,
144145
IClientWorkDoneManager clientWorkDoneManager,
145146
IRegistrationManager registrationManager,
146-
ILanguageClientWorkspaceFoldersManager languageClientWorkspaceFoldersManager, IEnumerable<OnLanguageClientInitializeDelegate> initializeDelegates,
147-
IEnumerable<IOnLanguageClientInitialize> initializeHandlers, IEnumerable<OnLanguageClientInitializedDelegate> initializedDelegates,
147+
ILanguageClientWorkspaceFoldersManager languageClientWorkspaceFoldersManager,
148+
IEnumerable<OnLanguageClientInitializeDelegate> initializeDelegates,
149+
IEnumerable<IOnLanguageClientInitialize> initializeHandlers,
150+
IEnumerable<OnLanguageClientInitializedDelegate> initializedDelegates,
148151
IEnumerable<IOnLanguageClientInitialized> initializedHandlers,
149152
LspSerializer serializer,
150153
InstanceHasStarted instanceHasStarted
@@ -250,12 +253,9 @@ public async Task Initialize(CancellationToken token)
250253
_serializer.JsonSerializer.Populate(reader, _clientCapabilities);
251254
}
252255

256+
_collection.Initialize();
253257
RegisterCapabilities(_clientCapabilities);
254258

255-
WorkDoneManager.Initialize(@params.Capabilities.Window);
256-
257-
ClientSettings = @params;
258-
259259
await LanguageProtocolEventingHelper.Run(
260260
_initializeDelegates,
261261
(handler, ct) => handler(this, @params, ct),
@@ -265,6 +265,10 @@ await LanguageProtocolEventingHelper.Run(
265265
token
266266
).ConfigureAwait(false);
267267

268+
WorkDoneManager.Initialize(@params.Capabilities.Window);
269+
270+
ClientSettings = @params;
271+
268272
_connection.Open();
269273
var serverParams = await SendRequest(ClientSettings, token).ConfigureAwait(false);
270274

src/Client/LanguageClientRegistrationManager.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919

2020
namespace OmniSharp.Extensions.LanguageServer.Client
2121
{
22+
[BuiltIn]
2223
internal class LanguageClientRegistrationManager : IRegisterCapabilityHandler, IUnregisterCapabilityHandler, IRegistrationManager, IDisposable
2324
{
2425
private readonly ISerializer _serializer;
2526
private readonly ILspHandlerTypeDescriptorProvider _handlerTypeDescriptorProvider;
2627
private readonly ILogger<LanguageClientRegistrationManager> _logger;
2728
private readonly ConcurrentDictionary<string, Registration> _registrations;
28-
private ReplaySubject<IEnumerable<Registration>> _registrationSubject = new ReplaySubject<IEnumerable<Registration>>(1);
29+
private readonly ReplaySubject<IEnumerable<Registration>> _registrationSubject = new ReplaySubject<IEnumerable<Registration>>(1);
2930

3031
public LanguageClientRegistrationManager(
3132
ISerializer serializer,

src/Client/LanguageClientWorkspaceFoldersManager.cs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
namespace OmniSharp.Extensions.LanguageServer.Client
1616
{
17+
[BuiltIn]
1718
internal class LanguageClientWorkspaceFoldersManager : ILanguageClientWorkspaceFoldersManager, IDisposable
1819
{
1920
private readonly IWorkspaceLanguageClient _client;

src/Dap.Protocol/AbstractHandlers.cs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using MediatR;
4+
using OmniSharp.Extensions.JsonRpc;
5+
6+
namespace OmniSharp.Extensions.DebugAdapter.Protocol
7+
{
8+
public static class AbstractHandlers
9+
{
10+
public abstract class Request<TParams, TResult> :
11+
IJsonRpcRequestHandler<TParams, TResult>
12+
where TParams : IRequest<TResult>
13+
{
14+
public abstract Task<TResult> Handle(TParams request, CancellationToken cancellationToken);
15+
}
16+
17+
public abstract class Notification<TParams> : IJsonRpcRequestHandler<TParams>
18+
where TParams : IRequest
19+
{
20+
public abstract Task<Unit> Handle(TParams request, CancellationToken cancellationToken);
21+
}
22+
}
23+
}

src/Dap.Protocol/Dap.Protocol.csproj

-18
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,6 @@
2727
</ItemGroup>
2828

2929
<ItemGroup>
30-
<Compile Update="Events\IProgressEndHandler.cs">
31-
<Generator></Generator>
32-
</Compile>
33-
<Compile Update="Events\IProgressStartHandler.cs">
34-
<Generator></Generator>
35-
</Compile>
36-
<Compile Update="Events\IProgressUpdateHandler.cs">
37-
<Generator></Generator>
38-
</Compile>
39-
<Compile Update="Events\ProgressEndEvent.cs">
40-
<Generator></Generator>
41-
</Compile>
42-
<Compile Update="Events\ProgressStartEvent.cs">
43-
<Generator></Generator>
44-
</Compile>
45-
<Compile Update="Events\ProgressUpdateEvent.cs">
46-
<Generator></Generator>
47-
</Compile>
4830
<Compile Update="Client\IDebugAdapterClient.cs">
4931
<Generator>MSBuild:GenerateCodeFromAttributes</Generator>
5032
</Compile>

0 commit comments

Comments
 (0)