Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a40c9ce

Browse files
authoredJul 31, 2020
Commands, bugs, helpers and more! (#268)
* Fixup commands to have a more reliable experience * Added helper base classes and helper methods for handling single commands with a known set of arguments up to 6
1 parent 7d4ecc5 commit a40c9ce

File tree

13 files changed

+1204
-65
lines changed

13 files changed

+1204
-65
lines changed
 

‎src/JsonRpc.Generators/Helpers.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ public static string GetSendMethodName(INamedTypeSymbol symbol, AttributeData at
828828
var name = SpecialCasedHandlerName(symbol);
829829
if (
830830
name.StartsWith("Run")
831+
|| name.StartsWith("Execute")
831832
// TODO: Change this next breaking change
832833
// || name.StartsWith("Set")
833834
// || name.StartsWith("Attach")

‎src/Protocol/Models/ExecuteCommandRegistrationOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
1+
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
22
{
33
/// <summary>
44
/// Execute command registration options.
55
/// </summary>
6-
public class ExecuteCommandRegistrationOptions : WorkDoneTextDocumentRegistrationOptions, IExecuteCommandOptions
6+
public class ExecuteCommandRegistrationOptions : WorkDoneProgressOptions, IExecuteCommandOptions
77
{
88
/// <summary>
99
/// The commands to be executed on the server

‎src/Protocol/Workspace/IExecuteCommandHandler.cs

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
using System;
12
using System.Threading;
23
using System.Threading.Tasks;
34
using MediatR;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Newtonsoft.Json.Linq;
47
using OmniSharp.Extensions.JsonRpc;
58
using OmniSharp.Extensions.JsonRpc.Generation;
69
using OmniSharp.Extensions.LanguageServer.Protocol.Client;
710
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
811
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
12+
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
913

1014
namespace OmniSharp.Extensions.LanguageServer.Protocol.Workspace
1115
{
@@ -27,4 +31,289 @@ public ExecuteCommandHandler(ExecuteCommandRegistrationOptions registrationOptio
2731
public virtual void SetCapability(ExecuteCommandCapability capability) => Capability = capability;
2832
protected ExecuteCommandCapability Capability { get; private set; }
2933
}
34+
35+
public abstract class ExecuteCommandHandlerBase<T> : ExecuteCommandHandler
36+
{
37+
private readonly ISerializer _serializer;
38+
39+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
40+
{
41+
_serializer = serializer;
42+
}
43+
44+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
45+
{
46+
var args = request.Arguments ?? new JArray();
47+
T arg1 = default;
48+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
49+
return Handle(arg1, cancellationToken);
50+
}
51+
52+
public abstract Task<Unit> Handle(T arg1, CancellationToken cancellationToken);
53+
}
54+
55+
public abstract class ExecuteCommandHandlerBase<T, T2> : ExecuteCommandHandler
56+
{
57+
private readonly ISerializer _serializer;
58+
59+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
60+
{
61+
_serializer = serializer;
62+
}
63+
64+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
65+
{
66+
var args = request.Arguments ?? new JArray();
67+
T arg1 = default;
68+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
69+
T2 arg2 = default;
70+
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
71+
return Handle(arg1, arg2, cancellationToken);
72+
}
73+
74+
public abstract Task<Unit> Handle(T arg1, T2 arg2, CancellationToken cancellationToken);
75+
}
76+
77+
public abstract class ExecuteCommandHandlerBase<T, T2, T3> : ExecuteCommandHandler
78+
{
79+
private readonly ISerializer _serializer;
80+
81+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
82+
{
83+
_serializer = serializer;
84+
}
85+
86+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
87+
{
88+
var args = request.Arguments ?? new JArray();
89+
T arg1 = default;
90+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
91+
T2 arg2 = default;
92+
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
93+
T3 arg3 = default;
94+
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
95+
return Handle(arg1, arg2, arg3, cancellationToken);
96+
}
97+
98+
public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken);
99+
}
100+
101+
public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4> : ExecuteCommandHandler
102+
{
103+
private readonly ISerializer _serializer;
104+
105+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
106+
{
107+
_serializer = serializer;
108+
}
109+
110+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
111+
{
112+
var args = request.Arguments ?? new JArray();
113+
T arg1 = default;
114+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
115+
T2 arg2 = default;
116+
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
117+
T3 arg3 = default;
118+
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
119+
T4 arg4 = default;
120+
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
121+
return Handle(arg1, arg2, arg3, arg4, cancellationToken);
122+
}
123+
124+
public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken cancellationToken);
125+
}
126+
127+
public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4, T5> : ExecuteCommandHandler
128+
{
129+
private readonly ISerializer _serializer;
130+
131+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
132+
{
133+
_serializer = serializer;
134+
}
135+
136+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
137+
{
138+
var args = request.Arguments ?? new JArray();
139+
T arg1 = default;
140+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
141+
T2 arg2 = default;
142+
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
143+
T3 arg3 = default;
144+
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
145+
T4 arg4 = default;
146+
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
147+
T5 arg5 = default;
148+
if (args.Count > 4) arg5 = args[4].ToObject<T5>(_serializer.JsonSerializer);
149+
return Handle(arg1, arg2, arg3, arg4, arg5, cancellationToken);
150+
}
151+
152+
public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken cancellationToken);
153+
}
154+
155+
public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4, T5, T6> : ExecuteCommandHandler
156+
{
157+
private readonly ISerializer _serializer;
158+
159+
public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
160+
{
161+
_serializer = serializer;
162+
}
163+
164+
public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
165+
{
166+
var args = request.Arguments ?? new JArray();
167+
T arg1 = default;
168+
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
169+
T2 arg2 = default;
170+
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
171+
T3 arg3 = default;
172+
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
173+
T4 arg4 = default;
174+
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
175+
T5 arg5 = default;
176+
if (args.Count > 4) arg5 = args[4].ToObject<T5>(_serializer.JsonSerializer);
177+
T6 arg6 = default;
178+
if (args.Count > 5) arg6 = args[5].ToObject<T6>(_serializer.JsonSerializer);
179+
return Handle(arg1, arg2, arg3, arg4, arg5, arg6, cancellationToken);
180+
}
181+
182+
public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, CancellationToken cancellationToken);
183+
}
184+
185+
public static partial class ExecuteCommandExtensions
186+
{
187+
public static Task ExecuteCommand(this IWorkspaceLanguageClient mediator, Command @params, CancellationToken cancellationToken = default)
188+
=> mediator.ExecuteCommand(new ExecuteCommandParams() { Arguments = @params.Arguments, Command = @params.Name }, cancellationToken);
189+
190+
public static Task ExecuteCommand(this ILanguageClient mediator, Command @params, CancellationToken cancellationToken = default)
191+
=> mediator.ExecuteCommand(new ExecuteCommandParams() { Arguments = @params.Arguments, Command = @params.Name }, cancellationToken);
192+
193+
public static ILanguageServerRegistry OnExecuteCommand<T>(this ILanguageServerRegistry registry, string command, Func<T, Task> handler)
194+
{
195+
return registry.AddHandler(_ => new Handler<T>(command, handler, _.GetRequiredService<ISerializer>()));
196+
}
197+
198+
class Handler<T> : ExecuteCommandHandlerBase<T>
199+
{
200+
private readonly Func<T, Task> _handler;
201+
202+
public Handler(string command, Func<T, Task> handler, ISerializer serializer) : base(command, serializer)
203+
{
204+
_handler = handler;
205+
}
206+
207+
public override async Task<Unit> Handle(T arg1, CancellationToken cancellationToken)
208+
{
209+
await _handler(arg1);
210+
return Unit.Value;
211+
}
212+
}
213+
214+
public static ILanguageServerRegistry OnExecuteCommand<T, T2>(this ILanguageServerRegistry registry, string command, Func<T, T2, Task> handler)
215+
{
216+
return registry.AddHandler(_ => new Handler<T, T2>(command, handler, _.GetRequiredService<ISerializer>()));
217+
}
218+
219+
class Handler<T, T2> : ExecuteCommandHandlerBase<T, T2>
220+
{
221+
private readonly Func<T, T2, Task> _handler;
222+
223+
public Handler(string command, Func<T, T2, Task> handler, ISerializer serializer) : base(command, serializer)
224+
{
225+
_handler = handler;
226+
}
227+
228+
public override async Task<Unit> Handle(T arg1, T2 arg2, CancellationToken cancellationToken)
229+
{
230+
await _handler(arg1, arg2);
231+
return Unit.Value;
232+
}
233+
}
234+
235+
public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, Task> handler)
236+
{
237+
return registry.AddHandler(_ => new Handler<T, T2, T3>(command, handler, _.GetRequiredService<ISerializer>()));
238+
}
239+
240+
class Handler<T, T2, T3> : ExecuteCommandHandlerBase<T, T2, T3>
241+
{
242+
private readonly Func<T, T2, T3, Task> _handler;
243+
244+
public Handler(string command, Func<T, T2, T3, Task> handler, ISerializer serializer) : base(command, serializer)
245+
{
246+
_handler = handler;
247+
}
248+
249+
public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken)
250+
{
251+
await _handler(arg1, arg2, arg3);
252+
return Unit.Value;
253+
}
254+
}
255+
256+
public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, Task> handler)
257+
{
258+
return registry.AddHandler(_ => new Handler<T, T2, T3, T4>(command, handler, _.GetRequiredService<ISerializer>()));
259+
}
260+
261+
class Handler<T, T2, T3, T4> : ExecuteCommandHandlerBase<T, T2, T3, T4>
262+
{
263+
private readonly Func<T, T2, T3, T4, Task> _handler;
264+
265+
public Handler(string command, Func<T, T2, T3, T4, Task> handler, ISerializer serializer) : base(command, serializer)
266+
{
267+
_handler = handler;
268+
}
269+
270+
public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken cancellationToken)
271+
{
272+
await _handler(arg1, arg2, arg3, arg4);
273+
return Unit.Value;
274+
}
275+
}
276+
277+
public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4, T5>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, T5, Task> handler)
278+
{
279+
return registry.AddHandler(_ => new Handler<T, T2, T3, T4, T5>(command, handler, _.GetRequiredService<ISerializer>()));
280+
}
281+
282+
class Handler<T, T2, T3, T4, T5> : ExecuteCommandHandlerBase<T, T2, T3, T4, T5>
283+
{
284+
private readonly Func<T, T2, T3, T4, T5, Task> _handler;
285+
286+
public Handler(string command, Func<T, T2, T3, T4, T5, Task> handler, ISerializer serializer) : base(command, serializer)
287+
{
288+
_handler = handler;
289+
}
290+
291+
public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken cancellationToken)
292+
{
293+
await _handler(arg1, arg2, arg3, arg4, arg5);
294+
return Unit.Value;
295+
}
296+
}
297+
298+
public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4, T5, T6>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, T5, T6, Task> handler)
299+
{
300+
return registry.AddHandler(_ => new Handler<T, T2, T3, T4, T5, T6>(command, handler, _.GetRequiredService<ISerializer>()));
301+
}
302+
303+
class Handler<T, T2, T3, T4, T5, T6> : ExecuteCommandHandlerBase<T, T2, T3, T4, T5, T6>
304+
{
305+
private readonly Func<T, T2, T3, T4, T5, T6, Task> _handler;
306+
307+
public Handler(string command, Func<T, T2, T3, T4, T5, T6, Task> handler, ISerializer serializer) : base(command, serializer)
308+
{
309+
_handler = handler;
310+
}
311+
312+
public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, CancellationToken cancellationToken)
313+
{
314+
await _handler(arg1, arg2, arg3, arg4, arg5, arg6);
315+
return Unit.Value;
316+
}
317+
}
318+
}
30319
}

