diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 9d6f7936508e6188da623f303e4cb77ad5f3a10e..50fec4a575e902bf4c59a12e81be593cd3c42dc8 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -30,8 +30,8 @@ use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; use slash_command::{ active_command, default_command, diagnostics_command, docs_command, fetch_command, - file_command, now_command, project_command, prompt_command, search_command, tabs_command, - term_command, + file_command, now_command, project_command, prompt_command, search_command, symbols_command, + tabs_command, term_command, }; use std::{ fmt::{self, Display}, @@ -367,6 +367,7 @@ fn register_slash_commands(cx: &mut AppContext) { let slash_command_registry = SlashCommandRegistry::global(cx); slash_command_registry.register_command(file_command::FileSlashCommand, true); slash_command_registry.register_command(active_command::ActiveSlashCommand, true); + slash_command_registry.register_command(symbols_command::OutlineSlashCommand, true); slash_command_registry.register_command(tabs_command::TabsSlashCommand, true); slash_command_registry.register_command(project_command::ProjectSlashCommand, true); slash_command_registry.register_command(search_command::SearchSlashCommand, true); diff --git a/crates/assistant/src/slash_command.rs b/crates/assistant/src/slash_command.rs index 6cec3861684458e81bf26d8e9029b9fd6bdf1b40..c64820cbd8f6e9e62c645e28356ca0644e8d87a6 100644 --- a/crates/assistant/src/slash_command.rs +++ b/crates/assistant/src/slash_command.rs @@ -27,6 +27,7 @@ pub mod now_command; pub mod project_command; pub mod prompt_command; pub mod search_command; +pub mod symbols_command; pub mod tabs_command; pub mod term_command; diff --git a/crates/assistant/src/slash_command/now_command.rs b/crates/assistant/src/slash_command/now_command.rs index c7bacf8746fa830376ebf3589dd3fcd2b920a212..73f4f7b2565f8303d62ac96d58fbf0a7441e4036 100644 --- a/crates/assistant/src/slash_command/now_command.rs +++ b/crates/assistant/src/slash_command/now_command.rs @@ -23,7 +23,7 @@ impl SlashCommand for NowSlashCommand { } fn menu_text(&self) -> String { - "Insert current date and time".into() + "Insert Current Date and Time".into() } fn requires_argument(&self) -> bool { diff --git a/crates/assistant/src/slash_command/symbols_command.rs b/crates/assistant/src/slash_command/symbols_command.rs new file mode 100644 index 0000000000000000000000000000000000000000..11a056f0daf5cbcd6429c5d327bb8b50e141096c --- /dev/null +++ b/crates/assistant/src/slash_command/symbols_command.rs @@ -0,0 +1,89 @@ +use super::{SlashCommand, SlashCommandOutput}; +use anyhow::{anyhow, Context as _, Result}; +use assistant_slash_command::{ArgumentCompletion, SlashCommandOutputSection}; +use editor::Editor; +use gpui::{AppContext, Task, WeakView}; +use language::LspAdapterDelegate; +use std::sync::Arc; +use std::{path::Path, sync::atomic::AtomicBool}; +use ui::{IconName, WindowContext}; +use workspace::Workspace; + +pub(crate) struct OutlineSlashCommand; + +impl SlashCommand for OutlineSlashCommand { + fn name(&self) -> String { + "symbols".into() + } + + fn description(&self) -> String { + "insert symbols for active tab".into() + } + + fn menu_text(&self) -> String { + "Insert Symbols for Active Tab".into() + } + + fn complete_argument( + self: Arc, + _query: String, + _cancel: Arc, + _workspace: Option>, + _cx: &mut AppContext, + ) -> Task>> { + Task::ready(Err(anyhow!("this command does not require argument"))) + } + + fn requires_argument(&self) -> bool { + false + } + + fn run( + self: Arc, + _argument: Option<&str>, + workspace: WeakView, + _delegate: Arc, + cx: &mut WindowContext, + ) -> Task> { + let output = workspace.update(cx, |workspace, cx| { + let Some(active_item) = workspace.active_item(cx) else { + return Task::ready(Err(anyhow!("no active tab"))); + }; + let Some(buffer) = active_item + .downcast::() + .and_then(|editor| editor.read(cx).buffer().read(cx).as_singleton()) + else { + return Task::ready(Err(anyhow!("active tab is not an editor"))); + }; + + let snapshot = buffer.read(cx).snapshot(); + let path = snapshot.resolve_file_path(cx, true); + + cx.background_executor().spawn(async move { + let outline = snapshot + .outline(None) + .context("no symbols for active tab")?; + + let path = path.as_deref().unwrap_or(Path::new("untitled")); + let mut outline_text = format!("Symbols for {}:\n", path.display()); + for item in &outline.path_candidates { + outline_text.push_str("- "); + outline_text.push_str(&item.string); + outline_text.push('\n'); + } + + Ok(SlashCommandOutput { + sections: vec![SlashCommandOutputSection { + range: 0..outline_text.len(), + icon: IconName::ListTree, + label: path.to_string_lossy().to_string().into(), + }], + text: outline_text, + run_commands_in_text: false, + }) + }) + }); + + output.unwrap_or_else(|error| Task::ready(Err(error))) + } +} diff --git a/crates/assistant/src/slash_command/term_command.rs b/crates/assistant/src/slash_command/term_command.rs index 09b7323a02503d3b46ba32e70a8aa2999ea6f8c6..e3ee2f9ece031c45876fdd24034800c7943bcf8d 100644 --- a/crates/assistant/src/slash_command/term_command.rs +++ b/crates/assistant/src/slash_command/term_command.rs @@ -31,7 +31,7 @@ impl SlashCommand for TermSlashCommand { } fn menu_text(&self) -> String { - "Insert terminal output".into() + "Insert Terminal Output".into() } fn requires_argument(&self) -> bool { diff --git a/crates/language/src/outline.rs b/crates/language/src/outline.rs index 0b6b8341e11900328e96eafaf38555203d25a226..53954a9fc8a85f6af63f0f57366a1b2fb21713a7 100644 --- a/crates/language/src/outline.rs +++ b/crates/language/src/outline.rs @@ -12,7 +12,7 @@ use theme::{color_alpha, ActiveTheme, ThemeSettings}; pub struct Outline { pub items: Vec>, candidates: Vec, - path_candidates: Vec, + pub path_candidates: Vec, path_candidate_prefixes: Vec, }