118 lines · 4.0 KB · Rust
RawDownload
use super::{    diagnostics_command::write_single_file_diagnostics,    file_command::{build_entry_output_section, codeblock_fence_for_path},    SlashCommand, SlashCommandOutput,};use anyhow::{anyhow, Result};use assistant_slash_command::ArgumentCompletion;use collections::HashMap;use editor::Editor;use gpui::{AppContext, Entity, Task, WeakView};use language::LspAdapterDelegate;use std::{fmt::Write, sync::Arc};use ui::WindowContext;use workspace::Workspace; pub(crate) struct TabsSlashCommand; impl SlashCommand for TabsSlashCommand {    fn name(&self) -> String {        "tabs".into()    }     fn description(&self) -> String {        "insert open tabs".into()    }     fn menu_text(&self) -> String {        "Insert Open Tabs".into()    }     fn requires_argument(&self) -> bool {        false    }     fn complete_argument(        self: Arc<Self>,        _query: String,        _cancel: Arc<std::sync::atomic::AtomicBool>,        _workspace: Option<WeakView<Workspace>>,        _cx: &mut AppContext,    ) -> Task<Result<Vec<ArgumentCompletion>>> {        Task::ready(Err(anyhow!("this command does not require argument")))    }     fn run(        self: Arc<Self>,        _argument: Option<&str>,        workspace: WeakView<Workspace>,        _delegate: Option<Arc<dyn LspAdapterDelegate>>,        cx: &mut WindowContext,    ) -> Task<Result<SlashCommandOutput>> {        let open_buffers = workspace.update(cx, |workspace, cx| {            let mut timestamps_by_entity_id = HashMap::default();            let mut open_buffers = Vec::new();             for pane in workspace.panes() {                let pane = pane.read(cx);                for entry in pane.activation_history() {                    timestamps_by_entity_id.insert(entry.entity_id, entry.timestamp);                }            }             for editor in workspace.items_of_type::<Editor>(cx) {                if let Some(buffer) = editor.read(cx).buffer().read(cx).as_singleton() {                    if let Some(timestamp) = timestamps_by_entity_id.get(&editor.entity_id()) {                        let snapshot = buffer.read(cx).snapshot();                        let full_path = snapshot.resolve_file_path(cx, true);                        open_buffers.push((full_path, snapshot, *timestamp));                    }                }            }             open_buffers        });         match open_buffers {            Ok(mut open_buffers) => cx.background_executor().spawn(async move {                open_buffers.sort_by_key(|(_, _, timestamp)| *timestamp);                 let mut sections = Vec::new();                let mut text = String::new();                let mut has_diagnostics = false;                for (full_path, buffer, _) in open_buffers {                    let section_start_ix = text.len();                    text.push_str(&codeblock_fence_for_path(full_path.as_deref(), None));                    for chunk in buffer.as_rope().chunks() {                        text.push_str(chunk);                    }                    if !text.ends_with('\n') {                        text.push('\n');                    }                    writeln!(text, "```").unwrap();                    if write_single_file_diagnostics(&mut text, full_path.as_deref(), &buffer) {                        has_diagnostics = true;                    }                    if !text.ends_with('\n') {                        text.push('\n');                    }                     let section_end_ix = text.len() - 1;                    sections.push(build_entry_output_section(                        section_start_ix..section_end_ix,                        full_path.as_deref(),                        false,                        None,                    ));                }                 Ok(SlashCommandOutput {                    text,                    sections,                    run_commands_in_text: has_diagnostics,                })            }),            Err(error) => Task::ready(Err(error)),        }    }}