Skip to content

Commit f453534

Browse files
Merge pull request #23 from OmniSharp/handler-collection
Update handler collection to support many handlers of a type
2 parents 4bc2a15 + 3d6de79 commit f453534

File tree

14 files changed

+2847
-79
lines changed

14 files changed

+2847
-79
lines changed

sample/SampleServer/Program.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class TextDocumentHandler : ITextDocumentSyncHandler
3939
private readonly ILanguageServer _router;
4040

4141
private readonly DocumentSelector _documentSelector = new DocumentSelector(
42-
new DocumentFilter() {
42+
new DocumentFilter()
43+
{
4344
Pattern = "**/*.csproj",
4445
Language = "xml"
4546
}
@@ -52,19 +53,24 @@ public TextDocumentHandler(ILanguageServer router)
5253
_router = router;
5354
}
5455

55-
public TextDocumentSyncOptions Options { get; } = new TextDocumentSyncOptions() {
56+
public TextDocumentSyncOptions Options { get; } = new TextDocumentSyncOptions()
57+
{
5658
WillSaveWaitUntil = false,
5759
WillSave = true,
5860
Change = TextDocumentSyncKind.Full,
59-
Save = new SaveOptions() {
61+
Save = new SaveOptions()
62+
{
6063
IncludeText = true
6164
},
6265
OpenClose = true
6366
};
6467

68+
public string Key => (string)_documentSelector;
69+
6570
public Task Handle(DidChangeTextDocumentParams notification)
6671
{
67-
_router.LogMessage(new LogMessageParams() {
72+
_router.LogMessage(new LogMessageParams()
73+
{
6874
Type = MessageType.Log,
6975
Message = "Hello World!!!!"
7076
});
@@ -73,7 +79,8 @@ public Task Handle(DidChangeTextDocumentParams notification)
7379

7480
TextDocumentChangeRegistrationOptions IRegistration<TextDocumentChangeRegistrationOptions>.GetRegistrationOptions()
7581
{
76-
return new TextDocumentChangeRegistrationOptions() {
82+
return new TextDocumentChangeRegistrationOptions()
83+
{
7784
DocumentSelector = _documentSelector,
7885
SyncKind = Options.Change
7986
};
@@ -86,15 +93,17 @@ public void SetCapability(SynchronizationCapability capability)
8693

8794
public async Task Handle(DidOpenTextDocumentParams notification)
8895
{
89-
_router.LogMessage(new LogMessageParams() {
96+
_router.LogMessage(new LogMessageParams()
97+
{
9098
Type = MessageType.Log,
9199
Message = "Hello World!!!!"
92100
});
93101
}
94102

95103
TextDocumentRegistrationOptions IRegistration<TextDocumentRegistrationOptions>.GetRegistrationOptions()
96104
{
97-
return new TextDocumentRegistrationOptions() {
105+
return new TextDocumentRegistrationOptions()
106+
{
98107
DocumentSelector = _documentSelector,
99108
};
100109
}
@@ -111,7 +120,8 @@ public Task Handle(DidSaveTextDocumentParams notification)
111120

112121
TextDocumentSaveRegistrationOptions IRegistration<TextDocumentSaveRegistrationOptions>.GetRegistrationOptions()
113122
{
114-
return new TextDocumentSaveRegistrationOptions() {
123+
return new TextDocumentSaveRegistrationOptions()
124+
{
115125
DocumentSelector = _documentSelector,
116126
IncludeText = Options.Save.IncludeText
117127
};

src/JsonRpc/IJsonRpcHandler.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
/// <summary>
44
/// A simple marker interface to use for storing handlings (which will be cast out later)
55
/// </summary>
6-
public interface IJsonRpcHandler { }
7-
}
6+
public interface IJsonRpcHandler
7+
{
8+
string Key { get; }
9+
}
10+
}

src/Lsp/Abstractions/IHandlerCollection.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ namespace OmniSharp.Extensions.LanguageServer.Abstractions
66
{
77
interface IHandlerCollection : IEnumerable<ILspHandlerDescriptor>
88
{
9-
IDisposable Add(IJsonRpcHandler handler);
10-
11-
IEnumerable<ILspHandlerDescriptor> Get(string method);
12-
IEnumerable<ILspHandlerDescriptor> Get(IJsonRpcHandler handler);
9+
IDisposable Add(params IJsonRpcHandler[] handlers);
10+
IDisposable Add(IEnumerable<IJsonRpcHandler> handlers);
1311
}
14-
}
12+
}

src/Lsp/HandlerCollection.cs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,51 +22,45 @@ IEnumerator IEnumerable.GetEnumerator()
2222
return GetEnumerator();
2323
}
2424

25-
public IDisposable Add(IJsonRpcHandler handler)
25+
public IDisposable Add(params IJsonRpcHandler[] handlers)
2626
{
27-
//var type = handler.GetType();
27+
return Add(handlers.AsEnumerable());
28+
}
2829

29-
var handlers = new List<HandlerDescriptor>();
30-
foreach (var implementedInterface in handler.GetType().GetTypeInfo()
31-
.ImplementedInterfaces
32-
.Where(x => !string.IsNullOrWhiteSpace(LspHelper.GetMethodName(x))))
30+
public IDisposable Add(IEnumerable<IJsonRpcHandler> handlers)
31+
{
32+
var descriptors = new List<HandlerDescriptor>();
33+
foreach (var handler in handlers)
3334
{
34-
var @interface = GetHandlerInterface(implementedInterface);
35-
var registration = UnwrapGenericType(typeof(IRegistration<>), implementedInterface);
36-
var capability = UnwrapGenericType(typeof(ICapability<>), implementedInterface);
37-
38-
Type @params = null;
39-
if (@interface.GetTypeInfo().IsGenericType)
35+
foreach (var implementedInterface in handler.GetType().GetTypeInfo()
36+
.ImplementedInterfaces
37+
.Where(x => !string.IsNullOrWhiteSpace(LspHelper.GetMethodName(x))))
4038
{
41-
@params = @interface.GetTypeInfo().GetGenericArguments()[0];
39+
var @interface = GetHandlerInterface(implementedInterface);
40+
var registration = UnwrapGenericType(typeof(IRegistration<>), implementedInterface);
41+
var capability = UnwrapGenericType(typeof(ICapability<>), implementedInterface);
42+
43+
Type @params = null;
44+
if (@interface.GetTypeInfo().IsGenericType)
45+
{
46+
@params = @interface.GetTypeInfo().GetGenericArguments()[0];
47+
}
48+
49+
var h = new HandlerDescriptor(
50+
LspHelper.GetMethodName(implementedInterface),
51+
handler,
52+
@interface,
53+
@params,
54+
registration,
55+
capability,
56+
() => _handlers.RemoveWhere(instance => instance.Handler == handler));
57+
58+
descriptors.Add(h);
59+
_handlers.Add(h);
4260
}
43-
44-
var h = new HandlerDescriptor(
45-
LspHelper.GetMethodName(implementedInterface),
46-
handler,
47-
@interface,
48-
@params,
49-
registration,
50-
capability,
51-
() => _handlers.RemoveWhere(instance => instance.Handler == handler));
52-
53-
handlers.Add(h);
5461
}
5562

56-
foreach (var a in handlers)
57-
_handlers.Add(a);
58-
59-
return new ImutableDisposable(handlers);
60-
}
61-
62-
public IEnumerable<ILspHandlerDescriptor> Get(IJsonRpcHandler handler)
63-
{
64-
return _handlers.Where(instance => instance.Handler == handler);
65-
}
66-
67-
public IEnumerable<ILspHandlerDescriptor> Get(string method)
68-
{
69-
return _handlers.Where(instance => instance.Method == method);
63+
return new ImutableDisposable(descriptors);
7064
}
7165

7266
private static readonly Type[] HandlerTypes = { typeof(INotificationHandler), typeof(INotificationHandler<>), typeof(IRequestHandler<>), typeof(IRequestHandler<,>), };
@@ -96,4 +90,4 @@ private Type UnwrapGenericType(Type genericType, Type type)
9690
?.GetGenericArguments()[0];
9791
}
9892
}
99-
}
93+
}

src/Lsp/HandlerDescriptor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,15 @@ public override bool Equals(object obj)
9494
{
9595
if (obj is HandlerDescriptor handler)
9696
{
97-
return handler.HandlerType == HandlerType;
97+
return handler.HandlerType == HandlerType && handler.Handler.Key == Handler.Key;
9898
}
9999
return false;
100100
}
101101

102102
public override int GetHashCode()
103103
{
104-
return HandlerType.GetHashCode();
104+
if (string.IsNullOrWhiteSpace(Handler.Key)) return HandlerType.GetHashCode();
105+
return Tuple.Create(HandlerType, Handler.Key).GetHashCode();
105106
}
106107
}
107-
}
108+
}

src/Lsp/Handlers/CancelRequestHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ internal CancelRequestHandler(LspRequestRouter requestRouter)
1313
_requestRouter = requestRouter;
1414
}
1515

16+
public string Key => nameof(ICancelRequestHandler);
17+
1618
public Task Handle(CancelParams notification)
1719
{
1820
_requestRouter.CancelRequest(notification.Id);

src/Lsp/Handlers/ExitHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public ExitHandler(ShutdownHandler shutdownHandler)
1212
_shutdownHandler = shutdownHandler;
1313
}
1414

15+
public string Key => nameof(IExitHandler);
16+
1517
public Task Handle()
1618
{
1719
Exit?.Invoke(_shutdownHandler.ShutdownRequested ? 0 : 1);

src/Lsp/Handlers/ShutdownHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace OmniSharp.Extensions.LanguageServer.Handlers
66
{
77
public class ShutdownHandler : IShutdownHandler, IAwaitableTermination
88
{
9+
public string Key => nameof(IShutdownHandler);
10+
911
public Task Handle()
1012
{
1113
ShutdownRequested = true;

src/Lsp/LanguageServer.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,35 @@ IRequestProcessIdentifier requestProcessIdentifier
6363
public InitializeParams Client { get; private set; }
6464
public InitializeResult Server { get; private set; }
6565

66+
public string Key => nameof(ILanguageServer);
67+
6668
public IDisposable AddHandler(IJsonRpcHandler handler)
6769
{
68-
var handlerDisposable = _collection.Add(handler);
70+
return AddHandler(handler);
71+
}
72+
73+
public IDisposable AddHandlers(params IJsonRpcHandler[] handlers)
74+
{
75+
return AddHandlers(handlers.AsEnumerable());
76+
}
77+
78+
public IDisposable AddHandlers(IEnumerable<IJsonRpcHandler> handlers)
79+
{
80+
var handlerDisposable = _collection.Add(handlers);
6981

7082
return new ImutableDisposable(
7183
handlerDisposable,
72-
new Disposable(() => {
73-
var handlers = _collection
74-
.Where(x => x.Handler == handler)
84+
new Disposable(() =>
85+
{
86+
var foundItems = handlers
87+
.SelectMany(handler => _collection
88+
.Where(x => handler == x.Handler)
7589
.Where(x => x.AllowsDynamicRegistration)
7690
.Select(x => x.Registration)
77-
.Where(x => x != null)
78-
.ToArray();
91+
.Where(x => x != null))
92+
.ToArray();
7993

80-
Task.Run(() => this.UnregisterCapability(new UnregistrationParams() { Unregisterations = handlers }));
94+
Task.Run(() => this.UnregisterCapability(new UnregistrationParams() { Unregisterations = foundItems }));
8195
}));
8296
}
8397

@@ -115,7 +129,8 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
115129
}
116130
}
117131

118-
var serverCapabilities = new ServerCapabilities() {
132+
var serverCapabilities = new ServerCapabilities()
133+
{
119134
CodeActionProvider = HasHandler<ICodeActionHandler>(),
120135
CodeLensProvider = GetOptions<ICodeLensOptions, CodeLensOptions>(CodeLensOptions.Of),
121136
CompletionProvider = GetOptions<ICompletionOptions, CompletionOptions>(CompletionOptions.Of),
@@ -145,7 +160,8 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
145160
}
146161
else
147162
{
148-
serverCapabilities.TextDocumentSync = textSyncHandler?.Options ?? new TextDocumentSyncOptions() {
163+
serverCapabilities.TextDocumentSync = textSyncHandler?.Options ?? new TextDocumentSyncOptions()
164+
{
149165
Change = TextDocumentSyncKind.None,
150166
OpenClose = false,
151167
Save = new SaveOptions() { IncludeText = false },

src/Lsp/Models/DocumentFilter.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Minimatch;
1+
using System.Collections.Generic;
2+
using System.Text;
3+
using Minimatch;
24
using Newtonsoft.Json;
35
using Newtonsoft.Json.Serialization;
46
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
@@ -39,7 +41,8 @@ public class DocumentFilter
3941
public string Pattern
4042
{
4143
get => _pattern;
42-
set {
44+
set
45+
{
4346
_pattern = value;
4447
_minimatcher = new Minimatcher(value, new Options() { MatchBase = true });
4548
}
@@ -54,6 +57,24 @@ public string Pattern
5457
private string _pattern;
5558
private Minimatcher _minimatcher;
5659

60+
public static explicit operator string(DocumentFilter documentFilter)
61+
{
62+
var items = new List<string>();
63+
if (documentFilter.HasLanguage)
64+
{
65+
items.Add(documentFilter.Language);
66+
}
67+
if (documentFilter.HasScheme)
68+
{
69+
items.Add(documentFilter.Scheme);
70+
}
71+
if (documentFilter.HasPattern)
72+
{
73+
items.Add(documentFilter.Pattern);
74+
}
75+
return $"[{string.Join(", ", items)}]";
76+
}
77+
5778
public bool IsMatch(TextDocumentAttributes attributes)
5879
{
5980
if (HasLanguage && HasPattern && HasScheme)
@@ -88,4 +109,4 @@ public bool IsMatch(TextDocumentAttributes attributes)
88109
return false;
89110
}
90111
}
91-
}
112+
}

src/Lsp/Models/DocumentSelector.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,14 @@ public static implicit operator DocumentSelector(List<DocumentFilter> items)
3838
return new DocumentSelector(items);
3939
}
4040

41+
public static explicit operator string(DocumentSelector documentSelector)
42+
{
43+
return string.Join(", ", documentSelector.Select(x => (string)x));
44+
}
45+
4146
public bool IsMatch(TextDocumentAttributes attributes)
4247
{
4348
return this.Any(z => z.IsMatch(attributes));
4449
}
4550
}
46-
}
51+
}

0 commit comments

Comments
 (0)