diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index e73a2d5c770..05567f8f579 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -720,11 +720,11 @@ pub struct ClientCommandsConfig { } #[derive(Debug)] -pub struct ConfigUpdateError { +pub struct ConfigError { errors: Vec<(String, serde_json::Error)>, } -impl fmt::Display for ConfigUpdateError { +impl fmt::Display for ConfigError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let errors = self.errors.iter().format_with("\n", |(key, e), f| { f(key)?; @@ -733,7 +733,7 @@ impl fmt::Display for ConfigUpdateError { }); write!( f, - "rust-analyzer found {} invalid config value{}:\n{}", + "invalid config value{}:\n{}", self.errors.len(), if self.errors.len() == 1 { "" } else { "s" }, errors @@ -777,7 +777,7 @@ impl Config { self.workspace_roots.extend(paths); } - pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> { + pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigError> { tracing::info!("updating config from JSON: {:#}", json); if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { return Ok(()); @@ -824,7 +824,7 @@ impl Config { if errors.is_empty() { Ok(()) } else { - Err(ConfigUpdateError { errors }) + Err(ConfigError { errors }) } } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index defb3e1461f..d68e51240b7 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -19,7 +19,7 @@ use triomphe::Arc; use vfs::AnchoredPathBuf; use crate::{ - config::Config, + config::{Config, ConfigError}, diagnostics::{CheckFixes, DiagnosticCollection}, from_proto, line_index::{LineEndings, LineIndex}, @@ -56,6 +56,7 @@ pub(crate) struct GlobalState { pub(crate) task_pool: Handle, Receiver>, pub(crate) config: Arc, + pub(crate) config_errors: Option, pub(crate) analysis_host: AnalysisHost, pub(crate) diagnostics: DiagnosticCollection, pub(crate) mem_docs: MemDocs, @@ -168,6 +169,7 @@ impl GlobalState { shutdown_requested: false, last_reported_status: None, source_root_config: SourceRootConfig::default(), + config_errors: Default::default(), proc_macro_changed: false, // FIXME: use `Arc::from_iter` when it becomes available diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index ca9ea77f305..481004988d3 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -169,13 +169,7 @@ pub(crate) fn handle_did_change_configuration( // Note that json can be null according to the spec if the client can't // provide a configuration. This is handled in Config::update below. let mut config = Config::clone(&*this.config); - if let Err(error) = config.update(json.take()) { - this.show_message( - lsp_types::MessageType::WARNING, - error.to_string(), - false, - ); - } + config.update(json.take()); this.update_configuration(config); } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b3522394cd6..49595a45ea9 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -419,7 +419,11 @@ impl GlobalState { if self.config.server_status_notification() { self.send_notification::(status); - } else if let (health, Some(message)) = (status.health, &status.message) { + } else if let ( + health @ (lsp_ext::Health::Warning | lsp_ext::Health::Error), + Some(message), + ) = (status.health, &status.message) + { let open_log_button = tracing::enabled!(tracing::Level::ERROR) && (self.fetch_build_data_error().is_err() || self.fetch_workspace_error().is_err()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 4c76392a0e7..5300349e7d2 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -27,6 +27,7 @@ use ide_db::{ use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{PackageRoot, ProjectWorkspace, WorkspaceBuildScripts}; +use stdx::format_to; use syntax::SmolStr; use triomphe::Arc; use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; @@ -134,6 +135,10 @@ impl GlobalState { message.push_str("Failed to discover workspace.\n"); message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n"); } + if let Some(err) = &self.config_errors { + status.health = lsp_ext::Health::Warning; + format_to!(message, "{err}\n"); + } for ws in self.workspaces.iter() { let (ProjectWorkspace::Cargo { sysroot, .. }