syntax_tree_view: Fix highlights persisting after view was closed (#47638)

Finn Evers created

Also ensured that we clear only the highlights of the current view
(which probably would have been the the case almost always anyway).

Release Notes:

- Fixed a small issue where highlights of the syntax tree view would
persist after the view was closed.

Change summary

crates/editor/src/editor.rs                   | 15 ++++++
crates/editor/src/items.rs                    |  2 
crates/language_tools/src/syntax_tree_view.rs | 49 ++++++++++++++------
crates/workspace/src/item.rs                  |  8 +-
4 files changed, 54 insertions(+), 20 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -23098,6 +23098,21 @@ impl Editor {
         Some(text_highlights)
     }
 
+    pub fn clear_background_highlights_key<T: 'static>(
+        &mut self,
+        key: usize,
+        cx: &mut Context<Self>,
+    ) -> Option<BackgroundHighlight> {
+        let text_highlights = self
+            .background_highlights
+            .remove(&HighlightKey::TypePlus(TypeId::of::<T>(), key))?;
+        if !text_highlights.1.is_empty() {
+            self.scrollbar_marker_state.dirty = true;
+            cx.notify();
+        }
+        Some(text_highlights)
+    }
+
     pub fn highlight_gutter<T: 'static>(
         &mut self,
         ranges: impl Into<Vec<Range<Anchor>>>,

crates/editor/src/items.rs 🔗

@@ -789,7 +789,7 @@ impl Item for Editor {
         self.nav_history = Some(history);
     }
 
-    fn on_removed(&self, cx: &App) {
+    fn on_removed(&self, cx: &mut Context<Self>) {
         self.report_editor_event(ReportEditorEvent::Closed, None, cx);
     }
 

crates/language_tools/src/syntax_tree_view.rs 🔗

@@ -339,7 +339,7 @@ impl SyntaxTreeView {
         descendant_ix: usize,
         window: &mut Window,
         cx: &mut Context<Self>,
-        mut f: impl FnMut(&mut Editor, Range<Anchor>, &mut Window, &mut Context<Editor>),
+        mut f: impl FnMut(&mut Editor, Range<Anchor>, usize, &mut Window, &mut Context<Editor>),
     ) -> Option<()> {
         let editor_state = self.editor.as_ref()?;
         let buffer_state = editor_state.active_buffer.as_ref()?;
@@ -360,10 +360,11 @@ impl SyntaxTreeView {
         let multibuffer = multibuffer.read(cx).snapshot(cx);
         let excerpt_id = buffer_state.excerpt_id;
         let range = multibuffer.anchor_range_in_excerpt(excerpt_id, range)?;
+        let key = cx.entity_id().as_u64() as usize;
 
         // Update the editor with the anchor range.
         editor_state.editor.update(cx, |editor, cx| {
-            f(editor, range, window, cx);
+            f(editor, range, key, window, cx);
         });
         Some(())
     }
@@ -431,7 +432,7 @@ impl SyntaxTreeView {
                                 descendant_ix,
                                 window,
                                 cx,
-                                |editor, mut range, window, cx| {
+                                |editor, mut range, _, window, cx| {
                                     // Put the cursor at the beginning of the node.
                                     mem::swap(&mut range.start, &mut range.end);
 
@@ -440,7 +441,7 @@ impl SyntaxTreeView {
                                         window,
                                         cx,
                                         |selections| {
-                                            selections.select_ranges(vec![range]);
+                                            selections.select_ranges([range]);
                                         },
                                     );
                                 },
@@ -455,17 +456,8 @@ impl SyntaxTreeView {
                                     descendant_ix,
                                     window,
                                     cx,
-                                    |editor, range, _, cx| {
-                                        editor.clear_background_highlights::<Self>(cx);
-                                        editor.highlight_background::<Self>(
-                                            &[range],
-                                            |_, theme| {
-                                                theme
-                                                    .colors()
-                                                    .editor_document_highlight_write_background
-                                            },
-                                            cx,
-                                        );
+                                    |editor, range, key, _, cx| {
+                                        Self::set_editor_highlights(editor, key, &[range], cx);
                                     },
                                 );
                                 cx.notify();
@@ -483,6 +475,27 @@ impl SyntaxTreeView {
         }
         items
     }
+
+    fn set_editor_highlights(
+        editor: &mut Editor,
+        key: usize,
+        ranges: &[Range<Anchor>],
+        cx: &mut Context<Editor>,
+    ) {
+        editor.highlight_background_key::<Self>(
+            key,
+            ranges,
+            |_, theme| theme.colors().editor_document_highlight_write_background,
+            cx,
+        );
+    }
+
+    fn clear_editor_highlights(editor: &Entity<Editor>, cx: &mut Context<Self>) {
+        let highlight_key = cx.entity_id().as_u64() as usize;
+        editor.update(cx, |editor, cx| {
+            editor.clear_background_highlights_key::<Self>(highlight_key, cx);
+        });
+    }
 }
 
 impl Render for SyntaxTreeView {
@@ -589,6 +602,12 @@ impl Item for SyntaxTreeView {
             clone
         })))
     }
+
+    fn on_removed(&self, cx: &mut Context<Self>) {
+        if let Some(state) = self.editor.as_ref() {
+            Self::clear_editor_highlights(&state.editor, cx);
+        }
+    }
 }
 
 impl Default for SyntaxTreeToolbarItemView {

crates/workspace/src/item.rs 🔗

@@ -217,7 +217,7 @@ pub trait Item: Focusable + EventEmitter<Self::Event> + Render + Sized {
 
     fn deactivated(&mut self, _window: &mut Window, _: &mut Context<Self>) {}
     fn discarded(&self, _project: Entity<Project>, _window: &mut Window, _cx: &mut Context<Self>) {}
-    fn on_removed(&self, _cx: &App) {}
+    fn on_removed(&self, _cx: &mut Context<Self>) {}
     fn workspace_deactivated(&mut self, _window: &mut Window, _: &mut Context<Self>) {}
     fn navigate(
         &mut self,
@@ -483,7 +483,7 @@ pub trait ItemHandle: 'static + Send {
         cx: &mut Context<Workspace>,
     );
     fn deactivated(&self, window: &mut Window, cx: &mut App);
-    fn on_removed(&self, cx: &App);
+    fn on_removed(&self, cx: &mut App);
     fn workspace_deactivated(&self, window: &mut Window, cx: &mut App);
     fn navigate(&self, data: Arc<dyn Any + Send>, window: &mut Window, cx: &mut App) -> bool;
     fn item_id(&self) -> EntityId;
@@ -941,8 +941,8 @@ impl<T: Item> ItemHandle for Entity<T> {
         self.update(cx, |this, cx| this.deactivated(window, cx));
     }
 
-    fn on_removed(&self, cx: &App) {
-        self.read(cx).on_removed(cx);
+    fn on_removed(&self, cx: &mut App) {
+        self.update(cx, |item, cx| item.on_removed(cx));
     }
 
     fn workspace_deactivated(&self, window: &mut Window, cx: &mut App) {