editor: Improve line number to use shape_line method. (#1265)

This commit is contained in:
Jason Lee 2025-09-19 19:23:57 +08:00 committed by GitHub
parent d3d2a9ee49
commit 7e9606369e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3,8 +3,8 @@ use std::{ops::Range, rc::Rc};
use gpui::{ use gpui::{
fill, point, px, relative, size, App, Bounds, Corners, Element, ElementId, ElementInputHandler, fill, point, px, relative, size, App, Bounds, Corners, Element, ElementId, ElementInputHandler,
Entity, GlobalElementId, Half, HighlightStyle, Hitbox, IntoElement, LayoutId, MouseButton, Entity, GlobalElementId, Half, HighlightStyle, Hitbox, IntoElement, LayoutId, MouseButton,
MouseMoveEvent, Path, Pixels, Point, SharedString, Size, Style, TextAlign, TextRun, MouseMoveEvent, Path, Pixels, Point, ShapedLine, SharedString, Size, Style, TextAlign, TextRun,
UnderlineStyle, Window, WrappedLine, UnderlineStyle, Window,
}; };
use rope::Rope; use rope::Rope;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -533,7 +533,9 @@ pub(super) struct PrepaintState {
/// The lines of entire lines. /// The lines of entire lines.
last_layout: LastLayout, last_layout: LastLayout,
/// The lines only contains the visible lines in the viewport, based on `visible_range`. /// The lines only contains the visible lines in the viewport, based on `visible_range`.
line_numbers: Option<Vec<SmallVec<[WrappedLine; 1]>>>, ///
/// The child is the soft lines.
line_numbers: Option<Vec<SmallVec<[ShapedLine; 1]>>>,
/// Size of the scrollable area by entire lines. /// Size of the scrollable area by entire lines.
scroll_size: Size<Pixels>, scroll_size: Size<Pixels>,
cursor_bounds: Option<Bounds<Pixels>>, cursor_bounds: Option<Bounds<Pixels>>,
@ -876,7 +878,7 @@ impl Element for TextElement {
let state = self.state.read(cx); let state = self.state.read(cx);
let line_numbers = if state.mode.line_number() { let line_numbers = if state.mode.line_number() {
let mut line_numbers = vec![]; let mut line_numbers = vec![];
let run_len = 4; let run_len = 6;
let other_line_runs = vec![TextRun { let other_line_runs = vec![TextRun {
len: run_len, len: run_len,
font: style.font(), font: style.font(),
@ -897,12 +899,7 @@ impl Element for TextElement {
// build line numbers // build line numbers
for (ix, line) in last_layout.lines.iter().enumerate() { for (ix, line) in last_layout.lines.iter().enumerate() {
let ix = last_layout.visible_range.start + ix; let ix = last_layout.visible_range.start + ix;
let line_no = ix + 1; let line_no_text = format!("{:>6}", ix + 1);
let mut line_no_text = format!("{:>6}", line_no);
if !line.wrap_boundaries.is_empty() {
line_no_text.push_str(&"\n ".repeat(line.wrap_boundaries.len()));
}
let runs = if current_row == Some(ix) { let runs = if current_row == Some(ix) {
&current_line_runs &current_line_runs
@ -910,11 +907,17 @@ impl Element for TextElement {
&other_line_runs &other_line_runs
}; };
let shape_line = window let mut sub_lines: SmallVec<[ShapedLine; 1]> = SmallVec::new();
.text_system() sub_lines.push(window.text_system().shape_line(
.shape_text(line_no_text.into(), font_size, &runs, None, None) line_no_text.into(),
.unwrap(); font_size,
line_numbers.push(shape_line); &runs,
None,
));
for _ in 0..line.wrap_boundaries.len() {
sub_lines.push(ShapedLine::default());
}
line_numbers.push(sub_lines);
} }
Some(line_numbers) Some(line_numbers)
} else { } else {
@ -1012,20 +1015,18 @@ impl Element for TextElement {
for (ix, lines) in line_numbers.iter().enumerate() { for (ix, lines) in line_numbers.iter().enumerate() {
let row = visible_range.start + ix; let row = visible_range.start + ix;
let is_active = prepaint.current_row == Some(row); let is_active = prepaint.current_row == Some(row);
for line in lines { let p = point(input_bounds.origin.x, origin.y + offset_y);
let p = point(input_bounds.origin.x, origin.y + offset_y); let height = line_height * lines.len() as f32;
let line_size = line.size(line_height); // Paint the current line background
// Paint the current line background if is_active {
if is_active { if let Some(bg_color) = active_line_color {
if let Some(bg_color) = active_line_color { window.paint_quad(fill(
window.paint_quad(fill( Bounds::new(p, size(bounds.size.width, height)),
Bounds::new(p, size(bounds.size.width, line_height)), bg_color,
bg_color, ));
));
}
} }
offset_y += line_size.height;
} }
offset_y += height;
} }
} }
@ -1089,27 +1090,24 @@ impl Element for TextElement {
// Each item is the normal lines. // Each item is the normal lines.
for (ix, lines) in line_numbers.iter().enumerate() { for (ix, lines) in line_numbers.iter().enumerate() {
let row = visible_range.start + ix; let row = visible_range.start + ix;
for line in lines {
let p = point(input_bounds.origin.x, origin.y + offset_y);
let is_active = prepaint.current_row == Some(row); let p = point(input_bounds.origin.x, origin.y + offset_y);
let line_size = line.size(line_height); let is_active = prepaint.current_row == Some(row);
// paint active line number background let height = line_height * lines.len() as f32;
if is_active { // paint active line number background
if let Some(bg_color) = active_line_color { if is_active {
window.paint_quad(fill( if let Some(bg_color) = active_line_color {
Bounds::new( window.paint_quad(fill(
p, Bounds::new(p, size(prepaint.last_layout.line_number_width, height)),
size(prepaint.last_layout.line_number_width, line_height), bg_color,
), ));
bg_color,
));
}
} }
}
_ = line.paint(p, line_height, TextAlign::Left, None, window, cx); for line in lines {
offset_y += line_size.height; _ = line.paint(p, line_height, window, cx);
offset_y += line_height;
} }
} }
} }