-
Notifications
You must be signed in to change notification settings - Fork 105
Initial port of LSP client from tintoy/dotnet-language-client. #43
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
Initial port of LSP client from tintoy/dotnet-language-client. #43
Conversation
It looks like CI may be failing due to an unrelated issue?
|
Ah, no, I see now. Need the |
Codecov Report
@@ Coverage Diff @@
## master #43 +/- ##
===========================================
- Coverage 66.38% 55.21% -11.17%
===========================================
Files 193 233 +40
Lines 2041 3142 +1101
===========================================
+ Hits 1355 1735 +380
- Misses 686 1407 +721
Continue to review full report at Codecov.
|
looking at this today, sorry I completely forgot about it this weekend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me... there are somethings I'd like to change, but I'm not going to block merging this for them. The timezone difference itself is enough, lol.
If can make some of the changes, great, if you need to do them later I say merge it in and we'll make some breaking changes and bump the version later.
src/Client/Client.csproj
Outdated
|
||
<ItemGroup> | ||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> | ||
<PackageReference Include="Serilog" Version="2.5.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm hesitant to depend on Serilog
by itself here, as I would generally prefer to not prescribe logging frameworks for consumers.
However Serilog is a great logger, so I'm okay with it for now, and perhaps refactor it away (for MS.Extensions) in a future (breaking) change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the reminder - I'm fine with changing over to MEL for logging, I just forgot about it :)
I'll modify them to take an ILogger
/ ILoggerFactory
instead (some components need to pass a different ILogger<TComponent>
to child components).
|
||
namespace OmniSharp.Extensions.LanguageServerProtocol.Client.Clients | ||
{ | ||
using Utilities; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Not a huge fan of nested usings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem; I tend to use it as a reminder of which namespaces are from "my" code vs external code, but I'm happy to change this over. My rule is usually "match the style already used by the project" :)
if (String.IsNullOrWhiteSpace(filePath)) | ||
throw new ArgumentException($"Argument cannot be null, empty, or entirely composed of whitespace: {nameof(filePath)}.", nameof(filePath)); | ||
|
||
return PositionalRequest<CompletionList>("textDocument/completion", filePath, line, column, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
future: Now that the strings are showing up in more places we should probably add a static constants class somewhere. I'll add an issue for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I probably should have done this in the first place (even when my project was stand-alone) but haven't got around to it.
/// <returns> | ||
/// A <see cref="Task{TResult}"/> that resolves to the completions or <c>null</c> if no completions are available at the specified position. | ||
/// </returns> | ||
public Task<CompletionList> Completions(Uri documentUri, int line, int column, CancellationToken cancellationToken = default(CancellationToken)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably make this a wrapper for the other method, and just pass documentUri as a string or better yet reverse it so that we pass filePath
into this method. That would ensure that the string is a proper Uri
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good catch :)
src/Client/HandlerDelegates.cs
Outdated
/// <returns> | ||
/// A <see cref="Task"/> representing the operation. | ||
/// </returns> | ||
public delegate void EmptyNotificationHandler(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be safe to rename to NotificationHandler
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was trying to make it explicit to consumers that empty notifications are not the same as notifications with payloads (the language server implementation will freak out if you don't pass a payload when one is expected.
But I agree it makes more sense to just vary by type parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed this, but I'd like to keep the underlying TryHandleEmptyNotification
methods where there are no generic type parameters because I got caught more than once by accidentally calling the wrong overload.
/// <param name="notification"> | ||
/// The notification message. | ||
/// </param> | ||
public delegate void NotificationHandler<TNotification>(TNotification notification); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recently changed these on the server to be Task
instead of void
to allow them to block processing until the operation completes, this ensures things like text updates are completed.
Question: Should we do the same here for the client? (I honestly don't know)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting point; I think that makes sense server-side, but I reckon sending a notification should be fire-and-forget. I can't think of a reason that a client would want to block until it's been sent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and thats why I ask the question. :D
src/Client/Handlers/IHandler.cs
Outdated
/// <summary> | ||
/// The kind of handler. | ||
/// </summary> | ||
HandlerKind Kind { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HandlerKind
and the Kind
property seem unnecessary. Worst case we can pattern match, but currently they aren't used anywhere but setting them..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original thinking on this was that the handlers themselves would be generic and so it would be hard to pattern-match on them without already knowing the handler payload type (but you're right it's probably redundant now).
src/Client/Protocol/LspConnection.cs
Outdated
} | ||
|
||
#pragma warning disable CS4014 // Continuation does the work we need; no need to await it as this would tie up the dispatch loop. | ||
handlerTask.ContinueWith(_ => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will throw if handlerTask
is null, should probably return
in the above if.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hah! Yes, good catch :)
Hi - I'll sort all these out over the next couple of days, thanks for taking the time to do a detailed review :) |
…that take document URIs (OmniSharp#43).
Ok - the only thing left to do (I think) is the switch from Serilog to MEL. That may take a little longer; Just need to make sure I'm not directly using Serilog-specific functionality anywhere and I'll need to rework the test framework to handle this (but that should be doable). |
I'll also see what I can do to bump up the test coverage. |
Logging switched over, too - that turned out to be easier than I expected 😁 |
FYI For logging I'm totally fine you bring in Serilog and MEL to handle logging into Xunit, it just makes things so much easier. I would just prefer that the external interface tie to MEL if possible. |
No worries - turns out it was easy to use MEL for in-test logging (see the |
We could probably also create an |
But if you want the Serilog logging stuff for Xunit, I'm happy to contribute that too (although it's no longer needed here). |
If it works we'll leave it alone for now. 👍 |
Hey Adam, were you going to try and bring up the coverage anymore? If not I'm fine merging this as is, and we can add additional coverage later. |
Yeah sorry that was on my list for this morning :) |
Actually given all the other stuff going on this morning, perhaps you can merge it and I'll open a new PR for the additional tests sometime tonight (at conference today)? |
Woohoo! |
Hey - as discussed in #42, I've pulled everything into the
OmniSharp.LanguageServerProtocol.Client
namespace. Have tried to change as little as possible as part of the port so we can talk it over in its present state.BTW, the client library has to target
netstandard2.0
(netstandard1.6
doesn't have the required support for Pipes).