Skip to content

Commit 69b540b

Browse files
fixed did-change callback to ensure it's part of lsp request router
1 parent b2bb198 commit 69b540b

File tree

7 files changed

+88
-55
lines changed

7 files changed

+88
-55
lines changed

src/JsonRpc/ProcessScheduler.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.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Threading;
@@ -128,7 +128,7 @@ public void Dispose()
128128
}
129129
}
130130

131-
static class Events
131+
public static class Events
132132
{
133133
public static EventId UnhandledException = new EventId(1337_100);
134134
public static EventId UnhandledRequest = new EventId(1337_101);

src/Lsp/ClientCapabilityProvider.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public ClientCapabilityProvider(IHandlerCollection collection)
1616
_collection = collection;
1717
}
1818

19-
public bool HasHandler<T>(Supports<T> capability)
19+
public bool HasStaticHandler<T>(Supports<T> capability)
2020
where T : DynamicCapability, ConnectedCapability<IJsonRpcHandler>
2121
{
2222
if (!capability.IsSupported) return false;
@@ -26,13 +26,16 @@ public bool HasHandler<T>(Supports<T> capability)
2626
var handlerType = typeof(T).GetTypeInfo().ImplementedInterfaces
2727
.Single(x => x.GetTypeInfo().IsGenericType && x.GetTypeInfo().GetGenericTypeDefinition() == typeof(ConnectedCapability<>))
2828
.GetTypeInfo().GetGenericArguments()[0].GetTypeInfo();
29-
return !capability.Value.DynamicRegistration && _collection.Any(z => z.HandlerType.GetTypeInfo().IsAssignableFrom(handlerType));
29+
return !capability.Value.DynamicRegistration &&
30+
_collection.Any(z =>
31+
z.HandlerType.GetTypeInfo().IsAssignableFrom(handlerType) ||
32+
z.Handler.GetType().GetTypeInfo().IsAssignableFrom(handlerType));
3033
}
3134

32-
public IOptionsGetter GetOptions<T>(Supports<T> capability)
35+
public IOptionsGetter GetStaticOptions<T>(Supports<T> capability)
3336
where T : DynamicCapability, ConnectedCapability<IJsonRpcHandler>
3437
{
35-
return !HasHandler(capability) ? Null : new OptionsGetter(_collection);
38+
return !HasStaticHandler(capability) ? Null : new OptionsGetter(_collection);
3639
}
3740

3841
private static readonly IOptionsGetter Null = new NullOptionsGetter();

src/Lsp/LanguageServer.cs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -130,22 +130,22 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
130130
var ccp = new ClientCapabilityProvider(_collection);
131131

