From a15a9565abeb43f4c77d7d2ced66a42d5aec608d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 12 Aug 2024 15:16:55 +0200 Subject: [PATCH] Accept finished inline transformations only if the user saves manually (#16112) Closes https://github.com/zed-industries/zed/issues/16042 This commit modifies the behavior of inline transformations to only accept finished transformations when the user manually saves the file. Previously, transformations were automatically accepted on any save event, including autosaves. This was achieved by updating the `Pane` and `Workspace` structs to emit a new `UserSavedItem` event when a manual save occurs, and modifying the `InlineAssistant` to register and handle this new event (instead of `editor::Saved`). Release Notes: - N/A --- crates/assistant/src/inline_assistant.rs | 38 +++++++++++++++++++----- crates/workspace/src/item.rs | 5 ++++ crates/workspace/src/pane.rs | 33 ++++++++++++++++---- crates/workspace/src/workspace.rs | 12 +++++++- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/crates/assistant/src/inline_assistant.rs b/crates/assistant/src/inline_assistant.rs index a6e71fc40b43ae80004dcf50bf630a71dc11f777..2ec7d154e36cb87fd4b144cb18b51fd153446555 100644 --- a/crates/assistant/src/inline_assistant.rs +++ b/crates/assistant/src/inline_assistant.rs @@ -58,6 +58,13 @@ pub fn init( cx: &mut AppContext, ) { cx.set_global(InlineAssistant::new(fs, prompt_builder, telemetry)); + cx.observe_new_views(|_, cx| { + let workspace = cx.view().clone(); + InlineAssistant::update_global(cx, |inline_assistant, cx| { + inline_assistant.register_workspace(&workspace, cx) + }) + }) + .detach(); } const PROMPT_HISTORY_MAX_LEN: usize = 20; @@ -100,6 +107,29 @@ impl InlineAssistant { } } + pub fn register_workspace(&mut self, workspace: &View, cx: &mut WindowContext) { + cx.subscribe(workspace, |_, event, cx| { + Self::update_global(cx, |this, cx| this.handle_workspace_event(event, cx)); + }) + .detach(); + } + + fn handle_workspace_event(&mut self, event: &workspace::Event, cx: &mut WindowContext) { + // When the user manually saves an editor, automatically accepts all finished transformations. + if let workspace::Event::UserSavedItem { item, .. } = event { + if let Some(editor) = item.upgrade().and_then(|item| item.act_as::(cx)) { + if let Some(editor_assists) = self.assists_by_editor.get(&editor.downgrade()) { + for assist_id in editor_assists.assist_ids.clone() { + let assist = &self.assists[&assist_id]; + if let CodegenStatus::Done = &assist.codegen.read(cx).status { + self.finish_assist(assist_id, false, cx) + } + } + } + } + } + } + pub fn assist( &mut self, editor: &View, @@ -558,14 +588,6 @@ impl InlineAssistant { }; match event { - EditorEvent::Saved => { - for assist_id in editor_assists.assist_ids.clone() { - let assist = &self.assists[&assist_id]; - if let CodegenStatus::Done = &assist.codegen.read(cx).status { - self.finish_assist(assist_id, false, cx) - } - } - } EditorEvent::Edited { transaction_id } => { let buffer = editor.read(cx).buffer().read(cx); let edited_ranges = diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 7e66e4835856d1444e10a1383e655cab9660c438..6ea8be830d382b4abbcb1f3a4829cb78f9c260eb 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -436,6 +436,7 @@ pub trait ItemHandle: 'static + Send { pub trait WeakItemHandle: Send + Sync { fn id(&self) -> EntityId; + fn boxed_clone(&self) -> Box; fn upgrade(&self) -> Option>; } @@ -852,6 +853,10 @@ impl WeakItemHandle for WeakView { self.entity_id() } + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + fn upgrade(&self) -> Option> { self.upgrade().map(|v| Box::new(v) as Box) } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 8ee5ef7a3e6db65b9dd1a70e1476fd63f54c002e..38c368074b0dbc89518c5d615365d4560d1f2d23 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -166,16 +166,28 @@ impl DeploySearch { const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; pub enum Event { - AddItem { item: Box }, - ActivateItem { local: bool }, + AddItem { + item: Box, + }, + ActivateItem { + local: bool, + }, Remove, - RemoveItem { idx: usize }, - RemovedItem { item_id: EntityId }, + RemoveItem { + idx: usize, + }, + RemovedItem { + item_id: EntityId, + }, Split(SplitDirection), ChangeItemTitle, Focus, ZoomIn, ZoomOut, + UserSavedItem { + item: Box, + save_intent: SaveIntent, + }, } impl fmt::Debug for Event { @@ -203,6 +215,11 @@ impl fmt::Debug for Event { Event::Focus => f.write_str("Focus"), Event::ZoomIn => f.write_str("ZoomIn"), Event::ZoomOut => f.write_str("ZoomOut"), + Event::UserSavedItem { item, save_intent } => f + .debug_struct("UserSavedItem") + .field("item", &item.id()) + .field("save_intent", save_intent) + .finish(), } } } @@ -1494,7 +1511,13 @@ impl Pane { } } - Ok(true) + pane.update(cx, |_, cx| { + cx.emit(Event::UserSavedItem { + item: item.downgrade_item(), + save_intent, + }); + true + }) } fn can_autosave_item(item: &dyn ItemHandle, cx: &AppContext) -> bool { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index db375d0d315255103d7024da9bd48d2e951469a4..643473f7dccfb4dd742ebbc4c547911ee01d7ea9 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -40,7 +40,7 @@ use gpui::{ }; use item::{ FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings, - ProjectItem, SerializableItem, SerializableItemHandle, + ProjectItem, SerializableItem, SerializableItemHandle, WeakItemHandle, }; use itertools::Itertools; use language::{LanguageRegistry, Rope}; @@ -670,6 +670,11 @@ pub enum Event { ItemAdded, ItemRemoved, ActiveItemChanged, + UserSavedItem { + pane: WeakView, + item: Box, + save_intent: SaveIntent, + }, ContactRequestedJoin(u64), WorkspaceCreated(WeakView), SpawnTask(Box), @@ -2934,6 +2939,11 @@ impl Workspace { self.update_active_view_for_followers(cx); } } + pane::Event::UserSavedItem { item, save_intent } => cx.emit(Event::UserSavedItem { + pane: pane.downgrade(), + item: item.boxed_clone(), + save_intent: *save_intent, + }), pane::Event::ChangeItemTitle => { if pane == self.active_pane { self.active_item_path_changed(cx);