Use cached standard glyphs for invisible symbols

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Kirill Bulatov 2023-05-04 23:17:42 +03:00
parent 714734d279
commit 1eeeec157e

View file

@ -864,16 +864,16 @@ impl EditorElement {
}
if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
let line_height = layout.position_map.line_height;
// Draw glyphs
for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
let row = start_row + ix as u32;
let line_y = row as f32 * line_height - scroll_top;
line_with_invisibles.line.paint(
scene,
content_origin
+ vec2f(
-scroll_left,
row as f32 * layout.position_map.line_height - scroll_top,
),
content_origin + vec2f(-scroll_left, line_y),
visible_text_bounds,
layout.position_map.line_height,
cx,
@ -889,38 +889,22 @@ impl EditorElement {
ShowInvisibles::None => {}
ShowInvisibles::All => {
for invisible in &line_with_invisibles.invisibles {
// TODO kb cache, deduplicate
let (token_offset, mut test_svg) = match invisible {
Invisible::Tab { line_start_offset } => (
*line_start_offset,
Svg::new("icons/arrow_right_16.svg")
.with_color(self.style.line_number),
),
Invisible::Whitespace { line_offset } => (
*line_offset,
Svg::new("icons/plus_8.svg").with_color(self.style.line_number),
),
let (token_offset, invisible_symbol) = match invisible {
Invisible::Tab { line_start_offset } => {
(*line_start_offset, &layout.tab_invisible)
}
Invisible::Whitespace { line_offset } => {
(*line_offset, &layout.space_invisible)
}
};
let x_offset = line_with_invisibles.line.x_for_index(token_offset);
let font_size = line_with_invisibles.line.font_size();
let max_size = vec2f(font_size, font_size);
let invisible_offset =
(layout.position_map.em_width - invisible_symbol.width()).max(0.0)
/ 2.0;
let origin = content_origin
+ vec2f(
-scroll_left + x_offset,
row as f32 * layout.position_map.line_height - scroll_top,
);
let (_, mut layout_state) =
test_svg.layout(SizeConstraint::new(origin, max_size), editor, cx);
test_svg.paint(
scene,
RectF::new(origin, max_size),
visible_bounds,
&mut layout_state,
editor,
cx,
);
+ vec2f(-scroll_left + x_offset + invisible_offset, line_y);
invisible_symbol.paint(scene, origin, visible_bounds, line_height, cx);
}
}
}
@ -1655,6 +1639,7 @@ pub struct LineWithInvisibles {
invisibles: Vec<Invisible>,
}
// TODO kb deduplicate? + tests
fn layout_highlighted_chunks<'a>(
chunks: impl Iterator<Item = HighlightedChunk<'a>>,
text_style: &TextStyle,
@ -2121,6 +2106,13 @@ impl Element<Editor> for EditorElement {
}
}
let invisible_symbol_font_size = self.style.text.font_size / 2.0;
let invisible_symbol_style = RunStyle {
color: self.style.line_number,
font_id: self.style.text.font_id,
underline: Default::default(),
};
(
size,
LayoutState {
@ -2153,6 +2145,16 @@ impl Element<Editor> for EditorElement {
context_menu,
code_actions_indicator,
fold_indicators,
tab_invisible: cx.text_layout_cache().layout_str(
"",
invisible_symbol_font_size,
&[("".len(), invisible_symbol_style)],
),
space_invisible: cx.text_layout_cache().layout_str(
"",
invisible_symbol_font_size,
&[("".len(), invisible_symbol_style)],
),
hover_popovers: hover,
},
)
@ -2290,6 +2292,8 @@ pub struct LayoutState {
code_actions_indicator: Option<(u32, AnyElement<Editor>)>,
hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
fold_indicators: Vec<Option<AnyElement<Editor>>>,
tab_invisible: Line,
space_invisible: Line,
}
struct PositionMap {