Skip to content

Commit 05be685

Browse files
Added support for strongly typed data to be attached to codelens, completion items, and document links. Adds support for multiple codelens, completion and document link handers for each text document.
1 parent 21f56ec commit 05be685

File tree

63 files changed

+3670
-1103
lines changed

Some content is hidden

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

63 files changed

+3670
-1103
lines changed

sample/SampleServer/TextDocumentHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ TextDocumentSaveRegistrationOptions IRegistration<TextDocumentSaveRegistrationOp
100100
};
101101
}
102102

103-
public TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri)
103+
public IEnumerable<TextDocumentAttributes> GetTextDocumentAttributes(DocumentUri uri)
104104
{
105-
return new TextDocumentAttributes(uri, "csharp");
105+
yield return new TextDocumentAttributes(uri, "csharp");
106106
}
107107
}
108108

src/JsonRpc.Testing/IRequestSettler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ public interface IRequestSettler
55
void OnStartRequest();
66
void OnEndRequest();
77
}
8-
}
8+
}

src/JsonRpc/IRequestRouter.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
25
using System.Threading;
36
using System.Threading.Tasks;
47
using OmniSharp.Extensions.JsonRpc.Server;
@@ -10,11 +13,38 @@ public interface IRequestRouter
1013
IServiceProvider ServiceProvider { get; }
1114
}
1215

16+
public interface IRequestDescriptor<out TDescriptor> : IEnumerable<TDescriptor>
17+
{
18+
TDescriptor Default { get; }
19+
}
20+
21+
class RequestDescriptor<TDescriptor> : IRequestDescriptor<TDescriptor>
22+
{
23+
private IEnumerable<TDescriptor> _descriptors;
24+
25+
public RequestDescriptor(IEnumerable<TDescriptor> descriptors)
26+
{
27+
var enumerable = descriptors as TDescriptor[] ?? descriptors.ToArray();
28+
_descriptors = enumerable;
29+
Default = enumerable.FirstOrDefault();
30+
}
31+
32+
public IEnumerator<TDescriptor> GetEnumerator() => _descriptors.GetEnumerator();
33+
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable) _descriptors).GetEnumerator();
34+
35+
public TDescriptor Default { get; }
36+
}
37+
1338
public interface IRequestRouter<TDescriptor> : IRequestRouter
1439
{
15-
TDescriptor GetDescriptor(Notification notification);
16-
TDescriptor GetDescriptor(Request request);
17-
Task RouteNotification(TDescriptor descriptor, Notification notification, CancellationToken token);
18-
Task<ErrorResponse> RouteRequest(TDescriptor descriptor, Request request, CancellationToken token);
40+
IRequestDescriptor<TDescriptor> GetDescriptor(Notification notification);
41+
IRequestDescriptor<TDescriptor> GetDescriptor(Request request);
42+
Task RouteNotification(IRequestDescriptor<TDescriptor> descriptors, Notification notification, CancellationToken token);
43+
Task<ErrorResponse> RouteRequest(IRequestDescriptor<TDescriptor> descriptors, Request request, CancellationToken token);
44+
}
45+
46+
interface IAggregateResults
47+
{
48+
object AggregateResults(IEnumerable<object> values);
1949
}
2050
}

src/JsonRpc/InputHandler.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public class InputHandler : IInputHandler, IDisposable
5454
private readonly CompositeDisposable _disposable;
5555
private readonly AsyncSubject<Unit> _inputActive;
5656

57-
private readonly ConcurrentDictionary<object, (CancellationTokenSource cancellationTokenSource, IHandlerDescriptor descriptor)> _requests =
58-
new ConcurrentDictionary<object, (CancellationTokenSource cancellationTokenSource, IHandlerDescriptor descriptor)>();
57+
private readonly ConcurrentDictionary<object, (CancellationTokenSource cancellationTokenSource, IRequestDescriptor<IHandlerDescriptor> descriptor)> _requests =
58+
new ConcurrentDictionary<object, (CancellationTokenSource cancellationTokenSource, IRequestDescriptor<IHandlerDescriptor> descriptor)>();
5959

6060
private readonly Subject<IObservable<Unit>> _inputQueue;
6161

