Skip to content

Commit 721c5ef

Browse files
Add support to properly handle custom extensions (#323)
* Add support to properly handle custom extenisons * Adjustments * Moved CapabilityKeyAttribute * Added support for a converter for registration options to static options * fixed failing tests * double time
1 parent 3f7cbe3 commit 721c5ef

File tree

182 files changed

+1614
-1182
lines changed

Some content is hidden

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

182 files changed

+1614
-1182
lines changed

.editorconfig

+6-5
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,20 @@ indent_style=space
1919
indent_size=4
2020
insert_final_newline=true
2121

22-
[*.{json,xml,yml,yaml}]
22+
[*.{xml,yml,yaml}]
2323
indent_style=space
2424
indent_size=2
2525
insert_final_newline=true
2626

27-
[*.{xml,csproj,props,targets}]
27+
[*.json]
2828
indent_style=space
29+
indent_size=4
30+
insert_final_newline=true
2931

30-
[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
32+
[*.{xml,csproj,props,targets}]
3133
indent_style=space
32-
indent_size=2
3334

34-
[{*.yaml,*.yml}]
35+
[{*.har,*.inputactions,*.jsb2,*.jsb3,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
3536
indent_style=space
3637
indent_size=2
3738

src/Client/LanguageClient.cs

+39-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Reactive.Linq;
66
using System.Reactive.Subjects;
77
using System.Reactive.Threading.Tasks;
8+
using System.Reflection;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using DryIoc;
@@ -42,6 +43,7 @@ public class LanguageClient : JsonRpcServerBase, ILanguageClient
4243
private readonly IEnumerable<IOnLanguageClientInitialize> _initializeHandlers;
4344
private readonly IEnumerable<OnLanguageClientInitializedDelegate> _initializedDelegates;
4445
private readonly IEnumerable<IOnLanguageClientInitialized> _initializedHandlers;
46+
private readonly ISerializer _serializer;
4547
private readonly IResponseRouter _responseRouter;
4648
private readonly ISubject<InitializeResult> _initializeComplete = new AsyncSubject<InitializeResult>();
4749
private readonly CompositeDisposable _disposable = new CompositeDisposable();
@@ -140,7 +142,8 @@ internal LanguageClient(
140142
IRegistrationManager registrationManager,
141143
ILanguageClientWorkspaceFoldersManager languageClientWorkspaceFoldersManager, IEnumerable<OnLanguageClientInitializeDelegate> initializeDelegates,
142144
IEnumerable<IOnLanguageClientInitialize> initializeHandlers, IEnumerable<OnLanguageClientInitializedDelegate> initializedDelegates,
143-
IEnumerable<IOnLanguageClientInitialized> initializedHandlers
145+
IEnumerable<IOnLanguageClientInitialized> initializedHandlers,
146+
ISerializer serializer
144147
) : base(handlerCollection, responseRouter)
145148
{
146149
_connection = connection;
@@ -167,6 +170,7 @@ IEnumerable<IOnLanguageClientInitialized> initializedHandlers
167170
_initializeHandlers = initializeHandlers;
168171
_initializedDelegates = initializedDelegates;
169172
_initializedHandlers = initializedHandlers;
173+
_serializer = serializer;
170174
_concurrency = options.Value.Concurrency;
171175

172176
// We need to at least create Window here in case any handler does loggin in their constructor
@@ -205,15 +209,43 @@ public async Task Initialize(CancellationToken token)
205209
{
206210
var @params = new InitializeParams {
207211
Trace = _trace,
208-
Capabilities = _clientCapabilities,
209212
ClientInfo = _clientInfo,
213+
Capabilities = _clientCapabilities,
210214
RootUri = _rootUri,
211215
RootPath = _rootUri?.GetFileSystemPath(),
212216
WorkspaceFolders = new Container<WorkspaceFolder>(WorkspaceFoldersManager.CurrentWorkspaceFolders),
213217
InitializationOptions = _initializationOptions
214218
};
215219

216-
RegisterCapabilities(@params.Capabilities);
220+
var capabilitiesObject = new JObject();
221+
foreach (var capability in _capabilities)
222+
{
223+
var keys = capability.GetType().GetCustomAttribute<CapabilityKeyAttribute>()?.Keys.Select(key => char.ToLower(key[0]) + key.Substring(1)).ToArray();
224+
if (keys != null)
225+
{
226+
var value = capabilitiesObject;
227+
foreach (var key in keys.Take(keys.Length - 1))
228+
{
229+
if (value.TryGetValue(key, out var t) && t is JObject to)
230+
{
231+
value = to;
232+
}
233+
else
234+
{
235+
value[key] = value = new JObject();
236+
}
237+
}
238+
var lastKey = keys[keys.Length - 1];
239+
value[lastKey] = JToken.FromObject(capability, _serializer.JsonSerializer);
240+
}
241+
}
242+
243+
using (var reader = capabilitiesObject.CreateReader())
244+
{
245+
_serializer.JsonSerializer.Populate(reader, _clientCapabilities);
246+
}
247+
248+
RegisterCapabilities(_clientCapabilities);
217249

218250
WorkDoneManager.Initialize(@params.Capabilities.Window);
219251

@@ -229,7 +261,7 @@ await LanguageProtocolEventingHelper.Run(
229261
);
230262

231263
_connection.Open();
232-
var serverParams = await this.RequestLanguageProtocolInitialize(ClientSettings, token);
264+
var serverParams = await SendRequest(ClientSettings, token);
233265
_receiver.Initialized();
234266

235267
ServerSettings = serverParams;
@@ -334,17 +366,17 @@ public async Task Shutdown()
334366
_connection.Dispose();
335367
}
336368

337-
private T UseOrTryAndFindCapability<T>(Supports<T> supports)
369+
private Supports<T> UseOrTryAndFindCapability<T>(Supports<T> supports) where T : class
338370
{
339371
var value = supports.IsSupported
340372
? supports.Value
341-
: _capabilities.OfType<T>().FirstOrDefault() ?? Activator.CreateInstance<T>();
373+
: _capabilities.OfType<T>().FirstOrDefault();
342374
if (value is IDynamicCapability dynamicCapability)
343375
{
344376
dynamicCapability.DynamicRegistration = _collection.ContainsHandler(typeof(IRegisterCapabilityHandler));
345377
}
346378

347-
return value;
379+
return Supports.OfValue(value);
348380
}
349381

350382
public IObservable<InitializeResult> Start => _initializeComplete.AsObservable();

src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public Task<RichGenerationResult> GenerateRichAsync(TransformationContext contex
7575
}
7676
);
7777

78+
var isInternal = handlerInterface.Modifiers.Any(z => z.IsKind(SyntaxKind.InternalKeyword));
79+
7880
return Task.FromResult(
7981
new RichGenerationResult {
8082
Usings = List(newUsings),
@@ -88,9 +90,12 @@ public Task<RichGenerationResult> GenerateRichAsync(TransformationContext contex
8890
.WithAttributeLists(attributes)
8991
.WithModifiers(
9092
TokenList(
91-
Token(SyntaxKind.PublicKeyword),
92-
Token(SyntaxKind.StaticKeyword),
93-
Token(SyntaxKind.PartialKeyword)
93+
new[] { isInternal ? Token(SyntaxKind.InternalKeyword) : Token(SyntaxKind.PublicKeyword) }.Concat(
94+
new[] {
95+
Token(SyntaxKind.StaticKeyword),
96+
Token(SyntaxKind.PartialKeyword)
97+
}
98+
)
9499
)
95100
)
96101
.WithMembers(List(methods))

src/JsonRpc.Generators/GenerateRequestMethodsGenerator.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public Task<RichGenerationResult> GenerateRichAsync(TransformationContext contex
9595
.Except(existingUsings)
9696
.Select(z => UsingDirective(IdentifierName(z)))
9797
;
98+
var isInternal = handlerInterface.Modifiers.Any(z => z.IsKind(SyntaxKind.InternalKeyword));
9899
return Task.FromResult(
99100
new RichGenerationResult {
100101
Usings = List(newUsings),
@@ -108,9 +109,12 @@ public Task<RichGenerationResult> GenerateRichAsync(TransformationContext contex
108109
.WithAttributeLists(attributes)
109110
.WithModifiers(
110111
TokenList(
111-
Token(SyntaxKind.PublicKeyword),
112-
Token(SyntaxKind.StaticKeyword),
113-
Token(SyntaxKind.PartialKeyword)
112+
new[] { isInternal ? Token(SyntaxKind.InternalKeyword) : Token(SyntaxKind.PublicKeyword) }.Concat(
113+
new[] {
114+
Token(SyntaxKind.StaticKeyword),
115+
Token(SyntaxKind.PartialKeyword)
116+
}
117+
)
114118
)
115119
)
116120
.WithMembers(List(methods))

src/JsonRpc/HandlerTypeDescriptorProvider.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ internal static IEnumerable<IHandlerTypeDescriptor> GetDescriptors(IEnumerable<A
125125
.Select(HandlerTypeDescriptorHelper.GetMethodType)
126126
.Distinct()
127127
.ToLookup(x => MethodAttribute.From(x).Method)
128-
.SelectMany(x => x.Select(z => new HandlerTypeDescriptor(z) as IHandlerTypeDescriptor));
128+
.SelectMany(
129+
x => x
130+
.Distinct()
131+
.Select(z => new HandlerTypeDescriptor(z) as IHandlerTypeDescriptor)
132+
);
129133

130134
public IHandlerTypeDescriptor GetHandlerTypeDescriptor<A>() => GetHandlerTypeDescriptor(typeof(A));
131135

src/Protocol/CapabilitiesBase.cs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
5+
namespace OmniSharp.Extensions.LanguageServer.Protocol
6+
{
7+
public abstract class CapabilitiesBase
8+
{
9+
[JsonExtensionData] public IDictionary<string, JToken> ExtensionData { get; set; } = new Dictionary<string, JToken>();
10+
}
11+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace OmniSharp.Extensions.LanguageServer.Protocol
6+
{
7+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
8+
public sealed class CapabilityKeyAttribute : Attribute
9+
{
10+
public IEnumerable<string> Keys { get; }
11+
12+
public CapabilityKeyAttribute(string key, params string[] additionalKeys)
13+
{
14+
Keys = new[] { key }.Concat(additionalKeys).ToArray();
15+
}
16+
}
17+
}

src/Protocol/Client/Capabilities/CallHierarchyCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
99
/// @since 3.16.0
1010
/// </summary>
1111
[Obsolete(Constants.Proposal)]
12+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.CallHierarchy))]
1213
public class CallHierarchyCapability : DynamicCapability, ConnectedCapability<ICallHierarchyHandler>,
1314
ConnectedCapability<ICallHierarchyIncomingHandler>, ConnectedCapability<ICallHierarchyOutgoingHandler>
1415
{

src/Protocol/Client/Capabilities/ClientCapabilities.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
55
{
6-
public class ClientCapabilities
6+
public class ClientCapabilities : CapabilitiesBase
77
{
88
/// <summary>
99
/// Workspace specific client capabilities.

src/Protocol/Client/Capabilities/CodeActionCapability.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
55
{
6+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.CodeAction))]
67
public class CodeActionCapability : DynamicCapability, ConnectedCapability<ICodeActionHandler>
78
{
89
/// <summary>
@@ -12,7 +13,7 @@ public class CodeActionCapability : DynamicCapability, ConnectedCapability<ICode
1213
/// Since 3.8.0
1314
/// </summary>
1415
[Optional]
15-
public CodeActionLiteralSupportCapability CodeActionLiteralSupport { get; set; }
16+
public CodeActionLiteralSupportOptions CodeActionLiteralSupport { get; set; }
1617

1718
/// <summary>
1819
/// Whether code action supports the `isPreferred` property.

src/Protocol/Client/Capabilities/CodeActionKindCapability.cs renamed to src/Protocol/Client/Capabilities/CodeActionKindCapabilityOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5-
public class CodeActionKindCapability
5+
public class CodeActionKindCapabilityOptions
66
{
77
/// <summary>
88
/// The code action kind values the client supports. When this
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
22
{
3-
public class CodeActionLiteralSupportCapability
3+
public class CodeActionLiteralSupportOptions
44
{
55
/// <summary>
66
/// The code action kind is support with the following value
77
/// set.
88
/// </summary>
99

10-
public CodeActionKindCapability CodeActionKind { get; set; }
10+
public CodeActionKindCapabilityOptions CodeActionKind { get; set; }
1111
}
1212
}

src/Protocol/Client/Capabilities/CodeLensCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.CodeLens))]
56
public class CodeLensCapability : DynamicCapability, ConnectedCapability<ICodeLensHandler>
67
{
78
}

src/Protocol/Client/Capabilities/ColorProviderCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.ColorProvider))]
56
public class ColorProviderCapability : DynamicCapability, ConnectedCapability<IDocumentColorHandler>, ConnectedCapability<IColorPresentationHandler>
67
{
78
}

src/Protocol/Client/Capabilities/CompletionCapability.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33

44
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
55
{
6+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.Completion))]
67
public class CompletionCapability : DynamicCapability, ConnectedCapability<ICompletionHandler>
78
{
89
/// <summary>
910
/// The client supports the following `CompletionItem` specific
1011
/// capabilities.
1112
/// </summary>
1213
[Optional]
13-
public CompletionItemCapability CompletionItem { get; set; }
14+
public CompletionItemCapabilityOptions CompletionItem { get; set; }
1415

1516
/// <summary>
1617
/// Specific capabilities for the `CompletionItemKind` in the `textDocument/completion` request.
1718
/// </summary>
1819
[Optional]
19-
public CompletionItemKindCapability CompletionItemKind { get; set; }
20+
public CompletionItemKindCapabilityOptions CompletionItemKind { get; set; }
2021

2122
/// <summary>
2223
/// The client supports to send additional context information for a `textDocument/completion` request.

src/Protocol/Client/Capabilities/CompletionItemCapability.cs renamed to src/Protocol/Client/Capabilities/CompletionItemCapabilityOptions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
55
{
6-
public class CompletionItemCapability
6+
public class CompletionItemCapabilityOptions
77
{
88
/// <summary>
99
/// Client supports snippets as insert text.
@@ -50,7 +50,7 @@ public class CompletionItemCapability
5050
/// @since 3.15.0
5151
/// </summary>
5252
[Optional]
53-
public Supports<CompletionItemTagSupportCapability> TagSupport { get; set; }
53+
public Supports<CompletionItemTagSupportCapabilityOptions> TagSupport { get; set; }
5454

5555
/// <summary>
5656
/// Client support insert replace edit to control different behavior if a

src/Protocol/Client/Capabilities/CompletionItemKindCapability.cs renamed to src/Protocol/Client/Capabilities/CompletionItemKindCapabilityOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
55
{
6-
public class CompletionItemKindCapability
6+
public class CompletionItemKindCapabilityOptions
77
{
88
/// <summary>
99
/// The completion item kind values the client supports. When this

src/Protocol/Client/Capabilities/CompletionItemTagSupportCapability.cs renamed to src/Protocol/Client/Capabilities/CompletionItemTagSupportCapabilityOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5-
public class CompletionItemTagSupportCapability
5+
public class CompletionItemTagSupportCapabilityOptions
66
{
77
/// <summary>
88
/// The tags supported by the client.

src/Protocol/Client/Capabilities/ConnectedCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using OmniSharp.Extensions.JsonRpc;
2+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
23

34
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
45
{

src/Protocol/Client/Capabilities/DeclarationCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.Declaration))]
56
public class DeclarationCapability : LinkSupportCapability, ConnectedCapability<IDeclarationHandler>
67
{
78
}

src/Protocol/Client/Capabilities/DefinitionCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
44
{
5+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.Definition))]
56
public class DefinitionCapability : LinkSupportCapability, ConnectedCapability<IDefinitionHandler>
67
{
78
}

src/Protocol/Client/Capabilities/DidChangeConfigurationCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
22
{
3+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(WorkspaceClientCapabilities.Configuration))]
34
public class DidChangeConfigurationCapability : DynamicCapability
45
{
56
}

src/Protocol/Client/Capabilities/DidChangeWatchedFilesCapability.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
22
{
3+
[CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(WorkspaceClientCapabilities.DidChangeWatchedFiles))]
34
public class DidChangeWatchedFilesCapability : DynamicCapability
45
{
56
}

0 commit comments

Comments
 (0)