Compare commits
7 Commits
additional
...
cursor-fas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c48cdcf315 | ||
|
|
e3f13c0aee | ||
|
|
26eabe94b5 | ||
|
|
3f70461585 | ||
|
|
4d56a6294e | ||
|
|
f31880931d | ||
|
|
253229464b |
@@ -94,6 +94,7 @@ uuid.workspace = true
|
||||
vim_mode_setting.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
zlog.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
criterion.workspace = true
|
||||
|
||||
@@ -5,7 +5,10 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
EditorStyle, GutterDimensions,
|
||||
display_map::{dimensions::RowDelta, wrap_map::WrapRow},
|
||||
display_map::{
|
||||
dimensions::RowDelta,
|
||||
wrap_map::{WrapPointCursor, WrapRow},
|
||||
},
|
||||
};
|
||||
use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, App, EntityId, Pixels, Window};
|
||||
@@ -525,6 +528,7 @@ impl BlockMap {
|
||||
}
|
||||
|
||||
fn sync(&self, wrap_snapshot: &WrapSnapshot, mut edits: WrapPatch) {
|
||||
let _timer = zlog::time!("BlockMap::sync").warn_if_gt(std::time::Duration::from_millis(50));
|
||||
let buffer = wrap_snapshot.buffer_snapshot();
|
||||
|
||||
// Handle changing the last excerpt if it is empty.
|
||||
@@ -561,6 +565,15 @@ impl BlockMap {
|
||||
let mut fold_point_cursor = wrap_snapshot.fold_point_cursor();
|
||||
let mut wrap_point_cursor = wrap_snapshot.wrap_point_cursor();
|
||||
|
||||
let mut inlay_cursor = wrap_snapshot.inlay_cursor();
|
||||
let mut tab_cursor = wrap_snapshot.tab_cursor();
|
||||
let mut fold_cursor = wrap_snapshot.fold_cursor();
|
||||
let mut wrap_cursor = wrap_snapshot.wrap_cursor();
|
||||
let mut multi_buffer_cursor2 = wrap_snapshot
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
|
||||
while let Some(edit) = edits.next() {
|
||||
let mut old_start = edit.old.start;
|
||||
let mut new_start = edit.new.start;
|
||||
@@ -599,10 +612,15 @@ impl BlockMap {
|
||||
if transform_rows_before_edit > RowDelta(0) {
|
||||
if transform.block.is_none() {
|
||||
// Preserve any portion of the old isomorphic transform that precedes this edit.
|
||||
push_isomorphic(
|
||||
push_isomorphic_(
|
||||
&mut new_transforms,
|
||||
transform_rows_before_edit,
|
||||
wrap_snapshot,
|
||||
&mut wrap_point_cursor2,
|
||||
&mut multi_buffer_cursor2,
|
||||
&mut inlay_point_cursor2,
|
||||
&mut fold_point_cursor2,
|
||||
&mut tab_point_cursor2,
|
||||
);
|
||||
} else {
|
||||
// We landed within a block that replaces some lines, so we
|
||||
@@ -758,7 +776,12 @@ impl BlockMap {
|
||||
}
|
||||
}
|
||||
|
||||
push_isomorphic(&mut new_transforms, rows_before_block, wrap_snapshot);
|
||||
push_isomorphic_(
|
||||
&mut new_transforms,
|
||||
rows_before_block,
|
||||
wrap_snapshot,
|
||||
&mut wrap_cursor,
|
||||
);
|
||||
new_transforms.push(
|
||||
Transform {
|
||||
summary,
|
||||
@@ -771,7 +794,12 @@ impl BlockMap {
|
||||
// Insert an isomorphic transform after the final block.
|
||||
let rows_after_last_block =
|
||||
RowDelta(new_end.0).saturating_sub(RowDelta(new_transforms.summary().input_rows.0));
|
||||
push_isomorphic(&mut new_transforms, rows_after_last_block, wrap_snapshot);
|
||||
push_isomorphic_(
|
||||
&mut new_transforms,
|
||||
rows_after_last_block,
|
||||
wrap_snapshot,
|
||||
&mut wrap_cursor,
|
||||
);
|
||||
}
|
||||
|
||||
new_transforms.append(cursor.suffix(), ());
|
||||
@@ -947,13 +975,60 @@ impl BlockMap {
|
||||
}
|
||||
|
||||
fn push_isomorphic(tree: &mut SumTree<Transform>, rows: RowDelta, wrap_snapshot: &WrapSnapshot) {
|
||||
let mut wrap_cursor = wrap_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<WrapPoint, super::tab_map::TabPoint>>(());
|
||||
let mut mb_cursor = wrap_snapshot
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
let mut inlay_cursor = wrap_snapshot
|
||||
.inlay_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::InlayOffset, MultiBufferOffset>>(());
|
||||
let mut fold_cursor = wrap_snapshot
|
||||
.fold_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::FoldPoint, super::InlayPoint>>(());
|
||||
let mut tab_cursor = wrap_snapshot.tab_point_cursor();
|
||||
|
||||
push_isomorphic_(
|
||||
tree,
|
||||
rows,
|
||||
wrap_snapshot,
|
||||
&mut wrap_cursor,
|
||||
&mut mb_cursor,
|
||||
&mut inlay_cursor,
|
||||
&mut fold_cursor,
|
||||
&mut tab_cursor,
|
||||
);
|
||||
}
|
||||
|
||||
// This is called whenever we push actual text (nonisomorphic is inlay hints and blocks)
|
||||
fn push_isomorphic_(
|
||||
tree: &mut SumTree<Transform>,
|
||||
rows: RowDelta,
|
||||
wrap_snapshot: &WrapSnapshot,
|
||||
wrap_cursor: &mut wrap_map::WrapCursor<'_>,
|
||||
mb_cursor: &mut multi_buffer::MBDiffCursor<'_>,
|
||||
inlay_cursor: &mut super::inlay_map::InlayOffsetCursor<'_>,
|
||||
fold_cursor: &mut super::fold_map::FoldCursor<'_>,
|
||||
tab_cursor: &mut super::tab_map::TabPointCursor<'_>,
|
||||
) {
|
||||
if rows == RowDelta(0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let wrap_row_start = tree.summary().input_rows;
|
||||
let wrap_row_end = wrap_row_start + rows;
|
||||
let wrap_summary = wrap_snapshot.text_summary_for_range(wrap_row_start..wrap_row_end);
|
||||
let wrap_summary = wrap_snapshot.text_summary_for_range_(
|
||||
wrap_row_start..wrap_row_end,
|
||||
wrap_cursor,
|
||||
mb_cursor,
|
||||
inlay_cursor,
|
||||
fold_cursor,
|
||||
tab_cursor,
|
||||
);
|
||||
let summary = TransformSummary {
|
||||
input_rows: WrapRow(rows.0),
|
||||
output_rows: BlockRow(rows.0),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::display_map::inlay_map::InlayChunk;
|
||||
use crate::display_map::inlay_map::{self, InlayChunk};
|
||||
|
||||
use super::{
|
||||
Highlights,
|
||||
@@ -23,6 +23,8 @@ use sum_tree::{Bias, Cursor, Dimensions, FilterCursor, SumTree, Summary, TreeMap
|
||||
use ui::IntoElement as _;
|
||||
use util::post_inc;
|
||||
|
||||
pub type FoldCursor<'a> = Cursor<'a, 'static, Transform, Dimensions<FoldPoint, InlayPoint>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FoldPlaceholder {
|
||||
/// Creates an element to represent this fold's placeholder.
|
||||
@@ -626,7 +628,7 @@ impl FoldMap {
|
||||
#[derive(Clone)]
|
||||
pub struct FoldSnapshot {
|
||||
pub inlay_snapshot: InlaySnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
pub transforms: SumTree<Transform>,
|
||||
folds: SumTree<Fold>,
|
||||
fold_metadata_by_id: TreeMap<FoldId, FoldMetadata>,
|
||||
pub version: usize,
|
||||
@@ -666,12 +668,34 @@ impl FoldSnapshot {
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> MBTextSummary {
|
||||
let mut summary = MBTextSummary::default();
|
||||
|
||||
let mut cursor = self
|
||||
let mut fold_cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldPoint, InlayPoint>>(());
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
let mut inlay_cursor = self
|
||||
.inlay_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
|
||||
let mut mbcursor = self
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
self.text_summary_for_range_(&mut mbcursor, &mut inlay_cursor, &mut fold_cursor, range)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_(
|
||||
&self,
|
||||
mbcursor: &mut multi_buffer::MBDiffCursor<'_>,
|
||||
inlay_cursor: &mut inlay_map::InlayOffsetCursor<'_>,
|
||||
cursor: &mut FoldCursor<'_>,
|
||||
range: Range<FoldPoint>,
|
||||
) -> MBTextSummary {
|
||||
let mut summary = MBTextSummary::default();
|
||||
|
||||
if cursor.did_seek() {
|
||||
cursor.seek_forward(&range.start, Bias::Right);
|
||||
} else {
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
}
|
||||
if let Some(transform) = cursor.item() {
|
||||
let start_in_transform = range.start.0 - cursor.start().0.0;
|
||||
let end_in_transform = cmp::min(range.end, cursor.end().0).0 - cursor.start().0.0;
|
||||
@@ -687,9 +711,11 @@ impl FoldSnapshot {
|
||||
let inlay_end = self
|
||||
.inlay_snapshot
|
||||
.to_offset(InlayPoint(cursor.start().1.0 + end_in_transform));
|
||||
summary = self
|
||||
.inlay_snapshot
|
||||
.text_summary_for_range(inlay_start..inlay_end);
|
||||
summary = self.inlay_snapshot.text_summary_for_range_(
|
||||
mbcursor,
|
||||
inlay_cursor,
|
||||
inlay_start..inlay_end,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,7 +961,7 @@ impl FoldSnapshot {
|
||||
}
|
||||
|
||||
pub struct FoldPointCursor<'transforms> {
|
||||
cursor: Cursor<'transforms, 'static, Transform, Dimensions<InlayPoint, FoldPoint>>,
|
||||
pub(crate) cursor: Cursor<'transforms, 'static, Transform, Dimensions<InlayPoint, FoldPoint>>,
|
||||
}
|
||||
|
||||
impl FoldPointCursor<'_> {
|
||||
@@ -1079,7 +1105,7 @@ fn consolidate_fold_edits(mut edits: Vec<FoldEdit>) -> Vec<FoldEdit> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct Transform {
|
||||
pub struct Transform {
|
||||
summary: TransformSummary,
|
||||
placeholder: Option<TransformPlaceholder>,
|
||||
}
|
||||
@@ -1098,7 +1124,7 @@ impl Transform {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
struct TransformSummary {
|
||||
pub struct TransformSummary {
|
||||
output: MBTextSummary,
|
||||
input: MBTextSummary,
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub struct InlayMap {
|
||||
#[derive(Clone)]
|
||||
pub struct InlaySnapshot {
|
||||
pub buffer: MultiBufferSnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
pub transforms: SumTree<Transform>,
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
@@ -43,8 +43,11 @@ impl std::ops::Deref for InlaySnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub type InlayOffsetCursor<'a> =
|
||||
Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Transform {
|
||||
pub enum Transform {
|
||||
Isomorphic(MBTextSummary),
|
||||
Inlay(Inlay),
|
||||
}
|
||||
@@ -67,7 +70,7 @@ impl sum_tree::Item for Transform {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct TransformSummary {
|
||||
pub struct TransformSummary {
|
||||
input: MBTextSummary,
|
||||
output: MBTextSummary,
|
||||
}
|
||||
@@ -207,7 +210,7 @@ pub struct InlayBufferRows<'a> {
|
||||
}
|
||||
|
||||
pub struct InlayChunks<'a> {
|
||||
transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>,
|
||||
transforms: InlayOffsetCursor<'a>,
|
||||
buffer_chunks: CustomHighlightsChunks<'a>,
|
||||
buffer_chunk: Option<Chunk<'a>>,
|
||||
inlay_chunks: Option<text::ChunkWithBitmaps<'a>>,
|
||||
@@ -988,13 +991,28 @@ impl InlaySnapshot {
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> MBTextSummary {
|
||||
let mut summary = MBTextSummary::default();
|
||||
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
let mut mbcursor = self
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
self.text_summary_for_range_(&mut mbcursor, &mut cursor, range)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_(
|
||||
&self,
|
||||
mbcursor: &mut multi_buffer::MBDiffCursor<'_>,
|
||||
cursor: &mut InlayOffsetCursor,
|
||||
range: Range<InlayOffset>,
|
||||
) -> MBTextSummary {
|
||||
if cursor.did_seek() {
|
||||
cursor.seek_forward(&range.start, Bias::Right);
|
||||
} else {
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
}
|
||||
let mut summary = MBTextSummary::default();
|
||||
let overshoot = range.start.0 - cursor.start().0.0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
@@ -1002,7 +1020,9 @@ impl InlaySnapshot {
|
||||
let suffix_start = buffer_start + overshoot;
|
||||
let suffix_end =
|
||||
buffer_start + (cmp::min(cursor.end().0, range.end).0 - cursor.start().0.0);
|
||||
summary = self.buffer.text_summary_for_range(suffix_start..suffix_end);
|
||||
summary = self
|
||||
.buffer
|
||||
.text_summary_for_range_(mbcursor, suffix_start..suffix_end);
|
||||
cursor.next();
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
@@ -1029,9 +1049,10 @@ impl InlaySnapshot {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let prefix_start = cursor.start().1;
|
||||
let prefix_end = prefix_start + overshoot;
|
||||
summary += self
|
||||
.buffer
|
||||
.text_summary_for_range::<MBTextSummary, _>(prefix_start..prefix_end);
|
||||
summary += self.buffer.text_summary_for_range_::<MBTextSummary, _>(
|
||||
mbcursor,
|
||||
prefix_start..prefix_end,
|
||||
);
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let prefix_end = overshoot;
|
||||
@@ -1142,7 +1163,7 @@ impl InlaySnapshot {
|
||||
}
|
||||
|
||||
pub struct InlayPointCursor<'transforms> {
|
||||
cursor: Cursor<'transforms, 'static, Transform, Dimensions<Point, InlayPoint>>,
|
||||
pub(crate) cursor: Cursor<'transforms, 'static, Transform, Dimensions<Point, InlayPoint>>,
|
||||
transforms: &'transforms SumTree<Transform>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use crate::display_map::{InlayOffset, InlayPoint, inlay_map};
|
||||
|
||||
use super::{
|
||||
Highlights,
|
||||
fold_map::{self, Chunk, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot},
|
||||
};
|
||||
|
||||
use language::Point;
|
||||
use multi_buffer::MultiBufferSnapshot;
|
||||
use multi_buffer::{MBDiffCursor, MultiBufferOffset, MultiBufferSnapshot};
|
||||
use std::{cmp, mem, num::NonZeroU32, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
use sum_tree::{Bias, Dimensions};
|
||||
|
||||
const MAX_EXPANSION_COLUMN: u32 = 256;
|
||||
|
||||
@@ -196,8 +198,41 @@ impl TabSnapshot {
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<TabPoint>) -> TextSummary {
|
||||
let mut mbcursor = self
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
let mut inlay_cursor = self
|
||||
.inlay_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
|
||||
let mut fold_cursor = self
|
||||
.fold_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldPoint, InlayPoint>>(());
|
||||
let mut cursor = self.tab_point_cursor();
|
||||
self.text_summary_for_range_(
|
||||
&mut mbcursor,
|
||||
&mut inlay_cursor,
|
||||
&mut fold_cursor,
|
||||
&mut cursor,
|
||||
range,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_(
|
||||
&self,
|
||||
mbcursor: &mut multi_buffer::MBDiffCursor<'_>,
|
||||
inlay_cursor: &mut inlay_map::InlayOffsetCursor<'_>,
|
||||
fold_cursor: &mut fold_map::FoldCursor<'_>,
|
||||
cursor: &mut TabPointCursor<'_>,
|
||||
range: Range<TabPoint>,
|
||||
) -> TextSummary {
|
||||
// TODO we can use cursor here
|
||||
let input_start = self.tab_point_to_fold_point(range.start, Bias::Left).0;
|
||||
// TODO we can use cursor here
|
||||
let input_end = self.tab_point_to_fold_point(range.end, Bias::Right).0;
|
||||
// TODO we can use cursor here
|
||||
let input_summary = self
|
||||
.fold_snapshot
|
||||
.text_summary_for_range(input_start..input_end);
|
||||
@@ -313,12 +348,12 @@ impl TabSnapshot {
|
||||
TabPointCursor { this: self }
|
||||
}
|
||||
|
||||
pub fn tab_point_to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) {
|
||||
let chunks = self
|
||||
.fold_snapshot
|
||||
.chunks_at(FoldPoint::new(output.row(), 0));
|
||||
|
||||
let tab_cursor = TabStopCursor::new(chunks);
|
||||
pub fn tab_point_to_fold_point_<'a, I: Iterator<Item = Chunk<'a>>>(
|
||||
&self,
|
||||
tab_cursor: &mut TabStopCursor<'a, I>,
|
||||
output: TabPoint,
|
||||
bias: Bias,
|
||||
) -> (FoldPoint, u32, u32) {
|
||||
let expanded = output.column();
|
||||
let (collapsed, expanded_char_column, to_next_stop) =
|
||||
self.collapse_tabs(tab_cursor, expanded, bias);
|
||||
@@ -330,6 +365,14 @@ impl TabSnapshot {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn tab_point_to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) {
|
||||
let chunks = self
|
||||
.fold_snapshot
|
||||
.chunks_at(FoldPoint::new(output.row(), 0));
|
||||
let mut tab_cursor = TabStopCursor::new(chunks);
|
||||
self.tab_point_to_fold_point_(&mut tab_cursor, output, bias)
|
||||
}
|
||||
|
||||
pub fn point_to_tab_point(&self, point: Point, bias: Bias) -> TabPoint {
|
||||
let inlay_point = self.fold_snapshot.inlay_snapshot.to_inlay_point(point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
@@ -379,7 +422,7 @@ impl TabSnapshot {
|
||||
|
||||
fn collapse_tabs<'a, I>(
|
||||
&self,
|
||||
mut cursor: TabStopCursor<'a, I>,
|
||||
cursor: &mut TabStopCursor<'a, I>,
|
||||
column: u32,
|
||||
bias: Bias,
|
||||
) -> (u32, u32, u32)
|
||||
@@ -1436,7 +1479,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
struct TabStopCursor<'a, I>
|
||||
pub struct TabStopCursor<'a, I>
|
||||
where
|
||||
I: Iterator<Item = Chunk<'a>>,
|
||||
{
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use crate::display_map::{
|
||||
fold_map::FoldCursor, inlay_map::InlayOffsetCursor, tab_map::TabPointCursor,
|
||||
};
|
||||
|
||||
use super::{
|
||||
Highlights,
|
||||
dimensions::RowDelta,
|
||||
@@ -6,7 +10,7 @@ use super::{
|
||||
};
|
||||
use gpui::{App, AppContext as _, Context, Entity, Font, LineWrapper, Pixels, Task};
|
||||
use language::Point;
|
||||
use multi_buffer::{MultiBufferSnapshot, RowInfo};
|
||||
use multi_buffer::{MBDiffCursor, MultiBufferSnapshot, RowInfo};
|
||||
use smol::future::yield_now;
|
||||
use std::{cmp, collections::VecDeque, mem, ops::Range, sync::LazyLock, time::Duration};
|
||||
use sum_tree::{Bias, Cursor, Dimensions, SumTree};
|
||||
@@ -36,10 +40,12 @@ pub struct WrapMap {
|
||||
font_with_size: (Font, Pixels),
|
||||
}
|
||||
|
||||
pub type WrapCursor<'a> = Cursor<'a, 'static, Transform, Dimensions<WrapPoint, TabPoint>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WrapSnapshot {
|
||||
pub(super) tab_snapshot: TabSnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
pub transforms: SumTree<Transform>,
|
||||
interpolated: bool,
|
||||
}
|
||||
|
||||
@@ -52,13 +58,13 @@ impl std::ops::Deref for WrapSnapshot {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
struct Transform {
|
||||
pub struct Transform {
|
||||
summary: TransformSummary,
|
||||
display_text: Option<&'static str>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
struct TransformSummary {
|
||||
pub struct TransformSummary {
|
||||
input: TextSummary,
|
||||
output: TextSummary,
|
||||
}
|
||||
@@ -665,22 +671,59 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, rows: Range<WrapRow>) -> TextSummary {
|
||||
let mut wrap_cursor = self.wrap_cursor();
|
||||
let mut mb_cursor = self
|
||||
.buffer
|
||||
.diff_transforms
|
||||
.cursor::<multi_buffer::CursorType>(());
|
||||
let mut inlay_cursor = self
|
||||
.inlay_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::InlayOffset, multi_buffer::MultiBufferOffset>>(());
|
||||
let mut fold_cursor = self
|
||||
.fold_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::FoldPoint, super::InlayPoint>>(());
|
||||
let mut tab_cursor = self.tab_point_cursor();
|
||||
self.text_summary_for_range_(
|
||||
rows,
|
||||
&mut wrap_cursor,
|
||||
&mut mb_cursor,
|
||||
&mut inlay_cursor,
|
||||
&mut fold_cursor,
|
||||
&mut tab_cursor,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_(
|
||||
&self,
|
||||
rows: Range<WrapRow>,
|
||||
wrap_cursor: &mut WrapCursor<'_>,
|
||||
mb_cursor: &mut MBDiffCursor<'_>,
|
||||
inlay_cursor: &mut super::inlay_map::InlayOffsetCursor<'_>,
|
||||
fold_cursor: &mut super::fold_map::FoldCursor<'_>,
|
||||
tab_cursor: &mut tab_map::TabPointCursor<'_>,
|
||||
) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
|
||||
let start = WrapPoint::new(rows.start, 0);
|
||||
let end = WrapPoint::new(rows.end, 0);
|
||||
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<WrapPoint, TabPoint>>(());
|
||||
cursor.seek(&start, Bias::Right);
|
||||
if let Some(transform) = cursor.item() {
|
||||
let start_in_transform = start.0 - cursor.start().0.0;
|
||||
let end_in_transform = cmp::min(end, cursor.end().0).0 - cursor.start().0.0;
|
||||
// Retain this wrap cursor
|
||||
wrap_cursor.seek(&start, Bias::Right);
|
||||
if let Some(transform) = wrap_cursor.item() {
|
||||
let start_in_transform = start.0 - wrap_cursor.start().0.0;
|
||||
let end_in_transform = cmp::min(end, wrap_cursor.end().0).0 - wrap_cursor.start().0.0;
|
||||
if transform.is_isomorphic() {
|
||||
let tab_start = TabPoint(cursor.start().1.0 + start_in_transform);
|
||||
let tab_end = TabPoint(cursor.start().1.0 + end_in_transform);
|
||||
summary += &self.tab_snapshot.text_summary_for_range(tab_start..tab_end);
|
||||
let tab_start = TabPoint(wrap_cursor.start().1.0 + start_in_transform);
|
||||
let tab_end = TabPoint(wrap_cursor.start().1.0 + end_in_transform);
|
||||
summary += &self.tab_snapshot.text_summary_for_range_(
|
||||
mb_cursor,
|
||||
inlay_cursor,
|
||||
fold_cursor,
|
||||
tab_cursor,
|
||||
tab_start..tab_end,
|
||||
);
|
||||
} else {
|
||||
debug_assert_eq!(start_in_transform.row, end_in_transform.row);
|
||||
let indent_len = end_in_transform.column - start_in_transform.column;
|
||||
@@ -693,18 +736,18 @@ impl WrapSnapshot {
|
||||
};
|
||||
}
|
||||
|
||||
cursor.next();
|
||||
wrap_cursor.next();
|
||||
}
|
||||
|
||||
if rows.end > cursor.start().0.row() {
|
||||
summary += &cursor
|
||||
if rows.end > wrap_cursor.start().0.row() {
|
||||
summary += &wrap_cursor
|
||||
.summary::<_, TransformSummary>(&WrapPoint::new(rows.end, 0), Bias::Right)
|
||||
.output;
|
||||
|
||||
if let Some(transform) = cursor.item() {
|
||||
let end_in_transform = end.0 - cursor.start().0.0;
|
||||
if let Some(transform) = wrap_cursor.item() {
|
||||
let end_in_transform = end.0 - wrap_cursor.start().0.0;
|
||||
if transform.is_isomorphic() {
|
||||
let char_start = cursor.start().1;
|
||||
let char_start = wrap_cursor.start().1;
|
||||
let char_end = TabPoint(char_start.0 + end_in_transform);
|
||||
summary += &self
|
||||
.tab_snapshot
|
||||
@@ -801,6 +844,11 @@ impl WrapSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrap_cursor(&self) -> WrapCursor<'_> {
|
||||
self.transforms
|
||||
.cursor::<Dimensions<WrapPoint, TabPoint>>(())
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, mut point: WrapPoint, bias: Bias) -> WrapPoint {
|
||||
if bias == Bias::Left {
|
||||
let (start, _, item) = self
|
||||
@@ -920,10 +968,30 @@ impl WrapSnapshot {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fold_cursor(&self) -> FoldCursor {
|
||||
self.fold_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::FoldPoint, super::InlayPoint>>(())
|
||||
}
|
||||
|
||||
pub(crate) fn tab_cursor(&self) -> TabPointCursor {
|
||||
self.tab_point_cursor()
|
||||
}
|
||||
|
||||
/// TODO redo all cursor names, make them make sense
|
||||
///
|
||||
/// maybe CursorInlayToOffset (pattern: Cursor<From>To<To>)
|
||||
/// that makes searching easier
|
||||
pub(crate) fn inlay_cursor(&self) -> InlayOffsetCursor {
|
||||
self.inlay_snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<super::InlayOffset, multi_buffer::MultiBufferOffset>>(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WrapPointCursor<'transforms> {
|
||||
cursor: Cursor<'transforms, 'static, Transform, Dimensions<TabPoint, WrapPoint>>,
|
||||
pub(crate) cursor: Cursor<'transforms, 'static, Transform, Dimensions<TabPoint, WrapPoint>>,
|
||||
}
|
||||
|
||||
impl WrapPointCursor<'_> {
|
||||
|
||||
@@ -822,12 +822,25 @@ impl WindowsPlatformInner {
|
||||
// we spent our budget on gpui tasks, we likely have a lot of work queued so drain system events first
|
||||
// before returning to main thread task work
|
||||
let mut msg = MSG::default();
|
||||
let peek_msg_type = PM_REMOVE | PM_QS_INPUT | PM_QS_PAINT;
|
||||
while unsafe { PeekMessageW(&mut msg, None, 0, 0, peek_msg_type) }.as_bool() {
|
||||
if translate_accelerator(&msg).is_none() {
|
||||
_ = unsafe { TranslateMessage(&msg) };
|
||||
unsafe { DispatchMessageW(&msg) };
|
||||
let process_message = |msg: &_| {
|
||||
if translate_accelerator(msg).is_none() {
|
||||
_ = unsafe { TranslateMessage(msg) };
|
||||
unsafe { DispatchMessageW(msg) };
|
||||
}
|
||||
};
|
||||
let peek_msg = |msg: &mut _, msg_kind| unsafe {
|
||||
PeekMessageW(msg, None, 0, 0, PM_REMOVE | msg_kind).as_bool()
|
||||
};
|
||||
// We process a paint at the start and end only to prevent getting stuck in a paint loop
|
||||
// due to on going gpui animations
|
||||
if peek_msg(&mut msg, PM_QS_PAINT) {
|
||||
process_message(&msg);
|
||||
}
|
||||
while peek_msg(&mut msg, PM_QS_INPUT) {
|
||||
process_message(&msg);
|
||||
}
|
||||
if peek_msg(&mut msg, PM_QS_PAINT) {
|
||||
process_message(&msg);
|
||||
}
|
||||
}
|
||||
match self.main_receiver.try_recv() {
|
||||
|
||||
@@ -1210,7 +1210,7 @@ impl Buffer {
|
||||
}
|
||||
|
||||
// Reparse the branch buffer so that we get syntax highlighting immediately.
|
||||
branch.reparse(cx);
|
||||
branch.reparse(cx, true);
|
||||
|
||||
branch
|
||||
})
|
||||
@@ -1367,7 +1367,7 @@ impl Buffer {
|
||||
self.syntax_map.lock().clear(&self.text);
|
||||
self.language = language;
|
||||
self.was_changed();
|
||||
self.reparse(cx);
|
||||
self.reparse(cx, false);
|
||||
cx.emit(BufferEvent::LanguageChanged);
|
||||
}
|
||||
|
||||
@@ -1623,7 +1623,7 @@ impl Buffer {
|
||||
/// initiate an additional reparse recursively. To avoid concurrent parses
|
||||
/// for the same buffer, we only initiate a new parse if we are not already
|
||||
/// parsing in the background.
|
||||
pub fn reparse(&mut self, cx: &mut Context<Self>) {
|
||||
pub fn reparse(&mut self, cx: &mut Context<Self>, may_block: bool) {
|
||||
if self.reparse.is_some() {
|
||||
return;
|
||||
}
|
||||
@@ -1652,43 +1652,31 @@ impl Buffer {
|
||||
});
|
||||
|
||||
self.parse_status.0.send(ParseStatus::Parsing).unwrap();
|
||||
match cx
|
||||
.background_executor()
|
||||
.block_with_timeout(self.sync_parse_timeout, parse_task)
|
||||
{
|
||||
Ok(new_syntax_snapshot) => {
|
||||
self.did_finish_parsing(new_syntax_snapshot, cx);
|
||||
self.reparse = None;
|
||||
}
|
||||
Err(parse_task) => {
|
||||
// todo(lw): hot foreground spawn
|
||||
self.reparse = Some(cx.spawn(async move |this, cx| {
|
||||
let new_syntax_map = cx.background_spawn(parse_task).await;
|
||||
this.update(cx, move |this, cx| {
|
||||
let grammar_changed = || {
|
||||
this.language.as_ref().is_none_or(|current_language| {
|
||||
!Arc::ptr_eq(&language, current_language)
|
||||
})
|
||||
};
|
||||
let language_registry_changed = || {
|
||||
new_syntax_map.contains_unknown_injections()
|
||||
&& language_registry.is_some_and(|registry| {
|
||||
registry.version() != new_syntax_map.language_registry_version()
|
||||
})
|
||||
};
|
||||
let parse_again = this.version.changed_since(&parsed_version)
|
||||
|| language_registry_changed()
|
||||
|| grammar_changed();
|
||||
this.did_finish_parsing(new_syntax_map, cx);
|
||||
this.reparse = None;
|
||||
if parse_again {
|
||||
this.reparse(cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
}
|
||||
self.reparse = Some(cx.spawn(async move |this, cx| {
|
||||
let new_syntax_map = cx.background_spawn(parse_task).await;
|
||||
this.update(cx, move |this, cx| {
|
||||
let grammar_changed = || {
|
||||
this.language
|
||||
.as_ref()
|
||||
.is_none_or(|current_language| !Arc::ptr_eq(&language, current_language))
|
||||
};
|
||||
let language_registry_changed = || {
|
||||
new_syntax_map.contains_unknown_injections()
|
||||
&& language_registry.is_some_and(|registry| {
|
||||
registry.version() != new_syntax_map.language_registry_version()
|
||||
})
|
||||
};
|
||||
let parse_again = this.version.changed_since(&parsed_version)
|
||||
|| language_registry_changed()
|
||||
|| grammar_changed();
|
||||
this.did_finish_parsing(new_syntax_map, cx);
|
||||
this.reparse = None;
|
||||
if parse_again {
|
||||
this.reparse(cx, may_block);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut Context<Self>) {
|
||||
@@ -2588,7 +2576,7 @@ impl Buffer {
|
||||
return;
|
||||
}
|
||||
|
||||
self.reparse(cx);
|
||||
self.reparse(cx, true);
|
||||
cx.emit(BufferEvent::Edited);
|
||||
if was_dirty != self.is_dirty() {
|
||||
cx.emit(BufferEvent::DirtyChanged);
|
||||
|
||||
@@ -66,6 +66,14 @@ pub struct ExcerptId(u32);
|
||||
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct BaseTextRow(pub u32);
|
||||
|
||||
pub type MBDiffCursor<'a> = Cursor<
|
||||
'a,
|
||||
'static,
|
||||
DiffTransform,
|
||||
Dimensions<MultiBufferOffset, ExcerptDimension<MultiBufferOffset>>,
|
||||
>;
|
||||
pub type CursorType = Dimensions<MultiBufferOffset, ExcerptDimension<MultiBufferOffset>>;
|
||||
|
||||
/// One or more [`Buffers`](Buffer) being edited in a single view.
|
||||
///
|
||||
/// See <https://zed.dev/features#multi-buffers>
|
||||
@@ -545,7 +553,7 @@ impl DiffState {
|
||||
pub struct MultiBufferSnapshot {
|
||||
excerpts: SumTree<Excerpt>,
|
||||
diffs: TreeMap<BufferId, BufferDiffSnapshot>,
|
||||
diff_transforms: SumTree<DiffTransform>,
|
||||
pub diff_transforms: SumTree<DiffTransform>,
|
||||
non_text_state_update_count: usize,
|
||||
edit_count: usize,
|
||||
is_dirty: bool,
|
||||
@@ -561,7 +569,7 @@ pub struct MultiBufferSnapshot {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum DiffTransform {
|
||||
pub enum DiffTransform {
|
||||
Unmodified {
|
||||
summary: MBTextSummary,
|
||||
},
|
||||
@@ -4762,11 +4770,23 @@ impl MultiBufferSnapshot {
|
||||
MBD: MultiBufferDimension + AddAssign,
|
||||
O: ToOffset,
|
||||
{
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
let mut cursor = self
|
||||
.diff_transforms
|
||||
.cursor::<Dimensions<MultiBufferOffset, ExcerptOffset>>(());
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
self.text_summary_for_range_(&mut cursor, range)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_<MBD, O>(&self, cursor: &mut MBDiffCursor, range: Range<O>) -> MBD
|
||||
where
|
||||
MBD: MultiBufferDimension + AddAssign,
|
||||
O: ToOffset,
|
||||
{
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
if cursor.did_seek() {
|
||||
cursor.seek_forward(&range.start, Bias::Right);
|
||||
} else {
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
}
|
||||
|
||||
let Some(first_transform) = cursor.item() else {
|
||||
return MBD::from_summary(&MBTextSummary::default());
|
||||
@@ -7399,7 +7419,7 @@ where
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||
struct ExcerptDimension<T>(T);
|
||||
pub struct ExcerptDimension<T>(T);
|
||||
|
||||
impl<T: PartialEq> PartialEq<T> for ExcerptDimension<T> {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
|
||||
@@ -4353,7 +4353,7 @@ impl LspStore {
|
||||
}
|
||||
|
||||
for buffer in buffers_with_unknown_injections {
|
||||
buffer.update(cx, |buffer, cx| buffer.reparse(cx));
|
||||
buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
|
||||
@@ -377,6 +377,7 @@ impl ProjectSearch {
|
||||
})
|
||||
.ok()?;
|
||||
while let Some(new_ranges) = new_ranges.next().await {
|
||||
smol::future::yield_now().await;
|
||||
project_search
|
||||
.update(cx, |project_search, cx| {
|
||||
project_search.match_ranges.extend(new_ranges);
|
||||
|
||||
@@ -403,6 +403,9 @@ where
|
||||
}
|
||||
|
||||
/// Returns whether we found the item you were seeking for.
|
||||
///
|
||||
/// # Panics
|
||||
/// If we did not seek before, use seek instead in that case
|
||||
#[track_caller]
|
||||
pub fn seek_forward<Target>(&mut self, pos: &Target, bias: Bias) -> bool
|
||||
where
|
||||
|
||||
@@ -1275,7 +1275,7 @@ impl Element for TerminalElement {
|
||||
}
|
||||
|
||||
for (relative_highlighted_range, color) in
|
||||
layout.relative_highlighted_ranges.iter()
|
||||
& layout.relative_highlighted_ranges
|
||||
{
|
||||
if let Some((start_y, highlighted_range_lines)) =
|
||||
to_highlighted_range_lines(relative_highlighted_range, layout, origin)
|
||||
@@ -1542,11 +1542,13 @@ fn to_highlighted_range_lines(
|
||||
}
|
||||
|
||||
let clamped_start_line = unclamped_start.line.0.max(0) as usize;
|
||||
|
||||
let clamped_end_line = unclamped_end
|
||||
.line
|
||||
.0
|
||||
.min(layout.dimensions.num_lines() as i32) as usize;
|
||||
//Convert the start of the range to pixels
|
||||
|
||||
// Convert the start of the range to pixels
|
||||
let start_y = origin.y + clamped_start_line as f32 * layout.dimensions.line_height;
|
||||
|
||||
// Step 3. Expand ranges that cross lines into a collection of single-line ranges.
|
||||
@@ -1556,10 +1558,11 @@ fn to_highlighted_range_lines(
|
||||
let mut line_start = 0;
|
||||
let mut line_end = layout.dimensions.columns();
|
||||
|
||||
if line == clamped_start_line {
|
||||
if line == clamped_start_line && unclamped_start.line.0 >= 0 {
|
||||
line_start = unclamped_start.column.0;
|
||||
}
|
||||
if line == clamped_end_line {
|
||||
if line == clamped_end_line && unclamped_end.line.0 <= layout.dimensions.num_lines() as i32
|
||||
{
|
||||
line_end = unclamped_end.column.0 + 1; // +1 for inclusive
|
||||
}
|
||||
|
||||
|
||||
@@ -2223,9 +2223,19 @@ impl BufferSnapshot {
|
||||
where
|
||||
D: TextDimension,
|
||||
{
|
||||
self.visible_text
|
||||
.cursor(range.start.to_offset(self))
|
||||
.summary(range.end.to_offset(self))
|
||||
let cursor = self.visible_text.cursor(range.start.to_offset(self));
|
||||
self.text_summary_for_range_(cursor, range)
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range_<D, O: ToOffset>(
|
||||
&self,
|
||||
mut cursor: Cursor<'_>,
|
||||
range: Range<O>,
|
||||
) -> D
|
||||
where
|
||||
D: TextDimension,
|
||||
{
|
||||
cursor.summary(range.end.to_offset(self))
|
||||
}
|
||||
|
||||
pub fn summaries_for_anchors<'a, D, A>(&'a self, anchors: A) -> impl 'a + Iterator<Item = D>
|
||||
|
||||
@@ -183,7 +183,7 @@ macro_rules! time {
|
||||
$crate::Timer::new($logger, $name)
|
||||
};
|
||||
($name:expr) => {
|
||||
time!($crate::default_logger!() => $name)
|
||||
$crate::time!($crate::default_logger!() => $name)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user