@@ -411,14 +411,14 @@ private void HandleRequest(in ReadOnlySequence<byte> request)
411411
{
412412
// _logger.LogDebug("Handling Request {Method} {ResponseId}", item.Request.Method, item.Request.Id);
413413
var descriptor = _requestRouter.GetDescriptor(item.Request);
414-
if (descriptor is null)
414+
if (descriptor.Default is null)
415415
{
416416
_logger.LogDebug("Request handler was not found (or not setup) {Method} {ResponseId}", item.Request.Method, item.Request.Id);
417417
_outputHandler.Send(new MethodNotFound(item.Request.Id, item.Request.Method));
418418
return;
419419
}
420420

421-
var type = _requestProcessIdentifier.Identify(descriptor);
421+
var type = _requestProcessIdentifier.Identify(descriptor.Default);
422422
_scheduler.Add(type, $"{item.Request.Method}:{item.Request.Id}", RouteRequest(descriptor, item.Request));
423423
}
424424

@@ -446,15 +446,15 @@ private void HandleRequest(in ReadOnlySequence<byte> request)
446446

447447
// _logger.LogDebug("Handling Request {Method}", item.Notification.Method);
448448
var descriptor = _requestRouter.GetDescriptor(item.Notification);
449-
if (descriptor is null)
449+
if (descriptor.Default is null)
450450
{
451451
_logger.LogDebug("Notification handler was not found (or not setup) {Method}", item.Notification.Method);
452452
// TODO: Figure out a good way to send this feedback back.
453453
// _outputHandler.Send(new RpcError(null, new ErrorMessage(-32601, $"Method not found - {item.Notification.Method}")));
454454
return;
455455
}
456456

457-
var type = _requestProcessIdentifier.Identify(descriptor);
457+
var type = _requestProcessIdentifier.Identify(descriptor.Default);
458458
_scheduler.Add(type, item.Notification.Method, RouteNotification(descriptor, item.Notification));
459459
}
460460

@@ -465,7 +465,7 @@ private void HandleRequest(in ReadOnlySequence<byte> request)
465465
}
466466
}
467467

468-
private SchedulerDelegate RouteRequest(IHandlerDescriptor descriptor, Request request)
468+
private SchedulerDelegate RouteRequest(IRequestDescriptor<IHandlerDescriptor> descriptor, Request request)
469469
{
470470
// start request, create cts, etc
471471
var cts = new CancellationTokenSource();
@@ -521,7 +521,7 @@ private SchedulerDelegate RouteRequest(IHandlerDescriptor descriptor, Request re
521521
});
522522
}
523523

