Return an LspResult from LSP Request handlers#1028
Open
DavisVaughan wants to merge 1 commit intomainfrom
Open
Conversation
DavisVaughan
commented
Feb 3, 2026
| Disabled, | ||
| Crashed(anyhow::Result<LspResponse>), | ||
| Result(anyhow::Result<LspResponse>), | ||
| Crashed(anyhow::Error), |
Contributor
Author
There was a problem hiding this comment.
I recognized along the way that Crashed is only ever intended to contain an anyhow::Error, i.e. it will never hold the Ok() variant of an anyhow::Result<>, so we can simplify this a little.
Comment on lines
+80
to
+83
| RequestResponse::Result(Err(err)) => match err { | ||
| LspError::JsonRpc(err) => Err(err), | ||
| LspError::Anyhow(err) => Err(new_jsonrpc_error(format!("{err:?}"))), | ||
| }, |
Contributor
Author
There was a problem hiding this comment.
This is most of the magic. We can now build a context aware jsonrpc::Error at the failure site and pipe it all the way through to be sent to the frontend. I think this will be useful for more than just statement_range() going forward.
Comment on lines
458
to
498
| @@ -478,22 +480,19 @@ fn respond<T>( | |||
| // This creates an uninformative backtrace that is reported in the | |||
| // LSP logs. Note that the relevant backtrace is the one created by | |||
| // our panic hook and reported via the _kernel_ logs. | |||
| anyhow!("Panic occurred while handling request: {msg}") | |||
| }) | |||
| // Unwrap nested Result | |||
| .and_then(|resp| resp); | |||
|
|
|||
| let out = match response { | |||
| Ok(_) => Ok(()), | |||
| Err(ref err) => Err(anyhow!("Error while handling request:\n{err:?}")), | |||
| RequestResponse::Crashed(anyhow!("Panic occurred while handling request: {msg}")) | |||
| }, | |||
| }; | |||
|
|
|||
| let response = response.map(into_lsp_response); | |||
|
|
|||
| let response = if crashed { | |||
| RequestResponse::Crashed(response) | |||
| } else { | |||
| RequestResponse::Result(response) | |||
| let out = match response { | |||
| RequestResponse::Result(Ok(_)) => Ok(()), | |||
| RequestResponse::Result(Err(ref error)) => { | |||
| Err(anyhow!("Error while handling request:\n{error:?}")) | |||
| }, | |||
| RequestResponse::Crashed(ref error) => { | |||
| Err(anyhow!("Crashed while handling request:\n{error:?}")) | |||
| }, | |||
| RequestResponse::Disabled => Err(anyhow!("Received impossible `Disabled` response state")), | |||
| }; | |||
|
|
|||
| // Ignore errors from a closed channel. This indicates the request has | |||
Contributor
Author
There was a problem hiding this comment.
A little bit of fiddling to get this right, but I think it reads a little clearer in the end
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I'm starting to look at posit-dev/positron#8350, and I believe that
statement_range()is going to need to be able to return a structuredjsonrpc::Errorwith a well definedcodeandmessagethat we can pick up on on the frontend.In particular, I'm likely going to have it return
RequestFailedhttps://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage
Currently all of our LSP Request handlers return an
anyhow::Result, and at the very last second we convert anyanyhow::Errors into ajsonrpc::Errorwith an arbitrary-1code. This is no longer going to be good enough for cases where we need to return structuredjsonrpc::Errors with a specificcode.Luckily I think we can get the best of both worlds, here's what I've come up with for the return type of all Request handlers:
This comes with nice
Frommethodswhich means there is very little code to change. We can still use
?on any helper method that returns ananyhow::Result, and theanyhow::Errorwill get wrapped intoLspError::Anyhowautomatically.I haven't actually done anything in
statement_range()yet, but I'm planning on returning something like this using this newLspResultfeature: