selection_command.rs

 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}