Skip to content
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

Start moving omnisharp to directly using Roslyn's completion service, with a separate resolve step #1877

Merged
merged 6 commits into from
Aug 17, 2020

Conversation

333fred
Copy link
Contributor

@333fred 333fred commented Aug 10, 2020

Today, Omnisharp uses Roslyn's completion service to gather completions, but doesn't then use the other completion helpers to fill in the rest of the detail of the completion. Additionally, Omnisharp does a bunch of work when creating and populating completions, and this can cause slow and inconsistent behavior when invoking completions in the middle of a pre-typed word. Some current issues:

  • vscode fuzzy-matching changes based on whether you invoke completion after typing a few characters.
  • Completions with large numbers of elements can take a bit of time to load, as Omnisharp does filtering and documentation building for all of them.
  • Completion is not well setup to play nicely with LSP, which uses a much different interface.
  • Completion is not capable of providing unimported types, particularly because providing the edits would be extremely expensive if not done only on request.

To solve these issues, this adds a new completion service that mirrors the structure of LSP completion and completion/resolve:

  • On request, only the completion item and initial edit are provided.
  • A new response service is added, which looks up documentation when a particular item is selected in the completion window.
    • This response service will additionally be able to provide extra edits, such as inserting the rest of an override statement or adding imports for unimported types, but these are not yet implemented.

An example of what this looks like in vscode:
image
image

Open questions/things still todo:

  • The first line of the documentation can likely be unconditionally formatted as C#, much like we do in the new quickinfo provider.
  • Do output diffing to insert other text. For example, in VS selecting a thing to override will fill in the rest of the signature. We might be able to use additionalTextEdits to do the same thing here, though the restrictions around the current insertion point are concerning and may be a technical limitation to work out.
  • I'm planning on using the right side of the completion window (the detail section of a CompletionItem) to show the unimported namespace, like VS. However, is there something else we want to put in there?
  • The implementation is currently triggered by space characters. This isn't something that VS does, except for override and possibly a few other scenarios. This is because the Roslyn APIs for ShouldTriggerCompletion returns true for space characters. Is this something that we actually want to have happen? It seems to me like this might be a bug, at which point we should likely ask Roslyn to fix the bug, not try to work around it ourselves.

@filipw @david-driscoll @JoeRobich for a first look. I'm putting it in draft for now while I try and figure out the output diffing bit, but I wanted to at least get eyes on what I've implemented so far.

This supersedes #884.

Fixes #1809.
Fixes #1725.
I think this fixes #78?

… with a separate resolve step

Today, Omnisharp uses Roslyn's completion service to gather completions, but doesn't then use the other completion helpers to fill in the rest of the detail of the completion. Additionally, Omnisharp does a bunch of work when creating and populating completions, and this can cause slow and inconsistent behavior when invoking completions in the middle of a pre-typed word. Some current issues:

* vscode fuzzy-matching changes based on whether you invoke completion after typing a few characters.
* Completions with large numbers of elements can take a bit of time to load, as Omnisharp does filtering and documentation building for all of them.
* Completion is not well setup to play nicely with LSP, which uses a much different interface.
* Completion is not capable of providing unimported types, particularly because providing the edits would be extremely expensive if not done only on request.

To solve these issues, this adds a new completion service that mirrors the structure of LSP completion and completion/resolve:

* On request, only the completion item and initial edit are provided.
* A new response service is added, which looks up documentation when a particular item is selected in the completion window.
    * This response service will additionally be able to provide extra edits, such as inserting the rest of an override statement or adding imports for unimported types, but these are not yet implemented.
@filipw filipw mentioned this pull request Aug 10, 2020
4 tasks
@filipw
Copy link
Member

filipw commented Aug 10, 2020

thank you so much! this makes me extremely happy 👏

The first line of the documentation can likely be unconditionally formatted as C#, much like we do in the new quickinfo provider.

yes that is a good idea

Do output diffing to insert other text. For example, in VS selecting a thing to override will fill in the rest of the signature. We might be able to use additionalTextEdits to do the same thing here, though the restrictions around the current insertion point are concerning and may be a technical limitation to work out.

