Compare commits

...

7 Commits

Author SHA1 Message Date
David
c48cdcf315 pull cursors trough the blockmap more 2025-12-02 17:21:41 +01:00
David
e3f13c0aee wip 2025-12-02 12:28:06 +01:00
David
26eabe94b5 more cursor stuff 2025-12-02 12:28:06 +01:00
David
3f70461585 log slow blockmap 2025-12-02 12:28:06 +01:00
Lukas Wirth
4d56a6294e gpui(windows): Only poll PAINT messages twice in foreground task timeout (#43883)
Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-12-02 12:28:06 +01:00
Lukas Wirth
f31880931d terminal_view: Fix selection columns not being clamped correctly for rendering (#43876)
Before:


https://github.com/user-attachments/assets/3be4d451-81a6-430b-bc36-d91f4cd44c9b

After:


https://github.com/user-attachments/assets/6d64bf0c-5bd1-45be-b9d8-20118e5a25e6



Release Notes:

- Fixed rendered selections in the terminal view not being clamped to
the line start/ends correctly
2025-12-02 12:28:06 +01:00
Lukas Wirth
253229464b buffer no reparse 2025-12-01 10:01:36 +01:00
15 changed files with 392 additions and 120 deletions

View File

@@ -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

View File

@@ -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),

View File

@@ -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,
}

View File

@@ -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>,
}

View File

@@ -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>>,
{

View File

@@ -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<'_> {

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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

View File

@@ -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
}

View File

@@ -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>

View File

@@ -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)
};
}