So...
We advertise that we can handle CodeActions that are either missing an
edit or a command (or both).
We also advertise that we will preserve server `data` that we receive in
a CodeAction, when we resolve the said fixit. This allows more servers
to take advantage of the lazy code actions.
The server chooses whether it supports either of the two. If it does, it
advertises itself as a "code action resolve provider".
For servers that are code action resolve providers:
- If either edit or command is missing, we need to try resolving the
code action via codeAction/resolve.
- Unless we actually got a LSP Command, in which case
codeAction/resove is skipped.
- After resolving it that way we have a CodeAction in one of these forms:
- A LSP Command
- A LSP CodeAction with only an edit.
- A LSP CodeAction with only a command.
- A LSP CodeAction with both an edit and a command.
- Edits are WorkspaceEdits and can easily be converted into ycmd FixIts.
- Commands are to be executed, yielding ApplyEdits. A single ApplyEdit
can be converted into a ycmd FixIt.
For servers that are not code action resolve providers, the steps are
the same, but we skip the codeAction/resolve route.
One thing missing is properly defined handling of fixit resolutions that
yield multiple fixits. That can happen in a few ways:
- On /resolve_fixit, by a LSP command yielding multiple ApplyEdits.
- When eagerly resolving a fixit, again by a LSP command yielding
multiple ApplyEdits.
- Even if all commands always yield a single ApplyEdit, if a CodeAction
has both an edit and a command, that's again two fixits.
The first two above don't seem to be used by any server ever. The LSP
specs nudges servers away from doing that, but no promises.
We are still not supporting any scenario where resolving a single fixit
results in more than one fixit.
Another scenario that does not seem to happen:
- The server is a code action resove provider.
- The received CodeAction has neither an edit nor a command.
- After resolving, we get only a command.
- We then need to execute the command and collect ApplyEdits.
In practice, such code actions resolve to a CodeAction containing an edit.
As for the ycmd<->client side of things... it's a bit ugly on the ycmd
side, but we're completely preserving the API, so clients do not need to
change a thing.
Previously, clients got `{ 'fixits': [ { 'command': LSPCommand ... } ]
}` for unresolved fixits. However, we have not given any guarantees
about the value of `'command'`. We have only said that it should be
returned to ycmd for the purposes of `/resolve_fixit`. With this pull
request, we need to pass the entire CodeAction, but we're still putting
it in the `command` key.