@@ -763,8 +763,14 @@ impl EditorElement {
.row;
if line_numbers
.get(&MultiBufferRow(multi_buffer_row))
- .and_then(|line_number| line_number.hitbox.as_ref())
- .is_some_and(|hitbox| hitbox.contains(&event.position))
+ .is_some_and(|line_layout| {
+ line_layout.segments.iter().any(|segment| {
+ segment
+ .hitbox
+ .as_ref()
+ .is_some_and(|hitbox| hitbox.contains(&event.position))
+ })
+ })
{
let line_offset_from_top = display_row - position_map.scroll_position.y as u32;
@@ -3249,70 +3255,79 @@ impl EditorElement {
let relative_rows =
self.calculate_relative_line_numbers(snapshot, &rows, relative_to, true);
let mut line_number = String::new();
- let line_numbers = buffer_rows
- .iter()
- .enumerate()
- .flat_map(|(ix, row_info)| {
- let display_row = DisplayRow(rows.start.0 + ix as u32);
- line_number.clear();
- let number = if let Some(relative_number) = relative_rows.get(&display_row) {
- *relative_number
- } else {
- row_info.buffer_row? + 1
- };
-
- write!(&mut line_number, "{number}").unwrap();
- if row_info
- .diff_status
- .is_some_and(|status| status.is_deleted())
- {
- return None;
- }
+ let segments = buffer_rows.iter().enumerate().flat_map(|(ix, row_info)| {
+ let display_row = DisplayRow(rows.start.0 + ix as u32);
+ line_number.clear();
+ let number = if let Some(relative_number) = relative_rows.get(&display_row) {
+ *relative_number
+ } else {
+ row_info.buffer_row? + 1
+ };
- let color = active_rows
- .get(&display_row)
- .map(|spec| {
- if spec.breakpoint {
- cx.theme().colors().debugger_accent
- } else {
- cx.theme().colors().editor_active_line_number
- }
- })
- .unwrap_or_else(|| cx.theme().colors().editor_line_number);
- let shaped_line =
- self.shape_line_number(SharedString::from(&line_number), color, window);
- let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
- let line_origin = gutter_hitbox.map(|hitbox| {
- hitbox.origin
- + point(
- hitbox.size.width - shaped_line.width - gutter_dimensions.right_padding,
- ix as f32 * line_height
- - Pixels::from(scroll_top % ScrollPixelOffset::from(line_height)),
- )
- });
+ write!(&mut line_number, "{number}").unwrap();
+ if row_info
+ .diff_status
+ .is_some_and(|status| status.is_deleted())
+ {
+ return None;
+ }
- #[cfg(not(test))]
- let hitbox = line_origin.map(|line_origin| {
- window.insert_hitbox(
- Bounds::new(line_origin, size(shaped_line.width, line_height)),
- HitboxBehavior::Normal,
+ let color = active_rows
+ .get(&display_row)
+ .map(|spec| {
+ if spec.breakpoint {
+ cx.theme().colors().debugger_accent
+ } else {
+ cx.theme().colors().editor_active_line_number
+ }
+ })
+ .unwrap_or_else(|| cx.theme().colors().editor_line_number);
+ let shaped_line =
+ self.shape_line_number(SharedString::from(&line_number), color, window);
+ let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
+ let line_origin = gutter_hitbox.map(|hitbox| {
+ hitbox.origin
+ + point(
+ hitbox.size.width - shaped_line.width - gutter_dimensions.right_padding,
+ ix as f32 * line_height
+ - Pixels::from(scroll_top % ScrollPixelOffset::from(line_height)),
)
- });
- #[cfg(test)]
- let hitbox = {
- let _ = line_origin;
- None
- };
+ });
- let multi_buffer_row = DisplayPoint::new(display_row, 0).to_point(snapshot).row;
- let multi_buffer_row = MultiBufferRow(multi_buffer_row);
- let line_number = LineNumberLayout {
- shaped_line,
- hitbox,
- };
- Some((multi_buffer_row, line_number))
- })
- .collect();
+ #[cfg(not(test))]
+ let hitbox = line_origin.map(|line_origin| {
+ window.insert_hitbox(
+ Bounds::new(line_origin, size(shaped_line.width, line_height)),
+ HitboxBehavior::Normal,
+ )
+ });
+ #[cfg(test)]
+ let hitbox = {
+ let _ = line_origin;
+ None
+ };
+
+ let segment = LineNumberSegment {
+ shaped_line,
+ hitbox,
+ };
+
+ let buffer_row = DisplayPoint::new(display_row, 0).to_point(snapshot).row;
+ let multi_buffer_row = MultiBufferRow(buffer_row);
+
+ Some((multi_buffer_row, segment))
+ });
+
+ let mut line_numbers: HashMap<MultiBufferRow, LineNumberLayout> = HashMap::default();
+ for (buffer_row, segment) in segments {
+ line_numbers
+ .entry(buffer_row)
+ .or_insert_with(|| LineNumberLayout {
+ segments: Vec::new(),
+ })
+ .segments
+ .push(segment);
+ }
Arc::new(line_numbers)
}
@@ -5861,34 +5876,36 @@ impl EditorElement {
let line_height = layout.position_map.line_height;
window.set_cursor_style(CursorStyle::Arrow, &layout.gutter_hitbox);
- for LineNumberLayout {
- shaped_line,
- hitbox,
- } in layout.line_numbers.values()
- {
- let Some(hitbox) = hitbox else {
- continue;
- };
+ for line_layout in layout.line_numbers.values() {
+ for LineNumberSegment {
+ shaped_line,
+ hitbox,
+ } in &line_layout.segments
+ {
+ let Some(hitbox) = hitbox else {
+ continue;
+ };
- let Some(()) = (if !is_singleton && hitbox.is_hovered(window) {
- let color = cx.theme().colors().editor_hover_line_number;
+ let Some(()) = (if !is_singleton && hitbox.is_hovered(window) {
+ let color = cx.theme().colors().editor_hover_line_number;
- let line = self.shape_line_number(shaped_line.text.clone(), color, window);
- line.paint(hitbox.origin, line_height, window, cx).log_err()
- } else {
- shaped_line
- .paint(hitbox.origin, line_height, window, cx)
- .log_err()
- }) else {
- continue;
- };
+ let line = self.shape_line_number(shaped_line.text.clone(), color, window);
+ line.paint(hitbox.origin, line_height, window, cx).log_err()
+ } else {
+ shaped_line
+ .paint(hitbox.origin, line_height, window, cx)
+ .log_err()
+ }) else {
+ continue;
+ };
- // In singleton buffers, we select corresponding lines on the line number click, so use | -like cursor.
- // In multi buffers, we open file at the line number clicked, so use a pointing hand cursor.
- if is_singleton {
- window.set_cursor_style(CursorStyle::IBeam, hitbox);
- } else {
- window.set_cursor_style(CursorStyle::PointingHand, hitbox);
+ // In singleton buffers, we select corresponding lines on the line number click, so use | -like cursor.
+ // In multi buffers, we open file at the line number clicked, so use a pointing hand cursor.
+ if is_singleton {
+ window.set_cursor_style(CursorStyle::IBeam, hitbox);
+ } else {
+ window.set_cursor_style(CursorStyle::PointingHand, hitbox);
+ }
}
}
}
@@ -9798,11 +9815,15 @@ impl EditorLayout {
}
}
-struct LineNumberLayout {
+struct LineNumberSegment {
shaped_line: ShapedLine,
hitbox: Option<Hitbox>,
}
+struct LineNumberLayout {
+ segments: Vec<LineNumberSegment>,
+}
+
struct ColoredRange<T> {
start: T,
end: T,