‎src/Server/Matchers/TextDocumentMatcher.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class TextDocumentMatcher : IHandlerMatcher
1717
public TextDocumentMatcher(ILogger<TextDocumentMatcher> logger, TextDocumentIdentifiers textDocumentIdentifiers)
1818
{
1919
_logger = logger;
20-
_textDocumentIdentifiers = textDocumentIdentifiers;;
20+
_textDocumentIdentifiers = textDocumentIdentifiers; ;
2121
}
2222

2323
public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumerable<ILspHandlerDescriptor> descriptors)
@@ -26,6 +26,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
2626
{
2727
case ITextDocumentIdentifierParams textDocumentIdentifierParams:
2828
{
29+
if (textDocumentIdentifierParams.TextDocument?.Uri == null) break;
2930
var attributes = GetTextDocumentAttributes(textDocumentIdentifierParams.TextDocument.Uri);
3031

3132
_logger.LogTrace("Found attributes {Count}, {Attributes}", attributes.Count, attributes.Select(x => $"{x.LanguageId}:{x.Scheme}:{x.Uri}"));
@@ -34,6 +35,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
3435
}
3536
case DidOpenTextDocumentParams openTextDocumentParams:
3637
{
38+
if (openTextDocumentParams.TextDocument?.Uri == null) break;
3739
var attributes = new TextDocumentAttributes(openTextDocumentParams.TextDocument.Uri, openTextDocumentParams.TextDocument.LanguageId);
3840

3941
_logger.LogTrace("Created attribute {Attribute}", $"{attributes.LanguageId}:{attributes.Scheme}:{attributes.Uri}");
@@ -42,6 +44,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
4244
}
4345
case DidChangeTextDocumentParams didChangeDocumentParams:
4446
{
47+
if (didChangeDocumentParams.TextDocument?.Uri == null) break;
4548
// TODO: Do something with document version here?
4649
var attributes = GetTextDocumentAttributes(didChangeDocumentParams.TextDocument.Uri);
4750

‎src/Shared/LspRequestRouter.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Newtonsoft.Json.Linq;
99
using OmniSharp.Extensions.JsonRpc;
1010
using OmniSharp.Extensions.JsonRpc.Server;
11+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
1112
using OmniSharp.Extensions.LanguageServer.Protocol.Shared;
1213
using ISerializer = OmniSharp.Extensions.LanguageServer.Protocol.Serialization.ISerializer;
1314

@@ -57,13 +58,20 @@ private ILspHandlerDescriptor FindDescriptor(string method, JToken @params)
5758
return null;
5859
}
5960

61+
6062
if (@params == null || descriptor.Params == null) return descriptor;
6163

6264
var lspHandlerDescriptors = _collection.Where(handler => handler.Method == method).ToList();
63-
if (lspHandlerDescriptors.Count == 1) return descriptor;
6465

6566
var paramsValue = @params.ToObject(descriptor.Params, _serializer.JsonSerializer);
66-
return _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).FirstOrDefault() ?? descriptor;
67+
var matchDescriptor = _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).FirstOrDefault();
68+
if (matchDescriptor != null) return matchDescriptor;
69+
// execute command is a special case
70+
// if no command was found to execute this must error
71+
// this is not great coupling but other options require api changes
72+
if (paramsValue is ExecuteCommandParams) return null;
73+
if (lspHandlerDescriptors.Count == 1) return descriptor;
74+
return null;
6775
}
6876

