1use super::{
2 diagnostics_command::write_single_file_diagnostics,
3 file_command::{build_entry_output_section, codeblock_fence_for_path},
4 SlashCommand, SlashCommandOutput,
5};
6use anyhow::{anyhow, Result};
7use assistant_slash_command::ArgumentCompletion;
8use editor::Editor;
9use gpui::{AppContext, Task, WeakView};
10use language::LspAdapterDelegate;
11use std::sync::atomic::AtomicBool;
12use std::sync::Arc;
13use ui::WindowContext;
14use workspace::Workspace;
15
16pub(crate) struct ActiveSlashCommand;
17
18impl SlashCommand for ActiveSlashCommand {
19 fn name(&self) -> String {
20 "active".into()
21 }
22
23 fn description(&self) -> String {
24 "insert active tab".into()
25 }
26
27 fn menu_text(&self) -> String {
28 "Insert Active Tab".into()
29 }
30
31 fn complete_argument(
32 self: Arc<Self>,
33 _query: String,
34 _cancel: Arc<AtomicBool>,
35 _workspace: Option<WeakView<Workspace>>,
36 _cx: &mut AppContext,
37 ) -> Task<Result<Vec<ArgumentCompletion>>> {
38 Task::ready(Err(anyhow!("this command does not require argument")))
39 }
40
41 fn requires_argument(&self) -> bool {
42 false
43 }
44
45 fn run(
46 self: Arc<Self>,
47 _argument: Option<&str>,
48 workspace: WeakView<Workspace>,
49 _delegate: Option<Arc<dyn LspAdapterDelegate>>,
50 cx: &mut WindowContext,
51 ) -> Task<Result<SlashCommandOutput>> {
52 let output = workspace.update(cx, |workspace, cx| {
53 let Some(active_item) = workspace.active_item(cx) else {
54 return Task::ready(Err(anyhow!("no active tab")));
55 };
56 let Some(buffer) = active_item
57 .downcast::<Editor>()
58 .and_then(|editor| editor.read(cx).buffer().read(cx).as_singleton())
59 else {
60 return Task::ready(Err(anyhow!("active tab is not an editor")));
61 };
62
63 let snapshot = buffer.read(cx).snapshot();
64 let path = snapshot.resolve_file_path(cx, true);
65 let task = cx.background_executor().spawn({
66 let path = path.clone();
67 async move {
68 let mut output = String::new();
69 output.push_str(&codeblock_fence_for_path(path.as_deref(), None));
70 for chunk in snapshot.as_rope().chunks() {
71 output.push_str(chunk);
72 }
73 if !output.ends_with('\n') {
74 output.push('\n');
75 }
76 output.push_str("```\n");
77 let has_diagnostics =
78 write_single_file_diagnostics(&mut output, path.as_deref(), &snapshot);
79 if output.ends_with('\n') {
80 output.pop();
81 }
82 (output, has_diagnostics)
83 }
84 });
85 cx.foreground_executor().spawn(async move {
86 let (text, has_diagnostics) = task.await;
87 let range = 0..text.len();
88 Ok(SlashCommandOutput {
89 text,
90 sections: vec![build_entry_output_section(
91 range,
92 path.as_deref(),
93 false,
94 None,
95 )],
96 run_commands_in_text: has_diagnostics,
97 })
98 })
99 });
100 output.unwrap_or_else(|error| Task::ready(Err(error)))
101 }
102}