1use crate::assistant_panel::selections_creases;
2use anyhow::{anyhow, Result};
3use assistant_slash_command::{
4 ArgumentCompletion, SlashCommand, SlashCommandContent, SlashCommandEvent,
5 SlashCommandOutputSection, SlashCommandResult,
6};
7use futures::StreamExt;
8use gpui::{AppContext, Task, WeakView};
9use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate};
10use std::sync::atomic::AtomicBool;
11use std::sync::Arc;
12use ui::{IconName, SharedString, WindowContext};
13use workspace::Workspace;
14
15pub(crate) struct SelectionCommand;
16
17impl SlashCommand for SelectionCommand {
18 fn name(&self) -> String {
19 "selection".into()
20 }
21
22 fn label(&self, _cx: &AppContext) -> CodeLabel {
23 CodeLabel::plain(self.name(), None)
24 }
25
26 fn description(&self) -> String {
27 "Insert editor selection".into()
28 }
29
30 fn icon(&self) -> IconName {
31 IconName::Quote
32 }
33
34 fn menu_text(&self) -> String {
35 self.description()
36 }
37
38 fn requires_argument(&self) -> bool {
39 false
40 }
41
42 fn accepts_arguments(&self) -> bool {
43 true
44 }
45
46 fn complete_argument(
47 self: Arc<Self>,
48 _arguments: &[String],
49 _cancel: Arc<AtomicBool>,
50 _workspace: Option<WeakView<Workspace>>,
51 _cx: &mut WindowContext,
52 ) -> Task<Result<Vec<ArgumentCompletion>>> {
53 Task::ready(Err(anyhow!("this command does not require argument")))
54 }
55
56 fn run(
57 self: Arc<Self>,
58 _arguments: &[String],
59 _context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],
60 _context_buffer: BufferSnapshot,
61 workspace: WeakView<Workspace>,
62 _delegate: Option<Arc<dyn LspAdapterDelegate>>,
63 cx: &mut WindowContext,
64 ) -> Task<SlashCommandResult> {
65 let mut events = vec![];
66
67 let Some(creases) = workspace
68 .update(cx, selections_creases)
69 .unwrap_or_else(|e| {
70 events.push(Err(e));
71 None
72 })
73 else {
74 return Task::ready(Err(anyhow!("no active selection")));
75 };
76
77 for (text, title) in creases {
78 events.push(Ok(SlashCommandEvent::StartSection {
79 icon: IconName::TextSnippet,
80 label: SharedString::from(title),
81 metadata: None,
82 }));
83 events.push(Ok(SlashCommandEvent::Content(SlashCommandContent::Text {
84 text,
85 run_commands_in_text: false,
86 })));
87 events.push(Ok(SlashCommandEvent::EndSection));
88 events.push(Ok(SlashCommandEvent::Content(SlashCommandContent::Text {
89 text: "\n".to_string(),
90 run_commands_in_text: false,
91 })));
92 }
93
94 let result = futures::stream::iter(events).boxed();
95
96 Task::ready(Ok(result))
97 }
98}