Skip to content

Commands, bugs, helpers and more! #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/JsonRpc.Generators/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ public static string GetSendMethodName(INamedTypeSymbol symbol, AttributeData at
var name = SpecialCasedHandlerName(symbol);
if (
name.StartsWith("Run")
|| name.StartsWith("Execute")
// TODO: Change this next breaking change
// || name.StartsWith("Set")
// || name.StartsWith("Attach")
Expand Down
4 changes: 2 additions & 2 deletions src/Protocol/Models/ExecuteCommandRegistrationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
/// <summary>
/// Execute command registration options.
/// </summary>
public class ExecuteCommandRegistrationOptions : WorkDoneTextDocumentRegistrationOptions, IExecuteCommandOptions
public class ExecuteCommandRegistrationOptions : WorkDoneProgressOptions, IExecuteCommandOptions
{
/// <summary>
/// The commands to be executed on the server
Expand Down
289 changes: 289 additions & 0 deletions src/Protocol/Workspace/IExecuteCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.JsonRpc.Generation;
using OmniSharp.Extensions.LanguageServer.Protocol.Client;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;

namespace OmniSharp.Extensions.LanguageServer.Protocol.Workspace
{
Expand All @@ -27,4 +31,289 @@ public ExecuteCommandHandler(ExecuteCommandRegistrationOptions registrationOptio
public virtual void SetCapability(ExecuteCommandCapability capability) => Capability = capability;
protected ExecuteCommandCapability Capability { get; private set; }
}

public abstract class ExecuteCommandHandlerBase<T> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
return Handle(arg1, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, CancellationToken cancellationToken);
}

public abstract class ExecuteCommandHandlerBase<T, T2> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
T2 arg2 = default;
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
return Handle(arg1, arg2, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, T2 arg2, CancellationToken cancellationToken);
}

public abstract class ExecuteCommandHandlerBase<T, T2, T3> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
T2 arg2 = default;
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
T3 arg3 = default;
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
return Handle(arg1, arg2, arg3, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken);
}

public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
T2 arg2 = default;
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
T3 arg3 = default;
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
T4 arg4 = default;
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
return Handle(arg1, arg2, arg3, arg4, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken cancellationToken);
}

public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4, T5> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
T2 arg2 = default;
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
T3 arg3 = default;
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
T4 arg4 = default;
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
T5 arg5 = default;
if (args.Count > 4) arg5 = args[4].ToObject<T5>(_serializer.JsonSerializer);
return Handle(arg1, arg2, arg3, arg4, arg5, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken cancellationToken);
}

public abstract class ExecuteCommandHandlerBase<T, T2, T3, T4, T5, T6> : ExecuteCommandHandler
{
private readonly ISerializer _serializer;

public ExecuteCommandHandlerBase(string command, ISerializer serializer) : base(new ExecuteCommandRegistrationOptions() { Commands = new Container<string>(command) })
{
_serializer = serializer;
}

public sealed override Task<Unit> Handle(ExecuteCommandParams request, CancellationToken cancellationToken)
{
var args = request.Arguments ?? new JArray();
T arg1 = default;
if (args.Count > 0) arg1 = args[0].ToObject<T>(_serializer.JsonSerializer);
T2 arg2 = default;
if (args.Count > 1) arg2 = args[1].ToObject<T2>(_serializer.JsonSerializer);
T3 arg3 = default;
if (args.Count > 2) arg3 = args[2].ToObject<T3>(_serializer.JsonSerializer);
T4 arg4 = default;
if (args.Count > 3) arg4 = args[3].ToObject<T4>(_serializer.JsonSerializer);
T5 arg5 = default;
if (args.Count > 4) arg5 = args[4].ToObject<T5>(_serializer.JsonSerializer);
T6 arg6 = default;
if (args.Count > 5) arg6 = args[5].ToObject<T6>(_serializer.JsonSerializer);
return Handle(arg1, arg2, arg3, arg4, arg5, arg6, cancellationToken);
}

public abstract Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, CancellationToken cancellationToken);
}

