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.
pull/2461/head
Blaž Hrastnik 3 years ago
parent 8b1a03a178
commit 7ae6cad52e
No known key found for this signature in database
GPG Key ID: 1238B9C4AD889640

@ -40,6 +40,8 @@ pub enum Error {
StreamClosed, StreamClosed,
#[error("LSP not defined")] #[error("LSP not defined")]
LspNotDefined, LspNotDefined,
#[error("Unhandled")]
Unhandled,
#[error(transparent)] #[error(transparent)]
Other(#[from] anyhow::Error), Other(#[from] anyhow::Error),
} }
@ -226,34 +228,27 @@ pub enum MethodCall {
} }
impl 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; use lsp::request::Request;
let request = match method { let request = match method {
lsp::request::WorkDoneProgressCreate::METHOD => { lsp::request::WorkDoneProgressCreate::METHOD => {
let params: lsp::WorkDoneProgressCreateParams = params let params: lsp::WorkDoneProgressCreateParams = params.parse()?;
.parse()
.expect("Failed to parse WorkDoneCreate params");
Self::WorkDoneProgressCreate(params) Self::WorkDoneProgressCreate(params)
} }
lsp::request::ApplyWorkspaceEdit::METHOD => { lsp::request::ApplyWorkspaceEdit::METHOD => {
let params: lsp::ApplyWorkspaceEditParams = params let params: lsp::ApplyWorkspaceEditParams = params.parse()?;
.parse()
.expect("Failed to parse ApplyWorkspaceEdit params");
Self::ApplyWorkspaceEdit(params) Self::ApplyWorkspaceEdit(params)
} }
lsp::request::WorkspaceFoldersRequest::METHOD => Self::WorkspaceFolders, lsp::request::WorkspaceFoldersRequest::METHOD => Self::WorkspaceFolders,
lsp::request::WorkspaceConfiguration::METHOD => { lsp::request::WorkspaceConfiguration::METHOD => {
let params: lsp::ConfigurationParams = params let params: lsp::ConfigurationParams = params.parse()?;
.parse()
.expect("Failed to parse WorkspaceConfiguration params");
Self::WorkspaceConfiguration(params) Self::WorkspaceConfiguration(params)
} }
_ => { _ => {
log::warn!("unhandled lsp request: {}", method); return Err(Error::Unhandled);
return None;
} }
}; };
Some(request) Ok(request)
} }
} }
@ -268,48 +263,34 @@ pub enum Notification {
} }
impl 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 _; use lsp::notification::Notification as _;
let notification = match method { let notification = match method {
lsp::notification::Initialized::METHOD => Self::Initialized, lsp::notification::Initialized::METHOD => Self::Initialized,
lsp::notification::PublishDiagnostics::METHOD => { lsp::notification::PublishDiagnostics::METHOD => {
let params: lsp::PublishDiagnosticsParams = params let params: lsp::PublishDiagnosticsParams = params.parse()?;
.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
Self::PublishDiagnostics(params) Self::PublishDiagnostics(params)
} }
lsp::notification::ShowMessage::METHOD => { lsp::notification::ShowMessage::METHOD => {
let params: lsp::ShowMessageParams = params.parse().ok()?; let params: lsp::ShowMessageParams = params.parse()?;
Self::ShowMessage(params) Self::ShowMessage(params)
} }
lsp::notification::LogMessage::METHOD => { lsp::notification::LogMessage::METHOD => {
let params: lsp::LogMessageParams = params.parse().ok()?; let params: lsp::LogMessageParams = params.parse()?;
Self::LogMessage(params) Self::LogMessage(params)
} }
lsp::notification::Progress::METHOD => { lsp::notification::Progress::METHOD => {
let params: lsp::ProgressParams = params.parse().ok()?; let params: lsp::ProgressParams = params.parse()?;
Self::ProgressMessage(params) Self::ProgressMessage(params)
} }
_ => { _ => {
log::error!("unhandled LSP notification: {}", method); return Err(Error::Unhandled);
return None;
} }
}; };
Some(notification) Ok(notification)
} }
} }

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

Loading…
Cancel
Save