6977
IHandlerDescriptor IRequestRouter<IHandlerDescriptor>.GetDescriptor(Notification notification) => GetDescriptor(notification);

‎src/Shared/SharedHandlerCollection.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ IEnumerator IEnumerable.GetEnumerator()
4646
return GetEnumerator();
4747
}
4848

49-
IDisposable IHandlersManager.Add(IJsonRpcHandler handler, JsonRpcHandlerOptions options) => Add(new[] {handler}, options);
49+
IDisposable IHandlersManager.Add(IJsonRpcHandler handler, JsonRpcHandlerOptions options) => Add(new[] { handler }, options);
5050

5151
IDisposable IHandlersManager.Add(string method, IJsonRpcHandler handler, JsonRpcHandlerOptions options) => Add(method, handler, options);
5252

@@ -58,7 +58,7 @@ IDisposable IHandlersManager.AddLink(string sourceMethod, string destinationMeth
5858
destinationMethod,
5959
source.HandlerType,
6060
source.Handler,
61-
source.RequestProcessType.HasValue ? new JsonRpcHandlerOptions() {RequestProcessType = source.RequestProcessType.Value} : null,
61+
source.RequestProcessType.HasValue ? new JsonRpcHandlerOptions() { RequestProcessType = source.RequestProcessType.Value } : null,
6262
source.TypeDescriptor,
6363
source.HandlerType,
6464
source.RegistrationType,
@@ -70,7 +70,7 @@ IDisposable IHandlersManager.AddLink(string sourceMethod, string destinationMeth
7070
cd.Add(_textDocumentIdentifiers.Add(textDocumentIdentifier));
7171
}
7272

73-
return new LspHandlerDescriptorDisposable(new[] {descriptor}, cd);
73+
return new LspHandlerDescriptorDisposable(new[] { descriptor }, cd);
7474
}
7575

