Do not serialize workspace for item activations with no focus changes (#22891)

Kirill Bulatov created

Follow-up of https://github.com/zed-industries/zed/pull/22730

Fixes excessive workspace serialization, when scrolling over outline
items in the outline panel: the panel will move the caret (selection)
over the file, following its outlines, causing the same item to be
re-activated over and over.


https://github.com/zed-industries/zed/blob/7a7cef2dd1085ba93bae29711f0adff8969e8bdf/crates/workspace/src/persistence/model.rs#L257-L268

does not seem to use position within an item, just the fact whether the
item is active or not:


https://github.com/zed-industries/zed/blob/7a7cef2dd1085ba93bae29711f0adff8969e8bdf/crates/workspace/src/persistence/model.rs#L511-L517

so, stop serializing the workspace state if no focus changes were made,
or the pane activated is the same.

Release Notes:

- N/A

Change summary

crates/assistant/src/assistant_panel.rs |  2 +-
crates/workspace/src/pane.rs            | 11 +++++++----
crates/workspace/src/workspace.rs       |  6 +++++-
3 files changed, 13 insertions(+), 6 deletions(-)

Detailed changes

crates/assistant/src/assistant_panel.rs 🔗

@@ -595,7 +595,7 @@ impl AssistantPanel {
                 true
             }
 
-            pane::Event::ActivateItem { local } => {
+            pane::Event::ActivateItem { local, .. } => {
                 if *local {
                     self.workspace
                         .update(cx, |workspace, cx| {

crates/workspace/src/pane.rs 🔗

@@ -206,6 +206,7 @@ pub enum Event {
     },
     ActivateItem {
         local: bool,
+        focus_changed: bool,
     },
     Remove {
         focus_on_pane: Option<View<Pane>>,
@@ -236,7 +237,7 @@ impl fmt::Debug for Event {
                 .debug_struct("AddItem")
                 .field("item", &item.item_id())
                 .finish(),
-            Event::ActivateItem { local } => f
+            Event::ActivateItem { local, .. } => f
                 .debug_struct("ActivateItem")
                 .field("local", local)
                 .finish(),
@@ -1092,9 +1093,6 @@ impl Pane {
                     prev_item.deactivated(cx);
                 }
             }
-            cx.emit(Event::ActivateItem {
-                local: activate_pane,
-            });
 
             if let Some(newly_active_item) = self.items.get(index) {
                 self.activation_history
@@ -1114,6 +1112,11 @@ impl Pane {
                 self.focus_active_item(cx);
             }
 
+            cx.emit(Event::ActivateItem {
+                local: activate_pane,
+                focus_changed: focus_item,
+            });
+
             if !self.is_tab_pinned(index) {
                 self.tab_bar_scroll_handle
                     .scroll_to_item(index - self.pinned_tab_count);

crates/workspace/src/workspace.rs 🔗

@@ -3101,7 +3101,10 @@ impl Workspace {
             pane::Event::Remove { focus_on_pane } => {
                 self.remove_pane(pane, focus_on_pane.clone(), cx);
             }
-            pane::Event::ActivateItem { local } => {
+            pane::Event::ActivateItem {
+                local,
+                focus_changed,
+            } => {
                 cx.on_next_frame(|_, cx| {
                     cx.invalidate_character_coordinates();
                 });
@@ -3116,6 +3119,7 @@ impl Workspace {
                     self.active_item_path_changed(cx);
                     self.update_active_view_for_followers(cx);
                 }
+                serialize_workspace = *focus_changed || &pane != self.active_pane();
             }
             pane::Event::UserSavedItem { item, save_intent } => {
                 cx.emit(Event::UserSavedItem {