diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 37cb5213cbaedd6b58c7629731a5e797e46f2e62..8b7e829efebe2cf568163d7384e855a6f6812cae 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -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 = 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, } +struct LineNumberLayout { + segments: Vec, +} + struct ColoredRange { start: T, end: T,