7676
public LspHandlerDescriptorDisposable Add(string method, IJsonRpcHandler handler, JsonRpcHandlerOptions options)
@@ -83,7 +83,7 @@ public LspHandlerDescriptorDisposable Add(string method, IJsonRpcHandler handler
8383
cd.Add(_textDocumentIdentifiers.Add(textDocumentIdentifier));
8484
}
8585

86-
return new LspHandlerDescriptorDisposable(new[] {descriptor}, cd);
86+
return new LspHandlerDescriptorDisposable(new[] { descriptor }, cd);
8787
}
8888

8989
public LspHandlerDescriptorDisposable Add(string method, Func<IServiceProvider, IJsonRpcHandler> handlerFunc, JsonRpcHandlerOptions options)
@@ -97,7 +97,7 @@ public LspHandlerDescriptorDisposable Add(string method, Func<IServiceProvider,
9797
cd.Add(_textDocumentIdentifiers.Add(textDocumentIdentifier));
9898
}
9999

100-
return new LspHandlerDescriptorDisposable(new[] {descriptor}, cd);
100+
return new LspHandlerDescriptorDisposable(new[] { descriptor }, cd);
101101
}
102102

103103
public LspHandlerDescriptorDisposable Add(string method, Type handlerType, JsonRpcHandlerOptions options)
@@ -110,7 +110,7 @@ public LspHandlerDescriptorDisposable Add(string method, Type handlerType, JsonR
110110
cd.Add(_textDocumentIdentifiers.Add(textDocumentIdentifier));
111111
}
112112

