Draw gutter highlights and indicators on top of blocks (#13142)

Antonio Scandurra created

This ensures that the gutter progress in the inline assistant is
contiguous.

Release Notes:

- N/A

Change summary

crates/assistant/src/inline_assistant.rs | 36 +++++---
crates/editor/src/editor.rs              |  2 
crates/editor/src/element.rs             | 99 ++++++++++++-------------
3 files changed, 73 insertions(+), 64 deletions(-)

Detailed changes

crates/assistant/src/inline_assistant.rs 🔗

@@ -335,24 +335,32 @@ impl InlineAssistant {
 
         let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
         let assist_range = assist.codegen.read(cx).range().to_offset(&buffer);
-        let editor = editor.read(cx);
-        if let Some(decorations) = assist.editor_decorations.as_ref() {
-            if editor.selections.count() == 1 {
-                let selection = editor.selections.newest::<usize>(cx);
-                if assist_range.contains(&selection.start) && assist_range.contains(&selection.end)
-                {
-                    decorations.prompt_editor.update(cx, |prompt_editor, cx| {
-                        prompt_editor.editor.update(cx, |editor, cx| {
-                            editor.select_all(&SelectAll, cx);
-                            editor.focus(cx);
+        let propagate = editor.update(cx, |editor, cx| {
+            if let Some(decorations) = assist.editor_decorations.as_ref() {
+                if editor.selections.count() == 1 {
+                    let selection = editor.selections.newest::<usize>(cx);
+                    if assist_range.contains(&selection.start)
+                        && assist_range.contains(&selection.end)
+                    {
+                        editor.change_selections(Some(Autoscroll::newest()), cx, |selections| {
+                            selections.select_ranges([assist_range.start..assist_range.start]);
                         });
-                    });
-                    return;
+                        decorations.prompt_editor.update(cx, |prompt_editor, cx| {
+                            prompt_editor.editor.update(cx, |prompt_editor, cx| {
+                                prompt_editor.select_all(&SelectAll, cx);
+                                prompt_editor.focus(cx);
+                            });
+                        });
+                        return false;
+                    }
                 }
             }
-        }
+            true
+        });
 
-        cx.propagate();
+        if propagate {
+            cx.propagate();
+        }
     }
 
     fn handle_editor_event(

crates/editor/src/editor.rs 🔗

@@ -2497,6 +2497,7 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         if !self.focus_handle.is_focused(cx) {
+            self.last_focused_descendant = None;
             cx.focus(&self.focus_handle);
         }
 
@@ -2564,6 +2565,7 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         if !self.focus_handle.is_focused(cx) {
+            self.last_focused_descendant = None;
             cx.focus(&self.focus_handle);
         }
 

crates/editor/src/element.rs 🔗

@@ -2810,38 +2810,12 @@ impl EditorElement {
         }
     }
 
-    fn paint_gutter(&mut self, layout: &mut EditorLayout, cx: &mut WindowContext) {
+    fn paint_line_numbers(&mut self, layout: &mut EditorLayout, cx: &mut WindowContext) {
         let line_height = layout.position_map.line_height;
-
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let scroll_top = scroll_position.y * line_height;
 
         cx.set_cursor_style(CursorStyle::Arrow, &layout.gutter_hitbox);
-        for (_, hunk_hitbox) in &layout.display_hunks {
-            if let Some(hunk_hitbox) = hunk_hitbox {
-                cx.set_cursor_style(CursorStyle::PointingHand, hunk_hitbox);
-            }
-        }
-
-        let show_git_gutter = layout
-            .position_map
-            .snapshot
-            .show_git_diff_gutter
-            .unwrap_or_else(|| {
-                matches!(
-                    ProjectSettings::get_global(cx).git.git_gutter,
-                    Some(GitGutterSetting::TrackedFiles)
-                )
-            });
-        if show_git_gutter {
-            Self::paint_diff_hunks(layout.gutter_hitbox.bounds, layout, cx)
-        }
-
-        self.paint_gutter_highlights(layout, cx);
-
-        if layout.blamed_display_rows.is_some() {
-            self.paint_blamed_display_rows(layout, cx);
-        }
 
         for (ix, line) in layout.line_numbers.iter().enumerate() {
             if let Some(line) = line {
@@ -2856,29 +2830,9 @@ impl EditorElement {
                 line.paint(line_origin, line_height, cx).log_err();
             }
         }
-
-        cx.paint_layer(layout.gutter_hitbox.bounds, |cx| {
-            cx.with_element_namespace("gutter_fold_toggles", |cx| {
-                for fold_indicator in layout.gutter_fold_toggles.iter_mut().flatten() {
-                    fold_indicator.paint(cx);
-                }
-            });
-
-            for test_indicators in layout.test_indicators.iter_mut() {
-                test_indicators.paint(cx);
-            }
-
-            if let Some(indicator) = layout.code_actions_indicator.as_mut() {
-                indicator.paint(cx);
-            }
-        });
     }
 
-    fn paint_diff_hunks(
-        gutter_bounds: Bounds<Pixels>,
-        layout: &EditorLayout,
-        cx: &mut WindowContext,
-    ) {
+    fn paint_diff_hunks(layout: &EditorLayout, cx: &mut WindowContext) {
         if layout.display_hunks.is_empty() {
             return;
         }
@@ -2891,7 +2845,7 @@ impl EditorElement {
                         let hunk_bounds = Self::diff_hunk_bounds(
                             &layout.position_map.snapshot,
                             line_height,
-                            gutter_bounds,
+                            layout.gutter_hitbox.bounds,
                             &hunk,
                         );
                         Some((
@@ -3008,7 +2962,45 @@ impl EditorElement {
         }
     }
 
+    fn paint_gutter_indicators(&self, layout: &mut EditorLayout, cx: &mut WindowContext) {
+        cx.paint_layer(layout.gutter_hitbox.bounds, |cx| {
+            cx.with_element_namespace("gutter_fold_toggles", |cx| {
+                for fold_indicator in layout.gutter_fold_toggles.iter_mut().flatten() {
+                    fold_indicator.paint(cx);
+                }
+            });
+
+            for test_indicators in layout.test_indicators.iter_mut() {
+                test_indicators.paint(cx);
+            }
+
+            if let Some(indicator) = layout.code_actions_indicator.as_mut() {
+                indicator.paint(cx);
+            }
+        });
+    }
+
     fn paint_gutter_highlights(&self, layout: &EditorLayout, cx: &mut WindowContext) {
+        for (_, hunk_hitbox) in &layout.display_hunks {
+            if let Some(hunk_hitbox) = hunk_hitbox {
+                cx.set_cursor_style(CursorStyle::PointingHand, hunk_hitbox);
+            }
+        }
+
+        let show_git_gutter = layout
+            .position_map
+            .snapshot
+            .show_git_diff_gutter
+            .unwrap_or_else(|| {
+                matches!(
+                    ProjectSettings::get_global(cx).git.git_gutter,
+                    Some(GitGutterSetting::TrackedFiles)
+                )
+            });
+        if show_git_gutter {
+            Self::paint_diff_hunks(layout, cx)
+        }
+
         let highlight_width = 0.275 * layout.position_map.line_height;
         let highlight_corner_radii = Corners::all(0.05 * layout.position_map.line_height);
         cx.paint_layer(layout.gutter_hitbox.bounds, |cx| {
@@ -5112,8 +5104,10 @@ impl Element for EditorElement {
                     self.paint_mouse_listeners(layout, hovered_hunk, cx);
                     self.paint_background(layout, cx);
                     self.paint_indent_guides(layout, cx);
+
                     if layout.gutter_hitbox.size.width > Pixels::ZERO {
-                        self.paint_gutter(layout, cx)
+                        self.paint_blamed_display_rows(layout, cx);
+                        self.paint_line_numbers(layout, cx);
                     }
 
                     self.paint_text(layout, cx);
@@ -5124,6 +5118,11 @@ impl Element for EditorElement {
                         });
                     }
 
+                    if layout.gutter_hitbox.size.width > Pixels::ZERO {
+                        self.paint_gutter_highlights(layout, cx);
+                        self.paint_gutter_indicators(layout, cx);
+                    }
+
                     self.paint_scrollbar(layout, cx);
                     self.paint_mouse_context_menu(layout, cx);
                 });