132132
var serverCapabilities = new ServerCapabilities() {
133-
CodeActionProvider = ccp.HasHandler(textDocumentCapabilities.CodeAction),
134-
CodeLensProvider = ccp.GetOptions(textDocumentCapabilities.CodeLens).Get<ICodeLensOptions, CodeLensOptions>(CodeLensOptions.Of),
135-
CompletionProvider = ccp.GetOptions(textDocumentCapabilities.Completion).Get<ICompletionOptions, CompletionOptions>(CompletionOptions.Of),
136-
DefinitionProvider = ccp.HasHandler(textDocumentCapabilities.Definition),
137-
DocumentFormattingProvider = ccp.HasHandler(textDocumentCapabilities.Formatting),
138-
DocumentHighlightProvider = ccp.HasHandler(textDocumentCapabilities.DocumentHighlight),
139-
DocumentLinkProvider = ccp.GetOptions(textDocumentCapabilities.DocumentLink).Get<IDocumentLinkOptions, DocumentLinkOptions>(DocumentLinkOptions.Of),
140-
DocumentOnTypeFormattingProvider = ccp.GetOptions(textDocumentCapabilities.OnTypeFormatting).Get<IDocumentOnTypeFormattingOptions, DocumentOnTypeFormattingOptions>(DocumentOnTypeFormattingOptions.Of),
141-
DocumentRangeFormattingProvider = ccp.HasHandler(textDocumentCapabilities.RangeFormatting),
142-
DocumentSymbolProvider = ccp.HasHandler(textDocumentCapabilities.DocumentSymbol),
143-
ExecuteCommandProvider = ccp.GetOptions(workspaceCapabilities.ExecuteCommand).Get<IExecuteCommandOptions, ExecuteCommandOptions>(ExecuteCommandOptions.Of),
144-
HoverProvider = ccp.HasHandler(textDocumentCapabilities.Hover),
145-
ReferencesProvider = ccp.HasHandler(textDocumentCapabilities.References),
146-
RenameProvider = ccp.HasHandler(textDocumentCapabilities.Rename),
147-
SignatureHelpProvider = ccp.GetOptions(textDocumentCapabilities.SignatureHelp).Get<ISignatureHelpOptions, SignatureHelpOptions>(SignatureHelpOptions.Of),
148-
WorkspaceSymbolProvider = ccp.HasHandler(workspaceCapabilities.Symbol)
133+
CodeActionProvider = ccp.HasStaticHandler(textDocumentCapabilities.CodeAction),
134+
CodeLensProvider = ccp.GetStaticOptions(textDocumentCapabilities.CodeLens).Get<ICodeLensOptions, CodeLensOptions>(CodeLensOptions.Of),
135+
CompletionProvider = ccp.GetStaticOptions(textDocumentCapabilities.Completion).Get<ICompletionOptions, CompletionOptions>(CompletionOptions.Of),
136+
DefinitionProvider = ccp.HasStaticHandler(textDocumentCapabilities.Definition),
137+
DocumentFormattingProvider = ccp.HasStaticHandler(textDocumentCapabilities.Formatting),
138+
DocumentHighlightProvider = ccp.HasStaticHandler(textDocumentCapabilities.DocumentHighlight),
139+
DocumentLinkProvider = ccp.GetStaticOptions(textDocumentCapabilities.DocumentLink).Get<IDocumentLinkOptions, DocumentLinkOptions>(DocumentLinkOptions.Of),
140+
DocumentOnTypeFormattingProvider = ccp.GetStaticOptions(textDocumentCapabilities.OnTypeFormatting).Get<IDocumentOnTypeFormattingOptions, DocumentOnTypeFormattingOptions>(DocumentOnTypeFormattingOptions.Of),
141+
DocumentRangeFormattingProvider = ccp.HasStaticHandler(textDocumentCapabilities.RangeFormatting),
142+
DocumentSymbolProvider = ccp.HasStaticHandler(textDocumentCapabilities.DocumentSymbol),
143+
ExecuteCommandProvider = ccp.GetStaticOptions(workspaceCapabilities.ExecuteCommand).Get<IExecuteCommandOptions, ExecuteCommandOptions>(ExecuteCommandOptions.Of),
144+
HoverProvider = ccp.HasStaticHandler(textDocumentCapabilities.Hover),
145+
ReferencesProvider = ccp.HasStaticHandler(textDocumentCapabilities.References),
146+
RenameProvider = ccp.HasStaticHandler(textDocumentCapabilities.Rename),
147+
SignatureHelpProvider = ccp.GetStaticOptions(textDocumentCapabilities.SignatureHelp).Get<ISignatureHelpOptions, SignatureHelpOptions>(SignatureHelpOptions.Of),
148+
WorkspaceSymbolProvider = ccp.HasStaticHandler(workspaceCapabilities.Symbol)
149149
};
150150

151151
var textSyncHandlers = _collection
@@ -168,16 +168,21 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
168168
}
169169
else
170170
{
171-
if (ccp.HasHandler(textDocumentCapabilities.Synchronization))
171+
if (ccp.HasStaticHandler(textDocumentCapabilities.Synchronization))
172172
{
173173
// TODO: Merge options
174-
serverCapabilities.TextDocumentSync = textSyncHandlers.FirstOrDefault()?.Options ?? new TextDocumentSyncOptions() {
175-
Change = TextDocumentSyncKind.None,
176-
OpenClose = false,
177-
Save = new SaveOptions() { IncludeText = false },
178-
WillSave = false,
179-
WillSaveWaitUntil = false
180-
};
174+
serverCapabilities.TextDocumentSync =
175+
textSyncHandlers.FirstOrDefault()?.Options ?? new TextDocumentSyncOptions() {
176+
Change = TextDocumentSyncKind.None,
177+
OpenClose = false,
178+
Save = new SaveOptions() { IncludeText = false },
179+
WillSave = false,
180+
WillSaveWaitUntil = false
181+
};
182+
}
183+
else
184+
{
185+
serverCapabilities.TextDocumentSync = TextDocumentSyncKind.None;
181186
}
182187
}
183188

