Render path headers in editor element

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-02-09 16:28:18 +01:00
parent f1e3d5285b
commit 8d95dbe3e6
4 changed files with 126 additions and 154 deletions

View File

@ -423,25 +423,16 @@ impl ProjectDiagnosticsEditor {
self.editor.update(cx, |editor, cx| {
blocks_to_remove.extend(path_state.header);
editor.remove_blocks(blocks_to_remove, cx);
let header_block = first_excerpt_id.map(|excerpt_id| BlockProperties {
position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, language::Anchor::min()),
height: 2,
render: path_header_renderer(buffer, self.build_settings.clone()),
disposition: BlockDisposition::Above,
});
let block_ids = editor.insert_blocks(
blocks_to_add
.into_iter()
.map(|block| {
let (excerpt_id, text_anchor) = block.position;
BlockProperties {
position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, text_anchor),
height: block.height,
render: block.render,
disposition: block.disposition,
}
})
.chain(header_block.into_iter()),
blocks_to_add.into_iter().map(|block| {
let (excerpt_id, text_anchor) = block.position;
BlockProperties {
position: excerpts_snapshot.anchor_in_excerpt(excerpt_id, text_anchor),
height: block.height,
render: block.render,
disposition: block.disposition,
}
}),
cx,
);
@ -660,51 +651,6 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
}
}
fn path_header_renderer(buffer: ModelHandle<Buffer>, build_settings: BuildSettings) -> RenderBlock {
Arc::new(move |cx| {
let settings = build_settings(cx);
let style = settings.style.diagnostic_path_header;
let font_size = (style.text_scale_factor * settings.style.text.font_size).round();
let mut filename = None;
let mut path = None;
if let Some(file) = buffer.read(&**cx).file() {
filename = file
.path()
.file_name()
.map(|f| f.to_string_lossy().to_string());
path = file
.path()
.parent()
.map(|p| p.to_string_lossy().to_string() + "/");
}
Flex::row()
.with_child(
Label::new(
filename.unwrap_or_else(|| "untitled".to_string()),
style.filename.text.clone().with_font_size(font_size),
)
.contained()
.with_style(style.filename.container)
.boxed(),
)
.with_children(path.map(|path| {
Label::new(path, style.path.text.clone().with_font_size(font_size))
.contained()
.with_style(style.path.container)
.boxed()
}))
.aligned()
.left()
.contained()
.with_style(style.container)
.with_padding_left(cx.gutter_padding + cx.scroll_x * cx.em_width)
.expanded()
.named("path header block")
})
}
fn diagnostic_header_renderer(
diagnostic: Diagnostic,
build_settings: BuildSettings,
@ -843,7 +789,10 @@ fn compare_diagnostics<L: language::ToOffset, R: language::ToOffset>(
#[cfg(test)]
mod tests {
use super::*;
use editor::{display_map::BlockContext, DisplayPoint, EditorSnapshot};
use editor::{
display_map::{BlockContext, TransformBlock},
DisplayPoint, EditorSnapshot,
};
use gpui::TestAppContext;
use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16};
use serde_json::json;
@ -1259,18 +1208,23 @@ mod tests {
editor
.blocks_in_range(0..editor.max_point().row())
.filter_map(|(row, block)| {
block
.render(&BlockContext {
cx,
anchor_x: 0.,
scroll_x: 0.,
gutter_padding: 0.,
gutter_width: 0.,
line_height: 0.,
em_width: 0.,
})
.name()
.map(|s| (row, s.to_string()))
let name = match block {
TransformBlock::Custom(block) => block
.render(&BlockContext {
cx,
anchor_x: 0.,
scroll_x: 0.,
gutter_padding: 0.,
gutter_width: 0.,
line_height: 0.,
em_width: 0.,
})
.name()?
.to_string(),
TransformBlock::ExcerptHeader { .. } => "path header block".to_string(),
};
Some((row, name))
})
.collect()
}

View File

@ -90,10 +90,7 @@ struct Transform {
#[derive(Clone)]
pub enum TransformBlock {
Custom {
block: Arc<Block>,
column: u32,
},
Custom(Arc<Block>),
ExcerptHeader {
buffer: BufferSnapshot,
range: Range<text::Anchor>,
@ -104,14 +101,14 @@ pub enum TransformBlock {
impl TransformBlock {
fn disposition(&self) -> BlockDisposition {
match self {
TransformBlock::Custom { block, .. } => block.disposition,
TransformBlock::Custom(block) => block.disposition,
TransformBlock::ExcerptHeader { .. } => BlockDisposition::Above,
}
}
fn height(&self) -> u8 {
pub fn height(&self) -> u8 {
match self {
TransformBlock::Custom { block, .. } => block.height,
TransformBlock::Custom(block) => block.height,
TransformBlock::ExcerptHeader { height, .. } => *height,
}
}
@ -120,11 +117,7 @@ impl TransformBlock {
impl Debug for TransformBlock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Custom { block, column } => f
.debug_struct("Custom")
.field("block", block)
.field("column", column)
.finish(),
Self::Custom(block) => f.debug_struct("Custom").field("block", block).finish(),
Self::ExcerptHeader { buffer, .. } => f
.debug_struct("ExcerptHeader")
.field("path", &buffer.path())
@ -319,7 +312,6 @@ impl BlockMap {
.iter()
.map(|block| {
let mut position = block.position.to_point(&buffer);
let column = wrap_snapshot.from_point(position, Bias::Left).column();
match block.disposition {
BlockDisposition::Above => position.column = 0,
BlockDisposition::Below => {
@ -327,13 +319,7 @@ impl BlockMap {
}
}
let position = wrap_snapshot.from_point(position, Bias::Left);
(
position.row(),
TransformBlock::Custom {
block: block.clone(),
column,
},
)
(position.row(), TransformBlock::Custom(block.clone()))
}),
);
blocks_in_edit.extend(
@ -362,10 +348,7 @@ impl BlockMap {
) => Ordering::Equal,
(TransformBlock::ExcerptHeader { .. }, _) => Ordering::Less,
(_, TransformBlock::ExcerptHeader { .. }) => Ordering::Greater,
(
TransformBlock::Custom { block: block_a, .. },
TransformBlock::Custom { block: block_b, .. },
) => block_a
(TransformBlock::Custom(block_a), TransformBlock::Custom(block_b)) => block_a
.disposition
.cmp(&block_b.disposition)
.then_with(|| block_a.id.cmp(&block_b.id)),
@ -908,6 +891,10 @@ impl Block {
pub fn render(&self, cx: &BlockContext) -> ElementBox {
self.render.lock()(cx)
}
pub fn position(&self) -> &Anchor {
&self.position
}
}
impl Debug for Block {
@ -1008,10 +995,9 @@ mod tests {
let blocks = snapshot
.blocks_in_range(0..8)
.map(|(start_row, block)| {
let (block, column) = block.as_custom().unwrap();
let block = block.as_custom().unwrap();
(
start_row..start_row + block.height as u32,
column,
block
.render(&BlockContext {
cx,
@ -1033,9 +1019,9 @@ mod tests {
assert_eq!(
blocks,
&[
(1..3, 2, "block 2".to_string()),
(3..4, 0, "block 1".to_string()),
(7..10, 3, "block 3".to_string()),
(1..2, "block 1".to_string()),
(2..4, "block 2".to_string()),
(7..10, "block 3".to_string()),
]
);
@ -1324,7 +1310,6 @@ mod tests {
let mut expected_blocks = Vec::new();
expected_blocks.extend(custom_blocks.iter().map(|(id, block)| {
let mut position = block.position.to_point(&buffer_snapshot);
let column = wraps_snapshot.from_point(position, Bias::Left).column();
match block.disposition {
BlockDisposition::Above => {
position.column = 0;
@ -1426,7 +1411,7 @@ mod tests {
assert_eq!(
blocks_snapshot
.blocks_in_range(0..(expected_row_count as u32))
.map(|(row, block)| (row, block.as_custom().map(|(b, _)| b.id)))
.map(|(row, block)| { (row, block.as_custom().map(|b| b.id)) })
.collect::<Vec<_>>(),
expected_block_positions
);
@ -1508,9 +1493,9 @@ mod tests {
}
impl TransformBlock {
fn as_custom(&self) -> Option<(&Block, u32)> {
fn as_custom(&self) -> Option<&Block> {
match self {
TransformBlock::Custom { block, column } => Some((block, *column)),
TransformBlock::Custom(block) => Some(block),
TransformBlock::ExcerptHeader { .. } => None,
}
}

View File

@ -588,10 +588,6 @@ impl WrapSnapshot {
}
}
pub fn text_summary(&self) -> TextSummary {
self.transforms.summary().output
}
pub fn max_point(&self) -> WrapPoint {
WrapPoint(self.transforms.summary().output.lines)
}
@ -955,10 +951,6 @@ impl WrapPoint {
&mut self.0.row
}
pub fn column(&self) -> u32 {
self.0.column
}
pub fn column_mut(&mut self) -> &mut u32 {
&mut self.0.column
}

View File

@ -3,11 +3,12 @@ use super::{
Anchor, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, Input,
Scroll, Select, SelectPhase, SoftWrap, ToPoint, MAX_LINE_LEN,
};
use crate::display_map::TransformBlock;
use clock::ReplicaId;
use collections::{BTreeMap, HashMap};
use gpui::{
color::Color,
elements::layout_highlighted_chunks,
elements::*,
fonts::{HighlightStyle, Underline},
geometry::{
rect::RectF,
@ -649,44 +650,84 @@ impl EditorElement {
line_layouts: &[text_layout::Line],
cx: &mut LayoutContext,
) -> Vec<(u32, ElementBox)> {
Default::default()
// snapshot
// .blocks_in_range(rows.clone())
// .map(|(start_row, block)| {
// let anchor_row = block
// .position()
// .to_point(&snapshot.buffer_snapshot)
// .to_display_point(snapshot)
// .row();
let scroll_x = snapshot.scroll_position.x();
snapshot
.blocks_in_range(rows.clone())
.map(|(block_row, block)| {
let mut element = match block {
TransformBlock::Custom(block) => {
let align_to = block
.position()
.to_point(&snapshot.buffer_snapshot)
.to_display_point(snapshot);
let anchor_x = text_x
+ if rows.contains(&align_to.row()) {
line_layouts[(align_to.row() - rows.start) as usize]
.x_for_index(align_to.column() as usize)
} else {
layout_line(align_to.row(), snapshot, style, cx.text_layout_cache)
.x_for_index(align_to.column() as usize)
};
// let anchor_x = text_x
// + if rows.contains(&anchor_row) {
// line_layouts[(anchor_row - rows.start) as usize]
// .x_for_index(block.column() as usize)
// } else {
// layout_line(anchor_row, snapshot, style, cx.text_layout_cache)
// .x_for_index(block.column() as usize)
// };
block.render(&BlockContext {
cx,
anchor_x,
gutter_padding,
line_height,
scroll_x,
gutter_width,
em_width,
})
}
TransformBlock::ExcerptHeader { buffer, .. } => {
let style = &self.settings.style.diagnostic_path_header;
let font_size =
(style.text_scale_factor * self.settings.style.text.font_size).round();
// let mut element = block.render(&BlockContext {
// cx,
// anchor_x,
// gutter_padding,
// line_height,
// scroll_x: snapshot.scroll_position.x(),
// gutter_width,
// em_width,
// });
// element.layout(
// SizeConstraint {
// min: Vector2F::zero(),
// max: vec2f(width, block.height() as f32 * line_height),
// },
// cx,
// );
// (start_row, element)
// })
// .collect()
let mut filename = None;
let mut parent_path = None;
if let Some(path) = buffer.path() {
filename = path.file_name().map(|f| f.to_string_lossy().to_string());
parent_path =
path.parent().map(|p| p.to_string_lossy().to_string() + "/");
}
Flex::row()
.with_child(
Label::new(
filename.unwrap_or_else(|| "untitled".to_string()),
style.filename.text.clone().with_font_size(font_size),
)
.contained()
.with_style(style.filename.container)
.boxed(),
)
.with_children(parent_path.map(|path| {
Label::new(path, style.path.text.clone().with_font_size(font_size))
.contained()
.with_style(style.path.container)
.boxed()
}))
.aligned()
.left()
.contained()
.with_style(style.container)
.with_padding_left(gutter_padding + scroll_x * em_width)
.expanded()
.named("path header block")
}
};
element.layout(
SizeConstraint {
min: Vector2F::zero(),
max: vec2f(width, block.height() as f32 * line_height),
},
cx,
);
(block_row, element)
})
.collect()
}
}