Skip to content
4 changes: 2 additions & 2 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
<PackageReference Update="xunit" Version="2.4.1"/>
<PackageReference Update="FluentAssertions" Version="5.10.2"/>
<PackageReference Update="NSubstitute" Version="4.2.1"/>
<PackageReference Update="Autofac" Version="4.8.1"/>
<PackageReference Update="Autofac.Extensions.DependencyInjection" Version="4.3.1"/>
<PackageReference Update="DryIoc.dll" Version="4.2.5" />
<PackageReference Update="DryIoc.Microsoft.DependencyInjection " Version="4.0.0" />
<PackageReference Update="Serilog.Extensions.Logging" Version="2.0.2"/>
<PackageReference Update="Serilog.Sinks.XUnit" Version="1.0.21"/>
<PackageReference Update="XunitXml.TestLogger" Version="2.1.26"/>
Expand Down
8 changes: 6 additions & 2 deletions sample/SampleServer/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals;
using OmniSharp.Extensions.LanguageServer.Server;
using Serilog;

Expand Down Expand Up @@ -40,15 +44,15 @@ static async Task MainAsync(string[] args)
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardOutput())
.ConfigureLogging(x => x
.AddSerilog()
.AddSerilog(Log.Logger)
.AddLanguageProtocolLogging()
.SetMinimumLevel(LogLevel.Debug))
.WithHandler<TextDocumentHandler>()
.WithHandler<DidChangeWatchedFilesHandler>()
.WithHandler<FoldingRangeHandler>()
.WithHandler<MyWorkspaceSymbolsHandler>()
.WithHandler<MyDocumentSymbolHandler>()
.WithHandler<SemanticTokens>()
.WithHandler<SemanticTokensHandler>()
.WithServices(x => x.AddLogging(b => b.SetMinimumLevel(LogLevel.Trace)))
.WithServices(services => {
services.AddSingleton(provider => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,45 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document.Proposals;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals;

namespace SampleServer
{
#pragma warning disable 618
public class SemanticTokens : SemanticTokensHandler
public class SemanticTokensHandler : SemanticTokensHandlerBase
{
private readonly ILogger _logger;

public SemanticTokens(ILogger<SemanticTokens> logger) : base(new SemanticTokensRegistrationOptions() {
public SemanticTokensHandler(ILogger<SemanticTokensHandler> logger) : base(new SemanticTokensRegistrationOptions() {
DocumentSelector = DocumentSelector.ForLanguage("csharp"),
Legend = new SemanticTokensLegend(),
DocumentProvider = new Supports<SemanticTokensDocumentProviderOptions>(true,
new SemanticTokensDocumentProviderOptions() {
Edits = true
}),
RangeProvider = true
Full = new SemanticTokensCapabilityRequestFull() {
Delta = true
},
Range = true
})
{
_logger = logger;
}

public override async Task<OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals.SemanticTokens> Handle(
public override async Task<SemanticTokens> Handle(
SemanticTokensParams request, CancellationToken cancellationToken)
{
var result = await base.Handle(request, cancellationToken);
return result;
}

public override async Task<OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals.SemanticTokens> Handle(
public override async Task<SemanticTokens> Handle(
SemanticTokensRangeParams request, CancellationToken cancellationToken)
{
var result = await base.Handle(request, cancellationToken);
return result;
}

public override async Task<SemanticTokensOrSemanticTokensEdits> Handle(SemanticTokensEditsParams request,
public override async Task<SemanticTokensFullOrDelta> Handle(SemanticTokensDeltaParams request,
CancellationToken cancellationToken)
{
var result = await base.Handle(request, cancellationToken);
Expand Down
1 change: 1 addition & 0 deletions src/Client/LanguageClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ internal LanguageClient(LanguageClientOptions options) : base(options)
var serviceIdentifiers = _serviceProvider.GetServices<ITextDocumentIdentifier>().ToArray();
_disposable.Add(_textDocumentIdentifiers.Add(serviceIdentifiers));
_disposable.Add(_collection.Add(serviceHandlers));
options.AddLinks(_collection);
}

public ITextDocumentLanguageClient TextDocument { get; }
Expand Down
13 changes: 10 additions & 3 deletions src/Client/RegistrationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,23 @@ public RegistrationManager(ISerializer serializer, ILogger<RegistrationManager>

Task<Unit> IRequestHandler<RegistrationParams, Unit>.Handle(RegistrationParams request, CancellationToken cancellationToken)
{
Register(request.Registrations.ToArray());
lock (this)
{
Register(request.Registrations.ToArray());
}

_registrationSubject.OnNext(_registrations.Values);
return Unit.Task;
}

Task<Unit> IRequestHandler<UnregistrationParams, Unit>.Handle(UnregistrationParams request, CancellationToken cancellationToken)
{
foreach (var item in request.Unregisterations ?? new UnregistrationContainer())
lock (this)
{
_registrations.TryRemove(item.Id, out _);
foreach (var item in request.Unregisterations ?? new UnregistrationContainer())
{
_registrations.TryRemove(item.Id, out _);
}
}

_registrationSubject.OnNext(_registrations.Values);
Expand Down
2 changes: 1 addition & 1 deletion src/JsonRpc.Testing/AggregateSettler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public Task SettleNext()
{
return _settlers.ToObservable()
.Select(z => z.Settle())
.Switch()
.Merge()
.Take(1)
//.Amb(Observable.Timer(_waitTime + _waitTime).Select(z => Unit.Value))
.ToTask();
Expand Down
8 changes: 4 additions & 4 deletions src/JsonRpc.Testing/Settler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public Settler(TimeSpan waitTime, TimeSpan timeout, CancellationToken cancellati
acc += next;
return acc;
})
.Select(z => z <= 0 ? Observable.Timer(waitTime).Select(_ => Unit.Default).Timeout(timeout, Observable.Return(Unit.Default)) : Observable.Never<Unit>())
.Switch()
.Replay(1)
.RefCount();
.RefCount()
.Select(z => z <= 0 ? Observable.Timer(waitTime).Select(_ => Unit.Default).Timeout(timeout, Observable.Return(Unit.Default)) : Observable.Never<Unit>())
.Switch();
_requester = subject;
}

Expand All @@ -43,7 +43,7 @@ public Task SettleNext()

public IObservable<Unit> Settle()
{
return _settle;
return _settle.Timeout(_timeout).Catch<Unit, Exception>(_ => Observable.Empty<Unit>());
}

void IRequestSettler.OnStartRequest()
Expand Down
2 changes: 2 additions & 0 deletions src/JsonRpc/CompositeHandlersManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public IDisposable Add(string method, IJsonRpcHandler handler, JsonRpcHandlerOpt
return result;
}

public IDisposable AddLink(string sourceMethod, string destinationMethod) => _parent.AddLink(sourceMethod, destinationMethod);

public CompositeDisposable GetDisposable() => _compositeDisposable;
}
}
54 changes: 51 additions & 3 deletions src/JsonRpc/HandlerCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

namespace OmniSharp.Extensions.JsonRpc
{


public class HandlerCollection : IEnumerable<IHandlerDescriptor>, IHandlersManager
{
internal readonly List<HandlerInstance> _handlers = new List<HandlerInstance>();
internal readonly List<IHandlerDescriptor> _handlers = new List<IHandlerDescriptor>();

public HandlerCollection() { }

Expand Down Expand Up @@ -70,6 +72,41 @@ public void Dispose()
}
}

[DebuggerDisplay("{Method}")]
internal class LinkedHandler : IHandlerDescriptor, IDisposable
{
private readonly IHandlerDescriptor _descriptor;
private readonly Action _disposeAction;

public LinkedHandler(string method, IHandlerDescriptor descriptor, Action disposeAction)
{
_descriptor = descriptor;
_disposeAction = disposeAction;
Method = method;
}
public string Method { get; }
public Type HandlerType => _descriptor.HandlerType;

public Type ImplementationType => _descriptor.ImplementationType;

public Type Params => _descriptor.Params;

public Type Response => _descriptor.Response;

public bool HasReturnType => _descriptor.HasReturnType;

public bool IsDelegatingHandler => _descriptor.IsDelegatingHandler;

public IJsonRpcHandler Handler => _descriptor.Handler;

public RequestProcessType? RequestProcessType => _descriptor.RequestProcessType;

public void Dispose()
{
_disposeAction();
}
}

public IEnumerator<IHandlerDescriptor> GetEnumerator()
{
return _handlers.GetEnumerator();
Expand All @@ -82,8 +119,11 @@ IEnumerator IEnumerable.GetEnumerator()

private void Remove(IJsonRpcHandler handler)
{
var i = _handlers.Find(instance => instance.Handler == handler);
if (i != null) _handlers.Remove(i);
var handlers = _handlers.FindAll(instance => instance.Handler == handler);
foreach (var item in handlers)
{
_handlers.Remove(item);
}
}

public IDisposable Add(params IJsonRpcHandler[] handlers)
Expand Down Expand Up @@ -132,6 +172,14 @@ public IDisposable Add(string method, IJsonRpcHandler handler, JsonRpcHandlerOpt
return h;
}

public IDisposable AddLink(string sourceMethod, string destinationMethod)
{
var source = _handlers.Find(z => z.Method == sourceMethod);
var h = new LinkedHandler(destinationMethod, source, () => _handlers.RemoveAll(z => z.Method == destinationMethod));
_handlers.Add(h);
return h;
}

private static readonly Type[] HandlerTypes = {
typeof(IJsonRpcNotificationHandler),
typeof(IJsonRpcNotificationHandler<>),
Expand Down
1 change: 1 addition & 0 deletions src/JsonRpc/IHandlersManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public interface IHandlersManager
{
IDisposable Add(IJsonRpcHandler handler, JsonRpcHandlerOptions options);
IDisposable Add(string method, IJsonRpcHandler handler, JsonRpcHandlerOptions options);
IDisposable AddLink(string sourceMethod, string destinationMethod);
}
}
10 changes: 10 additions & 0 deletions src/JsonRpc/JsonRpcOptionsRegistryBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;

namespace OmniSharp.Extensions.JsonRpc
{
public abstract class JsonRpcOptionsRegistryBase<T> : JsonRpcCommonMethodsBase<T> where T : IJsonRpcHandlerRegistry<T>
{
public IServiceCollection Services { get; set; } = new ServiceCollection();
protected internal HashSet<(string source, string destination)> Links= new HashSet<(string source, string destination)>();

public void AddLinks(IHandlersManager handlersManager)
{
foreach (var link in Links)
{
handlersManager.AddLink(link.source, link.destination);
}
}

#region AddHandler

Expand Down
1 change: 1 addition & 0 deletions src/JsonRpc/JsonRpcServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ internal JsonRpcServer(JsonRpcServerOptions options) : base(options)
);
_disposable.Add(_connection);
_collection.Add(_serviceProvider.GetRequiredService<IEnumerable<IJsonRpcHandler>>().ToArray());
options.AddLinks(_collection);
}

private async Task Initialize(CancellationToken cancellationToken)
Expand Down
6 changes: 6 additions & 0 deletions src/JsonRpc/JsonRpcServerOptionsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,11 @@ public T WithMaximumRequestTimeout(TimeSpan maximumRequestTimeout)
MaximumRequestTimeout = maximumRequestTimeout;
return (T)(object) this;
}

public T WithLink(string source, string destination)
{
Links.Add((source, destination));
return (T)(object) this;
}
}
}
2 changes: 2 additions & 0 deletions src/Protocol/AbstractHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ async Task<TResponse> IRequestHandler<TItem, TResponse>.Handle(TItem request,
}

var subject = new AsyncSubject<TItem>();
// in the event nothing is emitted...
subject.OnNext(default);
Handle(request, subject, cancellationToken);
return _factory(await subject);
}
Expand Down
16 changes: 16 additions & 0 deletions src/Protocol/Client/Capabilities/CallHierarchyCapability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using OmniSharp.Extensions.LanguageServer.Protocol.Document.Proposals;

namespace OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities
{
/// <summary>
/// Capabilities specific to the `textDocument/callHierarchy`.
///
/// @since 3.16.0
/// </summary>
[Obsolete(Constants.Proposal)]
public class CallHierarchyCapability : DynamicCapability, ConnectedCapability<ICallHierarchyHandler>,
ConnectedCapability<ICallHierarchyIncomingHandler>, ConnectedCapability<ICallHierarchyOutgoingHandler>
{
}
}
26 changes: 22 additions & 4 deletions src/Protocol/Client/Capabilities/CompletionItemCapability.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ public class CompletionItemCapability
public Container<MarkupKind> DocumentationFormat { get; set; }

/// <summary>
/// Client supports the deprecated property on a completion item.
/// </summary>
/// Client supports the deprecated property on a completion item.
/// </summary>
[Optional]
public bool DeprecatedSupport { get; set; }

/// <summary>
/// Client supports the preselect property on a completion item.
/// </summary>
/// Client supports the preselect property on a completion item.
/// </summary>
[Optional]
public bool PreselectSupport { get; set; }

Expand All @@ -51,5 +51,23 @@ public class CompletionItemCapability
/// </summary>
[Optional]
public Supports<CompletionItemTagSupportCapability> TagSupport { get; set; }

/// <summary>
/// Client support insert replace edit to control different behavior if a
/// completion item is inserted in the text or should replace text.
///
/// @since 3.16.0 - Proposed state
/// </summary>
[Optional]
public bool InsertReplaceSupport { get; set; }

/// <summary>
/// Client supports to resolve `additionalTextEdits` in the `completionItem/resolve`
/// request. So servers can postpone computing them.
///
/// @since 3.16.0 - Proposed state
/// </summary>
[Optional]
public bool ResolveAdditionalTextEditsSupport { get; set; }
}
}
Loading