Skip to content

Commit 93f8c56

Browse files
Merge pull request #148 from OmniSharp/fix/capabilities
Updated support for capabilities to be more generous to clients that …
2 parents 3daf73a + e2868ae commit 93f8c56

File tree

3 files changed

+64
-18
lines changed

3 files changed

+64
-18
lines changed

src/Server/ClientCapabilityProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ public ClientCapabilityProvider(IHandlerCollection collection)
2121
public bool HasStaticHandler<T>(Supports<T> capability)
2222
where T : DynamicCapability, ConnectedCapability<IJsonRpcHandler>
2323
{
24-
if (!capability.IsSupported) return false;
25-
if (capability.Value == null) return false;
26-
if (capability.Value.DynamicRegistration == true) return false;
24+
// Dynamic registration will cause us to double register things if we report our capabilities staticly.
25+
// However if the client does not tell us it's capabilities we should just assume that they do not support
26+
// dynamic registraiton but we should report any capabilities statically
27+
if (capability.IsSupported && capability.Value != null && capability.Value.DynamicRegistration == true) return false;
2728

2829
var handlerTypes = typeof(T).GetTypeInfo().ImplementedInterfaces
2930
.Where(x => x.GetTypeInfo().IsGenericType && x.GetTypeInfo().GetGenericTypeDefinition() == typeof(ConnectedCapability<>))

test/Lsp.Tests/ClientCapabilityProviderTests.cs

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using OmniSharp.Extensions.LanguageServer.Protocol;
1010
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
1111
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
12+
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
1213
using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities;
1314
using OmniSharp.Extensions.LanguageServer.Server;
1415
using Xunit;
@@ -42,15 +43,24 @@ public static IEnumerable<object[]> AllowSupportedCapabilities()
4243
});
4344
}
4445

45-
[Theory, MemberData(nameof(DisallowUnsupportedCapabilities))]
46-
public void Should_DisallowUnsupportedCapabilities(IJsonRpcHandler handler, object instance)
46+
[Theory, MemberData(nameof(AllowUnsupportedCapabilities))]
47+
public void Should_AllowUnsupportedCapabilities(IJsonRpcHandler handler, object instance)
4748
{
4849
var textDocumentSyncHandler = TextDocumentSyncHandlerExtensions.With(DocumentSelector.ForPattern("**/*.cs"));
4950

5051
var collection = new HandlerCollection(SupportedCapabilitiesFixture.AlwaysTrue) { textDocumentSyncHandler, handler };
5152
var provider = new ClientCapabilityProvider(collection);
5253

53-
HasHandler(provider, instance).Should().BeFalse();
54+
HasHandler(provider, instance).Should().BeTrue();
55+
}
56+
57+
public static IEnumerable<object[]> AllowUnsupportedCapabilities()
58+
{
59+
return GetItems(Capabilities, type => {
60+
var handlerTypes = GetHandlerTypes(type);
61+
var handler = Substitute.For(handlerTypes.ToArray(), new object[0]);
62+
return new[] { handler, Activator.CreateInstance(typeof(Supports<>).MakeGenericType(type), false) };
63+
});
5464
}
5565

5666
[Fact]
@@ -81,17 +91,29 @@ public void Should_Invoke_Reduce_Delegate()
8191
stub.Received().Invoke(Arg.Any<IEnumerable<IExecuteCommandOptions>>());
8292
}
8393

84-
public static IEnumerable<object[]> DisallowUnsupportedCapabilities()
94+
[Theory, MemberData(nameof(AllowNullSupportsCapabilities))]
95+
public void Should_AllowNullSupportedCapabilities(IJsonRpcHandler handler, object instance)
96+
{
97+
var textDocumentSyncHandler = TextDocumentSyncHandlerExtensions.With(DocumentSelector.ForPattern("**/*.cs"));
98+
99+
var collection = new HandlerCollection(SupportedCapabilitiesFixture.AlwaysTrue) { textDocumentSyncHandler, handler };
100+
var provider = new ClientCapabilityProvider(collection);
101+
102+
HasHandler(provider, instance).Should().BeTrue();
103+
}
104+
105+
public static IEnumerable<object[]> AllowNullSupportsCapabilities()
85106
{
86107
return GetItems(Capabilities, type => {
87108
var handlerTypes = GetHandlerTypes(type);
88109
var handler = Substitute.For(handlerTypes.ToArray(), new object[0]);
89-
return new[] { handler, Activator.CreateInstance(typeof(Supports<>).MakeGenericType(type), false) };
110+
return new[] { handler, Activator.CreateInstance(typeof(Supports<>).MakeGenericType(type), true) };
90111
});
91112
}
92113