public static partial class ExecuteCommandExtensions
{
public static Task ExecuteCommand(this IWorkspaceLanguageClient mediator, Command @params, CancellationToken cancellationToken = default)
=> mediator.ExecuteCommand(new ExecuteCommandParams() { Arguments = @params.Arguments, Command = @params.Name }, cancellationToken);

public static Task ExecuteCommand(this ILanguageClient mediator, Command @params, CancellationToken cancellationToken = default)
=> mediator.ExecuteCommand(new ExecuteCommandParams() { Arguments = @params.Arguments, Command = @params.Name }, cancellationToken);

public static ILanguageServerRegistry OnExecuteCommand<T>(this ILanguageServerRegistry registry, string command, Func<T, Task> handler)
{
return registry.AddHandler(_ => new Handler<T>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T> : ExecuteCommandHandlerBase<T>
{
private readonly Func<T, Task> _handler;

public Handler(string command, Func<T, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, CancellationToken cancellationToken)
{
await _handler(arg1);
return Unit.Value;
}
}

public static ILanguageServerRegistry OnExecuteCommand<T, T2>(this ILanguageServerRegistry registry, string command, Func<T, T2, Task> handler)
{
return registry.AddHandler(_ => new Handler<T, T2>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T, T2> : ExecuteCommandHandlerBase<T, T2>
{
private readonly Func<T, T2, Task> _handler;

public Handler(string command, Func<T, T2, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, T2 arg2, CancellationToken cancellationToken)
{
await _handler(arg1, arg2);
return Unit.Value;
}
}

public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, Task> handler)
{
return registry.AddHandler(_ => new Handler<T, T2, T3>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T, T2, T3> : ExecuteCommandHandlerBase<T, T2, T3>
{
private readonly Func<T, T2, T3, Task> _handler;

public Handler(string command, Func<T, T2, T3, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken)
{
await _handler(arg1, arg2, arg3);
return Unit.Value;
}
}

public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, Task> handler)
{
return registry.AddHandler(_ => new Handler<T, T2, T3, T4>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T, T2, T3, T4> : ExecuteCommandHandlerBase<T, T2, T3, T4>
{
private readonly Func<T, T2, T3, T4, Task> _handler;

public Handler(string command, Func<T, T2, T3, T4, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken cancellationToken)
{
await _handler(arg1, arg2, arg3, arg4);
return Unit.Value;
}
}

public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4, T5>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, T5, Task> handler)
{
return registry.AddHandler(_ => new Handler<T, T2, T3, T4, T5>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T, T2, T3, T4, T5> : ExecuteCommandHandlerBase<T, T2, T3, T4, T5>
{
private readonly Func<T, T2, T3, T4, T5, Task> _handler;

public Handler(string command, Func<T, T2, T3, T4, T5, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken cancellationToken)
{
await _handler(arg1, arg2, arg3, arg4, arg5);
return Unit.Value;
}
}

public static ILanguageServerRegistry OnExecuteCommand<T, T2, T3, T4, T5, T6>(this ILanguageServerRegistry registry, string command, Func<T, T2, T3, T4, T5, T6, Task> handler)
{
return registry.AddHandler(_ => new Handler<T, T2, T3, T4, T5, T6>(command, handler, _.GetRequiredService<ISerializer>()));
}

class Handler<T, T2, T3, T4, T5, T6> : ExecuteCommandHandlerBase<T, T2, T3, T4, T5, T6>
{
private readonly Func<T, T2, T3, T4, T5, T6, Task> _handler;

public Handler(string command, Func<T, T2, T3, T4, T5, T6, Task> handler, ISerializer serializer) : base(command, serializer)
{
_handler = handler;
}

public override async Task<Unit> Handle(T arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, CancellationToken cancellationToken)
{
await _handler(arg1, arg2, arg3, arg4, arg5, arg6);
return Unit.Value;
}
}
}
}
5 changes: 4 additions & 1 deletion src/Server/Matchers/TextDocumentMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class TextDocumentMatcher : IHandlerMatcher
public TextDocumentMatcher(ILogger<TextDocumentMatcher> logger, TextDocumentIdentifiers textDocumentIdentifiers)
{
_logger = logger;
_textDocumentIdentifiers = textDocumentIdentifiers;;
_textDocumentIdentifiers = textDocumentIdentifiers; ;
}

public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumerable<ILspHandlerDescriptor> descriptors)
Expand All @@ -26,6 +26,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
{
case ITextDocumentIdentifierParams textDocumentIdentifierParams:
{
if (textDocumentIdentifierParams.TextDocument?.Uri == null) break;
var attributes = GetTextDocumentAttributes(textDocumentIdentifierParams.TextDocument.Uri);

_logger.LogTrace("Found attributes {Count}, {Attributes}", attributes.Count, attributes.Select(x => $"{x.LanguageId}:{x.Scheme}:{x.Uri}"));
Expand All @@ -34,6 +35,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
}
case DidOpenTextDocumentParams openTextDocumentParams:
{
if (openTextDocumentParams.TextDocument?.Uri == null) break;
var attributes = new TextDocumentAttributes(openTextDocumentParams.TextDocument.Uri, openTextDocumentParams.TextDocument.LanguageId);

_logger.LogTrace("Created attribute {Attribute}", $"{attributes.LanguageId}:{attributes.Scheme}:{attributes.Uri}");
Expand All @@ -42,6 +44,7 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
}
case DidChangeTextDocumentParams didChangeDocumentParams:
{
if (didChangeDocumentParams.TextDocument?.Uri == null) break;
// TODO: Do something with document version here?
var attributes = GetTextDocumentAttributes(didChangeDocumentParams.TextDocument.Uri);

Expand Down
12 changes: 10 additions & 2 deletions src/Shared/LspRequestRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.JsonRpc.Server;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Shared;
using ISerializer = OmniSharp.Extensions.LanguageServer.Protocol.Serialization.ISerializer;

Expand Down Expand Up @@ -57,13 +58,20 @@ private ILspHandlerDescriptor FindDescriptor(string method, JToken @params)
return null;
}


if (@params == null || descriptor.Params == null) return descriptor;

var lspHandlerDescriptors = _collection.Where(handler => handler.Method == method).ToList();
if (lspHandlerDescriptors.Count == 1) return descriptor;

var paramsValue = @params.ToObject(descriptor.Params, _serializer.JsonSerializer);
return _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).FirstOrDefault() ?? descriptor;
var matchDescriptor = _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).FirstOrDefault();
if (matchDescriptor != null) return matchDescriptor;
// execute command is a special case
// if no command was found to execute this must error
// this is not great coupling but other options require api changes
if (paramsValue is ExecuteCommandParams) return null;
if (lspHandlerDescriptors.Count == 1) return descriptor;
return null;
}

IHandlerDescriptor IRequestRouter<IHandlerDescriptor>.GetDescriptor(Notification notification) => GetDescriptor(notification);
Expand Down
Loading