113-
return new LspHandlerDescriptorDisposable(new[] {descriptor}, cd);
113+
return new LspHandlerDescriptorDisposable(new[] { descriptor }, cd);
114114
}
115115

116116
public LspHandlerDescriptorDisposable Add(params Type[] handlerTypes)
@@ -168,16 +168,16 @@ public LspHandlerDescriptorDisposable Add(params IJsonRpcHandler[] handlers)
168168
class EqualityComparer : IEqualityComparer<(string method, Type implementedInterface)>
169169
{
170170

171-
public bool Equals((string method, Type implementedInterface) x, (string method, Type implementedInterface) y)
172-
{
173-
return x.method?.Equals(y.method) == true;
174-
}
171+
public bool Equals((string method, Type implementedInterface) x, (string method, Type implementedInterface) y)
172+
{
173+
return x.method?.Equals(y.method) == true;
174+
}
175175

176-
public int GetHashCode((string method, Type implementedInterface) obj)
177-
{
178-
return obj.method?.GetHashCode() ?? 0;
176+
public int GetHashCode((string method, Type implementedInterface) obj)
177+
{
178+
return obj.method?.GetHashCode() ?? 0;
179+
}
179180
}
180-
}
181181

182182
private LspHandlerDescriptorDisposable Add(IJsonRpcHandler[] handlers, JsonRpcHandlerOptions options)
183183
{
@@ -241,7 +241,7 @@ private LspHandlerDescriptor GetDescriptor(string method, Type handlerType, IJso
241241
{
242242
registrationOptions = GetRegistrationMethod
243243
.MakeGenericMethod(registrationType)
244-
.Invoke(null, new object[] {handler});
244+
.Invoke(null, new object[] { handler });
245245
}
246246

247247
var key = "default";
@@ -262,6 +262,10 @@ private LspHandlerDescriptor GetDescriptor(string method, Type handlerType, IJso
262262
key = handlerRegistration?.GetRegistrationOptions()?.DocumentSelector ?? key;
263263
}
264264
}
265+
else if (handler is IRegistration<ExecuteCommandRegistrationOptions> commandRegistration)
266+
{
267+
key = string.Join("|", commandRegistration.GetRegistrationOptions()?.Commands ?? Array.Empty<string>());
268+
}
265269

266270
if (string.IsNullOrWhiteSpace(key)) key = "default";
267271

@@ -281,7 +285,7 @@ private LspHandlerDescriptor GetDescriptor(string method, Type handlerType, IJso
281285
@params,
282286
registrationType,
283287
registrationOptions,
284-
(registrationType == null ? (Func<bool>) (() => false) : (() => _supportedCapabilities.AllowsDynamicRegistration(capabilityType))),
288+
(registrationType == null ? (Func<bool>)(() => false) : (() => _supportedCapabilities.AllowsDynamicRegistration(capabilityType))),
285289
capabilityType,
286290
requestProcessType,
287291
() => { _handlers.RemoveWhere(d => d.Handler == handler); },

‎test/JsonRpc.Tests/AutoNSubstitute/TestExtensions.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Threading;
22
using OmniSharp.Extensions.JsonRpc.Testing;
3+
using Serilog.Events;
34
using Xunit.Abstractions;
45

56
// ReSharper disable once CheckNamespace
@@ -12,11 +13,14 @@ public static void Wait(this CancellationTokenSource cancellationTokenSource)
1213
cancellationTokenSource.Token.WaitHandle.WaitOne();
1314
}
1415

15-
public static JsonRpcTestOptions ConfigureForXUnit(this JsonRpcTestOptions jsonRpcTestOptions, ITestOutputHelper outputHelper)
16+
public static JsonRpcTestOptions ConfigureForXUnit(
17+
this JsonRpcTestOptions jsonRpcTestOptions,
18+
ITestOutputHelper outputHelper,
19+
LogEventLevel logEventLevel = LogEventLevel.Debug)
1620
{
1721
return jsonRpcTestOptions
18-
.WithClientLoggerFactory(new TestLoggerFactory(outputHelper, "{Timestamp:yyyy-MM-dd HH:mm:ss} [Client] [{Level}] {Message}{NewLine}{Exception}"))
19-
.WithServerLoggerFactory(new TestLoggerFactory(outputHelper, "{Timestamp:yyyy-MM-dd HH:mm:ss} [Server] [{Level}] {Message}{NewLine}{Exception}"));
22+
.WithClientLoggerFactory(new TestLoggerFactory(outputHelper, "{Timestamp:yyyy-MM-dd HH:mm:ss} [Client] [{Level}] {Message}{NewLine}{Exception}", logEventLevel))
23+
.WithServerLoggerFactory(new TestLoggerFactory(outputHelper, "{Timestamp:yyyy-MM-dd HH:mm:ss} [Server] [{Level}] {Message}{NewLine}{Exception}", logEventLevel));
2024
}
2125
}
2226
}

