assistant: Include worktree name in diagnostics slash command (#13354)

Files included with the diagnostics command now include the worktree
name, making it more consistent with the way other commands work
(`/active`, `/tabs`, `/file`). Also, the diagnostics command will now
insert nothing when there are no diagnostics.

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2024-06-21 11:48:52 +02:00 committed by GitHub
parent 4dd05a80e0
commit 04a79780d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 9 deletions

View File

@ -10,6 +10,7 @@ use language::{
use project::{DiagnosticSummary, PathMatchCandidateSet, Project}; use project::{DiagnosticSummary, PathMatchCandidateSet, Project};
use rope::Point; use rope::Point;
use std::fmt::Write; use std::fmt::Write;
use std::path::PathBuf;
use std::{ use std::{
ops::Range, ops::Range,
sync::{atomic::AtomicBool, Arc}, sync::{atomic::AtomicBool, Arc},
@ -57,7 +58,7 @@ impl DiagnosticsCommand {
include_ignored: worktree include_ignored: worktree
.root_entry() .root_entry()
.map_or(false, |entry| entry.is_ignored), .map_or(false, |entry| entry.is_ignored),
include_root_name: false, include_root_name: true,
candidates: project::Candidates::Entries, candidates: project::Candidates::Entries,
} }
}) })
@ -161,7 +162,10 @@ impl SlashCommand for DiagnosticsCommand {
let task = collect_diagnostics(workspace.read(cx).project().clone(), options, cx); let task = collect_diagnostics(workspace.read(cx).project().clone(), options, cx);
cx.spawn(move |_| async move { cx.spawn(move |_| async move {
let (text, sections) = task.await?; let Some((text, sections)) = task.await? else {
return Ok(SlashCommandOutput::default());
};
Ok(SlashCommandOutput { Ok(SlashCommandOutput {
text, text,
sections: sections sections: sections
@ -257,7 +261,7 @@ fn collect_diagnostics(
project: Model<Project>, project: Model<Project>,
options: Options, options: Options,
cx: &mut AppContext, cx: &mut AppContext,
) -> Task<Result<(String, Vec<(Range<usize>, PlaceholderType)>)>> { ) -> Task<Result<Option<(String, Vec<(Range<usize>, PlaceholderType)>)>>> {
let error_source = if let Some(path_matcher) = &options.path_matcher { let error_source = if let Some(path_matcher) = &options.path_matcher {
debug_assert_eq!(path_matcher.sources().len(), 1); debug_assert_eq!(path_matcher.sources().len(), 1);
Some(path_matcher.sources().first().cloned().unwrap_or_default()) Some(path_matcher.sources().first().cloned().unwrap_or_default())
@ -266,7 +270,16 @@ fn collect_diagnostics(
}; };
let project_handle = project.downgrade(); let project_handle = project.downgrade();
let diagnostic_summaries: Vec<_> = project.read(cx).diagnostic_summaries(false, cx).collect(); let diagnostic_summaries: Vec<_> = project
.read(cx)
.diagnostic_summaries(false, cx)
.flat_map(|(path, _, summary)| {
let worktree = project.read(cx).worktree_for_id(path.worktree_id, cx)?;
let mut path_buf = PathBuf::from(worktree.read(cx).root_name());
path_buf.push(&path.path);
Some((path, path_buf, summary))
})
.collect();
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let mut text = String::new(); let mut text = String::new();
@ -278,9 +291,9 @@ fn collect_diagnostics(
let mut sections: Vec<(Range<usize>, PlaceholderType)> = Vec::new(); let mut sections: Vec<(Range<usize>, PlaceholderType)> = Vec::new();
let mut project_summary = DiagnosticSummary::default(); let mut project_summary = DiagnosticSummary::default();
for (project_path, _, summary) in diagnostic_summaries { for (project_path, path, summary) in diagnostic_summaries {
if let Some(path_matcher) = &options.path_matcher { if let Some(path_matcher) = &options.path_matcher {
if !path_matcher.is_match(&project_path.path) { if !path_matcher.is_match(&path) {
continue; continue;
} }
} }
@ -293,7 +306,7 @@ fn collect_diagnostics(
} }
let last_end = text.len(); let last_end = text.len();
let file_path = project_path.path.to_string_lossy().to_string(); let file_path = path.to_string_lossy().to_string();
writeln!(&mut text, "{file_path}").unwrap(); writeln!(&mut text, "{file_path}").unwrap();
if let Some(buffer) = project_handle if let Some(buffer) = project_handle
@ -314,12 +327,17 @@ fn collect_diagnostics(
PlaceholderType::File(file_path), PlaceholderType::File(file_path),
)) ))
} }
// No diagnostics found
if sections.is_empty() {
return Ok(None);
}
sections.push(( sections.push((
0..text.len(), 0..text.len(),
PlaceholderType::Root(project_summary, error_source), PlaceholderType::Root(project_summary, error_source),
)); ));
Ok(Some((text, sections)))
Ok((text, sections))
}) })
} }

View File

@ -50,6 +50,7 @@ pub type RenderFoldPlaceholder = Arc<
+ Fn(ElementId, Arc<dyn Fn(&mut WindowContext)>, &mut WindowContext) -> AnyElement, + Fn(ElementId, Arc<dyn Fn(&mut WindowContext)>, &mut WindowContext) -> AnyElement,
>; >;
#[derive(Default)]
pub struct SlashCommandOutput { pub struct SlashCommandOutput {
pub text: String, pub text: String,
pub sections: Vec<SlashCommandOutputSection<usize>>, pub sections: Vec<SlashCommandOutputSection<usize>>,