From 1eeeec157e226b160fad2164ac9f4016d526ee02 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 4 May 2023 23:17:42 +0300 Subject: [PATCH] Use cached standard glyphs for invisible symbols Co-Authored-By: Max Brunsfeld --- crates/editor/src/element.rs | 70 +++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 9c279199219b95e7c2b8b78591420dd5250eea59..88436f43e86e828efc1f5b2bd02cc6fb35c06118 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -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, } +// TODO kb deduplicate? + tests fn layout_highlighted_chunks<'a>( chunks: impl Iterator>, text_style: &TextStyle, @@ -2121,6 +2106,13 @@ impl Element 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 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)>, hover_popovers: Option<(DisplayPoint, Vec>)>, fold_indicators: Vec>>, + tab_invisible: Line, + space_invisible: Line, } struct PositionMap {