524-
private SchedulerDelegate RouteNotification(IHandlerDescriptor descriptor, Notification notification)
524+
private SchedulerDelegate RouteNotification(IRequestDescriptor<IHandlerDescriptor> descriptor, Notification notification)
525525
{
526526
return (contentModifiedToken, scheduler) =>
527527
// ITS A RACE!

src/JsonRpc/NotificationHandler.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@
55

66
namespace OmniSharp.Extensions.JsonRpc
77
{
8-
public static class NotificationHandler
9-
{
8+
public static class NotificationHandler {
9+
1010
public static DelegatingHandlers.Notification<TParams> For<TParams>(Action<TParams, CancellationToken> handler)
1111
where TParams : IRequest
1212
{
13-
return new DelegatingHandlers.Notification<TParams>(handler);
13+
return new DelegatingHandlers.Notification<TParams>( handler);
1414
}
1515

1616
public static DelegatingHandlers.Notification<TParams> For<TParams>(Func<TParams, CancellationToken, Task> handler)
1717
where TParams : IRequest
1818
{
1919
return new DelegatingHandlers.Notification<TParams>(handler);
2020
}
21-
2221
public static DelegatingHandlers.Notification<TParams> For<TParams>(Action<TParams> handler)
2322
where TParams : IRequest
2423
{
@@ -31,4 +30,4 @@ public static DelegatingHandlers.Notification<TParams> For<TParams>(Func<TParams
3130
return new DelegatingHandlers.Notification<TParams>((p, ct) => handler(p));
3231
}
3332
}
34-
}
33+
}

src/JsonRpc/RequestRouter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ public IDisposable Add(IJsonRpcHandler handler)
2222
return _collection.Add(handler);
2323
}
2424

25-
private IHandlerDescriptor FindDescriptor(IMethodWithParams instance)
25+
private IRequestDescriptor<IHandlerDescriptor> FindDescriptor(IMethodWithParams instance)
2626
{
27-
return _collection.FirstOrDefault(x => x.Method == instance.Method);
27+
return new RequestDescriptor<IHandlerDescriptor>(_collection.Where(x => x.Method == instance.Method));
2828
}
2929

30-
public override IHandlerDescriptor GetDescriptor(Notification notification)
30+
public override IRequestDescriptor<IHandlerDescriptor> GetDescriptor(Notification notification)
3131
{
3232
return FindDescriptor(notification);
3333
}
3434

35-
public override IHandlerDescriptor GetDescriptor(Request request)
35+
public override IRequestDescriptor<IHandlerDescriptor> GetDescriptor(Request request)
3636
{
3737
return FindDescriptor(request);
3838
}

src/JsonRpc/RequestRouterBase.cs

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.Extensions.Logging;
1111
using System.Collections.Generic;
1212
using System.Linq;
13+
using OmniSharp.Extensions.JsonRpc.Client;
1314

1415
namespace OmniSharp.Extensions.JsonRpc
1516
{
@@ -30,50 +31,76 @@ public RequestRouterBase(ISerializer serializer, IServiceProvider serviceProvide
3031

3132
public IServiceProvider ServiceProvider { get; }
3233

33-
public async Task RouteNotification(TDescriptor descriptor, Notification notification, CancellationToken token)
34+
public async Task RouteNotification(IRequestDescriptor<TDescriptor> descriptors, Notification notification, CancellationToken token)
3435
{
3536
using var debug = _logger.TimeDebug("Routing Notification {Method}", notification.Method);
3637
using var _ = _logger.BeginScope(new[] {
3738
new KeyValuePair<string, string>("Method", notification.Method),
3839
new KeyValuePair<string, string>("Params", notification.Params?.ToString())
3940
});
40-
using var scope = _serviceScopeFactory.CreateScope();
41-
var context = scope.ServiceProvider.GetRequiredService<IRequestContext>();
42-
context.Descriptor = descriptor;
43-
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
4441

45-
if (descriptor.Params is null)
46-
{
47-
await HandleNotification(mediator, descriptor, EmptyRequest.Instance, token);
48-
}
49-
else
42+
await Task.WhenAll(descriptors.Select(descriptor => InnerRouteNotification(descriptor)));
43+
44+
async Task InnerRouteNotification(TDescriptor descriptor)
5045
{
51-
_logger.LogDebug("Converting params for Notification {Method} to {Type}", notification.Method, descriptor.Params.FullName);
52-
object @params;
53-
if (descriptor.IsDelegatingHandler)
46+
using var scope = _serviceScopeFactory.CreateScope();
47+
var context = scope.ServiceProvider.GetRequiredService<IRequestContext>();
48+
context.Descriptor = descriptor;
49+
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
50+
51+
if (descriptor.Params is null)
5452
{
55-
// new DelegatingRequest();
56-
var o = notification.Params?.ToObject(descriptor.Params.GetGenericArguments()[0], _serializer.JsonSerializer);
57-
@params = Activator.CreateInstance(descriptor.Params, new object[] {o});
53+
await HandleNotification(mediator, descriptor, EmptyRequest.Instance, token);
5854
}
5955
else
6056
{
61-
@params = notification.Params?.ToObject(descriptor.Params, _serializer.JsonSerializer);
57+
_logger.LogDebug("Converting params for Notification {Method} to {Type}", notification.Method, descriptor.Params.FullName);
58+
object @params;
59+
if (descriptor.IsDelegatingHandler)
60+
{
61+
// new DelegatingRequest();
62+
var o = notification.Params?.ToObject(descriptor.Params.GetGenericArguments()[0], _serializer.JsonSerializer);
63+
@params = Activator.CreateInstance(descriptor.Params, new object[] {o});
64+
}
65+
else
66+
{
67+
@params = notification.Params?.ToObject(descriptor.Params, _serializer.JsonSerializer);
68+
}
69+
70+
await HandleNotification(mediator, descriptor, @params ?? Activator.CreateInstance(descriptor.Params), token);
6271
}
63-
64-
await HandleNotification(mediator, descriptor, @params ?? Activator.CreateInstance(descriptor.Params), token);
6572
}
6673
}
6774

68-
public virtual async Task<ErrorResponse> RouteRequest(TDescriptor descriptor, Request request, CancellationToken token)
75+
public virtual async Task<ErrorResponse> RouteRequest(IRequestDescriptor<TDescriptor> descriptors, Request request, CancellationToken token)
6976
{
7077
using var debug = _logger.TimeDebug("Routing Request ({Id}) {Method}", request.Id, request.Method);
7178
using var _ = _logger.BeginScope(new[] {
7279
new KeyValuePair<string, string>("Id", request.Id?.ToString()),
7380
new KeyValuePair<string, string>("Method", request.Method),
7481
new KeyValuePair<string, string>("Params", request.Params?.ToString())
7582
});
76-
using var scope = _serviceScopeFactory.CreateScope();
83+
84+
if (typeof(IAggregateResults).IsAssignableFrom(descriptors.Default.Response))
85+
{
86+
var responses = await Task.WhenAll(descriptors.Select(InnerRouteRequest));
87+
var errorResponse = responses.FirstOrDefault(x => x.IsError);
88+
if (errorResponse.IsError) return errorResponse;
89+
if (responses.Length == 1)
90+
{
91+
return responses[0];
92+
}
93+
94+
if (!(responses[0].Value is OutgoingResponse or)) throw new NotSupportedException("Unsupported response type");
95+
if (!(or.Result is IAggregateResults ar)) throw new NotSupportedException("Unsupported result type");
96+
return new OutgoingResponse(request.Id, ar.AggregateResults(responses.Skip(1).Select(z => z.Value).OfType<OutgoingResponse>().Select(z => z.Result)), request);
97+
}
98+
99+
return await InnerRouteRequest(descriptors.Default);
100+
101+
async Task<ErrorResponse> InnerRouteRequest(TDescriptor descriptor)
102+
{
103+
using var scope = _serviceScopeFactory.CreateScope();
77104
var context = scope.ServiceProvider.GetRequiredService<IRequestContext>();
78105
context.Descriptor = descriptor;
79106
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
@@ -132,12 +159,12 @@ public virtual async Task<ErrorResponse> RouteRequest(TDescriptor descriptor, Re
132159

133160
_logger.LogTrace("Response value was {Type}", responseValue?.GetType().FullName);
134161
}
135-
136162
return new JsonRpc.Client.OutgoingResponse(request.Id, responseValue, request);
163+
}
137164
}
138165

139-
public abstract TDescriptor GetDescriptor(Notification notification);
140-
public abstract TDescriptor GetDescriptor(Request request);
166+
public abstract IRequestDescriptor<TDescriptor> GetDescriptor(Notification notification);
167+
public abstract IRequestDescriptor<TDescriptor> GetDescriptor(Request request);
141168

142169
private static readonly MethodInfo SendRequestUnit = typeof(RequestRouterBase<TDescriptor>)
143170
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
2+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
23

34
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
45
{
5-
public class CodeLensCapability : DynamicCapability, ConnectedCapability<ICodeLensHandler> { }
6+
public class CodeLensCapability : DynamicCapability, ConnectedCapability<ICodeLensHandler<CanBeResolvedData>> { }
67
}

src/Protocol/Client/Capabilities/CompletionCapability.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
2+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
23
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
34

45
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
56
{
6-
public class CompletionCapability : DynamicCapability, ConnectedCapability<ICompletionHandler>
7+
public class CompletionCapability : DynamicCapability, ConnectedCapability<ICompletionHandler<CanBeResolvedData>>
78
{
89
/// <summary>
910
/// The client supports the following `CompletionItem` specific

src/Protocol/Client/Capabilities/DocumentLinkCapability.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
2+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
23
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
34

45
namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
56
{
6-
public class DocumentLinkCapability : DynamicCapability, ConnectedCapability<IDocumentLinkHandler>
7+
public class DocumentLinkCapability : DynamicCapability, ConnectedCapability<IDocumentLinkHandler<CanBeResolvedData>>
78
{
89
/// <summary>
910
/// Whether the client support the `tooltip` property on `DocumentLink`.

0 commit comments

Comments
 (0)