From 411934bb615a1a21958116497149259c58ee1086 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 6 Aug 2024 16:18:07 +0200 Subject: [PATCH] Introduce a new `/workflow` command (#15854) This subsumes the previous built-in prompt. Release Notes: - N/A --- assets/icons/route.svg | 1 + crates/assistant/src/assistant.rs | 3 +- crates/assistant/src/prompt_library.rs | 57 +++------------ crates/assistant/src/slash_command.rs | 1 + .../src/slash_command/workflow_command.rs | 71 +++++++++++++++++++ crates/ui/src/components/icon.rs | 2 + 6 files changed, 85 insertions(+), 50 deletions(-) create mode 100644 assets/icons/route.svg create mode 100644 crates/assistant/src/slash_command/workflow_command.rs diff --git a/assets/icons/route.svg b/assets/icons/route.svg new file mode 100644 index 00000000000000..7d2a5621ff425a --- /dev/null +++ b/assets/icons/route.svg @@ -0,0 +1 @@ + diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 4c6941d756dc57..47266cf03137e8 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -31,7 +31,7 @@ use settings::{update_settings_file, Settings, SettingsStore}; use slash_command::{ active_command, default_command, diagnostics_command, docs_command, fetch_command, file_command, now_command, project_command, prompt_command, search_command, symbols_command, - tabs_command, term_command, + tabs_command, term_command, workflow_command, }; use std::sync::Arc; pub(crate) use streaming_diff::*; @@ -260,6 +260,7 @@ fn register_slash_commands(cx: &mut AppContext) { slash_command_registry.register_command(now_command::NowSlashCommand, true); slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true); slash_command_registry.register_command(docs_command::DocsSlashCommand, true); + slash_command_registry.register_command(workflow_command::WorkflowSlashCommand, true); slash_command_registry.register_command(fetch_command::FetchSlashCommand, false); } diff --git a/crates/assistant/src/prompt_library.rs b/crates/assistant/src/prompt_library.rs index f83d16a571c053..23f76177f70200 100644 --- a/crates/assistant/src/prompt_library.rs +++ b/crates/assistant/src/prompt_library.rs @@ -1201,6 +1201,12 @@ impl PromptStore { let mut txn = db_env.write_txn()?; let metadata = db_env.create_database(&mut txn, Some("metadata.v2"))?; let bodies = db_env.create_database(&mut txn, Some("bodies.v2"))?; + + // Remove edit workflow prompt, as we decided to opt into it using + // a slash command instead. + metadata.delete(&mut txn, &PromptId::EditWorkflow).ok(); + bodies.delete(&mut txn, &PromptId::EditWorkflow).ok(); + txn.commit()?; Self::upgrade_dbs(&db_env, metadata, bodies).log_err(); @@ -1209,17 +1215,13 @@ impl PromptStore { let metadata_cache = MetadataCache::from_db(metadata, &txn)?; txn.commit()?; - let store = PromptStore { + Ok(PromptStore { executor, env: db_env, metadata_cache: RwLock::new(metadata_cache), metadata, bodies, - }; - - store.save_built_in_prompts().log_err(); - - Ok(store) + }) } }) } @@ -1425,49 +1427,6 @@ impl PromptStore { }) } - fn save_built_in_prompts(&self) -> Result<()> { - self.save_built_in_prompt( - PromptId::EditWorkflow, - "Built-in: Editing Workflow", - "prompts/edit_workflow.md", - )?; - Ok(()) - } - - /// Write a built-in prompt to the database, preserving the value of the default field - /// if a prompt with this id already exists. This method blocks. - fn save_built_in_prompt( - &self, - id: PromptId, - title: impl Into, - body_path: &str, - ) -> Result<()> { - let mut metadata_cache = self.metadata_cache.write(); - let existing_metadata = metadata_cache.metadata_by_id.get(&id).cloned(); - - let prompt_metadata = PromptMetadata { - id, - title: Some(title.into()), - default: existing_metadata.map_or(true, |m| m.default), - saved_at: Utc::now(), - }; - - metadata_cache.insert(prompt_metadata.clone()); - - let db_connection = self.env.clone(); - let bodies = self.bodies; - let metadata_db = self.metadata; - - let mut txn = db_connection.write_txn()?; - metadata_db.put(&mut txn, &id, &prompt_metadata)?; - - let body = String::from_utf8(Assets.load(body_path)?.unwrap().to_vec())?; - bodies.put(&mut txn, &id, &body)?; - - txn.commit()?; - Ok(()) - } - fn save_metadata( &self, id: PromptId, diff --git a/crates/assistant/src/slash_command.rs b/crates/assistant/src/slash_command.rs index c64820cbd8f6e9..516fe2fa5ebc3c 100644 --- a/crates/assistant/src/slash_command.rs +++ b/crates/assistant/src/slash_command.rs @@ -30,6 +30,7 @@ pub mod search_command; pub mod symbols_command; pub mod tabs_command; pub mod term_command; +pub mod workflow_command; pub(crate) struct SlashCommandCompletionProvider { cancel_flag: Mutex>, diff --git a/crates/assistant/src/slash_command/workflow_command.rs b/crates/assistant/src/slash_command/workflow_command.rs new file mode 100644 index 00000000000000..f55275f0114905 --- /dev/null +++ b/crates/assistant/src/slash_command/workflow_command.rs @@ -0,0 +1,71 @@ +use std::sync::atomic::AtomicBool; +use std::sync::Arc; + +use anyhow::{Context as _, Result}; +use assets::Assets; +use assistant_slash_command::{ + ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, +}; +use gpui::{AppContext, AssetSource, Task, WeakView}; +use language::LspAdapterDelegate; +use text::LineEnding; +use ui::prelude::*; +use workspace::Workspace; + +pub(crate) struct WorkflowSlashCommand; + +impl SlashCommand for WorkflowSlashCommand { + fn name(&self) -> String { + "workflow".into() + } + + fn description(&self) -> String { + "insert a prompt that opts into the edit workflow".into() + } + + fn menu_text(&self) -> String { + "Insert Workflow Prompt".into() + } + + fn requires_argument(&self) -> bool { + false + } + + fn complete_argument( + self: Arc, + _query: String, + _cancel: Arc, + _workspace: Option>, + _cx: &mut AppContext, + ) -> Task>> { + Task::ready(Ok(Vec::new())) + } + + fn run( + self: Arc, + _argument: Option<&str>, + _workspace: WeakView, + _delegate: Option>, + _cx: &mut WindowContext, + ) -> Task> { + let mut text = match Assets + .load("prompts/edit_workflow.md") + .and_then(|prompt| prompt.context("prompts/edit_workflow.md not found")) + { + Ok(prompt) => String::from_utf8_lossy(&prompt).into_owned(), + Err(error) => return Task::ready(Err(error)), + }; + LineEnding::normalize(&mut text); + let range = 0..text.len(); + + Task::ready(Ok(SlashCommandOutput { + text, + sections: vec![SlashCommandOutputSection { + range, + icon: IconName::Route, + label: "Workflow".into(), + }], + run_commands_in_text: false, + })) + } +} diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index fdcdeafa01bad6..4ef5e0574e1bac 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -223,6 +223,7 @@ pub enum IconName { Rerun, Return, Reveal, + Route, RotateCcw, RotateCw, Save, @@ -385,6 +386,7 @@ impl IconName { IconName::Reveal => "icons/reveal.svg", IconName::RotateCcw => "icons/rotate_ccw.svg", IconName::RotateCw => "icons/rotate_cw.svg", + IconName::Route => "icons/route.svg", IconName::Save => "icons/save.svg", IconName::Screen => "icons/desktop.svg", IconName::SearchSelection => "icons/search_selection.svg",