Don't panic on LSP parsing errors

This made sense initially when the implementation was still new (so we
got user reports more frequently), but a parsing error now generally
signifies a language server isn't properly implementing the spec.
This commit is contained in:
Blaž Hrastnik 2022-05-11 11:00:55 +09:00
parent 8b1a03a178
commit 7ae6cad52e
No known key found for this signature in database
GPG key ID: 1238B9C4AD889640
2 changed files with 34 additions and 39 deletions

View file

@ -40,6 +40,8 @@ pub enum Error {
StreamClosed,
#[error("LSP not defined")]
LspNotDefined,
#[error("Unhandled")]
Unhandled,
#[error(transparent)]
Other(#[from] anyhow::Error),
}
@ -226,34 +228,27 @@ pub enum MethodCall {
}
impl MethodCall {
pub fn parse(method: &str, params: jsonrpc::Params) -> Option<MethodCall> {
pub fn parse(method: &str, params: jsonrpc::Params) -> Result<MethodCall> {
use lsp::request::Request;
let request = match method {
lsp::request::WorkDoneProgressCreate::METHOD => {
let params: lsp::WorkDoneProgressCreateParams = params
.parse()
.expect("Failed to parse WorkDoneCreate params");
let params: lsp::WorkDoneProgressCreateParams = params.parse()?;
Self::WorkDoneProgressCreate(params)
}
lsp::request::ApplyWorkspaceEdit::METHOD => {
let params: lsp::ApplyWorkspaceEditParams = params
.parse()
.expect("Failed to parse ApplyWorkspaceEdit params");
let params: lsp::ApplyWorkspaceEditParams = params.parse()?;
Self::ApplyWorkspaceEdit(params)
}
lsp::request::WorkspaceFoldersRequest::METHOD => Self::WorkspaceFolders,
lsp::request::WorkspaceConfiguration::METHOD => {
let params: lsp::ConfigurationParams = params
.parse()
.expect("Failed to parse WorkspaceConfiguration params");
let params: lsp::ConfigurationParams = params.parse()?;
Self::WorkspaceConfiguration(params)
}
_ => {
log::warn!("unhandled lsp request: {}", method);
return None;
return Err(Error::Unhandled);
}
};
Some(request)
Ok(request)
}
}
@ -268,48 +263,34 @@ pub enum Notification {
}
impl Notification {
pub fn parse(method: &str, params: jsonrpc::Params) -> Option<Notification> {
pub fn parse(method: &str, params: jsonrpc::Params) -> Result<Notification> {
use lsp::notification::Notification as _;
let notification = match method {
lsp::notification::Initialized::METHOD => Self::Initialized,
lsp::notification::PublishDiagnostics::METHOD => {
let params: lsp::PublishDiagnosticsParams = params
.parse()
.map_err(|err| {
log::error!(
"received malformed PublishDiagnostic from Language Server: {}",
err
)
})
.ok()?;
// TODO: need to loop over diagnostics and distinguish them by URI
let params: lsp::PublishDiagnosticsParams = params.parse()?;
Self::PublishDiagnostics(params)
}
lsp::notification::ShowMessage::METHOD => {
let params: lsp::ShowMessageParams = params.parse().ok()?;
let params: lsp::ShowMessageParams = params.parse()?;
Self::ShowMessage(params)
}
lsp::notification::LogMessage::METHOD => {
let params: lsp::LogMessageParams = params.parse().ok()?;
let params: lsp::LogMessageParams = params.parse()?;
Self::LogMessage(params)
}
lsp::notification::Progress::METHOD => {
let params: lsp::ProgressParams = params.parse().ok()?;
let params: lsp::ProgressParams = params.parse()?;
Self::ProgressMessage(params)
}
_ => {
log::error!("unhandled LSP notification: {}", method);
return None;
return Err(Error::Unhandled);
}
};
Some(notification)
Ok(notification)
}
}

View file

@ -399,8 +399,14 @@ impl Application {
match call {
Call::Notification(helix_lsp::jsonrpc::Notification { method, params, .. }) => {
let notification = match Notification::parse(&method, params) {
Some(notification) => notification,
None => return,
Ok(notification) => notification,
Err(err) => {
log::error!(
"received malformed notification from Language Server: {}",
err
);
return;
}
};
match notification {
@ -613,9 +619,17 @@ impl Application {
method, params, id, ..
}) => {
let call = match MethodCall::parse(&method, params) {
Some(call) => call,
None => {
error!("Method not found {}", method);
Ok(call) => call,
Err(helix_lsp::Error::Unhandled) => {
error!("Language Server: Method not found {}", method);
return;
}
Err(err) => {
log::error!(
"received malformed method call from Language Server: {}: {}",
method,
err
);
return;
}
};