mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 05:15:00 +00:00
WIP - Add excerpt headers as a built-in feature of BlockMap
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
8b1fb9a2cc
commit
c7e2fae9cb
3 changed files with 105 additions and 13 deletions
|
@ -2,12 +2,13 @@ use super::wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot};
|
|||
use crate::{Anchor, ToPoint as _};
|
||||
use collections::{HashMap, HashSet};
|
||||
use gpui::{AppContext, ElementBox};
|
||||
use language::Chunk;
|
||||
use language::{BufferSnapshot, Chunk};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
cmp::{self, Ordering, Reverse},
|
||||
fmt::Debug,
|
||||
ops::{Deref, Range},
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
Arc,
|
||||
|
@ -84,13 +85,44 @@ pub enum BlockDisposition {
|
|||
#[derive(Clone, Debug)]
|
||||
struct Transform {
|
||||
summary: TransformSummary,
|
||||
block: Option<AlignedBlock>,
|
||||
block: Option<TransformBlock>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AlignedBlock {
|
||||
block: Arc<Block>,
|
||||
column: u32,
|
||||
#[derive(Clone)]
|
||||
enum TransformBlock {
|
||||
Custom {
|
||||
block: Arc<Block>,
|
||||
column: u32,
|
||||
},
|
||||
ExcerptHeader {
|
||||
buffer: BufferSnapshot,
|
||||
range: Range<text::Anchor>,
|
||||
path: Option<Arc<Path>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TransformBlock {
|
||||
fn disposition(&self) -> BlockDisposition {
|
||||
match self {
|
||||
TransformBlock::Custom { block, column } => block.disposition,
|
||||
TransformBlock::ExcerptHeader { .. } => BlockDisposition::Above,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::ExcerptHeader { buffer, path, .. } => {
|
||||
f.debug_struct("ExcerptHeader").field("path", path).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -244,12 +276,14 @@ impl BlockMap {
|
|||
Ok(ix) | Err(ix) => last_block_ix + ix,
|
||||
};
|
||||
|
||||
let end_anchor;
|
||||
let end_block_ix = if new_end.0 > wrap_snapshot.max_point().row() {
|
||||
end_anchor = Anchor::max();
|
||||
self.blocks.len()
|
||||
} else {
|
||||
let new_buffer_end =
|
||||
wrap_snapshot.to_point(WrapPoint::new(new_end.0, 0), Bias::Left);
|
||||
let end_anchor = buffer.anchor_before(new_buffer_end);
|
||||
end_anchor = buffer.anchor_before(new_buffer_end);
|
||||
match self.blocks[start_block_ix..].binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
|
@ -276,25 +310,44 @@ impl BlockMap {
|
|||
}
|
||||
}
|
||||
let position = wrap_snapshot.from_point(position, Bias::Left);
|
||||
(position.row(), column, block.clone())
|
||||
(
|
||||
position.row(),
|
||||
TransformBlock::Custom {
|
||||
block: block.clone(),
|
||||
column,
|
||||
},
|
||||
)
|
||||
}),
|
||||
);
|
||||
blocks_in_edit.extend(
|
||||
buffer
|
||||
.excerpt_boundaries_in_range(start_anchor..end_anchor)
|
||||
.map(|excerpt_boundary| {
|
||||
(
|
||||
excerpt_boundary.row,
|
||||
TransformBlock::ExcerptHeader {
|
||||
buffer: excerpt_boundary.buffer,
|
||||
range: excerpt_boundary.range,
|
||||
path: excerpt_boundary.path,
|
||||
},
|
||||
)
|
||||
}),
|
||||
);
|
||||
|
||||
// When multiple blocks are on the same row, newer blocks appear above older
|
||||
// blocks. This is arbitrary, but we currently rely on it in ProjectDiagnosticsEditor.
|
||||
blocks_in_edit
|
||||
.sort_by_key(|(row, _, block)| (*row, block.disposition, Reverse(block.id)));
|
||||
blocks_in_edit.sort();
|
||||
|
||||
// For each of these blocks, insert a new isomorphic transform preceding the block,
|
||||
// and then insert the block itself.
|
||||
for (block_row, column, block) in blocks_in_edit.drain(..) {
|
||||
let insertion_row = match block.disposition {
|
||||
for (block_row, block) in blocks_in_edit.drain(..) {
|
||||
let insertion_row = match block.disposition() {
|
||||
BlockDisposition::Above => block_row,
|
||||
BlockDisposition::Below => block_row + 1,
|
||||
};
|
||||
let extent_before_block = insertion_row - new_transforms.summary().input_rows;
|
||||
push_isomorphic(&mut new_transforms, extent_before_block);
|
||||
new_transforms.push(Transform::block(block, column), &());
|
||||
new_transforms.push(Transform::block(block), &());
|
||||
}
|
||||
|
||||
old_end = WrapRow(old_end.0.min(old_row_count));
|
||||
|
|
|
@ -3,6 +3,7 @@ mod element;
|
|||
pub mod items;
|
||||
pub mod movement;
|
||||
mod multi_buffer;
|
||||
mod multi_editor;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
|
|
@ -15,6 +15,7 @@ use std::{
|
|||
cmp, fmt, io,
|
||||
iter::{self, FromIterator},
|
||||
ops::{Range, Sub},
|
||||
path::Path,
|
||||
str,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
|
@ -101,6 +102,14 @@ pub struct ExcerptProperties<'a, T> {
|
|||
pub range: Range<T>,
|
||||
}
|
||||
|
||||
pub struct ExcerptBoundary {
|
||||
pub row: u32,
|
||||
pub buffer: BufferSnapshot,
|
||||
pub path: Option<Arc<Path>>,
|
||||
pub range: Range<text::Anchor>,
|
||||
pub starts_new_buffer: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Excerpt {
|
||||
id: ExcerptId,
|
||||
|
@ -1769,6 +1778,24 @@ impl MultiBufferSnapshot {
|
|||
start_id != end_id
|
||||
}
|
||||
|
||||
pub fn excerpt_boundaries_in_range<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> impl Iterator<Item = ExcerptBoundary> + 'a {
|
||||
let start = range.start.to_offset(self);
|
||||
let end = range.end.to_offset(self);
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
|
||||
cursor.seek(&start, Bias::Right, &());
|
||||
|
||||
let prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id);
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
let excerpt = cursor.item()?;
|
||||
let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
|
||||
todo!()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_count(&self) -> usize {
|
||||
self.parse_count
|
||||
}
|
||||
|
@ -2628,6 +2655,17 @@ mod tests {
|
|||
assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 0)..Point::new(4, 2)));
|
||||
assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 2)..Point::new(4, 2)));
|
||||
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.excerpt_boundaries_in_range(Point::new(0, 0)..Point::new(4, 2))
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
(Some(buffer_1.clone()), true),
|
||||
(Some(buffer_1.clone()), false),
|
||||
(Some(buffer_2.clone()), false),
|
||||
]
|
||||
);
|
||||
|
||||
buffer_1.update(cx, |buffer, cx| {
|
||||
buffer.edit(
|
||||
[
|
||||
|
|
Loading…
Reference in a new issue