93-
[Theory, MemberData(nameof(DisallowNullSupportsCapabilities))]
94-
public void Should_DisallowNullSupportedCapabilities(IJsonRpcHandler handler, object instance)
114+
115+
[Theory, MemberData(nameof(DisallowDynamicSupportsCapabilities))]
116+
public void Should_DisallowDynamicSupportedCapabilities(IJsonRpcHandler handler, object instance)
95117
{
96118
var textDocumentSyncHandler = TextDocumentSyncHandlerExtensions.With(DocumentSelector.ForPattern("**/*.cs"));
97119

@@ -101,27 +123,49 @@ public void Should_DisallowNullSupportedCapabilities(IJsonRpcHandler handler, ob
101123
HasHandler(provider, instance).Should().BeFalse();
102124
}
103125

104-
public static IEnumerable<object[]> DisallowNullSupportsCapabilities()
126+
public static IEnumerable<object[]> DisallowDynamicSupportsCapabilities()
105127
{
106128
return GetItems(Capabilities, type => {
107129
var handlerTypes = GetHandlerTypes(type);
108130
var handler = Substitute.For(handlerTypes.ToArray(), new object[0]);
109-
return new[] { handler, Activator.CreateInstance(typeof(Supports<>).MakeGenericType(type), true) };
131+
var capability = Activator.CreateInstance(type);
132+
if (capability is DynamicCapability dyn) dyn.DynamicRegistration = true;
133+
return new[] { handler, Activator.CreateInstance(typeof(Supports<>).MakeGenericType(type), true, capability) };
110134
});
111135
}
112136

113-
private static bool HasHandler(ClientCapabilityProvider provider, object instance)
137+
[Fact]
138+
public void Should_Handle_Mixed_Capabilities()
114139
{
115-
return (bool)typeof(ClientCapabilityProviderTests).GetTypeInfo()
116-
.GetMethod(nameof(GenericHasHandler), BindingFlags.Static | BindingFlags.NonPublic)
117-
.MakeGenericMethod(instance.GetType().GetTypeInfo().GetGenericArguments()[0]).Invoke(null, new[] { provider, instance });
140+
var textDocumentSyncHandler = TextDocumentSyncHandlerExtensions.With(DocumentSelector.ForPattern("**/*.cs"));
141+
142+
var codeActionHandler = Substitute.For<ICodeActionHandler>();
143+
var definitionHandler = Substitute.For<IDefinitionHandler>();
144+
var typeDefinitionHandler = Substitute.For<ITypeDefinitionHandler>();
145+
146+
var collection = new HandlerCollection(SupportedCapabilitiesFixture.AlwaysTrue) { textDocumentSyncHandler, codeActionHandler, definitionHandler, typeDefinitionHandler };
147+
var provider = new ClientCapabilityProvider(collection);
148+
var capabilities = new ClientCapabilities() {
149+
TextDocument = new TextDocumentClientCapabilities() {
150+
CodeAction = new Supports<CodeActionCapability>(true, new CodeActionCapability() {
151+
DynamicRegistration = false,
152+
}),
153+
TypeDefinition = new Supports<TypeDefinitionCapability>(true, new TypeDefinitionCapability() {
154+
DynamicRegistration = true,
155+
})
156+
}
157+
};
158+
159+
provider.GetStaticOptions(capabilities.TextDocument.CodeAction).Get<ICodeActionOptions, CodeActionOptions>(CodeActionOptions.Of).Should().NotBeNull();
160+
provider.HasStaticHandler(capabilities.TextDocument.Definition).Should().BeTrue();
161+
provider.HasStaticHandler(capabilities.TextDocument.TypeDefinition).Should().BeFalse();
118162
}
119163

120-
private static bool HasHandler(ClientCapabilityProvider provider, Type type)
164+
private static bool HasHandler(ClientCapabilityProvider provider, object instance)
121165
{
122166
return (bool)typeof(ClientCapabilityProviderTests).GetTypeInfo()
123167
.GetMethod(nameof(GenericHasHandler), BindingFlags.Static | BindingFlags.NonPublic)
124-
.MakeGenericMethod(type).Invoke(null, new object[] { provider, null });
168+
.MakeGenericMethod(instance.GetType().GetTypeInfo().GetGenericArguments()[0]).Invoke(null, new[] { provider, instance });
125169
}
126170

127171
private static bool GenericHasHandler<T>(ClientCapabilityProvider provider, Supports<T> supports)

test/Lsp.Tests/LanguageServerTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public async Task GH141_CrashesWithEmptyInitializeParams()
6666
.WithLoggerFactory(LoggerFactory)
6767
.AddDefaultLoggingProvider()
6868
.WithMinimumLogLevel(LogLevel.Trace)
69+
.AddHandlers(TextDocumentSyncHandlerExtensions.With(DocumentSelector.ForPattern("**/*.cs")))
6970
) as IRequestHandler<InitializeParams, InitializeResult>;
7071

7172
var handler = server as IRequestHandler<InitializeParams, InitializeResult>;

0 commit comments

Comments
 (0)