‎test/Lsp.Tests/FoundationTests.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.Linq;
@@ -106,7 +106,11 @@ public void HandlersShouldAbstractClass(ILspHandlerTypeDescriptor descriptor)
106106
var abstractHandler = descriptor.HandlerType.Assembly.ExportedTypes.FirstOrDefault(z => z.IsAbstract && z.IsClass && descriptor.HandlerType.IsAssignableFrom(z));
107107
abstractHandler.Should().NotBeNull($"{descriptor.HandlerType.FullName} is missing abstract base class");
108108

109-
var delegatingHandler = descriptor.HandlerType.Assembly.DefinedTypes.FirstOrDefault(z => abstractHandler.IsAssignableFrom(z) && abstractHandler != z);
109+
var delegatingHandler = descriptor.HandlerType.Assembly.DefinedTypes.FirstOrDefault(z =>
110+
abstractHandler.IsAssignableFrom(z)
111+
&& abstractHandler != z
112+
&& !z.IsGenericTypeDefinition
113+
);
110114
if (delegatingHandler != null)
111115
{
112116
_logger.LogInformation("Delegating Handler: {Type}", delegatingHandler);
@@ -575,6 +579,7 @@ private static string GetSendMethodName(ILspHandlerTypeDescriptor descriptor)
575579
|| name.StartsWith("Prepare")
576580
|| name.StartsWith("Publish")
577581
|| name.StartsWith("ApplyWorkspaceEdit")
582+
|| name.StartsWith("Execute")
578583
|| name.StartsWith("Unregister"))
579584
{
580585
return name;

‎test/Lsp.Tests/Integration/DynamicRegistrationTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Linq;
33
using System.Reactive.Linq;
44
using System.Reactive.Threading.Tasks;
@@ -83,7 +83,7 @@ public async Task Should_Register_Links_Dynamically_While_Server_Is_Running()
8383
})
8484
);
8585

