assistant: Show a warning indicator when the user needs to run cargo doc (#14262)

This PR updates the `/docs` slash command to show a warning to the user
if a crate's docs cannot be indexed due to the target directory not
containing docs:

<img width="782" alt="Screenshot 2024-07-11 at 5 11 46 PM"
src="https://github.com/user-attachments/assets/2f54f7a1-97f4-4d2d-b51f-57ba31e50a2f">

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-07-11 17:37:31 -04:00 committed by GitHub
parent c18e9aedcd
commit 906688f012
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 18 deletions

View file

@ -2445,10 +2445,10 @@ fn render_docs_slash_command_trailer(
return Empty.into_any(); return Empty.into_any();
}; };
if !store.is_indexing(&package) { let mut children = Vec::new();
return Empty.into_any();
}
if store.is_indexing(&package) {
children.push(
div() div()
.id(("crates-being-indexed", row.0)) .id(("crates-being-indexed", row.0))
.child(Icon::new(IconName::ArrowCircle).with_animation( .child(Icon::new(IconName::ArrowCircle).with_animation(
@ -2456,8 +2456,32 @@ fn render_docs_slash_command_trailer(
Animation::new(Duration::from_secs(4)).repeat(), Animation::new(Duration::from_secs(4)).repeat(),
|icon, delta| icon.transform(Transformation::rotate(percentage(delta))), |icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
)) ))
.tooltip(move |cx| Tooltip::text(format!("Indexing {package}"), cx)) .tooltip({
.into_any_element() 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();
}
h_flex().gap_2().children(children).into_any_element()
} }
fn make_lsp_adapter_delegate( fn make_lsp_adapter_delegate(

View file

@ -158,6 +158,11 @@ impl RustdocProvider for LocalProvider {
) -> Result<Option<String>> { ) -> Result<Option<String>> {
let mut local_cargo_doc_path = self.cargo_workspace_root.join("target/doc"); let mut local_cargo_doc_path = self.cargo_workspace_root.join("target/doc");
local_cargo_doc_path.push(crate_name.as_ref()); 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 { if let Some(item) = item {
local_cargo_doc_path.push(item.url_path()); local_cargo_doc_path.push(item.url_path());
} else { } else {

View file

@ -57,6 +57,7 @@ pub struct IndexedDocsStore {
provider: Box<dyn IndexedDocsProvider + Send + Sync + 'static>, provider: Box<dyn IndexedDocsProvider + Send + Sync + 'static>,
indexing_tasks_by_package: indexing_tasks_by_package:
RwLock<HashMap<PackageName, Shared<Task<Result<(), Arc<anyhow::Error>>>>>>, RwLock<HashMap<PackageName, Shared<Task<Result<(), Arc<anyhow::Error>>>>>>,
latest_errors_by_package: RwLock<HashMap<PackageName, Arc<str>>>,
} }
impl IndexedDocsStore { impl IndexedDocsStore {
@ -86,9 +87,14 @@ impl IndexedDocsStore {
database_future, database_future,
provider, provider,
indexing_tasks_by_package: RwLock::new(HashMap::default()), 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<Arc<str>> {
self.latest_errors_by_package.read().get(package).cloned()
}
/// Returns whether the package with the given name is currently being indexed. /// Returns whether the package with the given name is currently being indexed.
pub fn is_indexing(&self, package: &PackageName) -> bool { pub fn is_indexing(&self, package: &PackageName) -> bool {
self.indexing_tasks_by_package.read().contains_key(package) self.indexing_tasks_by_package.read().contains_key(package)
@ -125,16 +131,31 @@ impl IndexedDocsStore {
} }
}); });
let index_task = async { let index_task = {
let package = package.clone();
async {
let database = this let database = this
.database_future .database_future
.clone() .clone()
.await .await
.map_err(|err| anyhow!(err))?; .map_err(|err| anyhow!(err))?;
this.provider.index(package, database).await 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(); .shared();