diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 8137e46583003e13bd5beb79be6d168769fc4925..fa0f17331822b192f5d7ac6c7868175ae573e912 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -3,13 +3,12 @@ mod fold_map; mod tab_map; mod wrap_map; -pub use block_map::{BlockDisposition, BlockId, BlockProperties, BufferRows, Chunks}; +pub use block_map::{ + AlignedBlock, BlockContext, BlockDisposition, BlockId, BlockProperties, BufferRows, Chunks, +}; use block_map::{BlockMap, BlockPoint}; use fold_map::{FoldMap, ToFoldPoint as _}; -use gpui::{ - fonts::{FontId, HighlightStyle}, - AppContext, Entity, ModelContext, ModelHandle, -}; +use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle}; use language::{Anchor, Buffer, Point, Subscription as BufferSubscription, ToOffset, ToPoint}; use std::{ collections::{HashMap, HashSet}, @@ -17,8 +16,7 @@ use std::{ }; use sum_tree::Bias; use tab_map::TabMap; -use text::Rope; -use theme::{BlockStyle, SyntaxTheme}; +use theme::SyntaxTheme; use wrap_map::WrapMap; pub trait ToDisplayPoint { @@ -124,14 +122,13 @@ impl DisplayMap { self.block_map.read(snapshot, edits, cx); } - pub fn insert_blocks( + pub fn insert_blocks

( &mut self, - blocks: impl IntoIterator>, + blocks: impl IntoIterator>, cx: &mut ModelContext, ) -> Vec where P: ToOffset + Clone, - T: Into + Clone, { let snapshot = self.buffer.read(cx).snapshot(); let edits = self.buffer_subscription.consume().into_inner(); @@ -144,12 +141,11 @@ impl DisplayMap { block_map.insert(blocks, cx) } - pub fn restyle_blocks(&mut self, styles: HashMap, Option)>) + pub fn replace_blocks(&mut self, styles: HashMap) where - F1: 'static + Fn(&AppContext) -> Vec<(usize, HighlightStyle)>, - F2: 'static + Fn(&AppContext) -> BlockStyle, + F: 'static + Fn(&BlockContext) -> ElementBox, { - self.block_map.restyle(styles); + self.block_map.replace(styles); } pub fn remove_blocks(&mut self, ids: HashSet, cx: &mut ModelContext) { @@ -198,8 +194,8 @@ impl DisplayMapSnapshot { self.buffer_snapshot.len() == 0 } - pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: Option<&'a AppContext>) -> BufferRows<'a> { - self.blocks_snapshot.buffer_rows(start_row, cx) + pub fn buffer_rows<'a>(&'a self, start_row: u32) -> BufferRows<'a> { + self.blocks_snapshot.buffer_rows(start_row) } pub fn buffer_row_count(&self) -> u32 { @@ -256,7 +252,7 @@ impl DisplayMapSnapshot { pub fn text_chunks(&self, display_row: u32) -> impl Iterator { self.blocks_snapshot - .chunks(display_row..self.max_point().row() + 1, None, None) + .chunks(display_row..self.max_point().row() + 1, None) .map(|h| h.text) } @@ -264,9 +260,8 @@ impl DisplayMapSnapshot { &'a self, display_rows: Range, theme: Option<&'a SyntaxTheme>, - cx: &'a AppContext, ) -> block_map::Chunks<'a> { - self.blocks_snapshot.chunks(display_rows, theme, Some(cx)) + self.blocks_snapshot.chunks(display_rows, theme) } pub fn chars_at<'a>(&'a self, point: DisplayPoint) -> impl Iterator + 'a { @@ -322,6 +317,13 @@ impl DisplayMapSnapshot { self.folds_snapshot.folds_in_range(range) } + pub fn blocks_in_range<'a>( + &'a self, + rows: Range, + ) -> impl Iterator { + self.blocks_snapshot.blocks_in_range(rows) + } + pub fn intersects_fold(&self, offset: T) -> bool { self.folds_snapshot.intersects_fold(offset) } @@ -448,13 +450,6 @@ impl ToDisplayPoint for Anchor { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum DisplayRow { - Buffer(u32), - Block(BlockId, Option), - Wrap, -} - #[cfg(test)] mod tests { use super::*; @@ -1065,7 +1060,7 @@ mod tests { ) -> Vec<(String, Option)> { let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); let mut chunks: Vec<(String, Option)> = Vec::new(); - for chunk in snapshot.chunks(rows, Some(theme), cx) { + for chunk in snapshot.chunks(rows, Some(theme)) { let color = chunk.highlight_style.map(|s| s.color); if let Some((last_chunk, last_color)) = chunks.last_mut() { if color == *last_color { diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 5ed1ac65fb8919a076251e79e5e7ad2e43961ee3..58ae22403df48903b4ef4a45957340c2c0c27d3d 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1,26 +1,23 @@ -use super::{ - wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint}, - BlockStyle, DisplayRow, -}; -use gpui::{fonts::HighlightStyle, AppContext, ModelHandle}; +use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint}; +use gpui::{AppContext, ElementBox, ModelHandle}; use language::{Buffer, Chunk}; use parking_lot::Mutex; use std::{ cmp::{self, Ordering}, collections::{HashMap, HashSet}, fmt::Debug, - iter, ops::{Deref, Range}, sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, Arc, }, - vec, }; use sum_tree::SumTree; -use text::{rope, Anchor, Bias, Edit, Point, Rope, ToOffset, ToPoint as _}; +use text::{Anchor, Bias, Edit, Point, ToOffset, ToPoint as _}; use theme::SyntaxTheme; +const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; + pub struct BlockMap { buffer: ModelHandle, next_block_id: AtomicUsize, @@ -51,25 +48,27 @@ struct WrapRow(u32); pub struct Block { id: BlockId, position: Anchor, - text: Rope, - build_runs: Mutex Vec<(usize, HighlightStyle)>>>>, - build_style: Mutex BlockStyle>>>, + height: u8, + render: Mutex ElementBox>>, disposition: BlockDisposition, } #[derive(Clone)] -pub struct BlockProperties +pub struct BlockProperties

where P: Clone, - T: Clone, { pub position: P, - pub text: T, - pub build_runs: Option Vec<(usize, HighlightStyle)>>>, - pub build_style: Option BlockStyle>>, + pub height: u8, + pub render: Arc ElementBox>, pub disposition: BlockDisposition, } +pub struct BlockContext<'a> { + pub cx: &'a AppContext, + pub anchor_x: f32, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum BlockDisposition { Above, @@ -83,7 +82,7 @@ struct Transform { } #[derive(Clone, Debug)] -struct AlignedBlock { +pub struct AlignedBlock { block: Arc, column: u32, } @@ -92,35 +91,20 @@ struct AlignedBlock { struct TransformSummary { input_rows: u32, output_rows: u32, - longest_row_in_block: u32, - longest_row_in_block_chars: u32, } pub struct Chunks<'a> { transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>, input_chunks: wrap_map::Chunks<'a>, input_chunk: Chunk<'a>, - block_chunks: Option>, output_row: u32, max_output_row: u32, - cx: Option<&'a AppContext>, -} - -struct BlockChunks<'a> { - chunks: rope::Chunks<'a>, - runs: iter::Peekable>, - chunk: Option<&'a str>, - remaining_padding: u32, - padding_column: u32, - run_start: usize, - offset: usize, } pub struct BufferRows<'a> { transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>, input_buffer_rows: wrap_map::BufferRows<'a>, output_row: u32, - cx: Option<&'a AppContext>, started: bool, } @@ -333,19 +317,13 @@ impl BlockMap { *transforms = new_transforms; } - pub fn restyle(&mut self, mut styles: HashMap, Option)>) + pub fn replace(&mut self, mut element_builders: HashMap) where - F1: 'static + Fn(&AppContext) -> Vec<(usize, HighlightStyle)>, - F2: 'static + Fn(&AppContext) -> BlockStyle, + F: 'static + Fn(&BlockContext) -> ElementBox, { for block in &self.blocks { - if let Some((build_runs, build_style)) = styles.remove(&block.id) { - *block.build_runs.lock() = build_runs.map(|build_runs| { - Arc::new(build_runs) as Arc Vec<(usize, HighlightStyle)>> - }); - *block.build_style.lock() = build_style.map(|build_style| { - Arc::new(build_style) as Arc BlockStyle> - }); + if let Some(build_element) = element_builders.remove(&block.id) { + *block.render.lock() = Arc::new(build_element); } } } @@ -393,14 +371,13 @@ impl std::ops::DerefMut for BlockPoint { } impl<'a> BlockMapWriter<'a> { - pub fn insert( + pub fn insert

( &mut self, - blocks: impl IntoIterator>, + blocks: impl IntoIterator>, cx: &AppContext, ) -> Vec where P: ToOffset + Clone, - T: Into + Clone, { let buffer = self.0.buffer.read(cx); let mut ids = Vec::new(); @@ -436,9 +413,8 @@ impl<'a> BlockMapWriter<'a> { Arc::new(Block { id, position, - text: block.text.into(), - build_runs: Mutex::new(block.build_runs), - build_style: Mutex::new(block.build_style), + height: block.height, + render: Mutex::new(block.render), disposition: block.disposition, }), ); @@ -495,17 +471,12 @@ impl<'a> BlockMapWriter<'a> { impl BlockSnapshot { #[cfg(test)] fn text(&mut self) -> String { - self.chunks(0..self.transforms.summary().output_rows, None, None) + self.chunks(0..self.transforms.summary().output_rows, None) .map(|chunk| chunk.text) .collect() } - pub fn chunks<'a>( - &'a self, - rows: Range, - theme: Option<&'a SyntaxTheme>, - cx: Option<&'a AppContext>, - ) -> Chunks<'a> { + pub fn chunks<'a>(&'a self, rows: Range, theme: Option<&'a SyntaxTheme>) -> Chunks<'a> { let max_output_row = cmp::min(rows.end, self.transforms.summary().output_rows); let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); let input_end = { @@ -535,15 +506,13 @@ impl BlockSnapshot { Chunks { input_chunks: self.wrap_snapshot.chunks(input_start..input_end, theme), input_chunk: Default::default(), - block_chunks: None, transforms: cursor, output_row: rows.start, max_output_row, - cx, } } - pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: Option<&'a AppContext>) -> BufferRows<'a> { + pub fn buffer_rows<'a>(&'a self, start_row: u32) -> BufferRows<'a> { let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); cursor.seek(&BlockRow(start_row), Bias::Right, &()); let (output_start, input_start) = cursor.start(); @@ -554,7 +523,6 @@ impl BlockSnapshot { }; let input_start_row = input_start.0 + overshoot; BufferRows { - cx, transforms: cursor, input_buffer_rows: self.wrap_snapshot.buffer_rows(input_start_row), output_row: start_row, @@ -562,6 +530,29 @@ impl BlockSnapshot { } } + pub fn blocks_in_range<'a>( + &'a self, + rows: Range, + ) -> impl Iterator { + let mut cursor = self.transforms.cursor::(); + cursor.seek(&BlockRow(rows.start), Bias::Right, &()); + std::iter::from_fn(move || { + while let Some(transform) = cursor.item() { + let start_row = cursor.start().0; + if start_row >= rows.end { + break; + } + if let Some(block) = &transform.block { + cursor.next(&()); + return Some((start_row, block)); + } else { + cursor.next(&()); + } + } + None + }) + } + pub fn max_point(&self) -> BlockPoint { let row = self.transforms.summary().output_rows - 1; BlockPoint::new(row, self.line_len(row)) @@ -569,18 +560,7 @@ impl BlockSnapshot { pub fn longest_row(&self) -> u32 { let input_row = self.wrap_snapshot.longest_row(); - let input_row_chars = self.wrap_snapshot.line_char_count(input_row); - let TransformSummary { - longest_row_in_block: block_row, - longest_row_in_block_chars: block_row_chars, - .. - } = &self.transforms.summary(); - - if *block_row_chars > input_row_chars { - *block_row - } else { - self.to_block_point(WrapPoint::new(input_row, 0)).row - } + self.to_block_point(WrapPoint::new(input_row, 0)).row } pub fn line_len(&self, row: u32) -> u32 { @@ -589,12 +569,8 @@ impl BlockSnapshot { if let Some(transform) = cursor.item() { let (output_start, input_start) = cursor.start(); let overshoot = row - output_start.0; - if let Some(block) = &transform.block { - let mut len = block.text.line_len(overshoot); - if len > 0 { - len += block.column; - } - len + if transform.block.is_some() { + 0 } else { self.wrap_snapshot.line_len(input_start.0 + overshoot) } @@ -697,21 +673,16 @@ impl Transform { summary: TransformSummary { input_rows: rows, output_rows: rows, - longest_row_in_block: 0, - longest_row_in_block_chars: 0, }, block: None, } } fn block(block: Arc, column: u32) -> Self { - let text_summary = block.text.summary(); Self { summary: TransformSummary { input_rows: 0, - output_rows: text_summary.lines.row + 1, - longest_row_in_block: text_summary.longest_row, - longest_row_in_block_chars: column + text_summary.longest_row_chars, + output_rows: block.height as u32, }, block: Some(AlignedBlock { block, column }), } @@ -730,37 +701,25 @@ impl<'a> Iterator for Chunks<'a> { return None; } - if let Some(block_chunks) = self.block_chunks.as_mut() { - if let Some(block_chunk) = block_chunks.next() { - self.output_row += block_chunk.text.matches('\n').count() as u32; - return Some(block_chunk); - } else { - self.block_chunks.take(); - self.output_row += 1; - if self.output_row < self.max_output_row { - return Some(Chunk { - text: "\n", - ..Default::default() - }); - } else { - return None; - } - } - } - let transform = self.transforms.item()?; - if let Some(block) = transform.block.as_ref() { + if transform.block.is_some() { let block_start = self.transforms.start().0 .0; - let block_end = self.transforms.end(&()).0 .0; + let mut block_end = self.transforms.end(&()).0 .0; + self.transforms.next(&()); + if self.transforms.item().is_none() { + block_end -= 1; + } + let start_in_block = self.output_row - block_start; let end_in_block = cmp::min(self.max_output_row, block_end) - block_start; - self.transforms.next(&()); - self.block_chunks = Some(BlockChunks::new( - block, - start_in_block..end_in_block, - self.cx, - )); - return self.next(); + let line_count = end_in_block - start_in_block; + self.output_row += line_count; + + return Some(Chunk { + text: unsafe { std::str::from_utf8_unchecked(&NEWLINES[..line_count as usize]) }, + highlight_style: None, + diagnostic: None, + }); } if self.input_chunk.text.is_empty() { @@ -797,107 +756,8 @@ impl<'a> Iterator for Chunks<'a> { } } -impl<'a> BlockChunks<'a> { - fn new(block: &'a AlignedBlock, rows: Range, cx: Option<&'a AppContext>) -> Self { - let offset_range = block.text.point_to_offset(Point::new(rows.start, 0)) - ..block.text.point_to_offset(Point::new(rows.end, 0)); - - let mut runs = block - .build_runs - .lock() - .as_ref() - .zip(cx) - .map(|(build_runs, cx)| build_runs(cx)) - .unwrap_or_default() - .into_iter() - .peekable(); - let mut run_start = 0; - while let Some((run_len, _)) = runs.peek() { - let run_end = run_start + run_len; - if run_end <= offset_range.start { - run_start = run_end; - runs.next(); - } else { - break; - } - } - - Self { - chunk: None, - run_start, - padding_column: block.column, - remaining_padding: block.column, - chunks: block.text.chunks_in_range(offset_range.clone()), - runs, - offset: offset_range.start, - } - } -} - -impl<'a> Iterator for BlockChunks<'a> { - type Item = Chunk<'a>; - - fn next(&mut self) -> Option { - if self.chunk.is_none() { - self.chunk = self.chunks.next(); - } - - let chunk = self.chunk?; - - if chunk.starts_with('\n') { - self.remaining_padding = 0; - } - - if self.remaining_padding > 0 { - const PADDING: &'static str = " "; - let padding_len = self.remaining_padding.min(PADDING.len() as u32); - self.remaining_padding -= padding_len; - return Some(Chunk { - text: &PADDING[..padding_len as usize], - ..Default::default() - }); - } - - let mut chunk_len = if let Some(ix) = chunk.find('\n') { - ix + 1 - } else { - chunk.len() - }; - - let mut highlight_style = None; - if let Some((run_len, style)) = self.runs.peek() { - highlight_style = Some(style.clone()); - let run_end_in_chunk = self.run_start + run_len - self.offset; - if run_end_in_chunk <= chunk_len { - chunk_len = run_end_in_chunk; - self.run_start += run_len; - self.runs.next(); - } - } - - self.offset += chunk_len; - let (chunk, suffix) = chunk.split_at(chunk_len); - - if chunk.ends_with('\n') { - self.remaining_padding = self.padding_column; - } - - self.chunk = if suffix.is_empty() { - None - } else { - Some(suffix) - }; - - Some(Chunk { - text: chunk, - highlight_style, - diagnostic: None, - }) - } -} - impl<'a> Iterator for BufferRows<'a> { - type Item = DisplayRow; + type Item = Option; fn next(&mut self) -> Option { if self.started { @@ -911,11 +771,8 @@ impl<'a> Iterator for BufferRows<'a> { } let transform = self.transforms.item()?; - if let Some(block) = &transform.block { - let style = self - .cx - .and_then(|cx| block.build_style.lock().as_ref().map(|f| f(cx))); - Some(DisplayRow::Block(block.id, style)) + if transform.block.is_some() { + Some(None) } else { Some(self.input_buffer_rows.next().unwrap()) } @@ -934,11 +791,6 @@ impl sum_tree::Summary for TransformSummary { type Context = (); fn add_summary(&mut self, summary: &Self, _: &()) { - if summary.longest_row_in_block_chars > self.longest_row_in_block_chars { - self.longest_row_in_block_chars = summary.longest_row_in_block_chars; - self.longest_row_in_block = self.output_rows + summary.longest_row_in_block; - } - self.input_rows += summary.input_rows; self.output_rows += summary.output_rows; } @@ -962,6 +814,24 @@ impl BlockDisposition { } } +impl AlignedBlock { + pub fn height(&self) -> u32 { + self.height as u32 + } + + pub fn column(&self) -> u32 { + self.column + } + + pub fn render(&self, cx: &BlockContext) -> ElementBox { + self.render.lock()(cx) + } + + pub fn position(&self) -> &Anchor { + &self.block.position + } +} + impl Deref for AlignedBlock { type Target = Block; @@ -975,7 +845,6 @@ impl Debug for Block { f.debug_struct("Block") .field("id", &self.id) .field("position", &self.position) - .field("text", &self.text) .field("disposition", &self.disposition) .finish() } @@ -1003,7 +872,7 @@ fn offset_for_row(s: &str, target: u32) -> (u32, usize) { mod tests { use super::*; use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap}; - use gpui::color::Color; + use gpui::{elements::Empty, Element}; use language::Buffer; use rand::prelude::*; use std::env; @@ -1023,76 +892,6 @@ mod tests { assert_eq!(offset_for_row("abc\ndef\nghi", 3), (2, 11)); } - #[gpui::test] - fn test_block_chunks(cx: &mut gpui::MutableAppContext) { - let red = Color::red(); - let blue = Color::blue(); - let clear = Color::default(); - - let block = AlignedBlock { - column: 5, - block: Arc::new(Block { - id: BlockId(0), - position: Anchor::min(), - text: "one!\ntwo three\nfour".into(), - build_style: Mutex::new(None), - build_runs: Mutex::new(Some(Arc::new(move |_| { - vec![(3, red.into()), (6, Default::default()), (5, blue.into())] - }))), - disposition: BlockDisposition::Above, - }), - }; - - assert_eq!( - colored_chunks(&block, 0..3, cx), - &[ - (" ", clear), - ("one", red), - ("!\n", clear), - (" ", clear), - ("two ", clear), - ("three", blue), - ("\n", clear), - (" ", clear), - ("four", clear) - ] - ); - assert_eq!( - colored_chunks(&block, 0..1, cx), - &[ - (" ", clear), // - ("one", red), - ("!\n", clear), - ] - ); - assert_eq!( - colored_chunks(&block, 1..3, cx), - &[ - (" ", clear), - ("two ", clear), - ("three", blue), - ("\n", clear), - (" ", clear), - ("four", clear) - ] - ); - - fn colored_chunks<'a>( - block: &'a AlignedBlock, - row_range: Range, - cx: &'a AppContext, - ) -> Vec<(&'a str, Color)> { - BlockChunks::new(block, row_range, Some(cx)) - .map(|c| { - ( - c.text, - c.highlight_style.map_or(Color::default(), |s| s.color), - ) - }) - .collect() - } - } - #[gpui::test] fn test_basic_blocks(cx: &mut gpui::MutableAppContext) { let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); @@ -1110,49 +909,67 @@ mod tests { let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone()); let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx); - let block_ids = writer.insert( + writer.insert( vec![ BlockProperties { position: Point::new(1, 0), - text: "BLOCK 1", + height: 1, disposition: BlockDisposition::Above, - build_runs: None, - build_style: None, + render: Arc::new(|_| Empty::new().named("block 1")), }, BlockProperties { position: Point::new(1, 2), - text: "BLOCK 2", + height: 2, disposition: BlockDisposition::Above, - build_runs: None, - build_style: None, + render: Arc::new(|_| Empty::new().named("block 2")), }, BlockProperties { - position: Point::new(3, 2), - text: "BLOCK 3", + position: Point::new(3, 3), + height: 3, disposition: BlockDisposition::Below, - build_runs: None, - build_style: None, + render: Arc::new(|_| Empty::new().named("block 3")), }, ], cx, ); let mut snapshot = block_map.read(wraps_snapshot, vec![], cx); + assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n"); + + let blocks = snapshot + .blocks_in_range(0..8) + .map(|(start_row, block)| { + ( + start_row..start_row + block.height(), + block.column(), + block + .render(&BlockContext { cx, anchor_x: 0. }) + .name() + .unwrap() + .to_string(), + ) + }) + .collect::>(); assert_eq!( - snapshot.text(), - "aaa\nBLOCK 1\n BLOCK 2\nbbb\nccc\nddd\n BLOCK 3" + blocks, + &[ + (1..2, 0, "block 1".to_string()), + (2..4, 2, "block 2".to_string()), + (7..10, 3, "block 3".to_string()), + ] ); + assert_eq!( snapshot.to_block_point(WrapPoint::new(0, 3)), BlockPoint::new(0, 3) ); assert_eq!( snapshot.to_block_point(WrapPoint::new(1, 0)), - BlockPoint::new(3, 0) + BlockPoint::new(4, 0) ); assert_eq!( snapshot.to_block_point(WrapPoint::new(3, 3)), - BlockPoint::new(5, 3) + BlockPoint::new(6, 3) ); assert_eq!( @@ -1168,7 +985,7 @@ mod tests { WrapPoint::new(1, 0) ); assert_eq!( - snapshot.to_wrap_point(BlockPoint::new(6, 0)), + snapshot.to_wrap_point(BlockPoint::new(7, 0)), WrapPoint::new(3, 3) ); @@ -1178,7 +995,7 @@ mod tests { ); assert_eq!( snapshot.clip_point(BlockPoint::new(1, 0), Bias::Right), - BlockPoint::new(3, 0) + BlockPoint::new(4, 0) ); assert_eq!( snapshot.clip_point(BlockPoint::new(1, 1), Bias::Left), @@ -1186,43 +1003,46 @@ mod tests { ); assert_eq!( snapshot.clip_point(BlockPoint::new(1, 1), Bias::Right), - BlockPoint::new(3, 0) + BlockPoint::new(4, 0) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(3, 0), Bias::Left), - BlockPoint::new(3, 0) + snapshot.clip_point(BlockPoint::new(4, 0), Bias::Left), + BlockPoint::new(4, 0) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(3, 0), Bias::Right), - BlockPoint::new(3, 0) + snapshot.clip_point(BlockPoint::new(4, 0), Bias::Right), + BlockPoint::new(4, 0) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(5, 3), Bias::Left), - BlockPoint::new(5, 3) + snapshot.clip_point(BlockPoint::new(6, 3), Bias::Left), + BlockPoint::new(6, 3) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(5, 3), Bias::Right), - BlockPoint::new(5, 3) + snapshot.clip_point(BlockPoint::new(6, 3), Bias::Right), + BlockPoint::new(6, 3) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(6, 0), Bias::Left), - BlockPoint::new(5, 3) + snapshot.clip_point(BlockPoint::new(7, 0), Bias::Left), + BlockPoint::new(6, 3) ); assert_eq!( - snapshot.clip_point(BlockPoint::new(6, 0), Bias::Right), - BlockPoint::new(5, 3) + snapshot.clip_point(BlockPoint::new(7, 0), Bias::Right), + BlockPoint::new(6, 3) ); assert_eq!( - snapshot.buffer_rows(0, None).collect::>(), + snapshot.buffer_rows(0).collect::>(), &[ - DisplayRow::Buffer(0), - DisplayRow::Block(block_ids[0], None), - DisplayRow::Block(block_ids[1], None), - DisplayRow::Buffer(1), - DisplayRow::Buffer(2), - DisplayRow::Buffer(3), - DisplayRow::Block(block_ids[2], None) + Some(0), + None, + None, + None, + Some(1), + Some(2), + Some(3), + None, + None, + None ] ); @@ -1240,10 +1060,7 @@ mod tests { wrap_map.sync(tabs_snapshot, tab_edits, cx) }); let mut snapshot = block_map.read(wraps_snapshot, wrap_edits, cx); - assert_eq!( - snapshot.text(), - "aaa\nBLOCK 1\nb!!!\n BLOCK 2\nbb\nccc\nddd\n BLOCK 3" - ); + assert_eq!(snapshot.text(), "aaa\n\nb!!!\n\n\nbb\nccc\nddd\n\n\n"); } #[gpui::test] @@ -1267,17 +1084,15 @@ mod tests { vec![ BlockProperties { position: Point::new(1, 12), - text: "BLOCK 2", disposition: BlockDisposition::Below, - build_runs: None, - build_style: None, + render: Arc::new(|_| Empty::new().named("block 2")), + height: 1, }, ], cx, @@ -1288,7 +1103,7 @@ mod tests { let mut snapshot = block_map.read(wraps_snapshot, vec![], cx); assert_eq!( snapshot.text(), - "one two \nthree\n BLOCK 2\nseven \neight" + "one two \nthree\n\nfour five \nsix\n\nseven \neight" ); } @@ -1348,33 +1163,23 @@ mod tests { buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Left), ); - let len = rng.gen_range(0..10); - let mut text = Rope::from( - RandomCharIter::new(&mut rng) - .take(len) - .collect::() - .to_uppercase() - .as_str(), - ); let disposition = if rng.gen() { - text.push_front("<"); BlockDisposition::Above } else { - text.push_front(">"); BlockDisposition::Below }; + let height = rng.gen_range(1..5); log::info!( - "inserting block {:?} {:?} with text {:?}", + "inserting block {:?} {:?} with height {}", disposition, position.to_point(buffer), - text.to_string() + height ); BlockProperties { position, - text, + height, disposition, - build_runs: None, - build_style: None, + render: Arc::new(|_| Empty::new().boxed()), } }) .collect::>(); @@ -1454,10 +1259,9 @@ mod tests { id, BlockProperties { position: BlockPoint::new(row, column), - text: block.text, - build_runs: block.build_runs.clone(), - build_style: None, + height: block.height, disposition: block.disposition, + render: block.render.clone(), }, ) }) @@ -1479,17 +1283,12 @@ mod tests { .to_point(WrapPoint::new(row, 0), Bias::Left) .row; - while let Some((block_id, block)) = sorted_blocks.peek() { + while let Some((_, block)) = sorted_blocks.peek() { if block.position.row == row && block.disposition == BlockDisposition::Above { - let text = block.text.to_string(); - let padding = " ".repeat(block.position.column as usize); - for line in text.split('\n') { - if !line.is_empty() { - expected_text.push_str(&padding); - expected_text.push_str(line); - } - expected_text.push('\n'); - expected_buffer_rows.push(DisplayRow::Block(*block_id, None)); + let text = "\n".repeat(block.height as usize); + expected_text.push_str(&text); + for _ in 0..block.height { + expected_buffer_rows.push(None); } sorted_blocks.next(); } else { @@ -1498,24 +1297,15 @@ mod tests { } let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0; - expected_buffer_rows.push(if soft_wrapped { - DisplayRow::Wrap - } else { - DisplayRow::Buffer(buffer_row) - }); + expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) }); expected_text.push_str(input_line); - while let Some((block_id, block)) = sorted_blocks.peek() { + while let Some((_, block)) = sorted_blocks.peek() { if block.position.row == row && block.disposition == BlockDisposition::Below { - let text = block.text.to_string(); - let padding = " ".repeat(block.position.column as usize); - for line in text.split('\n') { - expected_text.push('\n'); - if !line.is_empty() { - expected_text.push_str(&padding); - expected_text.push_str(line); - } - expected_buffer_rows.push(DisplayRow::Block(*block_id, None)); + let text = "\n".repeat(block.height as usize); + expected_text.push_str(&text); + for _ in 0..block.height { + expected_buffer_rows.push(None); } sorted_blocks.next(); } else { @@ -1529,7 +1319,7 @@ mod tests { for start_row in 0..expected_row_count { let expected_text = expected_lines[start_row..].join("\n"); let actual_text = blocks_snapshot - .chunks(start_row as u32..expected_row_count as u32, None, None) + .chunks(start_row as u32..expected_row_count as u32, None) .map(|chunk| chunk.text) .collect::(); assert_eq!( @@ -1539,7 +1329,7 @@ mod tests { ); assert_eq!( blocks_snapshot - .buffer_rows(start_row as u32, None) + .buffer_rows(start_row as u32) .collect::>(), &expected_buffer_rows[start_row..] ); @@ -1569,7 +1359,6 @@ mod tests { } } - log::info!("getting longest row >>>>>>>>>>>>>>>>>>>>>>>>"); let longest_row = blocks_snapshot.longest_row(); assert!( expected_longest_rows.contains(&longest_row), diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 174e9df98eb7f35be03360973ab7512ed0ed6789..04b6c00d6b0476a52666631b9098c8777ed585f2 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -1,7 +1,6 @@ use super::{ fold_map, tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint}, - DisplayRow, }; use gpui::{ fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, ModelHandle, MutableAppContext, @@ -607,13 +606,6 @@ impl Snapshot { len as u32 } - pub fn line_char_count(&self, row: u32) -> u32 { - self.text_chunks(row) - .flat_map(|c| c.chars()) - .take_while(|c| *c != '\n') - .count() as u32 - } - pub fn soft_wrap_indent(&self, row: u32) -> Option { let mut cursor = self.transforms.cursor::(); cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Right, &()); @@ -719,11 +711,7 @@ impl Snapshot { prev_tab_row = tab_point.row(); soft_wrapped = false; } - expected_buffer_rows.push(if soft_wrapped { - DisplayRow::Wrap - } else { - DisplayRow::Buffer(buffer_row) - }); + expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) }); } for start_display_row in 0..expected_buffer_rows.len() { @@ -803,7 +791,7 @@ impl<'a> Iterator for Chunks<'a> { } impl<'a> Iterator for BufferRows<'a> { - type Item = DisplayRow; + type Item = Option; fn next(&mut self) -> Option { if self.output_row > self.max_output_row { @@ -823,11 +811,7 @@ impl<'a> Iterator for BufferRows<'a> { self.soft_wrapped = true; } - Some(if soft_wrapped { - DisplayRow::Wrap - } else { - DisplayRow::Buffer(buffer_row) - }) + Some(if soft_wrapped { None } else { Some(buffer_row) }) } } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index e61f1f79cdc7755e513bb4eb9fc90741ceca930d..539736aca254e803fe9ac2ab29c51c63e0f014cb 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -8,11 +8,12 @@ mod test; use aho_corasick::AhoCorasick; use clock::ReplicaId; +pub use display_map::DisplayPoint; use display_map::*; -pub use display_map::{DisplayPoint, DisplayRow}; pub use element::*; use gpui::{ action, + elements::Text, geometry::vector::{vec2f, Vector2F}, keymap::Binding, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, @@ -28,14 +29,14 @@ use std::{ cmp, collections::HashMap, iter, mem, - ops::{Range, RangeInclusive}, + ops::{Deref, Range, RangeInclusive}, rc::Rc, sync::Arc, time::Duration, }; use sum_tree::Bias; use text::rope::TextDimension; -use theme::{DiagnosticStyle, EditorStyle, SyntaxTheme}; +use theme::{DiagnosticStyle, EditorStyle}; use util::post_inc; use workspace::{EntryOpener, Workspace}; @@ -2877,35 +2878,16 @@ impl Editor { active_diagnostics.is_valid = is_valid; let mut new_styles = HashMap::new(); for (block_id, diagnostic) in &active_diagnostics.blocks { - let severity = diagnostic.severity; - let message_len = diagnostic.message.len(); - new_styles.insert( - *block_id, - ( - Some({ - let build_settings = self.build_settings.clone(); - move |cx: &AppContext| { - let settings = build_settings.borrow()(cx); - vec![( - message_len, - diagnostic_style(severity, is_valid, &settings.style) - .text - .into(), - )] - } - }), - Some({ - let build_settings = self.build_settings.clone(); - move |cx: &AppContext| { - let settings = build_settings.borrow()(cx); - diagnostic_style(severity, is_valid, &settings.style).block - } - }), - ), - ); + let build_settings = self.build_settings.clone(); + let diagnostic = diagnostic.clone(); + new_styles.insert(*block_id, move |cx: &BlockContext| { + let diagnostic = diagnostic.clone(); + let settings = build_settings.borrow()(cx.cx); + render_diagnostic(diagnostic, &settings.style, is_valid, cx.anchor_x) + }); } self.display_map - .update(cx, |display_map, _| display_map.restyle_blocks(new_styles)); + .update(cx, |display_map, _| display_map.replace_blocks(new_styles)); } } } @@ -2940,30 +2922,17 @@ impl Editor { .insert_blocks( diagnostic_group.iter().map(|(range, diagnostic)| { let build_settings = self.build_settings.clone(); - let message_len = diagnostic.message.len(); - let severity = diagnostic.severity; + let diagnostic = diagnostic.clone(); + let message_height = diagnostic.message.lines().count() as u8; + BlockProperties { position: range.start, - text: diagnostic.message.as_str(), - build_runs: Some(Arc::new({ - let build_settings = build_settings.clone(); - move |cx| { - let settings = build_settings.borrow()(cx); - vec![( - message_len, - diagnostic_style(severity, true, &settings.style) - .text - .into(), - )] - } - })), - build_style: Some(Arc::new({ - let build_settings = build_settings.clone(); - move |cx| { - let settings = build_settings.borrow()(cx); - diagnostic_style(severity, true, &settings.style).block - } - })), + height: message_height, + render: Arc::new(move |cx| { + let settings = build_settings.borrow()(cx.cx); + let diagnostic = diagnostic.clone(); + render_diagnostic(diagnostic, &settings.style, true, cx.anchor_x) + }), disposition: BlockDisposition::Below, } }), @@ -3482,10 +3451,6 @@ impl Editor { } impl Snapshot { - pub fn is_empty(&self) -> bool { - self.display_snapshot.is_empty() - } - pub fn is_focused(&self) -> bool { self.is_focused } @@ -3494,23 +3459,6 @@ impl Snapshot { self.placeholder_text.as_ref() } - pub fn buffer_row_count(&self) -> u32 { - self.display_snapshot.buffer_row_count() - } - - pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: &'a AppContext) -> BufferRows<'a> { - self.display_snapshot.buffer_rows(start_row, Some(cx)) - } - - pub fn chunks<'a>( - &'a self, - display_rows: Range, - theme: Option<&'a SyntaxTheme>, - cx: &'a AppContext, - ) -> display_map::Chunks<'a> { - self.display_snapshot.chunks(display_rows, theme, cx) - } - pub fn scroll_position(&self) -> Vector2F { compute_scroll_position( &self.display_snapshot, @@ -3518,29 +3466,13 @@ impl Snapshot { &self.scroll_top_anchor, ) } +} - pub fn max_point(&self) -> DisplayPoint { - self.display_snapshot.max_point() - } - - pub fn longest_row(&self) -> u32 { - self.display_snapshot.longest_row() - } - - pub fn line_len(&self, display_row: u32) -> u32 { - self.display_snapshot.line_len(display_row) - } - - pub fn line(&self, display_row: u32) -> String { - self.display_snapshot.line(display_row) - } - - pub fn prev_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) { - self.display_snapshot.prev_row_boundary(point) - } +impl Deref for Snapshot { + type Target = DisplayMapSnapshot; - pub fn next_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) { - self.display_snapshot.next_row_boundary(point) + fn deref(&self) -> &Self::Target { + &self.display_snapshot } } @@ -3709,6 +3641,20 @@ impl SelectionExt for Selection { } } +fn render_diagnostic( + diagnostic: Diagnostic, + style: &EditorStyle, + valid: bool, + anchor_x: f32, +) -> ElementBox { + let mut text_style = style.text.clone(); + text_style.color = diagnostic_style(diagnostic.severity, valid, &style).text; + Text::new(diagnostic.message, text_style) + .contained() + .with_margin_left(anchor_x) + .boxed() +} + pub fn diagnostic_style( severity: DiagnosticSeverity, valid: bool, diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 5acc5260140ca7509c99a6bddeda2cd3a2dd3b3b..db16b3f01d5c04add650a3116a9812f809da1b72 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1,6 +1,8 @@ +use crate::display_map::{BlockContext, ToDisplayPoint}; + use super::{ - DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, - Select, SelectPhase, Snapshot, SoftWrap, MAX_LINE_LEN, + DisplayPoint, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, Select, + SelectPhase, Snapshot, SoftWrap, MAX_LINE_LEN, }; use clock::ReplicaId; use gpui::{ @@ -13,11 +15,11 @@ use gpui::{ json::{self, ToJson}, keymap::Keystroke, text_layout::{self, RunStyle, TextLayoutCache}, - AppContext, Axis, Border, Element, Event, EventContext, FontCache, LayoutContext, + AppContext, Axis, Border, Element, ElementBox, Event, EventContext, FontCache, LayoutContext, MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle, }; use json::json; -use language::Chunk; +use language::{Chunk, ToPoint}; use smallvec::SmallVec; use std::{ cmp::{self, Ordering}, @@ -25,7 +27,6 @@ use std::{ fmt::Write, ops::Range, }; -use theme::BlockStyle; pub struct EditorElement { view: WeakViewHandle, @@ -219,7 +220,6 @@ impl EditorElement { ) { let bounds = gutter_bounds.union_rect(text_bounds); let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height; - let start_row = layout.snapshot.scroll_position().y() as u32; let editor = self.view(cx.app); let style = &self.settings.style; cx.scene.push_quad(Quad { @@ -278,51 +278,6 @@ impl EditorElement { }); } } - - // Draw block backgrounds - for (ixs, block_style) in &layout.block_layouts { - let row = start_row + ixs.start; - let offset = vec2f(0., row as f32 * layout.line_height - scroll_top); - let height = ixs.len() as f32 * layout.line_height; - cx.scene.push_quad(Quad { - bounds: RectF::new( - text_bounds.origin() + offset, - vec2f(text_bounds.width(), height), - ), - background: block_style.background, - border: block_style - .border - .map_or(Default::default(), |color| Border { - width: 1., - color, - overlay: true, - top: true, - right: false, - bottom: true, - left: false, - }), - corner_radius: 0., - }); - cx.scene.push_quad(Quad { - bounds: RectF::new( - gutter_bounds.origin() + offset, - vec2f(gutter_bounds.width(), height), - ), - background: block_style.gutter_background, - border: block_style - .gutter_border - .map_or(Default::default(), |color| Border { - width: 1., - color, - overlay: true, - top: true, - right: false, - bottom: true, - left: false, - }), - corner_radius: 0., - }); - } } fn paint_gutter( @@ -461,6 +416,24 @@ impl EditorElement { cx.scene.pop_layer(); } + fn paint_blocks( + &mut self, + text_bounds: RectF, + visible_bounds: RectF, + layout: &mut LayoutState, + cx: &mut PaintContext, + ) { + let scroll_position = layout.snapshot.scroll_position(); + let scroll_left = scroll_position.x() * layout.em_width; + let scroll_top = scroll_position.y() * layout.line_height; + + for (row, element) in &mut layout.blocks { + let origin = text_bounds.origin() + + vec2f(-scroll_left, *row as f32 * layout.line_height - scroll_top); + element.paint(origin, visible_bounds, cx); + } + } + fn max_line_number_width(&self, snapshot: &Snapshot, cx: &LayoutContext) -> f32 { let digit_count = (snapshot.buffer_row_count() as f32).log10().floor() as usize + 1; let style = &self.settings.style; @@ -487,18 +460,13 @@ impl EditorElement { active_rows: &BTreeMap, snapshot: &Snapshot, cx: &LayoutContext, - ) -> ( - Vec>, - Vec<(Range, BlockStyle)>, - ) { + ) -> Vec> { let style = &self.settings.style; let include_line_numbers = snapshot.mode == EditorMode::Full; - let mut last_block_id = None; - let mut blocks = Vec::<(Range, BlockStyle)>::new(); let mut line_number_layouts = Vec::with_capacity(rows.len()); let mut line_number = String::new(); for (ix, row) in snapshot - .buffer_rows(rows.start, cx) + .buffer_rows(rows.start) .take((rows.end - rows.start) as usize) .enumerate() { @@ -508,46 +476,29 @@ impl EditorElement { } else { style.line_number }; - match row { - DisplayRow::Buffer(buffer_row) => { - if include_line_numbers { - line_number.clear(); - write!(&mut line_number, "{}", buffer_row + 1).unwrap(); - line_number_layouts.push(Some(cx.text_layout_cache.layout_str( - &line_number, - style.text.font_size, - &[( - line_number.len(), - RunStyle { - font_id: style.text.font_id, - color, - underline: None, - }, - )], - ))); - } - last_block_id = None; - } - DisplayRow::Block(block_id, style) => { - let ix = ix as u32; - if last_block_id == Some(block_id) { - if let Some((row_range, _)) = blocks.last_mut() { - row_range.end += 1; - } - } else if let Some(style) = style { - blocks.push((ix..ix + 1, style)); - } - line_number_layouts.push(None); - last_block_id = Some(block_id); - } - DisplayRow::Wrap => { - line_number_layouts.push(None); - last_block_id = None; + if let Some(buffer_row) = row { + if include_line_numbers { + line_number.clear(); + write!(&mut line_number, "{}", buffer_row + 1).unwrap(); + line_number_layouts.push(Some(cx.text_layout_cache.layout_str( + &line_number, + style.text.font_size, + &[( + line_number.len(), + RunStyle { + font_id: style.text.font_id, + color, + underline: None, + }, + )], + ))); } + } else { + line_number_layouts.push(None); } } - (line_number_layouts, blocks) + line_number_layouts } fn layout_lines( @@ -598,7 +549,7 @@ impl EditorElement { let mut styles = Vec::new(); let mut row = rows.start; let mut line_exceeded_max_len = false; - let chunks = snapshot.chunks(rows.clone(), Some(&style.syntax), cx); + let chunks = snapshot.chunks(rows.clone(), Some(&style.syntax)); let newline_chunk = Chunk { text: "\n", @@ -668,6 +619,46 @@ impl EditorElement { layouts } + + fn layout_blocks( + &mut self, + rows: Range, + snapshot: &Snapshot, + text_width: f32, + line_height: f32, + style: &EditorStyle, + line_layouts: &[text_layout::Line], + cx: &mut LayoutContext, + ) -> Vec<(u32, ElementBox)> { + 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 = 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 }); + element.layout( + SizeConstraint { + min: Vector2F::zero(), + max: vec2f(text_width, block.height() as f32 * line_height), + }, + cx, + ); + (start_row, element) + }) + .collect() + } } impl Element for EditorElement { @@ -773,8 +764,7 @@ impl Element for EditorElement { } }); - let (line_number_layouts, block_layouts) = - self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx); + let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx); let mut max_visible_line_width = 0.0; let line_layouts = self.layout_lines(start_row..end_row, &mut snapshot, cx); @@ -784,6 +774,16 @@ impl Element for EditorElement { } } + let blocks = self.layout_blocks( + start_row..end_row, + &snapshot, + text_size.x(), + line_height, + &style, + &line_layouts, + cx, + ); + let mut layout = LayoutState { size, gutter_size, @@ -797,7 +797,7 @@ impl Element for EditorElement { highlighted_row, line_layouts, line_number_layouts, - block_layouts, + blocks, line_height, em_width, em_advance, @@ -853,6 +853,7 @@ impl Element for EditorElement { self.paint_gutter(gutter_bounds, visible_bounds, layout, cx); } self.paint_text(text_bounds, visible_bounds, layout, cx); + self.paint_blocks(text_bounds, visible_bounds, layout, cx); cx.scene.pop_layer(); @@ -927,7 +928,7 @@ pub struct LayoutState { highlighted_row: Option, line_layouts: Vec, line_number_layouts: Vec>, - block_layouts: Vec<(Range, BlockStyle)>, + blocks: Vec<(u32, ElementBox)>, line_height: f32, em_width: f32, em_advance: f32, @@ -940,7 +941,8 @@ pub struct LayoutState { impl LayoutState { fn scroll_width(&self, layout_cache: &TextLayoutCache) -> f32 { let row = self.snapshot.longest_row(); - let longest_line_width = self.layout_line(row, &self.snapshot, layout_cache).width(); + let longest_line_width = + layout_line(row, &self.snapshot, &self.style, layout_cache).width(); longest_line_width.max(self.max_visible_line_width) + self.overscroll.x() } @@ -955,36 +957,36 @@ impl LayoutState { max_row.saturating_sub(1) as f32, ) } +} - pub fn layout_line( - &self, - row: u32, - snapshot: &Snapshot, - layout_cache: &TextLayoutCache, - ) -> text_layout::Line { - let mut line = snapshot.line(row); - - if line.len() > MAX_LINE_LEN { - let mut len = MAX_LINE_LEN; - while !line.is_char_boundary(len) { - len -= 1; - } - line.truncate(len); +fn layout_line( + row: u32, + snapshot: &Snapshot, + style: &EditorStyle, + layout_cache: &TextLayoutCache, +) -> text_layout::Line { + let mut line = snapshot.line(row); + + if line.len() > MAX_LINE_LEN { + let mut len = MAX_LINE_LEN; + while !line.is_char_boundary(len) { + len -= 1; } - - layout_cache.layout_str( - &line, - self.style.text.font_size, - &[( - snapshot.line_len(row) as usize, - RunStyle { - font_id: self.style.text.font_id, - color: Color::black(), - underline: None, - }, - )], - ) + line.truncate(len); } + + layout_cache.layout_str( + &line, + style.text.font_size, + &[( + snapshot.line_len(row) as usize, + RunStyle { + font_id: style.text.font_id, + color: Color::black(), + underline: None, + }, + )], + ) } pub struct PaintState { @@ -1185,7 +1187,7 @@ mod tests { }); let element = EditorElement::new(editor.downgrade(), settings); - let (layouts, _) = editor.update(cx, |editor, cx| { + let layouts = editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); let mut presenter = cx.build_presenter(window_id, 30.); let mut layout_cx = presenter.build_layout_context(false, cx); diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index c8048ef3fa2f002656fb2a6943292e613f655aa0..c0b6cdd14391e6e8e6c7a628f04efc962e553e12 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -301,6 +301,10 @@ impl Default for Lifecycle { } impl ElementBox { + pub fn name(&self) -> Option<&str> { + self.0.name.as_deref() + } + pub fn metadata(&self) -> Option<&T> { let element = unsafe { &*self.0.element.as_ptr() }; element.metadata().and_then(|m| m.downcast_ref()) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 716ce4a46a42faa14409b3c18ba1e4be02cba5e6..6f685ce70d2118c6068ddcf26ff90239815d4de3 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -253,8 +253,6 @@ pub struct EditorStyle { #[derive(Copy, Clone, Deserialize, Default)] pub struct DiagnosticStyle { pub text: Color, - #[serde(flatten)] - pub block: BlockStyle, } #[derive(Clone, Copy, Default, Deserialize)] @@ -273,14 +271,6 @@ pub struct InputEditorStyle { pub selection: SelectionStyle, } -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)] -pub struct BlockStyle { - pub background: Option, - pub border: Option, - pub gutter_background: Option, - pub gutter_border: Option, -} - impl EditorStyle { pub fn placeholder_text(&self) -> &TextStyle { self.placeholder_text.as_ref().unwrap_or(&self.text)