diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 9a98f5aed8ee61f998ce53180148df63dfa44a34..85021081d4270d725a0de58ce8a03cc7eb423494 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -2445,19 +2445,43 @@ fn render_docs_slash_command_trailer( return Empty.into_any(); }; - if !store.is_indexing(&package) { + let mut children = Vec::new(); + + if store.is_indexing(&package) { + children.push( + div() + .id(("crates-being-indexed", row.0)) + .child(Icon::new(IconName::ArrowCircle).with_animation( + "arrow-circle", + Animation::new(Duration::from_secs(4)).repeat(), + |icon, delta| icon.transform(Transformation::rotate(percentage(delta))), + )) + .tooltip({ + let package = package.clone(); + move |cx| Tooltip::text(format!("Indexing {package}…"), cx) + }) + .into_any_element(), + ); + } + + if let Some(latest_error) = store.latest_error_for_package(&package) { + children.push( + div() + .id(("latest-error", row.0)) + .child(Icon::new(IconName::ExclamationTriangle).color(Color::Warning)) + .tooltip(move |cx| Tooltip::text(format!("failed to index: {latest_error}"), cx)) + .into_any_element(), + ) + } + + let is_indexing = store.is_indexing(&package); + let latest_error = store.latest_error_for_package(&package); + + if !is_indexing && latest_error.is_none() { return Empty.into_any(); } - div() - .id(("crates-being-indexed", row.0)) - .child(Icon::new(IconName::ArrowCircle).with_animation( - "arrow-circle", - Animation::new(Duration::from_secs(4)).repeat(), - |icon, delta| icon.transform(Transformation::rotate(percentage(delta))), - )) - .tooltip(move |cx| Tooltip::text(format!("Indexing {package}…"), cx)) - .into_any_element() + h_flex().gap_2().children(children).into_any_element() } fn make_lsp_adapter_delegate( diff --git a/crates/indexed_docs/src/providers/rustdoc.rs b/crates/indexed_docs/src/providers/rustdoc.rs index 9b3038a2e56851ba3ce8496485b413530c85fe7f..b8b345c39fe4296c853fd65c3a1f122f12fcc784 100644 --- a/crates/indexed_docs/src/providers/rustdoc.rs +++ b/crates/indexed_docs/src/providers/rustdoc.rs @@ -158,6 +158,11 @@ impl RustdocProvider for LocalProvider { ) -> Result> { let mut local_cargo_doc_path = self.cargo_workspace_root.join("target/doc"); local_cargo_doc_path.push(crate_name.as_ref()); + + if !self.fs.is_dir(&local_cargo_doc_path).await { + bail!("docs directory for '{crate_name}' does not exist. run `cargo doc`"); + } + if let Some(item) = item { local_cargo_doc_path.push(item.url_path()); } else { diff --git a/crates/indexed_docs/src/store.rs b/crates/indexed_docs/src/store.rs index 438cd19b69f563a4b02310276849aa943fc7dd23..f1a66ff3e403673cce57ab08031704375c6c1f6e 100644 --- a/crates/indexed_docs/src/store.rs +++ b/crates/indexed_docs/src/store.rs @@ -57,6 +57,7 @@ pub struct IndexedDocsStore { provider: Box, indexing_tasks_by_package: RwLock>>>>>, + latest_errors_by_package: RwLock>>, } impl IndexedDocsStore { @@ -86,9 +87,14 @@ impl IndexedDocsStore { database_future, provider, indexing_tasks_by_package: RwLock::new(HashMap::default()), + latest_errors_by_package: RwLock::new(HashMap::default()), } } + pub fn latest_error_for_package(&self, package: &PackageName) -> Option> { + self.latest_errors_by_package.read().get(package).cloned() + } + /// Returns whether the package with the given name is currently being indexed. pub fn is_indexing(&self, package: &PackageName) -> bool { self.indexing_tasks_by_package.read().contains_key(package) @@ -125,16 +131,31 @@ impl IndexedDocsStore { } }); - let index_task = async { - let database = this - .database_future - .clone() - .await - .map_err(|err| anyhow!(err))?; - this.provider.index(package, database).await + let index_task = { + let package = package.clone(); + async { + let database = this + .database_future + .clone() + .await + .map_err(|err| anyhow!(err))?; + this.provider.index(package, database).await + } }; - index_task.await.map_err(Arc::new) + let result = index_task.await.map_err(Arc::new); + match &result { + Ok(_) => { + this.latest_errors_by_package.write().remove(&package); + } + Err(err) => { + this.latest_errors_by_package + .write() + .insert(package, err.to_string().into()); + } + } + + result } }) .shared();