Clean up inline assist editor rendering (#15536)
Release Notes: - N/A --------- Co-authored-by: Nathan <nathan@zed.dev> Co-authored-by: Max <max@zed.dev>
This commit is contained in:
co-authored by
Nathan
Max
parent
73d8370177
commit
5b1ea7eda0
@@ -120,9 +120,9 @@ impl DisplayMap {
|
||||
font_size: Pixels,
|
||||
wrap_width: Option<Pixels>,
|
||||
show_excerpt_controls: bool,
|
||||
buffer_header_height: u8,
|
||||
excerpt_header_height: u8,
|
||||
excerpt_footer_height: u8,
|
||||
buffer_header_height: u32,
|
||||
excerpt_header_height: u32,
|
||||
excerpt_footer_height: u32,
|
||||
fold_placeholder: FoldPlaceholder,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
@@ -286,44 +286,11 @@ impl DisplayMap {
|
||||
block_map.insert(blocks)
|
||||
}
|
||||
|
||||
pub fn replace_blocks(
|
||||
pub fn resize_blocks(
|
||||
&mut self,
|
||||
heights_and_renderers: HashMap<CustomBlockId, (Option<u8>, RenderBlock)>,
|
||||
heights: HashMap<CustomBlockId, u32>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
//
|
||||
// Note: previous implementation of `replace_blocks` simply called
|
||||
// `self.block_map.replace(styles)` which just modified the render by replacing
|
||||
// the `RenderBlock` with the new one.
|
||||
//
|
||||
// ```rust
|
||||
// for block in &self.blocks {
|
||||
// if let Some(render) = renderers.remove(&block.id) {
|
||||
// *block.render.lock() = render;
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// If height changes however, we need to update the tree. There's a performance
|
||||
// cost to this, so we'll split the replace blocks into handling the old behavior
|
||||
// directly and the new behavior separately.
|
||||
//
|
||||
//
|
||||
let mut only_renderers = HashMap::<CustomBlockId, RenderBlock>::default();
|
||||
let mut full_replace = HashMap::<CustomBlockId, (u8, RenderBlock)>::default();
|
||||
for (id, (height, render)) in heights_and_renderers {
|
||||
if let Some(height) = height {
|
||||
full_replace.insert(id, (height, render));
|
||||
} else {
|
||||
only_renderers.insert(id, render);
|
||||
}
|
||||
}
|
||||
self.block_map.replace_renderers(only_renderers);
|
||||
|
||||
if full_replace.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
@@ -334,7 +301,11 @@ impl DisplayMap {
|
||||
.wrap_map
|
||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||
let mut block_map = self.block_map.write(snapshot, edits);
|
||||
block_map.replace(full_replace);
|
||||
block_map.resize(heights);
|
||||
}
|
||||
|
||||
pub fn replace_blocks(&mut self, renderers: HashMap<CustomBlockId, RenderBlock>) {
|
||||
self.block_map.replace_blocks(renderers);
|
||||
}
|
||||
|
||||
pub fn remove_blocks(&mut self, ids: HashSet<CustomBlockId>, cx: &mut ModelContext<Self>) {
|
||||
@@ -1051,6 +1022,18 @@ impl DisplaySnapshot {
|
||||
let type_id = TypeId::of::<Tag>();
|
||||
self.inlay_highlights.get(&type_id)
|
||||
}
|
||||
|
||||
pub fn buffer_header_height(&self) -> u32 {
|
||||
self.block_snapshot.buffer_header_height
|
||||
}
|
||||
|
||||
pub fn excerpt_footer_height(&self) -> u32 {
|
||||
self.block_snapshot.excerpt_footer_height
|
||||
}
|
||||
|
||||
pub fn excerpt_header_height(&self) -> u32 {
|
||||
self.block_snapshot.excerpt_header_height
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
|
||||
@@ -35,9 +35,9 @@ pub struct BlockMap {
|
||||
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
||||
transforms: RefCell<SumTree<Transform>>,
|
||||
show_excerpt_controls: bool,
|
||||
buffer_header_height: u8,
|
||||
excerpt_header_height: u8,
|
||||
excerpt_footer_height: u8,
|
||||
buffer_header_height: u32,
|
||||
excerpt_header_height: u32,
|
||||
excerpt_footer_height: u32,
|
||||
}
|
||||
|
||||
pub struct BlockMapReader<'a> {
|
||||
@@ -52,6 +52,9 @@ pub struct BlockSnapshot {
|
||||
wrap_snapshot: WrapSnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,
|
||||
pub(super) buffer_header_height: u32,
|
||||
pub(super) excerpt_header_height: u32,
|
||||
pub(super) excerpt_footer_height: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -77,15 +80,15 @@ pub type RenderBlock = Box<dyn Send + FnMut(&mut BlockContext) -> AnyElement>;
|
||||
pub struct CustomBlock {
|
||||
id: CustomBlockId,
|
||||
position: Anchor,
|
||||
height: u8,
|
||||
height: u32,
|
||||
style: BlockStyle,
|
||||
render: Mutex<RenderBlock>,
|
||||
render: Arc<Mutex<RenderBlock>>,
|
||||
disposition: BlockDisposition,
|
||||
}
|
||||
|
||||
pub struct BlockProperties<P> {
|
||||
pub position: P,
|
||||
pub height: u8,
|
||||
pub height: u32,
|
||||
pub style: BlockStyle,
|
||||
pub render: RenderBlock,
|
||||
pub disposition: BlockDisposition,
|
||||
@@ -189,14 +192,14 @@ pub enum Block {
|
||||
id: ExcerptId,
|
||||
buffer: BufferSnapshot,
|
||||
range: ExcerptRange<text::Anchor>,
|
||||
height: u8,
|
||||
height: u32,
|
||||
starts_new_buffer: bool,
|
||||
show_excerpt_controls: bool,
|
||||
},
|
||||
ExcerptFooter {
|
||||
id: ExcerptId,
|
||||
disposition: BlockDisposition,
|
||||
height: u8,
|
||||
height: u32,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -231,7 +234,7 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u8 {
|
||||
pub fn height(&self) -> u32 {
|
||||
match self {
|
||||
Block::Custom(block) => block.height,
|
||||
Block::ExcerptHeader { height, .. } => *height,
|
||||
@@ -301,9 +304,9 @@ impl BlockMap {
|
||||
pub fn new(
|
||||
wrap_snapshot: WrapSnapshot,
|
||||
show_excerpt_controls: bool,
|
||||
buffer_header_height: u8,
|
||||
excerpt_header_height: u8,
|
||||
excerpt_footer_height: u8,
|
||||
buffer_header_height: u32,
|
||||
excerpt_header_height: u32,
|
||||
excerpt_footer_height: u32,
|
||||
) -> Self {
|
||||
let row_count = wrap_snapshot.max_point().row() + 1;
|
||||
let map = Self {
|
||||
@@ -336,6 +339,9 @@ impl BlockMap {
|
||||
wrap_snapshot,
|
||||
transforms: self.transforms.borrow().clone(),
|
||||
custom_blocks_by_id: self.custom_blocks_by_id.clone(),
|
||||
buffer_header_height: self.buffer_header_height,
|
||||
excerpt_header_height: self.excerpt_header_height,
|
||||
excerpt_footer_height: self.excerpt_footer_height,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -551,7 +557,7 @@ impl BlockMap {
|
||||
*transforms = new_transforms;
|
||||
}
|
||||
|
||||
pub fn replace_renderers(&mut self, mut renderers: HashMap<CustomBlockId, RenderBlock>) {
|
||||
pub fn replace_blocks(&mut self, mut renderers: HashMap<CustomBlockId, RenderBlock>) {
|
||||
for block in &mut self.custom_blocks {
|
||||
if let Some(render) = renderers.remove(&block.id) {
|
||||
*block.render.lock() = render;
|
||||
@@ -565,9 +571,9 @@ impl BlockMap {
|
||||
|
||||
pub fn header_and_footer_blocks<'a, 'b: 'a, 'c: 'a + 'b, R, T>(
|
||||
show_excerpt_controls: bool,
|
||||
excerpt_footer_height: u8,
|
||||
buffer_header_height: u8,
|
||||
excerpt_header_height: u8,
|
||||
excerpt_footer_height: u32,
|
||||
buffer_header_height: u32,
|
||||
excerpt_header_height: u32,
|
||||
buffer: &'b multi_buffer::MultiBufferSnapshot,
|
||||
range: R,
|
||||
wrap_snapshot: &'c WrapSnapshot,
|
||||
@@ -793,7 +799,7 @@ impl<'a> BlockMapWriter<'a> {
|
||||
id,
|
||||
position,
|
||||
height: block.height,
|
||||
render: Mutex::new(block.render),
|
||||
render: Arc::new(Mutex::new(block.render)),
|
||||
disposition: block.disposition,
|
||||
style: block.style,
|
||||
});
|
||||
@@ -810,24 +816,21 @@ impl<'a> BlockMapWriter<'a> {
|
||||
ids
|
||||
}
|
||||
|
||||
pub fn replace(
|
||||
&mut self,
|
||||
mut heights_and_renderers: HashMap<CustomBlockId, (u8, RenderBlock)>,
|
||||
) {
|
||||
pub fn resize(&mut self, mut heights: HashMap<CustomBlockId, u32>) {
|
||||
let wrap_snapshot = &*self.0.wrap_snapshot.borrow();
|
||||
let buffer = wrap_snapshot.buffer_snapshot();
|
||||
let mut edits = Patch::default();
|
||||
let mut last_block_buffer_row = None;
|
||||
|
||||
for block in &mut self.0.custom_blocks {
|
||||
if let Some((new_height, render)) = heights_and_renderers.remove(&block.id) {
|
||||
if let Some(new_height) = heights.remove(&block.id) {
|
||||
if block.height != new_height {
|
||||
let new_block = CustomBlock {
|
||||
id: block.id,
|
||||
position: block.position,
|
||||
height: new_height,
|
||||
style: block.style,
|
||||
render: Mutex::new(render),
|
||||
render: block.render.clone(),
|
||||
disposition: block.disposition,
|
||||
};
|
||||
let new_block = Arc::new(new_block);
|
||||
@@ -1174,7 +1177,7 @@ impl Transform {
|
||||
Self {
|
||||
summary: TransformSummary {
|
||||
input_rows: 0,
|
||||
output_rows: block.height() as u32,
|
||||
output_rows: block.height(),
|
||||
},
|
||||
block: Some(block),
|
||||
}
|
||||
@@ -1445,7 +1448,7 @@ mod tests {
|
||||
.blocks_in_range(0..8)
|
||||
.map(|(start_row, block)| {
|
||||
let block = block.as_custom().unwrap();
|
||||
(start_row..start_row + block.height as u32, block.id)
|
||||
(start_row..start_row + block.height, block.id)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -1697,10 +1700,9 @@ mod tests {
|
||||
|
||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||
|
||||
let mut hash_map = HashMap::default();
|
||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
||||
hash_map.insert(block_ids[0], (2_u8, render));
|
||||
block_map_writer.replace(hash_map);
|
||||
let mut new_heights = HashMap::default();
|
||||
new_heights.insert(block_ids[0], 2);
|
||||
block_map_writer.resize(new_heights);
|
||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||
assert_eq!(snapshot.text(), "aaa\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||
}
|
||||
@@ -1708,10 +1710,9 @@ mod tests {
|
||||
{
|
||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||
|
||||
let mut hash_map = HashMap::default();
|
||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
||||
hash_map.insert(block_ids[0], (1_u8, render));
|
||||
block_map_writer.replace(hash_map);
|
||||
let mut new_heights = HashMap::default();
|
||||
new_heights.insert(block_ids[0], 1);
|
||||
block_map_writer.resize(new_heights);
|
||||
|
||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||
assert_eq!(snapshot.text(), "aaa\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||
@@ -1720,10 +1721,9 @@ mod tests {
|
||||
{
|
||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||
|
||||
let mut hash_map = HashMap::default();
|
||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
||||
hash_map.insert(block_ids[0], (0_u8, render));
|
||||
block_map_writer.replace(hash_map);
|
||||
let mut new_heights = HashMap::default();
|
||||
new_heights.insert(block_ids[0], 0);
|
||||
block_map_writer.resize(new_heights);
|
||||
|
||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||
assert_eq!(snapshot.text(), "aaa\n\n\nbbb\nccc\nddd\n\n\n");
|
||||
@@ -1732,10 +1732,9 @@ mod tests {
|
||||
{
|
||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||
|
||||
let mut hash_map = HashMap::default();
|
||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
||||
hash_map.insert(block_ids[0], (3_u8, render));
|
||||
block_map_writer.replace(hash_map);
|
||||
let mut new_heights = HashMap::default();
|
||||
new_heights.insert(block_ids[0], 3);
|
||||
block_map_writer.resize(new_heights);
|
||||
|
||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||
assert_eq!(snapshot.text(), "aaa\n\n\n\n\n\nbbb\nccc\nddd\n\n\n");
|
||||
@@ -1744,10 +1743,9 @@ mod tests {
|
||||
{
|
||||
let mut block_map_writer = block_map.write(wraps_snapshot.clone(), Default::default());
|
||||
|
||||
let mut hash_map = HashMap::default();
|
||||
let render: RenderBlock = Box::new(|_| div().into_any());
|
||||
hash_map.insert(block_ids[0], (3_u8, render));
|
||||
block_map_writer.replace(hash_map);
|
||||
let mut new_heights = HashMap::default();
|
||||
new_heights.insert(block_ids[0], 3);
|
||||
block_map_writer.resize(new_heights);
|
||||
|
||||
let snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
|
||||
// Same height as before, should remain the same
|
||||
@@ -2185,17 +2183,17 @@ mod tests {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum ExpectedBlock {
|
||||
ExcerptHeader {
|
||||
height: u8,
|
||||
height: u32,
|
||||
starts_new_buffer: bool,
|
||||
},
|
||||
ExcerptFooter {
|
||||
height: u8,
|
||||
height: u32,
|
||||
disposition: BlockDisposition,
|
||||
},
|
||||
Custom {
|
||||
disposition: BlockDisposition,
|
||||
id: CustomBlockId,
|
||||
height: u8,
|
||||
height: u32,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2214,7 +2212,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl ExpectedBlock {
|
||||
fn height(&self) -> u8 {
|
||||
fn height(&self) -> u32 {
|
||||
match self {
|
||||
ExpectedBlock::ExcerptHeader { height, .. } => *height,
|
||||
ExpectedBlock::Custom { height, .. } => *height,
|
||||
|
||||
+27
-15
@@ -160,9 +160,9 @@ use workspace::{OpenInTerminal, OpenTerminal, TabBarSettings, Toast};
|
||||
use crate::hover_links::find_url;
|
||||
use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
|
||||
|
||||
pub const FILE_HEADER_HEIGHT: u8 = 1;
|
||||
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u8 = 1;
|
||||
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u8 = 1;
|
||||
pub const FILE_HEADER_HEIGHT: u32 = 1;
|
||||
pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
|
||||
pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
|
||||
pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
|
||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
const MAX_LINE_LEN: usize = 1024;
|
||||
@@ -558,7 +558,7 @@ pub struct Editor {
|
||||
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
||||
tasks_update_task: Option<Task<()>>,
|
||||
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
|
||||
file_header_size: u8,
|
||||
file_header_size: u32,
|
||||
breadcrumb_header: Option<String>,
|
||||
focused_block: Option<FocusedBlock>,
|
||||
}
|
||||
@@ -9805,14 +9805,11 @@ impl Editor {
|
||||
for (block_id, diagnostic) in &active_diagnostics.blocks {
|
||||
new_styles.insert(
|
||||
*block_id,
|
||||
(
|
||||
None,
|
||||
diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
|
||||
),
|
||||
diagnostic_block_renderer(diagnostic.clone(), None, true, is_valid),
|
||||
);
|
||||
}
|
||||
self.display_map.update(cx, |display_map, cx| {
|
||||
display_map.replace_blocks(new_styles, cx)
|
||||
self.display_map.update(cx, |display_map, _cx| {
|
||||
display_map.replace_blocks(new_styles)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9855,7 +9852,7 @@ impl Editor {
|
||||
.insert_blocks(
|
||||
diagnostic_group.iter().map(|entry| {
|
||||
let diagnostic = entry.diagnostic.clone();
|
||||
let message_height = diagnostic.message.matches('\n').count() as u8 + 1;
|
||||
let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
position: buffer.anchor_after(entry.range.start),
|
||||
@@ -10170,19 +10167,34 @@ impl Editor {
|
||||
blocks
|
||||
}
|
||||
|
||||
pub fn replace_blocks(
|
||||
pub(crate) fn resize_blocks(
|
||||
&mut self,
|
||||
blocks: HashMap<CustomBlockId, (Option<u8>, RenderBlock)>,
|
||||
heights: HashMap<CustomBlockId, u32>,
|
||||
autoscroll: Option<Autoscroll>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.display_map
|
||||
.update(cx, |display_map, cx| display_map.replace_blocks(blocks, cx));
|
||||
.update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
|
||||
if let Some(autoscroll) = autoscroll {
|
||||
self.request_autoscroll(autoscroll, cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_blocks(
|
||||
&mut self,
|
||||
renderers: HashMap<CustomBlockId, RenderBlock>,
|
||||
autoscroll: Option<Autoscroll>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.display_map
|
||||
.update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
|
||||
if let Some(autoscroll) = autoscroll {
|
||||
self.request_autoscroll(autoscroll, cx);
|
||||
} else {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_blocks(
|
||||
&mut self,
|
||||
block_ids: HashSet<CustomBlockId>,
|
||||
@@ -11755,7 +11767,7 @@ impl Editor {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn file_header_size(&self) -> u8 {
|
||||
pub fn file_header_size(&self) -> u32 {
|
||||
self.file_header_size
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@ use crate::{
|
||||
hunk_diff::ExpandedHunk,
|
||||
hunk_status,
|
||||
items::BufferSearchHighlights,
|
||||
mouse_context_menu::MenuPosition,
|
||||
mouse_context_menu::{self, MouseContextMenu},
|
||||
mouse_context_menu::{self, MenuPosition, MouseContextMenu},
|
||||
scroll::scroll_amount::ScrollAmount,
|
||||
BlockId, CodeActionsMenu, CursorShape, DisplayPoint, DisplayRow, DocumentHighlightRead,
|
||||
DocumentHighlightWrite, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
|
||||
ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown, HalfPageUp, HoveredCursor,
|
||||
HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RangeToAnchorExt, RowExt,
|
||||
RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||
BlockId, CodeActionsMenu, CursorShape, CustomBlockId, DisplayPoint, DisplayRow,
|
||||
DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings,
|
||||
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
||||
HalfPageUp, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown, PageUp,
|
||||
Point, RangeToAnchorExt, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
||||
CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||
};
|
||||
use client::ParticipantIndex;
|
||||
use collections::{BTreeMap, HashMap};
|
||||
@@ -1929,7 +1929,7 @@ impl EditorElement {
|
||||
fn render_block(
|
||||
&self,
|
||||
block: &Block,
|
||||
available_space: Size<AvailableSpace>,
|
||||
available_width: AvailableSpace,
|
||||
block_id: BlockId,
|
||||
block_row_start: DisplayRow,
|
||||
snapshot: &EditorSnapshot,
|
||||
@@ -1941,6 +1941,7 @@ impl EditorElement {
|
||||
em_width: Pixels,
|
||||
text_hitbox: &Hitbox,
|
||||
scroll_width: &mut Pixels,
|
||||
resized_blocks: &mut HashMap<CustomBlockId, u32>,
|
||||
cx: &mut WindowContext,
|
||||
) -> (AnyElement, Size<Pixels>) {
|
||||
let mut element = match block {
|
||||
@@ -2021,7 +2022,7 @@ impl EditorElement {
|
||||
};
|
||||
|
||||
let line_offset_from_top =
|
||||
block_row_start.0 + *height as u32 + offset_from_excerpt_start
|
||||
block_row_start.0 + *height + offset_from_excerpt_start
|
||||
- snapshot
|
||||
.scroll_anchor
|
||||
.scroll_position(&snapshot.display_snapshot)
|
||||
@@ -2054,12 +2055,13 @@ impl EditorElement {
|
||||
|
||||
v_flex()
|
||||
.id(("path excerpt header", EntityId::from(block_id)))
|
||||
.size_full()
|
||||
.p(header_padding)
|
||||
.w_full()
|
||||
.px(header_padding)
|
||||
.child(
|
||||
h_flex()
|
||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.667)))
|
||||
.id("path header block")
|
||||
.h(2. * cx.line_height())
|
||||
.pl(gpui::px(12.))
|
||||
.pr(gpui::px(8.))
|
||||
.rounded_md()
|
||||
@@ -2112,6 +2114,7 @@ impl EditorElement {
|
||||
.children(show_excerpt_controls.then(|| {
|
||||
h_flex()
|
||||
.flex_basis(Length::Definite(DefiniteLength::Fraction(0.333)))
|
||||
.h(1. * cx.line_height())
|
||||
.pt_1()
|
||||
.justify_end()
|
||||
.flex_none()
|
||||
@@ -2157,7 +2160,8 @@ impl EditorElement {
|
||||
} else {
|
||||
v_flex()
|
||||
.id(("excerpt header", EntityId::from(block_id)))
|
||||
.size_full()
|
||||
.w_full()
|
||||
.h(snapshot.excerpt_header_height() as f32 * cx.line_height())
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
@@ -2309,7 +2313,8 @@ impl EditorElement {
|
||||
Block::ExcerptFooter { id, .. } => {
|
||||
let element = v_flex()
|
||||
.id(("excerpt footer", EntityId::from(block_id)))
|
||||
.size_full()
|
||||
.w_full()
|
||||
.h(snapshot.excerpt_footer_height() as f32 * cx.line_height())
|
||||
.child(
|
||||
h_flex()
|
||||
.justify_end()
|
||||
@@ -2357,8 +2362,24 @@ impl EditorElement {
|
||||
}
|
||||
};
|
||||
|
||||
let size = element.layout_as_root(available_space, cx);
|
||||
(element, size)
|
||||
// Discover the element's content height, then round up to the nearest multiple of line height.
|
||||
let preliminary_size =
|
||||
element.layout_as_root(size(available_width, AvailableSpace::MinContent), cx);
|
||||
let quantized_height = (preliminary_size.height / line_height).ceil() * line_height;
|
||||
let final_size = if preliminary_size.height == quantized_height {
|
||||
preliminary_size
|
||||
} else {
|
||||
element.layout_as_root(size(available_width, quantized_height.into()), cx)
|
||||
};
|
||||
|
||||
if let BlockId::Custom(custom_block_id) = block_id {
|
||||
let element_height_in_lines = (final_size.height / line_height).ceil() as u32;
|
||||
if element_height_in_lines != block.height() {
|
||||
resized_blocks.insert(custom_block_id, element_height_in_lines);
|
||||
}
|
||||
}
|
||||
|
||||
(element, final_size)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -2375,7 +2396,7 @@ impl EditorElement {
|
||||
line_height: Pixels,
|
||||
line_layouts: &[LineWithInvisibles],
|
||||
cx: &mut WindowContext,
|
||||
) -> Vec<BlockLayout> {
|
||||
) -> Result<Vec<BlockLayout>, HashMap<CustomBlockId, u32>> {
|
||||
let (fixed_blocks, non_fixed_blocks) = snapshot
|
||||
.blocks_in_range(rows.clone())
|
||||
.partition::<Vec<_>, _>(|(_, block)| block.style() == BlockStyle::Fixed);
|
||||
@@ -2385,11 +2406,9 @@ impl EditorElement {
|
||||
.update(cx, |editor, _| editor.take_focused_block());
|
||||
let mut fixed_block_max_width = Pixels::ZERO;
|
||||
let mut blocks = Vec::new();
|
||||
let mut resized_blocks = HashMap::default();
|
||||
|
||||
for (row, block) in fixed_blocks {
|
||||
let available_space = size(
|
||||
AvailableSpace::MinContent,
|
||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
||||
);
|
||||
let block_id = block.id();
|
||||
|
||||
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
||||
@@ -2398,7 +2417,7 @@ impl EditorElement {
|
||||
|
||||
let (element, element_size) = self.render_block(
|
||||
block,
|
||||
available_space,
|
||||
AvailableSpace::MinContent,
|
||||
block_id,
|
||||
row,
|
||||
snapshot,
|
||||
@@ -2410,6 +2429,7 @@ impl EditorElement {
|
||||
em_width,
|
||||
text_hitbox,
|
||||
scroll_width,
|
||||
&mut resized_blocks,
|
||||
cx,
|
||||
);
|
||||
fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width);
|
||||
@@ -2417,7 +2437,7 @@ impl EditorElement {
|
||||
id: block_id,
|
||||
row: Some(row),
|
||||
element,
|
||||
available_space,
|
||||
available_space: size(AvailableSpace::MinContent, element_size.height.into()),
|
||||
style: BlockStyle::Fixed,
|
||||
});
|
||||
}
|
||||
@@ -2432,19 +2452,15 @@ impl EditorElement {
|
||||
.max(gutter_dimensions.width + *scroll_width),
|
||||
BlockStyle::Fixed => unreachable!(),
|
||||
};
|
||||
let available_space = size(
|
||||
AvailableSpace::Definite(width),
|
||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
||||
);
|
||||
let block_id = block.id();
|
||||
|
||||
if focused_block.as_ref().map_or(false, |b| b.id == block_id) {
|
||||
focused_block = None;
|
||||
}
|
||||
|
||||
let (element, _) = self.render_block(
|
||||
let (element, element_size) = self.render_block(
|
||||
block,
|
||||
available_space,
|
||||
width.into(),
|
||||
block_id,
|
||||
row,
|
||||
snapshot,
|
||||
@@ -2456,13 +2472,15 @@ impl EditorElement {
|
||||
em_width,
|
||||
text_hitbox,
|
||||
scroll_width,
|
||||
&mut resized_blocks,
|
||||
cx,
|
||||
);
|
||||
|
||||
blocks.push(BlockLayout {
|
||||
id: block_id,
|
||||
row: Some(row),
|
||||
element,
|
||||
available_space,
|
||||
available_space: size(width.into(), element_size.height.into()),
|
||||
style,
|
||||
});
|
||||
}
|
||||
@@ -2483,14 +2501,10 @@ impl EditorElement {
|
||||
),
|
||||
BlockStyle::Sticky => AvailableSpace::Definite(hitbox.size.width),
|
||||
};
|
||||
let available_space = size(
|
||||
width,
|
||||
AvailableSpace::Definite(block.height() as f32 * line_height),
|
||||
);
|
||||
|
||||
let (element, _) = self.render_block(
|
||||
let (element, element_size) = self.render_block(
|
||||
&block,
|
||||
available_space,
|
||||
width,
|
||||
focused_block.id,
|
||||
rows.end,
|
||||
snapshot,
|
||||
@@ -2502,6 +2516,7 @@ impl EditorElement {
|
||||
em_width,
|
||||
text_hitbox,
|
||||
scroll_width,
|
||||
&mut resized_blocks,
|
||||
cx,
|
||||
);
|
||||
|
||||
@@ -2509,7 +2524,7 @@ impl EditorElement {
|
||||
id: block.id(),
|
||||
row: None,
|
||||
element,
|
||||
available_space,
|
||||
available_space: size(width, element_size.height.into()),
|
||||
style,
|
||||
});
|
||||
}
|
||||
@@ -2517,10 +2532,16 @@ impl EditorElement {
|
||||
}
|
||||
}
|
||||
|
||||
*scroll_width = (*scroll_width).max(fixed_block_max_width - gutter_dimensions.width);
|
||||
blocks
|
||||
if resized_blocks.is_empty() {
|
||||
*scroll_width = (*scroll_width).max(fixed_block_max_width - gutter_dimensions.width);
|
||||
Ok(blocks)
|
||||
} else {
|
||||
Err(resized_blocks)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if any of the blocks changed size since the previous frame. This will trigger
|
||||
/// a restart of rendering for the editor based on the new sizes.
|
||||
fn layout_blocks(
|
||||
&self,
|
||||
blocks: &mut Vec<BlockLayout>,
|
||||
@@ -4938,21 +4959,27 @@ impl Element for EditorElement {
|
||||
editor.gutter_dimensions = gutter_dimensions;
|
||||
editor.set_visible_line_count(bounds.size.height / line_height, cx);
|
||||
|
||||
let editor_width =
|
||||
text_width - gutter_dimensions.margin - overscroll.width - em_width;
|
||||
let wrap_width = match editor.soft_wrap_mode(cx) {
|
||||
SoftWrap::None => None,
|
||||
SoftWrap::PreferLine => Some((MAX_LINE_LEN / 2) as f32 * em_advance),
|
||||
SoftWrap::EditorWidth => Some(editor_width),
|
||||
SoftWrap::Column(column) => {
|
||||
Some(editor_width.min(column as f32 * em_advance))
|
||||
}
|
||||
};
|
||||
|
||||
if editor.set_wrap_width(wrap_width, cx) {
|
||||
editor.snapshot(cx)
|
||||
} else {
|
||||
if matches!(editor.mode, EditorMode::AutoHeight { .. }) {
|
||||
snapshot
|
||||
} else {
|
||||
let editor_width =
|
||||
text_width - gutter_dimensions.margin - overscroll.width - em_width;
|
||||
let wrap_width = match editor.soft_wrap_mode(cx) {
|
||||
SoftWrap::None => None,
|
||||
SoftWrap::PreferLine => {
|
||||
Some((MAX_LINE_LEN / 2) as f32 * em_advance)
|
||||
}
|
||||
SoftWrap::EditorWidth => Some(editor_width),
|
||||
SoftWrap::Column(column) => {
|
||||
Some(editor_width.min(column as f32 * em_advance))
|
||||
}
|
||||
};
|
||||
|
||||
if editor.set_wrap_width(wrap_width, cx) {
|
||||
editor.snapshot(cx)
|
||||
} else {
|
||||
snapshot
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4995,11 +5022,13 @@ impl Element for EditorElement {
|
||||
}
|
||||
};
|
||||
|
||||
let mut autoscroll_request = None;
|
||||
let mut autoscroll_containing_element = false;
|
||||
let mut autoscroll_horizontally = false;
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
autoscroll_request = editor.autoscroll_request();
|
||||
autoscroll_containing_element =
|
||||
editor.autoscroll_requested() || editor.has_pending_selection();
|
||||
autoscroll_request.is_some() || editor.has_pending_selection();
|
||||
autoscroll_horizontally =
|
||||
editor.autoscroll_vertically(bounds, line_height, max_scroll_top, cx);
|
||||
snapshot = editor.snapshot(cx);
|
||||
@@ -5116,7 +5145,7 @@ impl Element for EditorElement {
|
||||
let mut scroll_width =
|
||||
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
||||
|
||||
let mut blocks = cx.with_element_namespace("blocks", |cx| {
|
||||
let blocks = cx.with_element_namespace("blocks", |cx| {
|
||||
self.render_blocks(
|
||||
start_row..end_row,
|
||||
&snapshot,
|
||||
@@ -5131,6 +5160,15 @@ impl Element for EditorElement {
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let mut blocks = match blocks {
|
||||
Ok(blocks) => blocks,
|
||||
Err(resized_blocks) => {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.resize_blocks(resized_blocks, autoscroll_request, cx)
|
||||
});
|
||||
return self.prepaint(None, bounds, &mut (), cx);
|
||||
}
|
||||
};
|
||||
|
||||
let start_buffer_row =
|
||||
MultiBufferRow(start_anchor.to_point(&snapshot.buffer_snapshot).row);
|
||||
@@ -6430,7 +6468,7 @@ mod tests {
|
||||
disposition: BlockDisposition::Above,
|
||||
height: 3,
|
||||
position: Anchor::min(),
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Box::new(|cx| div().h(3. * cx.line_height()).into_any()),
|
||||
}],
|
||||
None,
|
||||
cx,
|
||||
|
||||
@@ -364,7 +364,7 @@ impl Editor {
|
||||
.row;
|
||||
let diff_end_row = diff_base.offset_to_point(hunk.diff_base_byte_range.end).row;
|
||||
let line_count = diff_end_row - diff_start_row;
|
||||
line_count as u8
|
||||
line_count
|
||||
})?;
|
||||
Some((diff_base_buffer, deleted_text_lines))
|
||||
} else {
|
||||
@@ -422,7 +422,7 @@ impl Editor {
|
||||
fn insert_deleted_text_block(
|
||||
&mut self,
|
||||
diff_base_buffer: Model<Buffer>,
|
||||
deleted_text_height: u8,
|
||||
deleted_text_height: u32,
|
||||
hunk: &HoveredHunk,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
) -> Option<CustomBlockId> {
|
||||
@@ -431,10 +431,11 @@ impl Editor {
|
||||
editor_with_deleted_text(diff_base_buffer, deleted_hunk_color, hunk, cx);
|
||||
let editor = cx.view().clone();
|
||||
let hunk = hunk.clone();
|
||||
let height = editor_height.max(deleted_text_height);
|
||||
let mut new_block_ids = self.insert_blocks(
|
||||
Some(BlockProperties {
|
||||
position: hunk.multi_buffer_range.start,
|
||||
height: editor_height.max(deleted_text_height),
|
||||
height,
|
||||
style: BlockStyle::Flex,
|
||||
disposition: BlockDisposition::Above,
|
||||
render: Box::new(move |cx| {
|
||||
@@ -474,7 +475,8 @@ impl Editor {
|
||||
h_flex()
|
||||
.id("gutter with editor")
|
||||
.bg(deleted_hunk_color)
|
||||
.size_full()
|
||||
.h(height as f32 * cx.line_height())
|
||||
.w_full()
|
||||
.child(
|
||||
h_flex()
|
||||
.id("gutter")
|
||||
@@ -783,7 +785,7 @@ fn editor_with_deleted_text(
|
||||
deleted_color: Hsla,
|
||||
hunk: &HoveredHunk,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) -> (u8, View<Editor>) {
|
||||
) -> (u32, View<Editor>) {
|
||||
let parent_editor = cx.view().downgrade();
|
||||
let editor = cx.new_view(|cx| {
|
||||
let multi_buffer =
|
||||
@@ -885,7 +887,7 @@ fn editor_with_deleted_text(
|
||||
editor
|
||||
});
|
||||
|
||||
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0 as u8);
|
||||
let editor_height = editor.update(cx, |editor, cx| editor.max_point(cx).row().0);
|
||||
(editor_height, editor)
|
||||
}
|
||||
|
||||
|
||||
@@ -307,8 +307,8 @@ impl ScrollManager {
|
||||
self.show_scrollbars
|
||||
}
|
||||
|
||||
pub fn autoscroll_requested(&self) -> bool {
|
||||
self.autoscroll_request.is_some()
|
||||
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
||||
self.autoscroll_request.map(|(autoscroll, _)| autoscroll)
|
||||
}
|
||||
|
||||
pub fn is_dragging_scrollbar(&self) -> bool {
|
||||
|
||||
@@ -61,8 +61,8 @@ impl AutoscrollStrategy {
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn autoscroll_requested(&self) -> bool {
|
||||
self.scroll_manager.autoscroll_requested()
|
||||
pub fn autoscroll_request(&self) -> Option<Autoscroll> {
|
||||
self.scroll_manager.autoscroll_request()
|
||||
}
|
||||
|
||||
pub fn autoscroll_vertically(
|
||||
|
||||
Reference in New Issue
Block a user