that was my fear too. is there some diffing service in roslyn that we can just use, or do you need to roll out something by hand?

The implementation is currently triggered by space characters. This isn't something that VS does, except for override and possibly a few other scenarios. This is because the Roslyn APIs for ShouldTriggerCompletion returns true for space characters. Is this something that we actually want to have happen? It seems to me like this might be a bug, at which point we should likely ask Roslyn to fix the bug, not try to work around it ourselves.

IMHO this is also a bug, and overloads the server unnecessarily. But shouldn't this be rather fixed client side? e.g. at the moment VS Code would send "WordToComplete": "" and "TriggerCharacter": " " as you are typing code and use space

…eto completion.

LSP does not support a concept of asynchronous edits that touch the current cursor location: anything that does needs to advertise those edits up front. That makes it impossible to do override or partial completion lazily: completing the method body _requires_ touching the insertion text, as depending on editorconfig settings braces might need to be inserted at the end of the line. Further, moving the cursor requires using a snippet, which cannot be accomplished in an additionalTextEdit. So, for those 4 providers that need to compute additional work at the current cursor location, we do so. We take any work that comes before the cursor location (such as turning override into public override returntype) and turn that into an additionalTextEdit, and then snippitize the rest of the completion and use it as insertionText.
@333fred
Copy link
Contributor Author

333fred commented Aug 14, 2020

Here's what override completion looks like:

override-completion

I still need to adjust the documentation stuff. I can drastically simplify the implementation and clean up code in both the new quickinfo provider and the completion service around it with a couple of small changes, but for this iteration I was focused on override completion :D

@filipw
Copy link
Member

filipw commented Aug 14, 2020

this is ⭐️⭐️⭐️!

@333fred
Copy link
Contributor Author

333fred commented Aug 15, 2020

IMHO this is also a bug, and overloads the server unnecessarily. But shouldn't this be rather fixed client side? e.g. at the moment VS Code would send "WordToComplete": "" and "TriggerCharacter": " " as you are typing code and use space

We do send the trigger character, and whether the completion was triggered explicitly or by typing. It's just that Roslyn thinks "This was triggered by typing " should always actually trigger completion.

This allows it to be fully shared by the QuickInfoProvider and the new CompletionService, with much less special casing and encapsulation violations.

Additionally, the responses from the CompletionService now no longer specify the same lower-cased names as the the LSP completion endpoint. This brings the service into consistency with the rest of omnisharp, and it won't be very hard for the LSP provider to wrap it.
@333fred 333fred marked this pull request as ready for review August 15, 2020 23:59
@333fred
Copy link
Contributor Author

333fred commented Aug 15, 2020

@filipw I believe this is now in a good state.

Copy link
Member

@filipw filipw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: thank you! I saw you made a corresponding VS Code PR too

@333fred
Copy link
Contributor Author

333fred commented Aug 17, 2020

@filipw can you confirm whether this fixes #78? I think it does, but I'm not 100%.

@filipw
Copy link
Member

filipw commented Aug 17, 2020

yes it does 👍

@filipw filipw merged commit 90def5b into OmniSharp:master Aug 17, 2020
@333fred 333fred deleted the completion-service branch August 17, 2020 06:15
@xcap2000
Copy link

xcap2000 commented Mar 3, 2021

Is it available in the current stable version? How do I complete using "override "?

@333fred
Copy link
Contributor Author

333fred commented Mar 3, 2021

Yes, it's available. You just invoke completion and it should work.

@xcap2000
Copy link

xcap2000 commented Mar 3, 2021

I am trying to use on vscode using C# extension and when I type "override+space" it shows nothing, is there any configuration for this?

@333fred
Copy link
Contributor Author

333fred commented Mar 3, 2021

Did you trigger completion, such as by hitting ctrl+space after typing override?

@xcap2000
Copy link

xcap2000 commented Mar 4, 2021

I just tried that with and without space after the override, did not work. latest stable omnisharp and vscode.

@333fred
Copy link
Contributor Author

333fred commented Mar 4, 2021

Please open an issue and include your omnisharp log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants