diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c4d9ad7dff5..8ea161dbdc4 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -989,6 +989,10 @@ impl Config { self.experimental("codeActionGroup") } + pub fn open_server_logs(&self) -> bool { + self.experimental("openServerLogs") + } + pub fn server_status_notification(&self) -> bool { self.experimental("serverStatusNotification") } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index b117acd1b0f..08b2c837de3 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -151,6 +151,13 @@ impl Notification for ClearFlycheck { const METHOD: &'static str = "rust-analyzer/clearFlycheck"; } +pub enum OpenServerLogs {} + +impl Notification for OpenServerLogs { + type Params = (); + const METHOD: &'static str = "rust-analyzer/openServerLogs"; +} + #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct RunFlycheckParams { diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index dcaee92857a..baa77a005e2 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -2,12 +2,13 @@ use std::{mem, ops::Range, sync::Arc}; use lsp_server::Notification; +use lsp_types::request::Request; use crate::{ from_proto, global_state::GlobalState, line_index::{LineEndings, LineIndex, PositionEncoding}, - LspError, + lsp_ext, LspError, }; pub(crate) fn invalid_params_error(message: String) -> LspError { @@ -46,20 +47,47 @@ impl GlobalState { /// If `additional_info` is [`Some`], appends a note to the notification telling to check the logs. /// This will always log `message` + `additional_info` to the server's error log. pub(crate) fn show_and_log_error(&mut self, message: String, additional_info: Option) { - let mut message = message; match additional_info { Some(additional_info) => { - tracing::error!("{}\n\n{}", &message, &additional_info); - if tracing::enabled!(tracing::Level::ERROR) { - message.push_str("\n\nCheck the server logs for additional info."); + tracing::error!("{}:\n{}", &message, &additional_info); + match self.config.open_server_logs() && tracing::enabled!(tracing::Level::ERROR) { + true => self.send_request::( + lsp_types::ShowMessageRequestParams { + typ: lsp_types::MessageType::ERROR, + message, + actions: Some(vec![lsp_types::MessageActionItem { + title: "Open server logs".to_owned(), + properties: Default::default(), + }]), + }, + |this, resp| { + let lsp_server::Response { error: None, result: Some(result), .. } = resp + else { return }; + if let Ok(Some(_item)) = crate::from_json::< + ::Result, + >( + lsp_types::request::ShowMessageRequest::METHOD, &result + ) { + this.send_notification::(()); + } + }, + ), + false => self.send_notification::( + lsp_types::ShowMessageParams { + typ: lsp_types::MessageType::ERROR, + message, + }, + ), } } - None => tracing::error!("{}", &message), - } + None => { + tracing::error!("{}", &message); - self.send_notification::( - lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message }, - ) + self.send_notification::( + lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message }, + ); + } + } } /// rust-analyzer is resilient -- if it fails, this doesn't usually affect @@ -77,7 +105,7 @@ impl GlobalState { let from_source_build = option_env!("POKE_RA_DEVS").is_some(); let profiling_enabled = std::env::var("RA_PROFILE").is_ok(); if from_source_build || profiling_enabled { - self.show_message(lsp_types::MessageType::ERROR, message) + self.show_and_log_error(message, None); } } diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 0f24ddbbc00..a794e866181 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@