debugger: Fix typing in active buffer resulting a jump to an active debug line (#27439)

Piotr Osiewicz and Anthony Eid created

/cc @iamnbutler 

Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>

Change summary

crates/assistant_context_editor/src/context_editor.rs | 11 +--
crates/editor/src/editor.rs                           |  5 
crates/editor/src/scroll/autoscroll.rs                | 43 +++++++++---
crates/markdown_preview/src/markdown_preview_view.rs  | 11 +--
crates/outline_panel/src/outline_panel.rs             |  2 
5 files changed, 42 insertions(+), 30 deletions(-)

Detailed changes

crates/assistant_context_editor/src/context_editor.rs 🔗

@@ -13,7 +13,7 @@ use editor::{
         BlockContext, BlockId, BlockPlacement, BlockProperties, BlockStyle, Crease, CreaseMetadata,
         CustomBlockId, FoldId, RenderBlock, ToDisplayPoint,
     },
-    scroll::{Autoscroll, AutoscrollStrategy},
+    scroll::Autoscroll,
     Anchor, Editor, EditorEvent, MenuInlineCompletionsPolicy, ProposedChangeLocation,
     ProposedChangesEditor, RowExt, ToOffset as _, ToPoint,
 };
@@ -414,12 +414,9 @@ impl ContextEditor {
                 cursor..cursor
             };
             self.editor.update(cx, |editor, cx| {
-                editor.change_selections(
-                    Some(Autoscroll::Strategy(AutoscrollStrategy::Fit)),
-                    window,
-                    cx,
-                    |selections| selections.select_ranges([new_selection]),
-                );
+                editor.change_selections(Some(Autoscroll::fit()), window, cx, |selections| {
+                    selections.select_ranges([new_selection])
+                });
             });
             // Avoid scrolling to the new cursor position so the assistant's output is stable.
             cx.defer_in(window, |this, _, _| this.scroll_position = None);

crates/editor/src/editor.rs 🔗

