diff --git a/src/JsonRpc/JsonRpc.csproj b/src/JsonRpc/JsonRpc.csproj index b0a0dffca..5800dd65b 100644 --- a/src/JsonRpc/JsonRpc.csproj +++ b/src/JsonRpc/JsonRpc.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 AnyCPU @@ -13,7 +13,7 @@ - - + + diff --git a/src/JsonRpc/RequestRouterBase.cs b/src/JsonRpc/RequestRouterBase.cs index c599654b0..d0d082bdb 100644 --- a/src/JsonRpc/RequestRouterBase.cs +++ b/src/JsonRpc/RequestRouterBase.cs @@ -65,7 +65,7 @@ public async Task RouteNotification(TDescriptor descriptor, Notification notific @params = notification.Params?.ToObject(descriptor.Params, _serializer.JsonSerializer); } - await HandleNotification(mediator, descriptor, @params ?? EmptyRequest.Instance, token); + await HandleNotification(mediator, descriptor, @params ?? Activator.CreateInstance(descriptor.Params), token); } } catch (Exception e) diff --git a/src/Protocol/Models/Registration.cs b/src/Protocol/Models/Registration.cs index e448a68ef..9158f19c8 100644 --- a/src/Protocol/Models/Registration.cs +++ b/src/Protocol/Models/Registration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; diff --git a/src/Server/Abstractions/ILspHandlerDescriptor.cs b/src/Server/Abstractions/ILspHandlerDescriptor.cs index 8929e6614..313bfc90f 100644 --- a/src/Server/Abstractions/ILspHandlerDescriptor.cs +++ b/src/Server/Abstractions/ILspHandlerDescriptor.cs @@ -6,9 +6,11 @@ namespace OmniSharp.Extensions.LanguageServer.Server.Abstractions { public interface ILspHandlerDescriptor : IHandlerDescriptor { + Guid Id { get; } bool HasRegistration { get; } Type RegistrationType { get; } - Registration Registration { get; } + object RegistrationOptions { get; } + bool AllowsDynamicRegistration { get; } bool HasCapability { get; } Type CapabilityType { get; } diff --git a/src/Server/ClientCapabilityProvider.cs b/src/Server/ClientCapabilityProvider.cs index d5088bafa..59fd1b233 100644 --- a/src/Server/ClientCapabilityProvider.cs +++ b/src/Server/ClientCapabilityProvider.cs @@ -92,7 +92,7 @@ public TOptions Get(Func action) where TOptions : class { return _collection - .Select(x => x.Registration?.RegisterOptions is TInterface cl ? action(cl) : null) + .Select(x => x.RegistrationOptions is TInterface cl ? action(cl) : null) .FirstOrDefault(x => x != null); } @@ -100,13 +100,13 @@ public Supports Can(Func a where TOptions : class { var options = _collection - .Select(x => x.Registration?.RegisterOptions is TInterface cl ? action(cl) : null) + .Select(x => x.RegistrationOptions is TInterface cl ? action(cl) : null) .FirstOrDefault(x => x != null); if (options == null) return Supports.OfBoolean(false); return _collection - .Select(x => x.Registration?.RegisterOptions is TInterface cl ? action(cl) : null) + .Select(x => x.RegistrationOptions is TInterface cl ? action(cl) : null) .FirstOrDefault(x => x != null); } @@ -114,7 +114,7 @@ public TOptions Reduce(Func, TOpti where TOptions : class { return action(_collection - .Select(x => x.Registration?.RegisterOptions is TInterface cl ? cl : default) + .Select(x => x.RegistrationOptions is TInterface cl ? cl : default) .Where(x => x != null)); } } diff --git a/src/Server/HandlerCollection.cs b/src/Server/HandlerCollection.cs index bae97fcf1..122cf4bef 100644 --- a/src/Server/HandlerCollection.cs +++ b/src/Server/HandlerCollection.cs @@ -145,7 +145,6 @@ private HandlerDescriptor GetDescriptor(string method, Type handlerType, IJsonRp Type @params = null; object registrationOptions = null; - Registration registration = null; if (@interface.GetTypeInfo().IsGenericType) { @params = @interface.GetTypeInfo().GetGenericArguments()[0]; @@ -156,15 +155,6 @@ private HandlerDescriptor GetDescriptor(string method, Type handlerType, IJsonRp registrationOptions = GetRegistrationMethod .MakeGenericMethod(registrationType) .Invoke(null, new object[] { handler }); - - if (_supportedCapabilities.AllowsDynamicRegistration(capabilityType)) - { - registration = new Registration() { - Id = Guid.NewGuid().ToString(), - Method = method, - RegisterOptions = registrationOptions - }; - } } var key = "default"; @@ -193,7 +183,8 @@ private HandlerDescriptor GetDescriptor(string method, Type handlerType, IJsonRp @interface, @params, registrationType, - registration, + registrationOptions, + registrationType != null && _supportedCapabilities.AllowsDynamicRegistration(capabilityType), capabilityType, () => { _handlers.RemoveWhere(d => d.Handler == handler); diff --git a/src/Server/HandlerDescriptor.cs b/src/Server/HandlerDescriptor.cs index 3e417b406..044c64e6e 100644 --- a/src/Server/HandlerDescriptor.cs +++ b/src/Server/HandlerDescriptor.cs @@ -22,11 +22,13 @@ public HandlerDescriptor( Type handlerType, Type @params, Type registrationType, - Registration registration, + object registrationOptions, + bool allowsDynamicRegistration, Type capabilityType, Action disposeAction) { _disposeAction = disposeAction; + Id = Guid.NewGuid(); Method = method; Key = key; ImplementationType = handler.GetType(); @@ -35,7 +37,8 @@ public HandlerDescriptor( Params = @params; Response = Response; RegistrationType = registrationType; - Registration = registration; + RegistrationOptions = registrationOptions; + AllowsDynamicRegistration = allowsDynamicRegistration; CapabilityType = capabilityType; var requestInterface = @params?.GetInterfaces() @@ -63,9 +66,11 @@ public HandlerDescriptor( public Type ImplementationType { get; } public Type HandlerType { get; } + public Guid Id { get; } public bool HasRegistration => RegistrationType != null; public Type RegistrationType { get; } - public Registration Registration { get; } + public object RegistrationOptions { get; } + public bool AllowsDynamicRegistration { get; } public bool HasCapability => CapabilityType != null; public Type CapabilityType { get; } diff --git a/src/Server/ISupportedCapabilities.cs b/src/Server/ISupportedCapabilities.cs index 896dfb0c6..3dbb57ae4 100644 --- a/src/Server/ISupportedCapabilities.cs +++ b/src/Server/ISupportedCapabilities.cs @@ -6,7 +6,6 @@ namespace OmniSharp.Extensions.LanguageServer.Server { public interface ISupportedCapabilities { - bool AllowsDynamicRegistration(ILspHandlerDescriptor descriptor); bool AllowsDynamicRegistration(Type capabilityType); void SetCapability(ILspHandlerDescriptor descriptor, IJsonRpcHandler handler); } diff --git a/src/Server/LanguageServer.cs b/src/Server/LanguageServer.cs index d2c7e20ca..975ce12b1 100644 --- a/src/Server/LanguageServer.cs +++ b/src/Server/LanguageServer.cs @@ -328,8 +328,12 @@ private IDisposable RegisterHandlers(LspHandlerDescriptorDisposable handlerDispo using (var scope = _serviceProvider.CreateScope()) { var registrations = handlerDisposable.Descriptors - .Select(x => x.Registration) - .Where(x => x != null) + .Where(d => d.AllowsDynamicRegistration) + .Select(d => new Registration() { + Id = d.Id.ToString(), + Method = d.Method, + RegisterOptions = d.RegistrationOptions + }) .ToArray(); // Fire and forget diff --git a/src/Server/Matchers/ExecuteCommandMatcher.cs b/src/Server/Matchers/ExecuteCommandMatcher.cs index 781cbe063..3d6171b1b 100644 --- a/src/Server/Matchers/ExecuteCommandMatcher.cs +++ b/src/Server/Matchers/ExecuteCommandMatcher.cs @@ -28,7 +28,7 @@ public IEnumerable FindHandler(object parameters, IEnumer _logger.LogTrace("Registration options {OptionsName}", executeCommandParams.GetType().FullName); foreach (var descriptor in descriptors) { - if (descriptor.Registration?.RegisterOptions is ExecuteCommandRegistrationOptions registrationOptions && registrationOptions.Commands.Any(x => x == executeCommandParams.Command)) + if (descriptor.RegistrationOptions is ExecuteCommandRegistrationOptions registrationOptions && registrationOptions.Commands.Any(x => x == executeCommandParams.Command)) { _logger.LogTrace("Checking handler {Method}:{Handler}", executeCommandParams.Command, diff --git a/src/Server/Matchers/TextDocumentMatcher.cs b/src/Server/Matchers/TextDocumentMatcher.cs index 80d12d603..da808b82a 100644 --- a/src/Server/Matchers/TextDocumentMatcher.cs +++ b/src/Server/Matchers/TextDocumentMatcher.cs @@ -75,7 +75,7 @@ private IEnumerable GetHandler(IEnumerable supports) } } - public bool AllowsDynamicRegistration(ILspHandlerDescriptor descriptor) - { - if (descriptor.HasCapability && _supports.TryGetValue(descriptor.CapabilityType, out var capability)) - { - if (capability is DynamicCapability dc) - return dc.DynamicRegistration; - } - return false; - } - public bool AllowsDynamicRegistration(Type capabilityType) { if (_supports.TryGetValue(capabilityType, out var capability)) diff --git a/test/Lsp.Tests/Matchers/ExecuteCommandHandlerMatcherTests.cs b/test/Lsp.Tests/Matchers/ExecuteCommandHandlerMatcherTests.cs index b8d488ab1..348ccb48a 100644 --- a/test/Lsp.Tests/Matchers/ExecuteCommandHandlerMatcherTests.cs +++ b/test/Lsp.Tests/Matchers/ExecuteCommandHandlerMatcherTests.cs @@ -58,6 +58,9 @@ public void Should_Return_Handler_Descriptor() // Given var handlerMatcher = AutoSubstitute.Resolve(); var executeCommandHandler = Substitute.For().With(new Container("Command")); + var registrationsOptions = new ExecuteCommandRegistrationOptions() { + Commands = new Container("Command") + }; // When var result = handlerMatcher.FindHandler(new ExecuteCommandParams { Command = "Command" }, @@ -68,11 +71,8 @@ public void Should_Return_Handler_Descriptor() executeCommandHandler.GetType(), typeof(ExecuteCommandParams), typeof(ExecuteCommandRegistrationOptions), - new Registration() { - RegisterOptions = new ExecuteCommandRegistrationOptions() { - Commands = new Container("Command") - } - }, + registrationsOptions, + true, typeof(ExecuteCommandCapability), () => { }) }); diff --git a/test/Lsp.Tests/Matchers/ResolveCommandMatcherTests.cs b/test/Lsp.Tests/Matchers/ResolveCommandMatcherTests.cs index 11dd71872..178bd71fa 100644 --- a/test/Lsp.Tests/Matchers/ResolveCommandMatcherTests.cs +++ b/test/Lsp.Tests/Matchers/ResolveCommandMatcherTests.cs @@ -67,6 +67,7 @@ public void Should_Not_Throw_Given_Another_Descriptor() typeof(CodeLensParams), null, null, + false, null, () => { }); var handlerMatcher = new ResolveCommandPipeline( @@ -100,6 +101,7 @@ public void Should_Return_CodeLensResolve_Descriptor() typeof(CodeLens), null, null, + false, null, () => { }), new HandlerDescriptor(DocumentNames.CodeLensResolve, @@ -109,6 +111,7 @@ public void Should_Return_CodeLensResolve_Descriptor() typeof(CodeLens), null, null, + false, null, () => { }), }) @@ -137,6 +140,7 @@ public void Should_Handle_Null_Data() typeof(CompletionItem), null, null, + false, null, () => { }), }) @@ -167,6 +171,7 @@ public void Should_Handle_Simple_Json_Data() typeof(CompletionItem), null, null, + false, null, () => { }), }) @@ -199,6 +204,7 @@ public void Should_Return_CompletionResolve_Descriptor() typeof(CompletionItem), null, null, + false, null, () => { }), new HandlerDescriptor(DocumentNames.CompletionResolve, @@ -208,6 +214,7 @@ public void Should_Return_CompletionResolve_Descriptor() typeof(CompletionItem), null, null, + false, null, () => { }), }) @@ -247,6 +254,7 @@ public void Should_Deal_WithHandlers_That_Not_Also_Resolvers() typeof(CompletionItem), null, null, + false, null, () => { }), new HandlerDescriptor(DocumentNames.CompletionResolve, @@ -256,6 +264,7 @@ public void Should_Deal_WithHandlers_That_Not_Also_Resolvers() typeof(CompletionItem), null, null, + false, null, () => { }), }) @@ -291,6 +300,7 @@ public void Should_Deal_WithHandlers_That_Not_Also_Resolvers2() typeof(CompletionItem), null, null, + false, null, () => { }), new HandlerDescriptor(DocumentNames.CompletionResolve, @@ -300,6 +310,7 @@ public void Should_Deal_WithHandlers_That_Not_Also_Resolvers2() typeof(CompletionItem), null, null, + false, null, () => { }), }) @@ -327,6 +338,7 @@ public async Task Should_Update_CompletionItems_With_HandlerType() typeof(CompletionParams), null, null, + false, null, () => { }); var handlerMatcher = new ResolveCommandPipeline( @@ -369,6 +381,7 @@ public async Task Should_Update_CodeLensContainer_With_HandlerType() typeof(CodeLensParams), null, null, + false, null, () => { }); var handlerMatcher = new ResolveCommandPipeline( @@ -411,6 +424,7 @@ public async Task Should_Update_CodeLens_Removing_HandlerType() typeof(CodeLens), null, null, + false, null, () => { }); var handlerMatcher = new ResolveCommandPipeline( diff --git a/vscode-testextension/src/extension.ts b/vscode-testextension/src/extension.ts index 43b463e29..a29f2c5c6 100644 --- a/vscode-testextension/src/extension.ts +++ b/vscode-testextension/src/extension.ts @@ -3,52 +3,70 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ // tslint:disable -'use strict'; +"use strict"; -import * as path from 'path'; +import * as path from "path"; -import { workspace, Disposable, ExtensionContext } from 'vscode'; -import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, TransportKind, InitializeParams } from 'vscode-languageclient'; -import { Trace } from 'vscode-jsonrpc'; +import { workspace, Disposable, ExtensionContext } from "vscode"; +import { + LanguageClient, + LanguageClientOptions, + SettingMonitor, + ServerOptions, + TransportKind, + InitializeParams +} from "vscode-languageclient"; +import { Trace } from "vscode-jsonrpc"; export function activate(context: ExtensionContext) { - // The server is implemented in node // let serverExe = 'dotnet'; - let serverExe = 'D:\\development\\omnisharp\\omnisharp-roslyn\\bin\\Debug\\OmniSharp.Stdio.Driver\\net461\\OmniSharp.exe'; - // let serverExe = context.asAbsolutePath('D:/Development/Omnisharp/omnisharp-roslyn/artifacts/publish/OmniSharp.Stdio/win7-x64/OmniSharp.exe'); + + // let serverExe = 'D:\\Development\\Omnisharp\\csharp-language-server-protocol\\sample\\SampleServer\\bin\\Debug\\netcoreapp2.0\\win7-x64\\SampleServer.exe'; + let serverExe = + "D:/Development/Omnisharp/omnisharp-roslyn/artifacts/publish/OmniSharp.Stdio.Driver/win7-x64/OmniSharp.exe"; // The debug options for the server // let debugOptions = { execArgv: ['-lsp', '-d' };5 // If the extension is launched in debug mode then the debug server options are used // Otherwise the run options are used let serverOptions: ServerOptions = { - run: { command: serverExe, args: ['-lsp', '-d'] }, - debug: { command: serverExe, args: ['-lsp', '-d'] } - } + // run: { command: serverExe, args: ['-lsp', '-d'] }, + run: { command: serverExe, args: ["-lsp"] }, + // debug: { command: serverExe, args: ['-lsp', '-d'] } + debug: { command: serverExe, args: ["-lsp"] } + }; // Options to control the language client let clientOptions: LanguageClientOptions = { // Register the server for plain text documents documentSelector: [ { - pattern: '**/*.cs', - }, { - pattern: '**/*.cake', + pattern: "**/*.cs" + }, + { + pattern: "**/*.csx" }, + { + pattern: "**/*.cake" + } ], synchronize: { // Synchronize the setting section 'languageServerExample' to the server - configurationSection: 'languageServerExample', - fileEvents: workspace.createFileSystemWatcher('**/*.cs') + configurationSection: "languageServerExample", + fileEvents: workspace.createFileSystemWatcher("**/*.cs") } - - } + }; // Create the language client and start the client. - const client = new LanguageClient('languageServerExample', 'Language Server Example', serverOptions, clientOptions); - client.trace = Trace.Verbose; - client.clientOptions.errorHandler + const client = new LanguageClient( + "languageServerExample", + "Language Server Example", + serverOptions, + clientOptions + ); + // client.trace = Trace.Verbose; + client.clientOptions.errorHandler; let disposable = client.start(); // Push the disposable to the context's subscriptions so that the