Pass a &mut BlockContext when rendering blocks

This wraps and derefs to `RenderContext<Editor>`, so that we can
easily use `MouseEventHandler`s in blocks.
This commit is contained in:
Antonio Scandurra 2022-05-31 15:44:35 +02:00
parent 9fa03b2f28
commit aefdde66a6
4 changed files with 83 additions and 82 deletions

View file

@ -702,7 +702,7 @@ mod tests {
use super::*; use super::*;
use editor::{ use editor::{
display_map::{BlockContext, TransformBlock}, display_map::{BlockContext, TransformBlock},
DisplayPoint, EditorSnapshot, DisplayPoint,
}; };
use gpui::TestAppContext; use gpui::TestAppContext;
use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16}; use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16};
@ -835,10 +835,8 @@ mod tests {
view.next_notification(&cx).await; view.next_notification(&cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
let editor = view.editor.update(cx, |editor, cx| editor.snapshot(cx));
assert_eq!( assert_eq!(
editor_blocks(&editor, cx), editor_blocks(&view.editor, cx),
[ [
(0, "path header block".into()), (0, "path header block".into()),
(2, "diagnostic header".into()), (2, "diagnostic header".into()),
@ -848,7 +846,7 @@ mod tests {
] ]
); );
assert_eq!( assert_eq!(
editor.text(), view.editor.update(cx, |editor, cx| editor.display_text(cx)),
concat!( concat!(
// //
// main.rs // main.rs
@ -923,10 +921,8 @@ mod tests {
view.next_notification(&cx).await; view.next_notification(&cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
let editor = view.editor.update(cx, |editor, cx| editor.snapshot(cx));
assert_eq!( assert_eq!(
editor_blocks(&editor, cx), editor_blocks(&view.editor, cx),
[ [
(0, "path header block".into()), (0, "path header block".into()),
(2, "diagnostic header".into()), (2, "diagnostic header".into()),
@ -938,7 +934,7 @@ mod tests {
] ]
); );
assert_eq!( assert_eq!(
editor.text(), view.editor.update(cx, |editor, cx| editor.display_text(cx)),
concat!( concat!(
// //
// consts.rs // consts.rs
@ -1038,10 +1034,8 @@ mod tests {
view.next_notification(&cx).await; view.next_notification(&cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
let editor = view.editor.update(cx, |editor, cx| editor.snapshot(cx));
assert_eq!( assert_eq!(
editor_blocks(&editor, cx), editor_blocks(&view.editor, cx),
[ [
(0, "path header block".into()), (0, "path header block".into()),
(2, "diagnostic header".into()), (2, "diagnostic header".into()),
@ -1055,7 +1049,7 @@ mod tests {
] ]
); );
assert_eq!( assert_eq!(
editor.text(), view.editor.update(cx, |editor, cx| editor.display_text(cx)),
concat!( concat!(
// //
// consts.rs // consts.rs
@ -1115,36 +1109,44 @@ mod tests {
}); });
} }
fn editor_blocks(editor: &EditorSnapshot, cx: &AppContext) -> Vec<(u32, String)> { fn editor_blocks(
editor editor: &ViewHandle<Editor>,
.blocks_in_range(0..editor.max_point().row()) cx: &mut MutableAppContext,
.filter_map(|(row, block)| { ) -> Vec<(u32, String)> {
let name = match block { let mut presenter = cx.build_presenter(editor.id(), 0.);
TransformBlock::Custom(block) => block let mut cx = presenter.build_layout_context(Default::default(), false, cx);
.render(&BlockContext { cx.render(editor, |editor, cx| {
cx, let snapshot = editor.snapshot(cx);
anchor_x: 0., snapshot
scroll_x: 0., .blocks_in_range(0..snapshot.max_point().row())
gutter_padding: 0., .filter_map(|(row, block)| {
gutter_width: 0., let name = match block {
line_height: 0., TransformBlock::Custom(block) => block
em_width: 0., .render(&mut BlockContext {
}) cx,
.name()? anchor_x: 0.,
.to_string(), scroll_x: 0.,
TransformBlock::ExcerptHeader { gutter_padding: 0.,
starts_new_buffer, .. gutter_width: 0.,
} => { line_height: 0.,
if *starts_new_buffer { em_width: 0.,
"path header block".to_string() })
} else { .name()?
"collapsed context".to_string() .to_string(),
TransformBlock::ExcerptHeader {
starts_new_buffer, ..
} => {
if *starts_new_buffer {
"path header block".to_string()
} else {
"collapsed context".to_string()
}
} }
} };
};
Some((row, name)) Some((row, name))
}) })
.collect() .collect()
})
} }
} }

View file

@ -4,14 +4,14 @@ use super::{
}; };
use crate::{Anchor, ToPoint as _}; use crate::{Anchor, ToPoint as _};
use collections::{Bound, HashMap, HashSet}; use collections::{Bound, HashMap, HashSet};
use gpui::{AppContext, ElementBox}; use gpui::{ElementBox, RenderContext};
use language::{BufferSnapshot, Chunk, Patch}; use language::{BufferSnapshot, Chunk, Patch};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ use std::{
cell::RefCell, cell::RefCell,
cmp::{self, Ordering}, cmp::{self, Ordering},
fmt::Debug, fmt::Debug,
ops::{Deref, Range}, ops::{Deref, DerefMut, Range},
sync::{ sync::{
atomic::{AtomicUsize, Ordering::SeqCst}, atomic::{AtomicUsize, Ordering::SeqCst},
Arc, Arc,
@ -50,7 +50,7 @@ struct BlockRow(u32);
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
struct WrapRow(u32); struct WrapRow(u32);
pub type RenderBlock = Arc<dyn Fn(&BlockContext) -> ElementBox>; pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> ElementBox>;
pub struct Block { pub struct Block {
id: BlockId, id: BlockId,
@ -67,12 +67,12 @@ where
{ {
pub position: P, pub position: P,
pub height: u8, pub height: u8,
pub render: Arc<dyn Fn(&BlockContext) -> ElementBox>, pub render: Arc<dyn Fn(&mut BlockContext) -> ElementBox>,
pub disposition: BlockDisposition, pub disposition: BlockDisposition,
} }
pub struct BlockContext<'a> { pub struct BlockContext<'a, 'b> {
pub cx: &'a AppContext, pub cx: &'b mut RenderContext<'a, crate::Editor>,
pub anchor_x: f32, pub anchor_x: f32,
pub scroll_x: f32, pub scroll_x: f32,
pub gutter_width: f32, pub gutter_width: f32,
@ -916,16 +916,22 @@ impl BlockDisposition {
} }
} }
impl<'a> Deref for BlockContext<'a> { impl<'a, 'b> Deref for BlockContext<'a, 'b> {
type Target = AppContext; type Target = RenderContext<'a, crate::Editor>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.cx self.cx
}
}
impl<'a, 'b> DerefMut for BlockContext<'a, 'b> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.cx
} }
} }
impl Block { impl Block {
pub fn render(&self, cx: &BlockContext) -> ElementBox { pub fn render(&self, cx: &mut BlockContext) -> ElementBox {
self.render.lock()(cx) self.render.lock()(cx)
} }
@ -1008,7 +1014,7 @@ mod tests {
let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1); let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
let mut writer = block_map.write(wraps_snapshot.clone(), Default::default()); let mut writer = block_map.write(wraps_snapshot.clone(), Default::default());
writer.insert(vec![ let block_ids = writer.insert(vec![
BlockProperties { BlockProperties {
position: buffer_snapshot.anchor_after(Point::new(1, 0)), position: buffer_snapshot.anchor_after(Point::new(1, 0)),
height: 1, height: 1,
@ -1036,22 +1042,7 @@ mod tests {
.blocks_in_range(0..8) .blocks_in_range(0..8)
.map(|(start_row, block)| { .map(|(start_row, block)| {
let block = block.as_custom().unwrap(); let block = block.as_custom().unwrap();
( (start_row..start_row + block.height as u32, block.id)
start_row..start_row + block.height as u32,
block
.render(&BlockContext {
cx,
anchor_x: 0.,
gutter_padding: 0.,
scroll_x: 0.,
gutter_width: 0.,
line_height: 0.,
em_width: 0.,
})
.name()
.unwrap()
.to_string(),
)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -1059,9 +1050,9 @@ mod tests {
assert_eq!( assert_eq!(
blocks, blocks,
&[ &[
(1..2, "block 1".to_string()), (1..2, block_ids[0]),
(2..4, "block 2".to_string()), (2..4, block_ids[1]),
(7..10, "block 3".to_string()), (7..10, block_ids[2]),
] ]
); );

View file

@ -4745,7 +4745,7 @@ impl Editor {
height: 1, height: 1,
render: Arc::new({ render: Arc::new({
let editor = rename_editor.clone(); let editor = rename_editor.clone();
move |cx: &BlockContext| { move |cx: &mut BlockContext| {
ChildView::new(editor.clone()) ChildView::new(editor.clone())
.contained() .contained()
.with_padding_left(cx.anchor_x) .with_padding_left(cx.anchor_x)
@ -5866,7 +5866,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
highlighted_lines.push(highlight_diagnostic_message(line)); highlighted_lines.push(highlight_diagnostic_message(line));
} }
Arc::new(move |cx: &BlockContext| { Arc::new(move |cx: &mut BlockContext| {
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let theme = &settings.theme.editor; let theme = &settings.theme.editor;
let style = diagnostic_style(diagnostic.severity, is_valid, theme); let style = diagnostic_style(diagnostic.severity, is_valid, theme);

View file

@ -755,6 +755,12 @@ impl EditorElement {
line_layouts: &[text_layout::Line], line_layouts: &[text_layout::Line],
cx: &mut LayoutContext, cx: &mut LayoutContext,
) -> Vec<(u32, ElementBox)> { ) -> Vec<(u32, ElementBox)> {
let editor = if let Some(editor) = self.view.upgrade(cx) {
editor
} else {
return Default::default();
};
let scroll_x = snapshot.scroll_position.x(); let scroll_x = snapshot.scroll_position.x();
snapshot snapshot
.blocks_in_range(rows.clone()) .blocks_in_range(rows.clone())
@ -774,14 +780,16 @@ impl EditorElement {
.x_for_index(align_to.column() as usize) .x_for_index(align_to.column() as usize)
}; };
block.render(&BlockContext { cx.render(&editor, |_, cx| {
cx, block.render(&mut BlockContext {
anchor_x, cx,
gutter_padding, anchor_x,
line_height, gutter_padding,
scroll_x, line_height,
gutter_width, scroll_x,
em_width, gutter_width,
em_width,
})
}) })
} }
TransformBlock::ExcerptHeader { TransformBlock::ExcerptHeader {