@@ -12644,15 +12644,14 @@ impl Editor {
         let start = snapshot.buffer_snapshot.anchor_before(start);
         let end = snapshot.buffer_snapshot.anchor_before(end);
 
-        self.clear_row_highlights::<T>();
         self.highlight_rows::<T>(
             start..end,
             highlight_color
                 .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
-            true,
+            false,
             cx,
         );
-        self.request_autoscroll(Autoscroll::center(), cx);
+        self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
     }
 
     pub fn go_to_definition(

crates/editor/src/scroll/autoscroll.rs 🔗

@@ -3,54 +3,66 @@ use crate::{
 };
 use gpui::{px, Bounds, Context, Pixels, Window};
 use language::Point;
+use multi_buffer::Anchor;
 use std::{cmp, f32};
 
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub enum Autoscroll {
     Next,
-    Strategy(AutoscrollStrategy),
+    Strategy(AutoscrollStrategy, Option<Anchor>),
 }
 
 impl Autoscroll {
     /// scrolls the minimal amount to (try) and fit all cursors onscreen
     pub fn fit() -> Self {
-        Self::Strategy(AutoscrollStrategy::Fit)
+        Self::Strategy(AutoscrollStrategy::Fit, None)
     }
 
     /// scrolls the minimal amount to fit the newest cursor
     pub fn newest() -> Self {
-        Self::Strategy(AutoscrollStrategy::Newest)
+        Self::Strategy(AutoscrollStrategy::Newest, None)
     }
 
     /// scrolls so the newest cursor is vertically centered
     pub fn center() -> Self {
-        Self::Strategy(AutoscrollStrategy::Center)
+        Self::Strategy(AutoscrollStrategy::Center, None)
     }
 
     /// scrolls so the newest cursor is near the top
     /// (offset by vertical_scroll_margin)
     pub fn focused() -> Self {
-        Self::Strategy(AutoscrollStrategy::Focused)
+        Self::Strategy(AutoscrollStrategy::Focused, None)
     }
 
     /// Scrolls so that the newest cursor is roughly an n-th line from the top.
     pub fn top_relative(n: usize) -> Self {
-        Self::Strategy(AutoscrollStrategy::TopRelative(n))
+        Self::Strategy(AutoscrollStrategy::TopRelative(n), None)
     }
 
     /// Scrolls so that the newest cursor is at the top.
     pub fn top() -> Self {
-        Self::Strategy(AutoscrollStrategy::Top)
+        Self::Strategy(AutoscrollStrategy::Top, None)
     }
 
     /// Scrolls so that the newest cursor is roughly an n-th line from the bottom.
     pub fn bottom_relative(n: usize) -> Self {
-        Self::Strategy(AutoscrollStrategy::BottomRelative(n))
+        Self::Strategy(AutoscrollStrategy::BottomRelative(n), None)
     }
 
     /// Scrolls so that the newest cursor is at the bottom.
     pub fn bottom() -> Self {
-        Self::Strategy(AutoscrollStrategy::Bottom)
+        Self::Strategy(AutoscrollStrategy::Bottom, None)
+    }
+
+    /// Applies a given auto-scroll strategy to a given anchor instead of a cursor.
+    /// E.G: Autoscroll::center().for_anchor(...) results in the anchor being at the center of the screen.
+    pub fn for_anchor(self, anchor: Anchor) -> Self {
+        match self {
+            Autoscroll::Next => self,
+            Autoscroll::Strategy(autoscroll_strategy, _) => {
+                Self::Strategy(autoscroll_strategy, Some(anchor))
+            }
+        }
     }
 }
 
@@ -142,8 +154,11 @@ impl Editor {
                 .as_f32();
 
             let selections_fit = target_bottom - target_top <= visible_lines;
-            if autoscroll == Autoscroll::newest()
-                || (autoscroll == Autoscroll::fit() && !selections_fit)
+            if matches!(
+                autoscroll,
+                Autoscroll::Strategy(AutoscrollStrategy::Newest, _)
+            ) || (matches!(autoscroll, Autoscroll::Strategy(AutoscrollStrategy::Fit, _))
+                && !selections_fit)
             {
                 let newest_selection_top = selections
                     .iter()
@@ -165,7 +180,7 @@ impl Editor {
         };
 
         let strategy = match autoscroll {
-            Autoscroll::Strategy(strategy) => strategy,
+            Autoscroll::Strategy(strategy, _) => strategy,
             Autoscroll::Next => {
                 let last_autoscroll = &self.scroll_manager.last_autoscroll;
                 if let Some(last_autoscroll) = last_autoscroll {
@@ -182,6 +197,10 @@ impl Editor {
                 }
             }
         };
+        if let Autoscroll::Strategy(_, Some(anchor)) = autoscroll {
+            target_top = anchor.to_display_point(&display_map).row().as_f32();
+            target_bottom = target_top + 1.;
+        }
 
         match strategy {
             AutoscrollStrategy::Fit | AutoscrollStrategy::Newest => {

crates/markdown_preview/src/markdown_preview_view.rs 🔗

@@ -3,7 +3,7 @@ use std::time::Duration;
 use std::{ops::Range, path::PathBuf};
 
 use anyhow::Result;
-use editor::scroll::{Autoscroll, AutoscrollStrategy};
+use editor::scroll::Autoscroll;
 use editor::{Editor, EditorEvent};
 use gpui::{
     list, App, ClickEvent, Context, Entity, EventEmitter, FocusHandle, Focusable,
@@ -408,12 +408,9 @@ impl MarkdownPreviewView {
     ) {
         if let Some(state) = &self.active_editor {
             state.editor.update(cx, |editor, cx| {
-                editor.change_selections(
-                    Some(Autoscroll::Strategy(AutoscrollStrategy::Center)),
-                    window,
-                    cx,
-                    |selections| selections.select_ranges(vec![selection]),
-                );
+                editor.change_selections(Some(Autoscroll::center()), window, cx, |selections| {
+                    selections.select_ranges(vec![selection])
+                });
                 window.focus(&editor.focus_handle(cx));
             });
         }

crates/outline_panel/src/outline_panel.rs 🔗

@@ -1067,7 +1067,7 @@ impl OutlinePanel {
                 if change_selection {
                     active_editor.update(cx, |editor, cx| {
                         editor.change_selections(
-                            Some(Autoscroll::Strategy(AutoscrollStrategy::Center)),
+                            Some(Autoscroll::Strategy(AutoscrollStrategy::Center, None)),
                             window,
                             cx,
                             |s| s.select_ranges(Some(anchor..anchor)),