src/Lsp/LspRequestRouter.cs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,35 +57,48 @@ private ILspHandlerDescriptor FindDescriptor(string method, JToken @params)
5757
if (typeof(ITextDocumentIdentifierParams).GetTypeInfo().IsAssignableFrom(descriptor.Params))
5858
{
5959
var textDocumentIdentifierParams = @params.ToObject(descriptor.Params) as ITextDocumentIdentifierParams;
60-
var textDocumentSyncHandlers = _collection
61-
.Select(x => x.Handler is ITextDocumentSyncHandler r ? r : null)
62-
.Where(x => x != null)
63-
.Distinct();
64-
var attributes = textDocumentSyncHandlers
65-
.Select(x => x.GetTextDocumentAttributes(textDocumentIdentifierParams.TextDocument.Uri))
66-
.Where(x => x != null)
67-
.Distinct()
68-
.ToList();
60+
var attributes = GetTextDocumentAttributes(textDocumentIdentifierParams.TextDocument.Uri);
6961

7062
_logger.LogTrace("Found attributes {Count}, {Attributes}", attributes.Count, attributes.Select(x => $"{x.LanguageId}:{x.Scheme}:{x.Uri}"));
7163

7264
return GetHandler(method, attributes);
7365
}
74-
else if (typeof(DidOpenTextDocumentParams).GetTypeInfo().IsAssignableFrom(descriptor.Params))
66+
else if (@params?.ToObject(descriptor.Params) is DidOpenTextDocumentParams openTextDocumentParams)
7567
{
76-
var openTextDocumentParams = @params.ToObject(descriptor.Params) as DidOpenTextDocumentParams;
7768
var attributes = new TextDocumentAttributes(openTextDocumentParams.TextDocument.Uri, openTextDocumentParams.TextDocument.LanguageId);
7869

7970
_logger.LogTrace("Created attribute {Attribute}", $"{attributes.LanguageId}:{attributes.Scheme}:{attributes.Uri}");
8071

8172
return GetHandler(method, attributes);
8273
}
74+
else if (@params?.ToObject(descriptor.Params) is DidChangeTextDocumentParams didChangeDocumentParams)
75+
{
76+
// TODO: Do something with document version here?
77+
var attributes = GetTextDocumentAttributes(didChangeDocumentParams.TextDocument.Uri);
78+
79+
_logger.LogTrace("Found attributes {Count}, {Attributes}", attributes.Count, attributes.Select(x => $"{x.LanguageId}:{x.Scheme}:{x.Uri}"));
80+
81+
return GetHandler(method, attributes);
82+
}
8383

8484
// TODO: How to split these
8585
// Do they fork and join?
8686
return descriptor;
8787
}
8888

