Start work on generalizing the BlockMap to allow arbitrary elements

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2021-12-01 15:25:55 -08:00
parent e668ff8bcd
commit 0c714210ff
7 changed files with 579 additions and 897 deletions

View file

@ -3,13 +3,12 @@ mod fold_map;
mod tab_map; mod tab_map;
mod wrap_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 block_map::{BlockMap, BlockPoint};
use fold_map::{FoldMap, ToFoldPoint as _}; use fold_map::{FoldMap, ToFoldPoint as _};
use gpui::{ use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle};
fonts::{FontId, HighlightStyle},
AppContext, Entity, ModelContext, ModelHandle,
};
use language::{Anchor, Buffer, Point, Subscription as BufferSubscription, ToOffset, ToPoint}; use language::{Anchor, Buffer, Point, Subscription as BufferSubscription, ToOffset, ToPoint};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -17,8 +16,7 @@ use std::{
}; };
use sum_tree::Bias; use sum_tree::Bias;
use tab_map::TabMap; use tab_map::TabMap;
use text::Rope; use theme::SyntaxTheme;
use theme::{BlockStyle, SyntaxTheme};
use wrap_map::WrapMap; use wrap_map::WrapMap;
pub trait ToDisplayPoint { pub trait ToDisplayPoint {
@ -124,14 +122,13 @@ impl DisplayMap {
self.block_map.read(snapshot, edits, cx); self.block_map.read(snapshot, edits, cx);
} }
pub fn insert_blocks<P, T>( pub fn insert_blocks<P>(
&mut self, &mut self,
blocks: impl IntoIterator<Item = BlockProperties<P, T>>, blocks: impl IntoIterator<Item = BlockProperties<P>>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Vec<BlockId> ) -> Vec<BlockId>
where where
P: ToOffset + Clone, P: ToOffset + Clone,
T: Into<Rope> + Clone,
{ {
let snapshot = self.buffer.read(cx).snapshot(); let snapshot = self.buffer.read(cx).snapshot();
let edits = self.buffer_subscription.consume().into_inner(); let edits = self.buffer_subscription.consume().into_inner();
@ -144,12 +141,11 @@ impl DisplayMap {
block_map.insert(blocks, cx) block_map.insert(blocks, cx)
} }
pub fn restyle_blocks<F1, F2>(&mut self, styles: HashMap<BlockId, (Option<F1>, Option<F2>)>) pub fn replace_blocks<F>(&mut self, styles: HashMap<BlockId, F>)
where where
F1: 'static + Fn(&AppContext) -> Vec<(usize, HighlightStyle)>, F: 'static + Fn(&BlockContext) -> ElementBox,
F2: 'static + Fn(&AppContext) -> BlockStyle,
{ {
self.block_map.restyle(styles); self.block_map.replace(styles);
} }
pub fn remove_blocks(&mut self, ids: HashSet<BlockId>, cx: &mut ModelContext<Self>) { pub fn remove_blocks(&mut self, ids: HashSet<BlockId>, cx: &mut ModelContext<Self>) {
@ -198,8 +194,8 @@ impl DisplayMapSnapshot {
self.buffer_snapshot.len() == 0 self.buffer_snapshot.len() == 0
} }
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> {
self.blocks_snapshot.buffer_rows(start_row, cx) self.blocks_snapshot.buffer_rows(start_row)
} }
pub fn buffer_row_count(&self) -> u32 { pub fn buffer_row_count(&self) -> u32 {
@ -256,7 +252,7 @@ impl DisplayMapSnapshot {
pub fn text_chunks(&self, display_row: u32) -> impl Iterator<Item = &str> { pub fn text_chunks(&self, display_row: u32) -> impl Iterator<Item = &str> {
self.blocks_snapshot 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) .map(|h| h.text)
} }
@ -264,9 +260,8 @@ impl DisplayMapSnapshot {
&'a self, &'a self,
display_rows: Range<u32>, display_rows: Range<u32>,
theme: Option<&'a SyntaxTheme>, theme: Option<&'a SyntaxTheme>,
cx: &'a AppContext,
) -> block_map::Chunks<'a> { ) -> 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<Item = char> + 'a { pub fn chars_at<'a>(&'a self, point: DisplayPoint) -> impl Iterator<Item = char> + 'a {
@ -322,6 +317,13 @@ impl DisplayMapSnapshot {
self.folds_snapshot.folds_in_range(range) self.folds_snapshot.folds_in_range(range)
} }
pub fn blocks_in_range<'a>(
&'a self,
rows: Range<u32>,
) -> impl Iterator<Item = (u32, &'a AlignedBlock)> {
self.blocks_snapshot.blocks_in_range(rows)
}
pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool { pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool {
self.folds_snapshot.intersects_fold(offset) 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<BlockStyle>),
Wrap,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -1065,7 +1060,7 @@ mod tests {
) -> Vec<(String, Option<Color>)> { ) -> Vec<(String, Option<Color>)> {
let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
let mut chunks: Vec<(String, Option<Color>)> = Vec::new(); let mut chunks: Vec<(String, Option<Color>)> = 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); let color = chunk.highlight_style.map(|s| s.color);
if let Some((last_chunk, last_color)) = chunks.last_mut() { if let Some((last_chunk, last_color)) = chunks.last_mut() {
if color == *last_color { if color == *last_color {

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,6 @@
use super::{ use super::{
fold_map, fold_map,
tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint}, tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint},
DisplayRow,
}; };
use gpui::{ use gpui::{
fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, ModelHandle, MutableAppContext, fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, ModelHandle, MutableAppContext,
@ -607,13 +606,6 @@ impl Snapshot {
len as u32 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<u32> { pub fn soft_wrap_indent(&self, row: u32) -> Option<u32> {
let mut cursor = self.transforms.cursor::<WrapPoint>(); let mut cursor = self.transforms.cursor::<WrapPoint>();
cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Right, &()); cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Right, &());
@ -719,11 +711,7 @@ impl Snapshot {
prev_tab_row = tab_point.row(); prev_tab_row = tab_point.row();
soft_wrapped = false; soft_wrapped = false;
} }
expected_buffer_rows.push(if soft_wrapped { expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) });
DisplayRow::Wrap
} else {
DisplayRow::Buffer(buffer_row)
});
} }
for start_display_row in 0..expected_buffer_rows.len() { 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> { impl<'a> Iterator for BufferRows<'a> {
type Item = DisplayRow; type Item = Option<u32>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.output_row > self.max_output_row { if self.output_row > self.max_output_row {
@ -823,11 +811,7 @@ impl<'a> Iterator for BufferRows<'a> {
self.soft_wrapped = true; self.soft_wrapped = true;
} }
Some(if soft_wrapped { Some(if soft_wrapped { None } else { Some(buffer_row) })
DisplayRow::Wrap
} else {
DisplayRow::Buffer(buffer_row)
})
} }
} }

View file

@ -8,11 +8,12 @@ mod test;
use aho_corasick::AhoCorasick; use aho_corasick::AhoCorasick;
use clock::ReplicaId; use clock::ReplicaId;
pub use display_map::DisplayPoint;
use display_map::*; use display_map::*;
pub use display_map::{DisplayPoint, DisplayRow};
pub use element::*; pub use element::*;
use gpui::{ use gpui::{
action, action,
elements::Text,
geometry::vector::{vec2f, Vector2F}, geometry::vector::{vec2f, Vector2F},
keymap::Binding, keymap::Binding,
text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle,
@ -28,14 +29,14 @@ use std::{
cmp, cmp,
collections::HashMap, collections::HashMap,
iter, mem, iter, mem,
ops::{Range, RangeInclusive}, ops::{Deref, Range, RangeInclusive},
rc::Rc, rc::Rc,
sync::Arc, sync::Arc,
time::Duration, time::Duration,
}; };
use sum_tree::Bias; use sum_tree::Bias;
use text::rope::TextDimension; use text::rope::TextDimension;
use theme::{DiagnosticStyle, EditorStyle, SyntaxTheme}; use theme::{DiagnosticStyle, EditorStyle};
use util::post_inc; use util::post_inc;
use workspace::{EntryOpener, Workspace}; use workspace::{EntryOpener, Workspace};
@ -2877,35 +2878,16 @@ impl Editor {
active_diagnostics.is_valid = is_valid; active_diagnostics.is_valid = is_valid;
let mut new_styles = HashMap::new(); let mut new_styles = HashMap::new();
for (block_id, diagnostic) in &active_diagnostics.blocks { 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(); let build_settings = self.build_settings.clone();
move |cx: &AppContext| { let diagnostic = diagnostic.clone();
let settings = build_settings.borrow()(cx); new_styles.insert(*block_id, move |cx: &BlockContext| {
vec![( let diagnostic = diagnostic.clone();
message_len, let settings = build_settings.borrow()(cx.cx);
diagnostic_style(severity, is_valid, &settings.style) render_diagnostic(diagnostic, &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
}
}),
),
);
} }
self.display_map 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( .insert_blocks(
diagnostic_group.iter().map(|(range, diagnostic)| { diagnostic_group.iter().map(|(range, diagnostic)| {
let build_settings = self.build_settings.clone(); let build_settings = self.build_settings.clone();
let message_len = diagnostic.message.len(); let diagnostic = diagnostic.clone();
let severity = diagnostic.severity; let message_height = diagnostic.message.lines().count() as u8;
BlockProperties { BlockProperties {
position: range.start, position: range.start,
text: diagnostic.message.as_str(), height: message_height,
build_runs: Some(Arc::new({ render: Arc::new(move |cx| {
let build_settings = build_settings.clone(); let settings = build_settings.borrow()(cx.cx);
move |cx| { let diagnostic = diagnostic.clone();
let settings = build_settings.borrow()(cx); render_diagnostic(diagnostic, &settings.style)
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
}
})),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
} }
}), }),
@ -3482,10 +3451,6 @@ impl Editor {
} }
impl Snapshot { impl Snapshot {
pub fn is_empty(&self) -> bool {
self.display_snapshot.is_empty()
}
pub fn is_focused(&self) -> bool { pub fn is_focused(&self) -> bool {
self.is_focused self.is_focused
} }
@ -3494,23 +3459,6 @@ impl Snapshot {
self.placeholder_text.as_ref() 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<u32>,
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 { pub fn scroll_position(&self) -> Vector2F {
compute_scroll_position( compute_scroll_position(
&self.display_snapshot, &self.display_snapshot,
@ -3518,29 +3466,13 @@ impl Snapshot {
&self.scroll_top_anchor, &self.scroll_top_anchor,
) )
} }
pub fn max_point(&self) -> DisplayPoint {
self.display_snapshot.max_point()
} }
pub fn longest_row(&self) -> u32 { impl Deref for Snapshot {
self.display_snapshot.longest_row() type Target = DisplayMapSnapshot;
}
pub fn line_len(&self, display_row: u32) -> u32 { fn deref(&self) -> &Self::Target {
self.display_snapshot.line_len(display_row) &self.display_snapshot
}
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)
}
pub fn next_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
self.display_snapshot.next_row_boundary(point)
} }
} }
@ -3709,6 +3641,12 @@ impl SelectionExt for Selection<Point> {
} }
} }
fn render_diagnostic(diagnostic: Diagnostic, style: &EditorStyle) -> ElementBox {
let mut text_style = style.text.clone();
text_style.color = diagnostic_style(diagnostic.severity, true, &style).text;
Text::new(diagnostic.message, text_style).boxed()
}
pub fn diagnostic_style( pub fn diagnostic_style(
severity: DiagnosticSeverity, severity: DiagnosticSeverity,
valid: bool, valid: bool,

View file

@ -1,6 +1,8 @@
use crate::display_map::BlockContext;
use super::{ use super::{
DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, DisplayPoint, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, Select,
Select, SelectPhase, Snapshot, SoftWrap, MAX_LINE_LEN, SelectPhase, Snapshot, SoftWrap, MAX_LINE_LEN,
}; };
use clock::ReplicaId; use clock::ReplicaId;
use gpui::{ use gpui::{
@ -13,7 +15,7 @@ use gpui::{
json::{self, ToJson}, json::{self, ToJson},
keymap::Keystroke, keymap::Keystroke,
text_layout::{self, RunStyle, TextLayoutCache}, 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, MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
}; };
use json::json; use json::json;
@ -25,7 +27,6 @@ use std::{
fmt::Write, fmt::Write,
ops::Range, ops::Range,
}; };
use theme::BlockStyle;
pub struct EditorElement { pub struct EditorElement {
view: WeakViewHandle<Editor>, view: WeakViewHandle<Editor>,
@ -278,51 +279,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( fn paint_gutter(
@ -461,6 +417,18 @@ impl EditorElement {
cx.scene.pop_layer(); cx.scene.pop_layer();
} }
fn paint_blocks(
&mut self,
bounds: RectF,
visible_bounds: RectF,
layout: &LayoutState,
cx: &mut PaintContext,
) {
for (row_range, block) in &layout.blocks {
//
}
}
fn max_line_number_width(&self, snapshot: &Snapshot, cx: &LayoutContext) -> f32 { 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 digit_count = (snapshot.buffer_row_count() as f32).log10().floor() as usize + 1;
let style = &self.settings.style; let style = &self.settings.style;
@ -487,18 +455,13 @@ impl EditorElement {
active_rows: &BTreeMap<u32, bool>, active_rows: &BTreeMap<u32, bool>,
snapshot: &Snapshot, snapshot: &Snapshot,
cx: &LayoutContext, cx: &LayoutContext,
) -> ( ) -> Vec<Option<text_layout::Line>> {
Vec<Option<text_layout::Line>>,
Vec<(Range<u32>, BlockStyle)>,
) {
let style = &self.settings.style; let style = &self.settings.style;
let include_line_numbers = snapshot.mode == EditorMode::Full; let include_line_numbers = snapshot.mode == EditorMode::Full;
let mut last_block_id = None;
let mut blocks = Vec::<(Range<u32>, BlockStyle)>::new();
let mut line_number_layouts = Vec::with_capacity(rows.len()); let mut line_number_layouts = Vec::with_capacity(rows.len());
let mut line_number = String::new(); let mut line_number = String::new();
for (ix, row) in snapshot for (ix, row) in snapshot
.buffer_rows(rows.start, cx) .buffer_rows(rows.start)
.take((rows.end - rows.start) as usize) .take((rows.end - rows.start) as usize)
.enumerate() .enumerate()
{ {
@ -508,8 +471,7 @@ impl EditorElement {
} else { } else {
style.line_number style.line_number
}; };
match row { if let Some(buffer_row) = row {
DisplayRow::Buffer(buffer_row) => {
if include_line_numbers { if include_line_numbers {
line_number.clear(); line_number.clear();
write!(&mut line_number, "{}", buffer_row + 1).unwrap(); write!(&mut line_number, "{}", buffer_row + 1).unwrap();
@ -526,28 +488,12 @@ impl EditorElement {
)], )],
))); )));
} }
last_block_id = None; } else {
}
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); line_number_layouts.push(None);
last_block_id = Some(block_id);
}
DisplayRow::Wrap => {
line_number_layouts.push(None);
last_block_id = None;
}
} }
} }
(line_number_layouts, blocks) line_number_layouts
} }
fn layout_lines( fn layout_lines(
@ -598,7 +544,7 @@ impl EditorElement {
let mut styles = Vec::new(); let mut styles = Vec::new();
let mut row = rows.start; let mut row = rows.start;
let mut line_exceeded_max_len = false; 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 { let newline_chunk = Chunk {
text: "\n", text: "\n",
@ -668,6 +614,27 @@ impl EditorElement {
layouts layouts
} }
fn layout_blocks(
&mut self,
rows: Range<u32>,
snapshot: &Snapshot,
cx: &LayoutContext,
) -> Vec<(Range<u32>, ElementBox)> {
snapshot
.blocks_in_range(rows)
.map(|(start_row, block)| {
(
start_row..start_row + block.height(),
block.render(&BlockContext {
cx,
gutter_width: 0.0,
anchor_x: 0.0,
}),
)
})
.collect()
}
} }
impl Element for EditorElement { impl Element for EditorElement {
@ -773,8 +740,7 @@ impl Element for EditorElement {
} }
}); });
let (line_number_layouts, block_layouts) = let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
let mut max_visible_line_width = 0.0; let mut max_visible_line_width = 0.0;
let line_layouts = self.layout_lines(start_row..end_row, &mut snapshot, cx); let line_layouts = self.layout_lines(start_row..end_row, &mut snapshot, cx);
@ -784,6 +750,8 @@ impl Element for EditorElement {
} }
} }
let blocks = self.layout_blocks(start_row..end_row, &snapshot, cx);
let mut layout = LayoutState { let mut layout = LayoutState {
size, size,
gutter_size, gutter_size,
@ -797,7 +765,7 @@ impl Element for EditorElement {
highlighted_row, highlighted_row,
line_layouts, line_layouts,
line_number_layouts, line_number_layouts,
block_layouts, blocks,
line_height, line_height,
em_width, em_width,
em_advance, em_advance,
@ -853,6 +821,7 @@ impl Element for EditorElement {
self.paint_gutter(gutter_bounds, visible_bounds, layout, cx); self.paint_gutter(gutter_bounds, visible_bounds, layout, cx);
} }
self.paint_text(text_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(); cx.scene.pop_layer();
@ -927,7 +896,7 @@ pub struct LayoutState {
highlighted_row: Option<u32>, highlighted_row: Option<u32>,
line_layouts: Vec<text_layout::Line>, line_layouts: Vec<text_layout::Line>,
line_number_layouts: Vec<Option<text_layout::Line>>, line_number_layouts: Vec<Option<text_layout::Line>>,
block_layouts: Vec<(Range<u32>, BlockStyle)>, blocks: Vec<(Range<u32>, ElementBox)>,
line_height: f32, line_height: f32,
em_width: f32, em_width: f32,
em_advance: f32, em_advance: f32,
@ -1185,7 +1154,7 @@ mod tests {
}); });
let element = EditorElement::new(editor.downgrade(), settings); 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 snapshot = editor.snapshot(cx);
let mut presenter = cx.build_presenter(window_id, 30.); let mut presenter = cx.build_presenter(window_id, 30.);
let mut layout_cx = presenter.build_layout_context(false, cx); let mut layout_cx = presenter.build_layout_context(false, cx);

View file

@ -301,6 +301,10 @@ impl<T: Element> Default for Lifecycle<T> {
} }
impl ElementBox { impl ElementBox {
pub fn name(&self) -> Option<&str> {
self.0.name.as_deref()
}
pub fn metadata<T: 'static>(&self) -> Option<&T> { pub fn metadata<T: 'static>(&self) -> Option<&T> {
let element = unsafe { &*self.0.element.as_ptr() }; let element = unsafe { &*self.0.element.as_ptr() };
element.metadata().and_then(|m| m.downcast_ref()) element.metadata().and_then(|m| m.downcast_ref())

View file

@ -253,8 +253,6 @@ pub struct EditorStyle {
#[derive(Copy, Clone, Deserialize, Default)] #[derive(Copy, Clone, Deserialize, Default)]
pub struct DiagnosticStyle { pub struct DiagnosticStyle {
pub text: Color, pub text: Color,
#[serde(flatten)]
pub block: BlockStyle,
} }
#[derive(Clone, Copy, Default, Deserialize)] #[derive(Clone, Copy, Default, Deserialize)]
@ -273,14 +271,6 @@ pub struct InputEditorStyle {
pub selection: SelectionStyle, pub selection: SelectionStyle,
} }
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
pub struct BlockStyle {
pub background: Option<Color>,
pub border: Option<Color>,
pub gutter_background: Option<Color>,
pub gutter_border: Option<Color>,
}
impl EditorStyle { impl EditorStyle {
pub fn placeholder_text(&self) -> &TextStyle { pub fn placeholder_text(&self) -> &TextStyle {
self.placeholder_text.as_ref().unwrap_or(&self.text) self.placeholder_text.as_ref().unwrap_or(&self.text)