streaming_example_command.rs

  1use std::sync::Arc;
  2use std::sync::atomic::AtomicBool;
  3use std::time::Duration;
  4
  5use anyhow::Result;
  6use assistant_slash_command::{
  7    ArgumentCompletion, SlashCommand, SlashCommandContent, SlashCommandEvent,
  8    SlashCommandOutputSection, SlashCommandResult,
  9};
 10use feature_flags::FeatureFlag;
 11use futures::channel::mpsc;
 12use gpui::{Task, WeakEntity};
 13use language::{BufferSnapshot, LspAdapterDelegate};
 14use smol::Timer;
 15use smol::stream::StreamExt;
 16use ui::prelude::*;
 17use workspace::Workspace;
 18
 19pub struct StreamingExampleSlashCommandFeatureFlag;
 20
 21impl FeatureFlag for StreamingExampleSlashCommandFeatureFlag {
 22    const NAME: &'static str = "streaming-example-slash-command";
 23}
 24
 25pub struct StreamingExampleSlashCommand;
 26
 27impl SlashCommand for StreamingExampleSlashCommand {
 28    fn name(&self) -> String {
 29        "streaming-example".into()
 30    }
 31
 32    fn description(&self) -> String {
 33        "An example slash command that showcases streaming.".into()
 34    }
 35
 36    fn menu_text(&self) -> String {
 37        self.description()
 38    }
 39
 40    fn requires_argument(&self) -> bool {
 41        false
 42    }
 43
 44    fn complete_argument(
 45        self: Arc<Self>,
 46        _arguments: &[String],
 47        _cancel: Arc<AtomicBool>,
 48        _workspace: Option<WeakEntity<Workspace>>,
 49        _window: &mut Window,
 50        _cx: &mut App,
 51    ) -> Task<Result<Vec<ArgumentCompletion>>> {
 52        Task::ready(Ok(Vec::new()))
 53    }
 54
 55    fn run(
 56        self: Arc<Self>,
 57        _arguments: &[String],
 58        _context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],
 59        _context_buffer: BufferSnapshot,
 60        _workspace: WeakEntity<Workspace>,
 61        _delegate: Option<Arc<dyn LspAdapterDelegate>>,
 62        _: &mut Window,
 63        cx: &mut App,
 64    ) -> Task<SlashCommandResult> {
 65        let (events_tx, events_rx) = mpsc::unbounded();
 66        cx.background_spawn(async move {
 67            events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
 68                icon: IconName::FileRust,
 69                label: "Section 1".into(),
 70                metadata: None,
 71            }))?;
 72            events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
 73                SlashCommandContent::Text {
 74                    text: "Hello".into(),
 75                    run_commands_in_text: false,
 76                },
 77            )))?;
 78            events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
 79
 80            Timer::after(Duration::from_secs(1)).await;
 81
 82            events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
 83                icon: IconName::FileRust,
 84                label: "Section 2".into(),
 85                metadata: None,
 86            }))?;
 87            events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
 88                SlashCommandContent::Text {
 89                    text: "World".into(),
 90                    run_commands_in_text: false,
 91                },
 92            )))?;
 93            events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
 94
 95            for n in 1..=10 {
 96                Timer::after(Duration::from_secs(1)).await;
 97
 98                events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
 99                    icon: IconName::StarFilled,
100                    label: format!("Section {n}").into(),
101                    metadata: None,
102                }))?;
103                events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
104                    SlashCommandContent::Text {
105                        text: "lorem ipsum ".repeat(n).trim().into(),
106                        run_commands_in_text: false,
107                    },
108                )))?;
109                events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
110            }
111
112            anyhow::Ok(())
113        })
114        .detach_and_log_err(cx);
115
116        Task::ready(Ok(events_rx.boxed()))
117    }
118}