89+
private List<TextDocumentAttributes> GetTextDocumentAttributes(Uri uri)
90+
{
91+
var textDocumentSyncHandlers = _collection
92+
.Select(x => x.Handler is ITextDocumentSyncHandler r ? r : null)
93+
.Where(x => x != null)
94+
.Distinct();
95+
return textDocumentSyncHandlers
96+
.Select(x => x.GetTextDocumentAttributes(uri))
97+
.Where(x => x != null)
98+
.Distinct()
99+
.ToList();
100+
}
101+
89102
private ILspHandlerDescriptor GetHandler(string method, IEnumerable<TextDocumentAttributes> attributes)
90103
{
91104
return attributes
@@ -105,6 +118,7 @@ private ILspHandlerDescriptor GetHandler(string method, TextDocumentAttributes a
105118
_logger.LogTrace("Document Selector {DocumentSelector}", registrationOptions.DocumentSelector.ToString());
106119
if (registrationOptions.DocumentSelector == null || registrationOptions.DocumentSelector.IsMatch(attributes))
107120
{
121+
_logger.LogTrace("Handler Selected: {Handler} via {DocumentSelector} (targeting {HandlerInterface})", handler.Handler.GetType().FullName, registrationOptions.DocumentSelector.ToString(), handler.HandlerType.GetType().FullName);
108122
return handler;
109123
}
110124
}
@@ -116,18 +130,25 @@ public async void RouteNotification(Notification notification)
116130
var handler = FindDescriptor(notification.Method, notification.Params);
117131
if (handler is null) { return; }
118132

119-
Task result;
120-
if (handler.Params is null)
133+
try
121134
{
122-
result = ReflectionRequestHandlers.HandleNotification(handler);
135+
Task result;
136+
if (handler.Params is null)
137+
{
138+
result = ReflectionRequestHandlers.HandleNotification(handler);
139+
}
140+
else
141+
{
142+
var @params = notification.Params.ToObject(handler.Params);
143+
result = ReflectionRequestHandlers.HandleNotification(handler, @params);
144+
}
145+
146+
await result;
123147
}
124-
else
148+
catch (Exception e)
125149
{
126-
var @params = notification.Params.ToObject(handler.Params);
127-
result = ReflectionRequestHandlers.HandleNotification(handler, @params);
150+
_logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}", notification.Method);
128151
}
129-
130-
await result;
131152
}
132153

133154
public async Task<ErrorResponse> RouteRequest(Request request)
@@ -184,6 +205,11 @@ public async Task<ErrorResponse> RouteRequest(Request request)
184205
{
185206
return new RequestCancelled();
186207
}
208+
catch (Exception e)
209+
{
210+
_logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle notification {Method}", request.Method);
211+
return new InternalError(id);
212+
}
187213
finally
188214
{
189215
_requests.TryRemove(id, out var _);

src/Lsp/Models/DidChangeTextDocumentParams.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Newtonsoft.Json;
1+
using Newtonsoft.Json;
22
using Newtonsoft.Json.Serialization;
33

44
namespace OmniSharp.Extensions.LanguageServer.Models
@@ -18,4 +18,4 @@ public class DidChangeTextDocumentParams
1818
/// </summary>
1919
public Container<TextDocumentContentChangeEvent> ContentChanges { get; set; }
2020
}
21-
}
21+
}

test/Lsp.Tests/ClientCapabilityProviderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private static bool HasHandler(ClientCapabilityProvider provider, Type type)
111111
private static bool GenericHasHandler<T>(ClientCapabilityProvider provider, Supports<T> supports)
112112
where T : DynamicCapability, ConnectedCapability<IJsonRpcHandler>
113113
{
114-
return provider.HasHandler(supports);
114+
return provider.HasStaticHandler(supports);
115115
}
116116

117117
private static IEnumerable<object[]> GetItems<T>(IEnumerable<T> types, Func<T, IEnumerable<object>> func)

vscode-testextension/src/extension.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Trace } from 'vscode-jsonrpc';
1313
export function activate(context: ExtensionContext) {
1414

1515
// The server is implemented in node
16-
let serverExe = 'D:/Development/Omnisharp/omnisharp-roslyn/bin/Debug/OmniSharp.Stdio/net46/OmniSharp.exe';
16+
let serverExe = 'C:/Other/omnisharp-roslyn/bin/Debug/OmniSharp.Stdio/net46/OmniSharp.exe';
1717
// let serverExe = 'D:/Development/Omnisharp/omnisharp-roslyn/artifacts/publish/OmniSharp.Stdio/win7-x64/OmniSharp.exe';
1818
// let serverExe = context.asAbsolutePath('D:/Development/Omnisharp/omnisharp-roslyn/artifacts/publish/OmniSharp.Stdio/win7-x64/OmniSharp.exe');
1919
// The debug options for the server
@@ -39,8 +39,7 @@ export function activate(context: ExtensionContext) {
3939
synchronize: {
4040
// Synchronize the setting section 'languageServerExample' to the server
4141
configurationSection: 'languageServerExample',
42-
// Notify the server about file changes to '.clientrc files contain in the workspace
43-
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
42+
fileEvents: workspace.createFileSystemWatcher('**/*.cs')
4443
},
4544
}
4645

0 commit comments

Comments
 (0)