125 lines · 4.5 KB · Rust
RawDownload
use crate::slash_command::file_command::{FileCommandMetadata, FileSlashCommand};use anyhow::{anyhow, Result};use assistant_slash_command::{    ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,    SlashCommandResult,};use collections::HashSet;use futures::future;use gpui::{Task, WeakView, WindowContext};use language::{BufferSnapshot, LspAdapterDelegate};use std::sync::{atomic::AtomicBool, Arc};use text::OffsetRangeExt;use ui::prelude::*;use workspace::Workspace; pub(crate) struct DeltaSlashCommand; impl SlashCommand for DeltaSlashCommand {    fn name(&self) -> String {        "delta".into()    }     fn description(&self) -> String {        "Re-insert changed files".into()    }     fn menu_text(&self) -> String {        self.description()    }     fn icon(&self) -> IconName {        IconName::Diff    }     fn requires_argument(&self) -> bool {        false    }     fn complete_argument(        self: Arc<Self>,        _arguments: &[String],        _cancellation_flag: Arc<AtomicBool>,        _workspace: Option<WeakView<Workspace>>,        _cx: &mut WindowContext,    ) -> Task<Result<Vec<ArgumentCompletion>>> {        Task::ready(Err(anyhow!("this command does not require argument")))    }     fn run(        self: Arc<Self>,        _arguments: &[String],        context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],        context_buffer: BufferSnapshot,        workspace: WeakView<Workspace>,        delegate: Option<Arc<dyn LspAdapterDelegate>>,        cx: &mut WindowContext,    ) -> Task<SlashCommandResult> {        let mut paths = HashSet::default();        let mut file_command_old_outputs = Vec::new();        let mut file_command_new_outputs = Vec::new();         for section in context_slash_command_output_sections.iter().rev() {            if let Some(metadata) = section                .metadata                .as_ref()                .and_then(|value| serde_json::from_value::<FileCommandMetadata>(value.clone()).ok())            {                if paths.insert(metadata.path.clone()) {                    file_command_old_outputs.push(                        context_buffer                            .as_rope()                            .slice(section.range.to_offset(&context_buffer)),                    );                    file_command_new_outputs.push(Arc::new(FileSlashCommand).run(                        &[metadata.path.clone()],                        context_slash_command_output_sections,                        context_buffer.clone(),                        workspace.clone(),                        delegate.clone(),                        cx,                    ));                }            }        }         cx.background_executor().spawn(async move {            let mut output = SlashCommandOutput::default();            let mut changes_detected = false;             let file_command_new_outputs = future::join_all(file_command_new_outputs).await;            for (old_text, new_output) in file_command_old_outputs                .into_iter()                .zip(file_command_new_outputs)            {                if let Ok(new_output) = new_output {                    if let Ok(new_output) = SlashCommandOutput::from_event_stream(new_output).await                    {                        if let Some(file_command_range) = new_output.sections.first() {                            let new_text = &new_output.text[file_command_range.range.clone()];                            if old_text.chars().ne(new_text.chars()) {                                changes_detected = true;                                output.sections.extend(new_output.sections.into_iter().map(                                    |section| SlashCommandOutputSection {                                        range: output.text.len() + section.range.start                                            ..output.text.len() + section.range.end,                                        icon: section.icon,                                        label: section.label,                                        metadata: section.metadata,                                    },                                ));                                output.text.push_str(&new_output.text);                            }                        }                    }                }            }             if !changes_detected {                return Err(anyhow!("no new changes detected"));            }             Ok(output.to_event_stream())        })    }}