From 8d95dbe3e6278af117d938f6a76d5463e92c44ac Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Feb 2022 16:28:18 +0100 Subject: [PATCH] Render path headers in editor element Co-Authored-By: Nathan Sobo --- crates/diagnostics/src/diagnostics.rs | 106 ++++++------------ crates/editor/src/display_map/block_map.rs | 51 ++++----- crates/editor/src/display_map/wrap_map.rs | 8 -- crates/editor/src/element.rs | 119 ++++++++++++++------- 4 files changed, 128 insertions(+), 156 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 8342d742d60db7a6ce552d4c14b2493d4ca02312..6a7f135a6253244e53d0e1909b0526f22b7bd215 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -423,25 +423,16 @@ impl ProjectDiagnosticsEditor { self.editor.update(cx, |editor, cx| { blocks_to_remove.extend(path_state.header); editor.remove_blocks(blocks_to_remove, cx); - let header_block = first_excerpt_id.map(|excerpt_id| BlockProperties { - position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, language::Anchor::min()), - height: 2, - render: path_header_renderer(buffer, self.build_settings.clone()), - disposition: BlockDisposition::Above, - }); let block_ids = editor.insert_blocks( - blocks_to_add - .into_iter() - .map(|block| { - let (excerpt_id, text_anchor) = block.position; - BlockProperties { - position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, text_anchor), - height: block.height, - render: block.render, - disposition: block.disposition, - } - }) - .chain(header_block.into_iter()), + blocks_to_add.into_iter().map(|block| { + let (excerpt_id, text_anchor) = block.position; + BlockProperties { + position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, text_anchor), + height: block.height, + render: block.render, + disposition: block.disposition, + } + }), cx, ); @@ -660,51 +651,6 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { } } -fn path_header_renderer(buffer: ModelHandle, build_settings: BuildSettings) -> RenderBlock { - Arc::new(move |cx| { - let settings = build_settings(cx); - let style = settings.style.diagnostic_path_header; - let font_size = (style.text_scale_factor * settings.style.text.font_size).round(); - - let mut filename = None; - let mut path = None; - if let Some(file) = buffer.read(&**cx).file() { - filename = file - .path() - .file_name() - .map(|f| f.to_string_lossy().to_string()); - path = file - .path() - .parent() - .map(|p| p.to_string_lossy().to_string() + "/"); - } - - Flex::row() - .with_child( - Label::new( - filename.unwrap_or_else(|| "untitled".to_string()), - style.filename.text.clone().with_font_size(font_size), - ) - .contained() - .with_style(style.filename.container) - .boxed(), - ) - .with_children(path.map(|path| { - Label::new(path, style.path.text.clone().with_font_size(font_size)) - .contained() - .with_style(style.path.container) - .boxed() - })) - .aligned() - .left() - .contained() - .with_style(style.container) - .with_padding_left(cx.gutter_padding + cx.scroll_x * cx.em_width) - .expanded() - .named("path header block") - }) -} - fn diagnostic_header_renderer( diagnostic: Diagnostic, build_settings: BuildSettings, @@ -843,7 +789,10 @@ fn compare_diagnostics( #[cfg(test)] mod tests { use super::*; - use editor::{display_map::BlockContext, DisplayPoint, EditorSnapshot}; + use editor::{ + display_map::{BlockContext, TransformBlock}, + DisplayPoint, EditorSnapshot, + }; use gpui::TestAppContext; use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16}; use serde_json::json; @@ -1259,18 +1208,23 @@ mod tests { editor .blocks_in_range(0..editor.max_point().row()) .filter_map(|(row, block)| { - block - .render(&BlockContext { - cx, - anchor_x: 0., - scroll_x: 0., - gutter_padding: 0., - gutter_width: 0., - line_height: 0., - em_width: 0., - }) - .name() - .map(|s| (row, s.to_string())) + let name = match block { + TransformBlock::Custom(block) => block + .render(&BlockContext { + cx, + anchor_x: 0., + scroll_x: 0., + gutter_padding: 0., + gutter_width: 0., + line_height: 0., + em_width: 0., + }) + .name()? + .to_string(), + TransformBlock::ExcerptHeader { .. } => "path header block".to_string(), + }; + + Some((row, name)) }) .collect() } diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 1ca3c32ff1d0247c29b3bda10caef39ddf1ddc22..7b3e51fda32fe362705a59dd12007d22033708e0 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -90,10 +90,7 @@ struct Transform { #[derive(Clone)] pub enum TransformBlock { - Custom { - block: Arc, - column: u32, - }, + Custom(Arc), ExcerptHeader { buffer: BufferSnapshot, range: Range, @@ -104,14 +101,14 @@ pub enum TransformBlock { impl TransformBlock { fn disposition(&self) -> BlockDisposition { match self { - TransformBlock::Custom { block, .. } => block.disposition, + TransformBlock::Custom(block) => block.disposition, TransformBlock::ExcerptHeader { .. } => BlockDisposition::Above, } } - fn height(&self) -> u8 { + pub fn height(&self) -> u8 { match self { - TransformBlock::Custom { block, .. } => block.height, + TransformBlock::Custom(block) => block.height, TransformBlock::ExcerptHeader { height, .. } => *height, } } @@ -120,11 +117,7 @@ impl TransformBlock { impl Debug for TransformBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Custom { block, column } => f - .debug_struct("Custom") - .field("block", block) - .field("column", column) - .finish(), + Self::Custom(block) => f.debug_struct("Custom").field("block", block).finish(), Self::ExcerptHeader { buffer, .. } => f .debug_struct("ExcerptHeader") .field("path", &buffer.path()) @@ -319,7 +312,6 @@ impl BlockMap { .iter() .map(|block| { let mut position = block.position.to_point(&buffer); - let column = wrap_snapshot.from_point(position, Bias::Left).column(); match block.disposition { BlockDisposition::Above => position.column = 0, BlockDisposition::Below => { @@ -327,13 +319,7 @@ impl BlockMap { } } let position = wrap_snapshot.from_point(position, Bias::Left); - ( - position.row(), - TransformBlock::Custom { - block: block.clone(), - column, - }, - ) + (position.row(), TransformBlock::Custom(block.clone())) }), ); blocks_in_edit.extend( @@ -362,10 +348,7 @@ impl BlockMap { ) => Ordering::Equal, (TransformBlock::ExcerptHeader { .. }, _) => Ordering::Less, (_, TransformBlock::ExcerptHeader { .. }) => Ordering::Greater, - ( - TransformBlock::Custom { block: block_a, .. }, - TransformBlock::Custom { block: block_b, .. }, - ) => block_a + (TransformBlock::Custom(block_a), TransformBlock::Custom(block_b)) => block_a .disposition .cmp(&block_b.disposition) .then_with(|| block_a.id.cmp(&block_b.id)), @@ -908,6 +891,10 @@ impl Block { pub fn render(&self, cx: &BlockContext) -> ElementBox { self.render.lock()(cx) } + + pub fn position(&self) -> &Anchor { + &self.position + } } impl Debug for Block { @@ -1008,10 +995,9 @@ mod tests { let blocks = snapshot .blocks_in_range(0..8) .map(|(start_row, block)| { - let (block, column) = block.as_custom().unwrap(); + let block = block.as_custom().unwrap(); ( start_row..start_row + block.height as u32, - column, block .render(&BlockContext { cx, @@ -1033,9 +1019,9 @@ mod tests { assert_eq!( blocks, &[ - (1..3, 2, "block 2".to_string()), - (3..4, 0, "block 1".to_string()), - (7..10, 3, "block 3".to_string()), + (1..2, "block 1".to_string()), + (2..4, "block 2".to_string()), + (7..10, "block 3".to_string()), ] ); @@ -1324,7 +1310,6 @@ mod tests { let mut expected_blocks = Vec::new(); expected_blocks.extend(custom_blocks.iter().map(|(id, block)| { let mut position = block.position.to_point(&buffer_snapshot); - let column = wraps_snapshot.from_point(position, Bias::Left).column(); match block.disposition { BlockDisposition::Above => { position.column = 0; @@ -1426,7 +1411,7 @@ mod tests { assert_eq!( blocks_snapshot .blocks_in_range(0..(expected_row_count as u32)) - .map(|(row, block)| (row, block.as_custom().map(|(b, _)| b.id))) + .map(|(row, block)| { (row, block.as_custom().map(|b| b.id)) }) .collect::>(), expected_block_positions ); @@ -1508,9 +1493,9 @@ mod tests { } impl TransformBlock { - fn as_custom(&self) -> Option<(&Block, u32)> { + fn as_custom(&self) -> Option<&Block> { match self { - TransformBlock::Custom { block, column } => Some((block, *column)), + TransformBlock::Custom(block) => Some(block), TransformBlock::ExcerptHeader { .. } => None, } } diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 1d5e64c8a565798948a46c08b4b32dbaa08b96e7..647ee4f9aa386719c465a22fcf9e62acb0b0ca09 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -588,10 +588,6 @@ impl WrapSnapshot { } } - pub fn text_summary(&self) -> TextSummary { - self.transforms.summary().output - } - pub fn max_point(&self) -> WrapPoint { WrapPoint(self.transforms.summary().output.lines) } @@ -955,10 +951,6 @@ impl WrapPoint { &mut self.0.row } - pub fn column(&self) -> u32 { - self.0.column - } - pub fn column_mut(&mut self) -> &mut u32 { &mut self.0.column } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2f391aa9a9e4548d3f8a0b83215562969ab7df9a..67f349dc8bf0766915d21cdcb404f1949457ec79 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -3,11 +3,12 @@ use super::{ Anchor, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, Input, Scroll, Select, SelectPhase, SoftWrap, ToPoint, MAX_LINE_LEN, }; +use crate::display_map::TransformBlock; use clock::ReplicaId; use collections::{BTreeMap, HashMap}; use gpui::{ color::Color, - elements::layout_highlighted_chunks, + elements::*, fonts::{HighlightStyle, Underline}, geometry::{ rect::RectF, @@ -649,44 +650,84 @@ impl EditorElement { line_layouts: &[text_layout::Line], cx: &mut LayoutContext, ) -> Vec<(u32, ElementBox)> { - Default::default() - // snapshot - // .blocks_in_range(rows.clone()) - // .map(|(start_row, block)| { - // let anchor_row = block - // .position() - // .to_point(&snapshot.buffer_snapshot) - // .to_display_point(snapshot) - // .row(); - - // let anchor_x = text_x - // + if rows.contains(&anchor_row) { - // line_layouts[(anchor_row - rows.start) as usize] - // .x_for_index(block.column() as usize) - // } else { - // layout_line(anchor_row, snapshot, style, cx.text_layout_cache) - // .x_for_index(block.column() as usize) - // }; - - // let mut element = block.render(&BlockContext { - // cx, - // anchor_x, - // gutter_padding, - // line_height, - // scroll_x: snapshot.scroll_position.x(), - // gutter_width, - // em_width, - // }); - // element.layout( - // SizeConstraint { - // min: Vector2F::zero(), - // max: vec2f(width, block.height() as f32 * line_height), - // }, - // cx, - // ); - // (start_row, element) - // }) - // .collect() + let scroll_x = snapshot.scroll_position.x(); + snapshot + .blocks_in_range(rows.clone()) + .map(|(block_row, block)| { + let mut element = match block { + TransformBlock::Custom(block) => { + let align_to = block + .position() + .to_point(&snapshot.buffer_snapshot) + .to_display_point(snapshot); + let anchor_x = text_x + + if rows.contains(&align_to.row()) { + line_layouts[(align_to.row() - rows.start) as usize] + .x_for_index(align_to.column() as usize) + } else { + layout_line(align_to.row(), snapshot, style, cx.text_layout_cache) + .x_for_index(align_to.column() as usize) + }; + + block.render(&BlockContext { + cx, + anchor_x, + gutter_padding, + line_height, + scroll_x, + gutter_width, + em_width, + }) + } + TransformBlock::ExcerptHeader { buffer, .. } => { + let style = &self.settings.style.diagnostic_path_header; + let font_size = + (style.text_scale_factor * self.settings.style.text.font_size).round(); + + let mut filename = None; + let mut parent_path = None; + if let Some(path) = buffer.path() { + filename = path.file_name().map(|f| f.to_string_lossy().to_string()); + parent_path = + path.parent().map(|p| p.to_string_lossy().to_string() + "/"); + } + + Flex::row() + .with_child( + Label::new( + filename.unwrap_or_else(|| "untitled".to_string()), + style.filename.text.clone().with_font_size(font_size), + ) + .contained() + .with_style(style.filename.container) + .boxed(), + ) + .with_children(parent_path.map(|path| { + Label::new(path, style.path.text.clone().with_font_size(font_size)) + .contained() + .with_style(style.path.container) + .boxed() + })) + .aligned() + .left() + .contained() + .with_style(style.container) + .with_padding_left(gutter_padding + scroll_x * em_width) + .expanded() + .named("path header block") + } + }; + + element.layout( + SizeConstraint { + min: Vector2F::zero(), + max: vec2f(width, block.height() as f32 * line_height), + }, + cx, + ); + (block_row, element) + }) + .collect() } }