86-
await SettleNext();
86+
await Settle().Take(2);
8787

8888
client.RegistrationManager.CurrentRegistrations.Should().Contain(x =>
8989
x.Method == TextDocumentNames.Completion && SelectorMatches(x, z=> z.HasLanguage && z.Language == "vb")

‎test/Lsp.Tests/Integration/ExecuteCommandTests.cs

Lines changed: 809 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using FluentAssertions;
4+
using NSubstitute;
5+
using OmniSharp.Extensions.JsonRpc.Testing;
6+
using OmniSharp.Extensions.LanguageProtocol.Testing;
7+
using OmniSharp.Extensions.LanguageServer.Client;
8+
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
9+
using OmniSharp.Extensions.LanguageServer.Server;
10+
using Xunit;
11+
using Xunit.Abstractions;
12+
13+
namespace Lsp.Tests.Integration
14+
{
15+
public class InitializationTests : LanguageProtocolTestBase
16+
{
17+
public InitializationTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions().ConfigureForXUnit(outputHelper)) { }
18+
19+
[Fact]
20+
public async Task Logs_should_be_allowed_during_startup()
21+
{
22+
var (client, server) = await Initialize(ConfigureClient, ConfigureServer);
23+
24+
_logs.Should().HaveCount(2);
25+
_logs.Should().ContainInOrder("OnInitialize", "OnInitialized");
26+
}
27+
28+
private List<string> _logs = new List<string>();
29+
30+
private void ConfigureClient(LanguageClientOptions options)
31+
{
32+
options.OnLogMessage(log => {
33+
_logs.Add(log.Message);
34+
});
35+
}
36+
37+
private void ConfigureServer(LanguageServerOptions options)
38+
{
39+
options.OnInitialize((server, request, token) => {
40+
server.Window.LogInfo("OnInitialize");
41+
return Task.CompletedTask;
42+
});
43+
options.OnInitialized((server, request, response, token) => {
44+
server.Window.LogInfo("OnInitialized");
45+
return Task.CompletedTask;
46+
});
47+
}
48+
}
49+
}

