Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/flycheck/src/lib.rs2
-rw-r--r--crates/project_model/src/build_scripts.rs22
-rw-r--r--crates/project_model/src/workspace.rs4
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs6
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs20
-rw-r--r--crates/rust-analyzer/src/main_loop.rs12
-rw-r--r--crates/rust-analyzer/src/reload.rs63
8 files changed, 82 insertions, 51 deletions
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 4c84c62016..2cd1995267 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -329,7 +329,7 @@ impl CargoActor {
Ok(output) if output.status.success() => Ok(()),
Ok(output) => {
Err(io::Error::new(io::ErrorKind::Other, format!(
- "Cargo watcher failed, the command produced no valid metadata (exit code: {:?})\nCargo's stderr output:\n{}",
+ "Cargo watcher failed, the command produced no valid metadata (exit code: {:?}):\n{}",
output.status, error
)))
}
diff --git a/crates/project_model/src/build_scripts.rs b/crates/project_model/src/build_scripts.rs
index d96c135ba5..5aa23331a1 100644
--- a/crates/project_model/src/build_scripts.rs
+++ b/crates/project_model/src/build_scripts.rs
@@ -7,11 +7,11 @@
//! here, but it covers procedural macros as well.
use std::{
+ io,
path::PathBuf,
process::{Command, Stdio},
};
-use anyhow::Result;
use cargo_metadata::{camino::Utf8Path, Message};
use la_arena::ArenaMap;
use paths::AbsPathBuf;
@@ -80,7 +80,7 @@ impl WorkspaceBuildScripts {
config: &CargoConfig,
workspace: &CargoWorkspace,
progress: &dyn Fn(String),
- ) -> Result<WorkspaceBuildScripts> {
+ ) -> io::Result<WorkspaceBuildScripts> {
let mut cmd = Self::build_command(config);
if config.wrap_rustc_in_build_scripts {
@@ -107,12 +107,12 @@ impl WorkspaceBuildScripts {
by_id.insert(workspace[package].id.clone(), package);
}
- let mut callback_err = None;
+ let mut cfg_err = None;
let mut stderr = String::new();
let output = stdx::process::streaming_output(
cmd,
&mut |line| {
- if callback_err.is_some() {
+ if cfg_err.is_some() {
return;
}
@@ -126,7 +126,7 @@ impl WorkspaceBuildScripts {
match message {
Message::BuildScriptExecuted(message) => {
let package = match by_id.get(&message.package_id.repr) {
- Some(it) => *it,
+ Some(&it) => it,
None => return,
};
let cfgs = {
@@ -135,7 +135,7 @@ impl WorkspaceBuildScripts {
match cfg.parse::<CfgFlag>() {
Ok(it) => acc.push(it),
Err(err) => {
- callback_err = Some(anyhow::format_err!(
+ cfg_err = Some(format!(
"invalid cfg from cargo-metadata: {}",
err
));
@@ -191,6 +191,11 @@ impl WorkspaceBuildScripts {
for package in workspace.packages() {
let package_build_data = &mut res.outputs[package];
+ tracing::info!(
+ "{} BuildScriptOutput: {:?}",
+ workspace[package].manifest.parent().display(),
+ package_build_data,
+ );
// inject_cargo_env(package, package_build_data);
if let Some(out_dir) = &package_build_data.out_dir {
// NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
@@ -200,6 +205,11 @@ impl WorkspaceBuildScripts {
}
}
+ if let Some(cfg_err) = cfg_err {
+ stderr.push_str(&cfg_err);
+ stderr.push('\n');
+ }
+
if !output.status.success() {
if stderr.is_empty() {
stderr = "cargo check failed".to_string();
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 3ceb046939..1330a86950 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -256,7 +256,9 @@ impl ProjectWorkspace {
) -> Result<WorkspaceBuildScripts> {
match self {
ProjectWorkspace::Cargo { cargo, .. } => {
- WorkspaceBuildScripts::run(config, cargo, progress)
+ WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| {
+ format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
+ })
}
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
Ok(WorkspaceBuildScripts::default())
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index a4e985f43b..15ae0e6480 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -119,7 +119,9 @@ fn setup_logging(log_file: Option<&Path>) -> Result<()> {
None => None,
};
let filter = env::var("RA_LOG").ok();
- logger::Logger::new(log_file, filter.as_deref()).install()?;
+ // deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually useful
+ // information in there for debugging
+ logger::Logger::new(log_file, filter.as_deref().or(Some("error"))).install()?;
profile::init();
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 02482d5889..8b47ef0283 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -190,6 +190,7 @@ impl GlobalState {
for file in changed_files {
if !file.is_created_or_deleted() {
+ // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/11357
let crates = self.analysis_host.raw_database().relevant_crates(file.file_id);
let crate_graph = self.analysis_host.raw_database().crate_graph();
@@ -255,6 +256,7 @@ impl GlobalState {
let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
self.send(request.into());
}
+
pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
let handler = self
.req_queue
@@ -281,6 +283,7 @@ impl GlobalState {
.incoming
.register(request.id.clone(), (request.method.clone(), request_received));
}
+
pub(crate) fn respond(&mut self, response: lsp_server::Response) {
if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
if let Some(err) = &response.error {
@@ -294,6 +297,7 @@ impl GlobalState {
self.send(response.into());
}
}
+
pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
if let Some(response) = self.req_queue.incoming.cancel(request_id) {
self.send(response.into());
@@ -307,7 +311,7 @@ impl GlobalState {
impl Drop for GlobalState {
fn drop(&mut self) {
- self.analysis_host.request_cancellation()
+ self.analysis_host.request_cancellation();
}
}
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index b09c411908..460ae4ef4d 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -47,6 +47,26 @@ impl GlobalState {
)
}
+ /// Sends a notification to the client containing the error `message`.
+ /// 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<String>) {
+ 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.");
+ }
+ }
+ None => tracing::error!("{}", &message),
+ }
+
+ self.send_notification::<lsp_types::notification::ShowMessage>(
+ lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message },
+ )
+ }
+
/// rust-analyzer is resilient -- if it fails, this doesn't usually affect
/// the user experience. Part of that is that we deliberately hide panics
/// from the user.
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e305212165..de44ba5e07 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -111,10 +111,7 @@ impl GlobalState {
&& self.config.detached_files().is_empty()
&& self.config.notifications().cargo_toml_not_found
{
- self.show_message(
- lsp_types::MessageType::ERROR,
- "rust-analyzer failed to discover workspace".to_string(),
- );
+ self.show_and_log_error("rust-analyzer failed to discover workspace".to_string(), None);
};
if self.config.did_save_text_document_dynamic_registration() {
@@ -406,9 +403,9 @@ impl GlobalState {
flycheck::Progress::DidCancel => (Progress::End, None),
flycheck::Progress::DidFinish(result) => {
if let Err(err) = result {
- self.show_message(
- lsp_types::MessageType::ERROR,
- format!("cargo check failed: {}", err),
+ self.show_and_log_error(
+ "cargo check failed".to_string(),
+ Some(err.to_string()),
);
}
(Progress::End, None)
@@ -564,7 +561,6 @@ impl GlobalState {
if self.workspaces.is_empty() && !self.is_quiescent() {
self.respond(lsp_server::Response::new_err(
req.id,
- // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
lsp_server::ErrorCode::ContentModified as i32,
"waiting for cargo metadata or cargo check".to_owned(),
));
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index eecc83e02a..5189d94eae 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -72,9 +72,10 @@ impl GlobalState {
status.message =
Some("Reload required due to source changes of a procedural macro.".into())
}
- if let Some(error) = self.fetch_build_data_error() {
+ if let Err(_) = self.fetch_build_data_error() {
status.health = lsp_ext::Health::Warning;
- status.message = Some(error)
+ status.message =
+ Some("Failed to run build scripts of some packages, check the logs.".to_string());
}
if !self.config.cargo_autoreload()
&& self.is_quiescent()
@@ -84,7 +85,7 @@ impl GlobalState {
status.message = Some("Workspace reload required".to_string())
}
- if let Some(error) = self.fetch_workspace_error() {
+ if let Err(error) = self.fetch_workspace_error() {
status.health = lsp_ext::Health::Error;
status.message = Some(error)
}
@@ -167,8 +168,8 @@ impl GlobalState {
let _p = profile::span("GlobalState::switch_workspaces");
tracing::info!("will switch workspaces");
- if let Some(error_message) = self.fetch_workspace_error() {
- tracing::error!("failed to switch workspaces: {}", error_message);
+ if let Err(error_message) = self.fetch_workspace_error() {
+ self.show_and_log_error(error_message, None);
if !self.workspaces.is_empty() {
// It only makes sense to switch to a partially broken workspace
// if we don't have any workspace at all yet.
@@ -176,8 +177,11 @@ impl GlobalState {
}
}
- if let Some(error_message) = self.fetch_build_data_error() {
- tracing::error!("failed to switch build data: {}", error_message);
+ if let Err(error) = self.fetch_build_data_error() {
+ self.show_and_log_error(
+ "rust-analyzer failed to run build scripts".to_string(),
+ Some(error),
+ );
}
let workspaces = self
@@ -277,20 +281,18 @@ impl GlobalState {
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
if self.proc_macro_client.is_none() {
- self.proc_macro_client = match self.config.proc_macro_srv() {
- None => None,
- Some((path, args)) => match ProcMacroServer::spawn(path.clone(), args) {
- Ok(it) => Some(it),
+ if let Some((path, args)) = self.config.proc_macro_srv() {
+ match ProcMacroServer::spawn(path.clone(), args) {
+ Ok(it) => self.proc_macro_client = Some(it),
Err(err) => {
tracing::error!(
"Failed to run proc_macro_srv from path {}, error: {:?}",
path.display(),
err
);
- None
}
- },
- };
+ }
+ }
}
let watch = match files_config.watcher {
@@ -348,7 +350,7 @@ impl GlobalState {
tracing::info!("did switch workspaces");
}
- fn fetch_workspace_error(&self) -> Option<String> {
+ fn fetch_workspace_error(&self) -> Result<(), String> {
let mut buf = String::new();
for ws in self.fetch_workspaces_queue.last_op_result() {
@@ -358,35 +360,30 @@ impl GlobalState {
}
if buf.is_empty() {
- return None;
+ return Ok(());
}
- Some(buf)
+ Err(buf)
}
- fn fetch_build_data_error(&self) -> Option<String> {
- let mut buf = "rust-analyzer failed to run build scripts:\n".to_string();
- let mut has_errors = false;
+ fn fetch_build_data_error(&self) -> Result<(), String> {
+ let mut buf = String::new();
for ws in &self.fetch_build_data_queue.last_op_result().1 {
match ws {
- Ok(data) => {
- if let Some(err) = data.error() {
- has_errors = true;
- stdx::format_to!(buf, "{:#}\n", err);
- }
- }
- Err(err) => {
- has_errors = true;
- stdx::format_to!(buf, "{:#}\n", err);
- }
+ Ok(data) => match data.error() {
+ Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr),
+ _ => (),
+ },
+ // io errors
+ Err(err) => stdx::format_to!(buf, "{:#}\n", err),
}
}
- if has_errors {
- Some(buf)
+ if buf.is_empty() {
+ Ok(())
} else {
- None
+ Err(buf)
}
}