‎test/Lsp.Tests/Integration/RequestCancellationTests.cs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using OmniSharp.Extensions.LanguageServer.Protocol;
1414
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
1515
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
16-
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
1716
using OmniSharp.Extensions.LanguageServer.Server;
1817
using Xunit;
1918
using Xunit.Abstractions;
@@ -142,39 +141,4 @@ private void ConfigureServer(LanguageServerOptions options)
142141
options.OnDidChangeTextDocument(async x => { await Task.Delay(20); }, new TextDocumentChangeRegistrationOptions());
143142
}
144143
}
145-
146-
public class InitializationTests : LanguageProtocolTestBase
147-
{
148-
public InitializationTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions().ConfigureForXUnit(outputHelper)) { }
149-
150-
[Fact]
151-
public async Task Logs_should_be_allowed_during_startup()
152-
{
153-
var (client, server) = await Initialize(ConfigureClient, ConfigureServer);
154-
155-
_logs.Should().HaveCount(2);
156-
_logs.Should().ContainInOrder("OnInitialize", "OnInitialized");
157-
}
158-
159-
private List<string> _logs = new List<string>();
160-
161-
private void ConfigureClient(LanguageClientOptions options)
162-
{
163-
options.OnLogMessage(log => {
164-
_logs.Add(log.Message);
165-
});
166-
}
167-
168-
private void ConfigureServer(LanguageServerOptions options)
169-
{
170-
options.OnInitialize((server, request, token) => {
171-
server.Window.LogInfo("OnInitialize");
172-
return Task.CompletedTask;
173-
});
174-
options.OnInitialized((server, request, response, token) => {
175-
server.Window.LogInfo("OnInitialized");
176-
return Task.CompletedTask;
177-
});
178-
}
179-
}
180144
}

‎test/Lsp.Tests/LspRequestRouterTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using ISerializer = OmniSharp.Extensions.LanguageServer.Protocol.Serialization.ISerializer;
1818
using Serializer = OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Serializer;
1919
using System.Reactive.Disposables;
20+
using Microsoft.Extensions.Logging;
2021
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
2122
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
2223
using OmniSharp.Extensions.LanguageServer.Protocol.General;
@@ -267,11 +268,13 @@ public async Task ShouldRouteToCorrect_Request_WithManyHandlers_CodeLensHandler(
267268
.Handle(Arg.Any<CodeLensParams>(), Arg.Any<CancellationToken>())
268269
.Returns(new CodeLensContainer());
269270

271+
var tdi = new TextDocumentIdentifiers();
270272
var collection =
271-
new SharedHandlerCollection(SupportedCapabilitiesFixture.AlwaysTrue, new TextDocumentIdentifiers())
273+
new SharedHandlerCollection(SupportedCapabilitiesFixture.AlwaysTrue, tdi)
272274
{textDocumentSyncHandler, textDocumentSyncHandler2, codeActionHandler, codeActionHandler2};
273275
AutoSubstitute.Provide<IHandlerCollection>(collection);
274276
AutoSubstitute.Provide<IEnumerable<ILspHandlerDescriptor>>(collection);
277+
AutoSubstitute.Provide<IHandlerMatcher>(new TextDocumentMatcher(LoggerFactory.CreateLogger<TextDocumentMatcher>(), tdi));
275278
var mediator = AutoSubstitute.Resolve<LspRequestRouter>();
276279

277280
var id = Guid.NewGuid().ToString();

0 commit comments

Comments
 (0)
Please sign in to comment.