Compare commits
53 Commits
debug-shel
...
new-diff-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df81a91bf9 | ||
|
|
7adcf903cc | ||
|
|
062b4a2dd8 | ||
|
|
2cca833d7b | ||
|
|
0b3715ae44 | ||
|
|
2b68817ed8 | ||
|
|
d1239f6cdb | ||
|
|
d600c58d3c | ||
|
|
c160ce6a24 | ||
|
|
9450de73b3 | ||
|
|
5cc3bd1585 | ||
|
|
87d50ee54c | ||
|
|
2f5ea92fe1 | ||
|
|
2625719ca2 | ||
|
|
88b4628c00 | ||
|
|
241c7a6645 | ||
|
|
f6aa7df14f | ||
|
|
472fee6b62 | ||
|
|
093c3d3652 | ||
|
|
1f28437c82 | ||
|
|
2266b3cb96 | ||
|
|
4369890646 | ||
|
|
82fbe27c08 | ||
|
|
41c5e45ca2 | ||
|
|
243d7c6d5a | ||
|
|
9025fb226a | ||
|
|
07eb573a2c | ||
|
|
b552e32b18 | ||
|
|
9b526a4d42 | ||
|
|
cc4ecacc04 | ||
|
|
dc814cb3af | ||
|
|
ad87dfe908 | ||
|
|
99edc9583c | ||
|
|
c015553b1f | ||
|
|
e53d8bb8d2 | ||
|
|
6e724c1168 | ||
|
|
a8a9177878 | ||
|
|
9dc5ebab85 | ||
|
|
2630dfdd23 | ||
|
|
20ec116932 | ||
|
|
dac0a07770 | ||
|
|
61e42b986a | ||
|
|
a20715d663 | ||
|
|
33833533bd | ||
|
|
023f9239b4 | ||
|
|
946ae93f68 | ||
|
|
011880c48c | ||
|
|
440b632b09 | ||
|
|
d0a8b0f8b1 | ||
|
|
09082d103e | ||
|
|
90c9ad4fd6 | ||
|
|
67ffe999e5 | ||
|
|
159c2239cc |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -7702,11 +7702,13 @@ dependencies = [
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"futures 0.3.31",
|
||||
"git",
|
||||
"gpui",
|
||||
"itertools 0.13.0",
|
||||
"language",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"project",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"settings",
|
||||
|
||||
@@ -9,6 +9,7 @@ use editor::{
|
||||
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst, Redo, Rename,
|
||||
ToggleCodeActions, Undo,
|
||||
},
|
||||
display_map::RowInfo,
|
||||
test::editor_test_context::{AssertionContextManager, EditorTestContext},
|
||||
Editor,
|
||||
};
|
||||
@@ -20,7 +21,6 @@ use language::{
|
||||
language_settings::{AllLanguageSettings, InlayHintSettings},
|
||||
FakeLspAdapter,
|
||||
};
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use project::{
|
||||
project_settings::{InlineBlameSettings, ProjectSettings},
|
||||
SERVER_PROGRESS_THROTTLE_TIMEOUT,
|
||||
@@ -2075,7 +2075,15 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||
let entries = blame.update(cx, |blame, cx| {
|
||||
blame
|
||||
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(0..4)
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx,
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
@@ -2114,7 +2122,15 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||
let entries = blame.update(cx, |blame, cx| {
|
||||
blame
|
||||
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(0..4)
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx,
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
@@ -2141,7 +2157,15 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||
let blame = editor_b.blame().expect("editor_b should have blame now");
|
||||
let entries = blame.update(cx, |blame, cx| {
|
||||
blame
|
||||
.blame_for_rows((0..4).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(0..4)
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx,
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
mod block_map;
|
||||
mod crease_map;
|
||||
mod custom_highlights;
|
||||
mod diff_map;
|
||||
mod fold_map;
|
||||
mod inlay_map;
|
||||
pub(crate) mod invisibles;
|
||||
@@ -30,16 +31,19 @@ use crate::{
|
||||
hover_links::InlayHighlight, movement::TextLayoutDetails, EditorStyle, InlayId, RowExt,
|
||||
};
|
||||
pub use block_map::{
|
||||
Block, BlockBufferRows, BlockChunks as DisplayChunks, BlockContext, BlockId, BlockMap,
|
||||
BlockPlacement, BlockPoint, BlockProperties, BlockStyle, CustomBlockId, RenderBlock,
|
||||
Block, BlockChunks as DisplayChunks, BlockContext, BlockId, BlockMap, BlockPlacement,
|
||||
BlockPoint, BlockProperties, BlockRows, BlockStyle, CustomBlockId, RenderBlock,
|
||||
};
|
||||
use block_map::{BlockRow, BlockSnapshot};
|
||||
use collections::{HashMap, HashSet};
|
||||
pub use crease_map::*;
|
||||
use diff_map::{DiffMap, DiffMapSnapshot, DiffOffset, DiffPoint};
|
||||
pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint};
|
||||
use fold_map::{FoldMap, FoldSnapshot};
|
||||
use git::diff::DiffHunkStatus;
|
||||
use gpui::{
|
||||
AnyElement, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels, UnderlineStyle,
|
||||
AnyElement, AppContext, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels,
|
||||
UnderlineStyle,
|
||||
};
|
||||
pub(crate) use inlay_map::Inlay;
|
||||
use inlay_map::{InlayMap, InlaySnapshot};
|
||||
@@ -51,9 +55,10 @@ use language::{
|
||||
};
|
||||
use lsp::DiagnosticSeverity;
|
||||
use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, MultiBuffer, MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot,
|
||||
ToOffset, ToPoint,
|
||||
Anchor, AnchorRangeExt, MultiBuffer, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
|
||||
MultiBufferSnapshot, RowInfo, ToOffset, ToPoint,
|
||||
};
|
||||
use project::buffer_store::BufferChangeSet;
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
@@ -66,7 +71,7 @@ use std::{
|
||||
};
|
||||
use sum_tree::{Bias, TreeMap};
|
||||
use tab_map::{TabMap, TabSnapshot};
|
||||
use text::LineIndent;
|
||||
use text::{BufferId, LineIndent};
|
||||
use ui::{px, SharedString, WindowContext};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use wrap_map::{WrapMap, WrapSnapshot};
|
||||
@@ -96,6 +101,8 @@ pub struct DisplayMap {
|
||||
buffer_subscription: BufferSubscription,
|
||||
/// Decides where the [`Inlay`]s should be displayed.
|
||||
inlay_map: InlayMap,
|
||||
/// Decides where diff hunks should be.
|
||||
diff_map: Model<DiffMap>,
|
||||
/// Decides where the fold indicators should be and tracks parts of a source file that are currently folded.
|
||||
fold_map: FoldMap,
|
||||
/// Keeps track of hard tabs in a buffer.
|
||||
@@ -134,7 +141,8 @@ impl DisplayMap {
|
||||
let tab_size = Self::tab_size(&buffer, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let crease_map = CreaseMap::new(&buffer_snapshot);
|
||||
let (inlay_map, snapshot) = InlayMap::new(buffer_snapshot);
|
||||
let (diff_map, snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (inlay_map, snapshot) = InlayMap::new(snapshot);
|
||||
let (fold_map, snapshot) = FoldMap::new(snapshot);
|
||||
let (tab_map, snapshot) = TabMap::new(snapshot, tab_size);
|
||||
let (wrap_map, snapshot) = WrapMap::new(snapshot, font, font_size, wrap_width, cx);
|
||||
@@ -153,6 +161,7 @@ impl DisplayMap {
|
||||
buffer_subscription,
|
||||
fold_map,
|
||||
inlay_map,
|
||||
diff_map,
|
||||
tab_map,
|
||||
wrap_map,
|
||||
block_map,
|
||||
@@ -168,7 +177,10 @@ impl DisplayMap {
|
||||
pub fn snapshot(&mut self, cx: &mut ModelContext<Self>) -> DisplaySnapshot {
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
|
||||
let (diff_snapshot, edits) = self.diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), edits, cx)
|
||||
});
|
||||
let (inlay_snapshot, edits) = self.inlay_map.sync(diff_snapshot, edits);
|
||||
let (fold_snapshot, edits) = self.fold_map.read(inlay_snapshot.clone(), edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (tab_snapshot, edits) = self.tab_map.sync(fold_snapshot.clone(), edits, tab_size);
|
||||
@@ -217,7 +229,10 @@ impl DisplayMap {
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot.clone(), edits);
|
||||
let (snapshot, edits) = self.diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), edits, cx)
|
||||
});
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
@@ -290,6 +305,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -319,6 +337,9 @@ impl DisplayMap {
|
||||
.collect::<Vec<_>>();
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -341,6 +362,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -355,6 +379,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -387,6 +414,71 @@ impl DisplayMap {
|
||||
self.crease_map.remove(crease_ids, &snapshot)
|
||||
}
|
||||
|
||||
pub fn add_change_set(
|
||||
&mut self,
|
||||
change_set: Model<BufferChangeSet>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
self.diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.add_change_set(change_set, cx);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn has_multiple_hunks(&self, cx: &AppContext) -> bool {
|
||||
self.diff_map.read(cx).has_multiple_hunks()
|
||||
}
|
||||
|
||||
pub fn has_expanded_diff_hunks_in_ranges(
|
||||
&mut self,
|
||||
ranges: &[Range<multi_buffer::Anchor>],
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> bool {
|
||||
self.diff_map
|
||||
.read(cx)
|
||||
.has_expanded_diff_hunks_in_ranges(ranges)
|
||||
}
|
||||
|
||||
pub fn set_all_hunks_expanded(&mut self, cx: &mut ModelContext<Self>) {
|
||||
self.update_diff_map(cx, |diff_map, cx| diff_map.set_all_hunks_expanded(cx))
|
||||
}
|
||||
|
||||
pub fn expand_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut ModelContext<Self>) {
|
||||
self.update_diff_map(cx, |diff_map, cx| diff_map.expand_diff_hunks(ranges, cx))
|
||||
}
|
||||
|
||||
pub fn collapse_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut ModelContext<Self>) {
|
||||
self.update_diff_map(cx, |diff_map, cx| diff_map.collapse_diff_hunks(ranges, cx))
|
||||
}
|
||||
|
||||
pub fn diff_base_for<'a>(
|
||||
&'a self,
|
||||
buffer_id: BufferId,
|
||||
cx: &'a AppContext,
|
||||
) -> Option<&'a Model<BufferChangeSet>> {
|
||||
self.diff_map.read(cx).diff_base_for(buffer_id)
|
||||
}
|
||||
|
||||
fn update_diff_map(
|
||||
&mut self,
|
||||
cx: &mut ModelContext<Self>,
|
||||
f: impl FnOnce(&mut DiffMap, &mut ModelContext<DiffMap>),
|
||||
) {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (snapshot, edits) = self.diff_map.update(cx, |diff_map, cx| {
|
||||
f(diff_map, cx);
|
||||
diff_map.sync(snapshot, edits, cx)
|
||||
});
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||
self.block_map.write(snapshot, edits);
|
||||
}
|
||||
|
||||
pub fn insert_blocks(
|
||||
&mut self,
|
||||
blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
|
||||
@@ -395,6 +487,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -413,6 +508,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -431,6 +529,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -449,6 +550,9 @@ impl DisplayMap {
|
||||
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);
|
||||
let (snapshot, edits) = self
|
||||
.diff_map
|
||||
.update(cx, |diff_map, cx| diff_map.sync(snapshot, edits, cx));
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -524,7 +628,10 @@ impl DisplayMap {
|
||||
}
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
|
||||
let (snapshot, edits) = self.diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), edits, cx)
|
||||
});
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot.clone(), edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
@@ -710,17 +817,35 @@ impl DisplaySnapshot {
|
||||
self.fold_snapshot.fold_count()
|
||||
}
|
||||
|
||||
pub fn diff_hunks<'a>(&'a self) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
self.diff_snapshot()
|
||||
.diff_hunks_in_range(0..self.buffer_snapshot.len())
|
||||
}
|
||||
|
||||
pub fn diff_hunks_in_range<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
self.diff_snapshot().diff_hunks_in_range(range)
|
||||
}
|
||||
|
||||
pub fn diff_hunks_in_range_rev<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
self.diff_snapshot().diff_hunks_in_range_rev(range)
|
||||
}
|
||||
|
||||
pub fn has_diff_hunks(&self) -> bool {
|
||||
self.diff_snapshot().has_diff_hunks()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.buffer_snapshot.len() == 0
|
||||
}
|
||||
|
||||
pub fn buffer_rows(
|
||||
&self,
|
||||
start_row: DisplayRow,
|
||||
) -> impl Iterator<Item = Option<MultiBufferRow>> + '_ {
|
||||
self.block_snapshot
|
||||
.buffer_rows(BlockRow(start_row.0))
|
||||
.map(|row| row.map(MultiBufferRow))
|
||||
pub fn row_infos(&self, start_row: DisplayRow) -> impl Iterator<Item = RowInfo> + '_ {
|
||||
self.block_snapshot.row_infos(BlockRow(start_row.0))
|
||||
}
|
||||
|
||||
pub fn widest_line_number(&self) -> u32 {
|
||||
@@ -729,7 +854,7 @@ impl DisplaySnapshot {
|
||||
|
||||
pub fn prev_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) {
|
||||
loop {
|
||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
let mut inlay_point = self.inlay_snapshot.make_inlay_point(point);
|
||||
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Left);
|
||||
fold_point.0.column = 0;
|
||||
inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
|
||||
@@ -751,7 +876,7 @@ impl DisplaySnapshot {
|
||||
) -> (MultiBufferPoint, DisplayPoint) {
|
||||
let original_point = point;
|
||||
loop {
|
||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
let mut inlay_point = self.inlay_snapshot.make_inlay_point(point);
|
||||
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Right);
|
||||
fold_point.0.column = self.fold_snapshot.line_len(fold_point.row());
|
||||
inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
|
||||
@@ -795,7 +920,7 @@ impl DisplaySnapshot {
|
||||
}
|
||||
|
||||
pub fn point_to_display_point(&self, point: MultiBufferPoint, bias: Bias) -> DisplayPoint {
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
let inlay_point = self.inlay_snapshot.make_inlay_point(point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
||||
let wrap_point = self.wrap_snapshot.tab_point_to_wrap_point(tab_point);
|
||||
@@ -813,9 +938,15 @@ impl DisplaySnapshot {
|
||||
.to_offset(self.display_point_to_inlay_point(point, bias))
|
||||
}
|
||||
|
||||
pub fn display_point_to_diff_offset(&self, point: DisplayPoint, bias: Bias) -> DiffOffset {
|
||||
self.diff_snapshot()
|
||||
.point_to_offset(self.display_point_to_diff_point(point, bias))
|
||||
}
|
||||
|
||||
pub fn anchor_to_inlay_offset(&self, anchor: Anchor) -> InlayOffset {
|
||||
self.inlay_snapshot
|
||||
.to_inlay_offset(anchor.to_offset(&self.buffer_snapshot))
|
||||
let multibuffer_offset = anchor.to_offset(&self.buffer_snapshot);
|
||||
let diff_offset = self.diff_snapshot().to_diff_offset(multibuffer_offset);
|
||||
self.inlay_snapshot.to_inlay_offset(diff_offset)
|
||||
}
|
||||
|
||||
pub fn display_point_to_anchor(&self, point: DisplayPoint, bias: Bias) -> Anchor {
|
||||
@@ -831,6 +962,17 @@ impl DisplaySnapshot {
|
||||
fold_point.to_inlay_point(&self.fold_snapshot)
|
||||
}
|
||||
|
||||
fn diff_point_to_display_point(&self, diff_point: DiffPoint, bias: Bias) -> DisplayPoint {
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(diff_point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
self.fold_point_to_display_point(fold_point)
|
||||
}
|
||||
|
||||
fn display_point_to_diff_point(&self, point: DisplayPoint, bias: Bias) -> DiffPoint {
|
||||
self.inlay_snapshot
|
||||
.to_diff_point(self.display_point_to_inlay_point(point, bias))
|
||||
}
|
||||
|
||||
pub fn display_point_to_fold_point(&self, point: DisplayPoint, bias: Bias) -> FoldPoint {
|
||||
let block_point = point.0;
|
||||
let wrap_point = self.block_snapshot.to_wrap_point(block_point, bias);
|
||||
@@ -1068,6 +1210,22 @@ impl DisplaySnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn anchor_before(&self, point: DisplayPoint) -> DisplayAnchor {
|
||||
let diff_point = self.display_point_to_diff_point(point, Bias::Left);
|
||||
self.diff_snapshot().point_to_anchor(diff_point, Bias::Left)
|
||||
}
|
||||
|
||||
pub fn anchor_after(&self, point: DisplayPoint) -> DisplayAnchor {
|
||||
let diff_point = self.display_point_to_diff_point(point, Bias::Left);
|
||||
self.diff_snapshot()
|
||||
.point_to_anchor(diff_point, Bias::Right)
|
||||
}
|
||||
|
||||
pub fn anchor_to_point(&self, anchor: DisplayAnchor) -> DisplayPoint {
|
||||
let diff_point = self.diff_snapshot().anchor_to_point(anchor);
|
||||
self.diff_point_to_display_point(diff_point, Bias::Left)
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint {
|
||||
let mut clipped = self.block_snapshot.clip_point(point.0, bias);
|
||||
if self.clip_at_line_ends {
|
||||
@@ -1307,6 +1465,51 @@ impl DisplaySnapshot {
|
||||
pub fn excerpt_header_height(&self) -> u32 {
|
||||
self.block_snapshot.excerpt_header_height
|
||||
}
|
||||
|
||||
pub(crate) fn diff_snapshot(&self) -> &DiffMapSnapshot {
|
||||
&self.inlay_snapshot.diff_map_snapshot
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
|
||||
pub struct DisplayAnchor {
|
||||
pub anchor: multi_buffer::Anchor,
|
||||
pub diff_base_anchor: Option<text::Anchor>,
|
||||
}
|
||||
|
||||
impl DisplayAnchor {
|
||||
pub fn min() -> Self {
|
||||
Self {
|
||||
anchor: multi_buffer::Anchor::min(),
|
||||
diff_base_anchor: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max() -> Self {
|
||||
Self {
|
||||
anchor: multi_buffer::Anchor::max(),
|
||||
diff_base_anchor: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmp(&self, other: &DisplayAnchor, map: &DisplaySnapshot) -> std::cmp::Ordering {
|
||||
map.diff_snapshot().compare_anchors(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DisplayCoordinate {
|
||||
fn to_display_anchor(self, map: &DisplaySnapshot) -> DisplayAnchor;
|
||||
}
|
||||
|
||||
impl DisplayCoordinate for DisplayAnchor {
|
||||
fn to_display_anchor(self, _: &DisplaySnapshot) -> DisplayAnchor {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl DisplayCoordinate for DisplayPoint {
|
||||
fn to_display_anchor(self, map: &DisplaySnapshot) -> DisplayAnchor {
|
||||
map.anchor_before(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::{
|
||||
wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use crate::{EditorStyle, GutterDimensions};
|
||||
use crate::{EditorStyle, GutterDimensions, RowInfo};
|
||||
use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, AppContext, EntityId, Pixels, WindowContext};
|
||||
use language::{Chunk, Patch, Point};
|
||||
@@ -399,9 +399,9 @@ pub struct BlockChunks<'a> {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlockBufferRows<'a> {
|
||||
pub struct BlockRows<'a> {
|
||||
transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
|
||||
input_buffer_rows: wrap_map::WrapBufferRows<'a>,
|
||||
input_rows: wrap_map::WrapRows<'a>,
|
||||
output_row: BlockRow,
|
||||
started: bool,
|
||||
}
|
||||
@@ -1360,7 +1360,7 @@ impl BlockSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn buffer_rows(&self, start_row: BlockRow) -> BlockBufferRows {
|
||||
pub(super) fn row_infos(&self, start_row: BlockRow) -> BlockRows {
|
||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
|
||||
cursor.seek(&start_row, Bias::Right, &());
|
||||
let (output_start, input_start) = cursor.start();
|
||||
@@ -1373,9 +1373,9 @@ impl BlockSnapshot {
|
||||
0
|
||||
};
|
||||
let input_start_row = input_start.0 + overshoot;
|
||||
BlockBufferRows {
|
||||
BlockRows {
|
||||
transforms: cursor,
|
||||
input_buffer_rows: self.wrap_snapshot.buffer_rows(input_start_row),
|
||||
input_rows: self.wrap_snapshot.row_infos(input_start_row),
|
||||
output_row: start_row,
|
||||
started: false,
|
||||
}
|
||||
@@ -1766,8 +1766,8 @@ impl<'a> Iterator for BlockChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BlockBufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
impl<'a> Iterator for BlockRows<'a> {
|
||||
type Item = RowInfo;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.started {
|
||||
@@ -1796,7 +1796,7 @@ impl<'a> Iterator for BlockBufferRows<'a> {
|
||||
.as_ref()
|
||||
.map_or(true, |block| block.is_replacement())
|
||||
{
|
||||
self.input_buffer_rows.seek(self.transforms.start().1 .0);
|
||||
self.input_rows.seek(self.transforms.start().1 .0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1804,15 +1804,15 @@ impl<'a> Iterator for BlockBufferRows<'a> {
|
||||
if let Some(block) = transform.block.as_ref() {
|
||||
if block.is_replacement() && self.transforms.start().0 == self.output_row {
|
||||
if matches!(block, Block::FoldedBuffer { .. }) {
|
||||
Some(None)
|
||||
Some(RowInfo::default())
|
||||
} else {
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
Some(self.input_rows.next().unwrap())
|
||||
}
|
||||
} else {
|
||||
Some(None)
|
||||
Some(RowInfo::default())
|
||||
}
|
||||
} else {
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
Some(self.input_rows.next().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1928,7 +1928,8 @@ fn offset_for_row(s: &str, target: u32) -> (u32, usize) {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::display_map::{
|
||||
fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap, wrap_map::WrapMap,
|
||||
diff_map::DiffMap, fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap,
|
||||
wrap_map::WrapMap,
|
||||
};
|
||||
use gpui::{div, font, px, AppContext, Context as _, Element};
|
||||
use itertools::Itertools;
|
||||
@@ -1962,7 +1963,8 @@ mod tests {
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(text, cx));
|
||||
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
|
||||
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
|
||||
let (wrap_map, wraps_snapshot) =
|
||||
@@ -2087,7 +2089,10 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|row_info| row_info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
Some(0),
|
||||
None,
|
||||
@@ -2108,8 +2113,10 @@ mod tests {
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot, subscription.consume().into_inner(), cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap());
|
||||
@@ -2171,8 +2178,8 @@ mod tests {
|
||||
.width;
|
||||
}
|
||||
|
||||
let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(multi_buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(multi_buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot);
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font, font_size, Some(wrap_width), cx);
|
||||
@@ -2210,7 +2217,8 @@ mod tests {
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(text, cx));
|
||||
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
|
||||
let _subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (_inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_diff_map, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (_inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
|
||||
let (_wrap_map, wraps_snapshot) =
|
||||
@@ -2312,7 +2320,8 @@ mod tests {
|
||||
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(text, cx));
|
||||
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (_, wraps_snapshot) = cx.update(|cx| {
|
||||
@@ -2356,7 +2365,8 @@ mod tests {
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(text, cx));
|
||||
let buffer_subscription = buffer.update(cx, |buffer, _cx| buffer.subscribe());
|
||||
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let tab_size = 1.try_into().unwrap();
|
||||
let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, tab_size);
|
||||
@@ -2383,10 +2393,14 @@ mod tests {
|
||||
buffer.edit([(Point::new(2, 0)..Point::new(3, 0), "")], None, cx);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(
|
||||
buffer_snapshot.clone(),
|
||||
buffer_subscription.consume().into_inner(),
|
||||
);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer_snapshot,
|
||||
buffer_subscription.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot.clone(), diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
@@ -2406,10 +2420,14 @@ mod tests {
|
||||
);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(
|
||||
buffer_snapshot.clone(),
|
||||
buffer_subscription.consume().into_inner(),
|
||||
);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer_snapshot.clone(),
|
||||
buffer_subscription.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
@@ -2524,7 +2542,8 @@ mod tests {
|
||||
let buffer_id_2 = buffer_ids[1];
|
||||
let buffer_id_3 = buffer_ids[2];
|
||||
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (_, wrap_snapshot) =
|
||||
@@ -2537,7 +2556,10 @@ mod tests {
|
||||
"\n\n\n111\n\n\n\n\n222\n\n\n333\n\n\n444\n\n\n\n\n555\n\n\n666\n"
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2613,7 +2635,10 @@ mod tests {
|
||||
"\n\n\n111\n\n\n\n\n\n222\n\n\n\n333\n\n\n444\n\n\n\n\n\n\n555\n\n\n666\n\n"
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2688,7 +2713,10 @@ mod tests {
|
||||
"\n\n\n\n\n\n222\n\n\n\n333\n\n\n444\n\n\n\n\n\n\n555\n\n\n666\n\n"
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2753,7 +2781,10 @@ mod tests {
|
||||
);
|
||||
assert_eq!(blocks_snapshot.text(), "\n\n\n\n\n\n\n\n555\n\n\n666\n\n");
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2807,7 +2838,10 @@ mod tests {
|
||||
"Should have extra newline for 111 buffer, due to a new block added when it was folded"
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2861,7 +2895,10 @@ mod tests {
|
||||
"Should have a single, first buffer left after folding"
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
None,
|
||||
None,
|
||||
@@ -2895,7 +2932,8 @@ mod tests {
|
||||
assert_eq!(buffer_ids.len(), 1);
|
||||
let buffer_id = buffer_ids[0];
|
||||
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (_, wrap_snapshot) =
|
||||
@@ -2931,7 +2969,10 @@ mod tests {
|
||||
);
|
||||
assert_eq!(blocks_snapshot.text(), "\n");
|
||||
assert_eq!(
|
||||
blocks_snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
blocks_snapshot
|
||||
.row_infos(BlockRow(0))
|
||||
.map(|i| i.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![None, None],
|
||||
"When fully folded, should be no buffer rows"
|
||||
);
|
||||
@@ -2977,7 +3018,8 @@ mod tests {
|
||||
};
|
||||
|
||||
let mut buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (mut tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (wrap_map, wraps_snapshot) = cx
|
||||
@@ -3035,8 +3077,10 @@ mod tests {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), vec![]);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), vec![], cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
@@ -3073,8 +3117,10 @@ mod tests {
|
||||
.map(|block| block.id)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), vec![]);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), vec![], cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
@@ -3094,8 +3140,11 @@ mod tests {
|
||||
log::info!("Noop fold/unfold operation on a singleton buffer");
|
||||
continue;
|
||||
}
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), vec![], cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), vec![]);
|
||||
inlay_map.sync(diff_snapshot.clone(), diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
@@ -3180,8 +3229,10 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), buffer_edits, cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
@@ -3384,7 +3435,8 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot
|
||||
.buffer_rows(BlockRow(start_row as u32))
|
||||
.row_infos(BlockRow(start_row as u32))
|
||||
.map(|row_info| row_info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[start_row..],
|
||||
"incorrect buffer_rows starting at row {:?}",
|
||||
|
||||
2562
crates/editor/src/display_map/diff_map.rs
Normal file
2562
crates/editor/src/display_map/diff_map.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
use crate::RowInfo;
|
||||
|
||||
use super::{
|
||||
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
|
||||
Highlights,
|
||||
@@ -139,7 +141,7 @@ impl<'a> FoldMapWriter<'a> {
|
||||
let mut folds = Vec::new();
|
||||
let snapshot = self.0.snapshot.inlay_snapshot.clone();
|
||||
for (range, fold_text) in ranges.into_iter() {
|
||||
let buffer = &snapshot.buffer;
|
||||
let buffer = snapshot.buffer();
|
||||
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
|
||||
|
||||
// Ignore any empty ranges.
|
||||
@@ -161,14 +163,14 @@ impl<'a> FoldMapWriter<'a> {
|
||||
});
|
||||
|
||||
let inlay_range =
|
||||
snapshot.to_inlay_offset(range.start)..snapshot.to_inlay_offset(range.end);
|
||||
snapshot.make_inlay_offset(range.start)..snapshot.make_inlay_offset(range.end);
|
||||
edits.push(InlayEdit {
|
||||
old: inlay_range.clone(),
|
||||
new: inlay_range,
|
||||
});
|
||||
}
|
||||
|
||||
let buffer = &snapshot.buffer;
|
||||
let buffer = snapshot.buffer();
|
||||
folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(&a.range, &b.range, buffer));
|
||||
|
||||
self.0.snapshot.folds = {
|
||||
@@ -220,7 +222,7 @@ impl<'a> FoldMapWriter<'a> {
|
||||
let mut edits = Vec::new();
|
||||
let mut fold_ixs_to_delete = Vec::new();
|
||||
let snapshot = self.0.snapshot.inlay_snapshot.clone();
|
||||
let buffer = &snapshot.buffer;
|
||||
let buffer = snapshot.buffer();
|
||||
for range in ranges.into_iter() {
|
||||
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
|
||||
let mut folds_cursor =
|
||||
@@ -230,8 +232,8 @@ impl<'a> FoldMapWriter<'a> {
|
||||
fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer);
|
||||
if should_unfold(fold) {
|
||||
if offset_range.end > offset_range.start {
|
||||
let inlay_range = snapshot.to_inlay_offset(offset_range.start)
|
||||
..snapshot.to_inlay_offset(offset_range.end);
|
||||
let inlay_range = snapshot.make_inlay_offset(offset_range.start)
|
||||
..snapshot.make_inlay_offset(offset_range.end);
|
||||
edits.push(InlayEdit {
|
||||
old: inlay_range.clone(),
|
||||
new: inlay_range,
|
||||
@@ -275,7 +277,7 @@ impl FoldMap {
|
||||
pub(crate) fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) {
|
||||
let this = Self {
|
||||
snapshot: FoldSnapshot {
|
||||
folds: SumTree::new(&inlay_snapshot.buffer),
|
||||
folds: SumTree::new(inlay_snapshot.buffer()),
|
||||
transforms: SumTree::from_item(
|
||||
Transform {
|
||||
summary: TransformSummary {
|
||||
@@ -336,9 +338,7 @@ impl FoldMap {
|
||||
let mut folds = self.snapshot.folds.iter().peekable();
|
||||
while let Some(fold) = folds.next() {
|
||||
if let Some(next_fold) = folds.peek() {
|
||||
let comparison = fold
|
||||
.range
|
||||
.cmp(&next_fold.range, &self.snapshot.inlay_snapshot.buffer);
|
||||
let comparison = fold.range.cmp(&next_fold.range, self.snapshot.buffer());
|
||||
assert!(comparison.is_le());
|
||||
}
|
||||
}
|
||||
@@ -410,31 +410,31 @@ impl FoldMap {
|
||||
InlayOffset(((edit.new.start + edit.old_len()).0 as isize + delta) as usize);
|
||||
|
||||
let anchor = inlay_snapshot
|
||||
.buffer
|
||||
.buffer()
|
||||
.anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start));
|
||||
let mut folds_cursor = self
|
||||
.snapshot
|
||||
.folds
|
||||
.cursor::<FoldRange>(&inlay_snapshot.buffer);
|
||||
.cursor::<FoldRange>(&inlay_snapshot.buffer());
|
||||
folds_cursor.seek(
|
||||
&FoldRange(anchor..Anchor::max()),
|
||||
Bias::Left,
|
||||
&inlay_snapshot.buffer,
|
||||
&inlay_snapshot.buffer(),
|
||||
);
|
||||
|
||||
let mut folds = iter::from_fn({
|
||||
let inlay_snapshot = &inlay_snapshot;
|
||||
move || {
|
||||
let item = folds_cursor.item().map(|fold| {
|
||||
let buffer_start = fold.range.start.to_offset(&inlay_snapshot.buffer);
|
||||
let buffer_end = fold.range.end.to_offset(&inlay_snapshot.buffer);
|
||||
let buffer_start = fold.range.start.to_offset(&inlay_snapshot.buffer());
|
||||
let buffer_end = fold.range.end.to_offset(&inlay_snapshot.buffer());
|
||||
(
|
||||
fold.clone(),
|
||||
inlay_snapshot.to_inlay_offset(buffer_start)
|
||||
..inlay_snapshot.to_inlay_offset(buffer_end),
|
||||
inlay_snapshot.make_inlay_offset(buffer_start)
|
||||
..inlay_snapshot.make_inlay_offset(buffer_end),
|
||||
)
|
||||
});
|
||||
folds_cursor.next(&inlay_snapshot.buffer);
|
||||
folds_cursor.next(&inlay_snapshot.buffer());
|
||||
item
|
||||
}
|
||||
})
|
||||
@@ -578,6 +578,10 @@ pub struct FoldSnapshot {
|
||||
}
|
||||
|
||||
impl FoldSnapshot {
|
||||
pub fn buffer(&self) -> &MultiBufferSnapshot {
|
||||
self.inlay_snapshot.buffer()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(FoldOffset(0)..self.len(), false, Highlights::default())
|
||||
@@ -587,7 +591,7 @@ impl FoldSnapshot {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn fold_count(&self) -> usize {
|
||||
self.folds.items(&self.inlay_snapshot.buffer).len()
|
||||
self.folds.items(self.inlay_snapshot.buffer()).len()
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> TextSummary {
|
||||
@@ -641,6 +645,32 @@ impl FoldSnapshot {
|
||||
summary
|
||||
}
|
||||
|
||||
pub fn make_fold_point(&self, point: Point, bias: Bias) -> FoldPoint {
|
||||
self.to_fold_point(self.inlay_snapshot.make_inlay_point(point), bias)
|
||||
}
|
||||
|
||||
pub fn make_fold_offset(&self, buffer_offset: usize, bias: Bias) -> FoldOffset {
|
||||
self.to_fold_offset(self.inlay_snapshot.make_inlay_offset(buffer_offset), bias)
|
||||
}
|
||||
|
||||
pub fn to_fold_offset(&self, inlay_offset: InlayOffset, bias: Bias) -> FoldOffset {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, FoldOffset)>(&());
|
||||
cursor.seek(&inlay_offset, Bias::Right, &());
|
||||
if cursor.item().map_or(false, |t| t.is_fold()) {
|
||||
if bias == Bias::Left || inlay_offset == cursor.start().0 {
|
||||
cursor.start().1
|
||||
} else {
|
||||
cursor.end(&()).1
|
||||
}
|
||||
} else {
|
||||
let overshoot = inlay_offset.0 - cursor.start().0 .0;
|
||||
FoldOffset(cmp::min(
|
||||
cursor.start().1 .0 + overshoot,
|
||||
cursor.end(&()).1 .0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_fold_point(&self, point: InlayPoint, bias: Bias) -> FoldPoint {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>(&());
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
@@ -673,7 +703,7 @@ impl FoldSnapshot {
|
||||
(line_end - line_start) as u32
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, start_row: u32) -> FoldBufferRows {
|
||||
pub fn row_infos(&self, start_row: u32) -> FoldRows {
|
||||
if start_row > self.transforms.summary().output.lines.row {
|
||||
panic!("invalid display row {}", start_row);
|
||||
}
|
||||
@@ -684,11 +714,11 @@ impl FoldSnapshot {
|
||||
|
||||
let overshoot = fold_point.0 - cursor.start().0 .0;
|
||||
let inlay_point = InlayPoint(cursor.start().1 .0 + overshoot);
|
||||
let input_buffer_rows = self.inlay_snapshot.buffer_rows(inlay_point.row());
|
||||
let input_rows = self.inlay_snapshot.row_infos(inlay_point.row());
|
||||
|
||||
FoldBufferRows {
|
||||
FoldRows {
|
||||
fold_point,
|
||||
input_buffer_rows,
|
||||
input_rows,
|
||||
cursor,
|
||||
}
|
||||
}
|
||||
@@ -706,12 +736,12 @@ impl FoldSnapshot {
|
||||
where
|
||||
T: ToOffset,
|
||||
{
|
||||
let buffer = &self.inlay_snapshot.buffer;
|
||||
let buffer = self.inlay_snapshot.buffer();
|
||||
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
|
||||
let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false);
|
||||
iter::from_fn(move || {
|
||||
let item = folds.item();
|
||||
folds.next(&self.inlay_snapshot.buffer);
|
||||
folds.next(buffer);
|
||||
item
|
||||
})
|
||||
}
|
||||
@@ -720,8 +750,8 @@ impl FoldSnapshot {
|
||||
where
|
||||
T: ToOffset,
|
||||
{
|
||||
let buffer_offset = offset.to_offset(&self.inlay_snapshot.buffer);
|
||||
let inlay_offset = self.inlay_snapshot.to_inlay_offset(buffer_offset);
|
||||
let buffer_offset = offset.to_offset(self.inlay_snapshot.buffer());
|
||||
let inlay_offset = self.inlay_snapshot.make_inlay_offset(buffer_offset);
|
||||
let mut cursor = self.transforms.cursor::<InlayOffset>(&());
|
||||
cursor.seek(&inlay_offset, Bias::Right, &());
|
||||
cursor.item().map_or(false, |t| t.placeholder.is_some())
|
||||
@@ -730,7 +760,7 @@ impl FoldSnapshot {
|
||||
pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool {
|
||||
let mut inlay_point = self
|
||||
.inlay_snapshot
|
||||
.to_inlay_point(Point::new(buffer_row.0, 0));
|
||||
.make_inlay_point(Point::new(buffer_row.0, 0));
|
||||
let mut cursor = self.transforms.cursor::<InlayPoint>(&());
|
||||
cursor.seek(&inlay_point, Bias::Right, &());
|
||||
loop {
|
||||
@@ -870,7 +900,7 @@ fn intersecting_folds<'a>(
|
||||
range: Range<usize>,
|
||||
inclusive: bool,
|
||||
) -> FilterCursor<'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize> {
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let buffer = inlay_snapshot.buffer();
|
||||
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
||||
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
||||
let mut cursor = folds.filter::<_, usize>(buffer, move |summary| {
|
||||
@@ -1134,25 +1164,25 @@ impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FoldBufferRows<'a> {
|
||||
pub struct FoldRows<'a> {
|
||||
cursor: Cursor<'a, Transform, (FoldPoint, InlayPoint)>,
|
||||
input_buffer_rows: InlayBufferRows<'a>,
|
||||
input_rows: InlayBufferRows<'a>,
|
||||
fold_point: FoldPoint,
|
||||
}
|
||||
|
||||
impl<'a> FoldBufferRows<'a> {
|
||||
impl<'a> FoldRows<'a> {
|
||||
pub(crate) fn seek(&mut self, row: u32) {
|
||||
let fold_point = FoldPoint::new(row, 0);
|
||||
self.cursor.seek(&fold_point, Bias::Left, &());
|
||||
let overshoot = fold_point.0 - self.cursor.start().0 .0;
|
||||
let inlay_point = InlayPoint(self.cursor.start().1 .0 + overshoot);
|
||||
self.input_buffer_rows.seek(inlay_point.row());
|
||||
self.input_rows.seek(inlay_point.row());
|
||||
self.fold_point = fold_point;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FoldBufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
impl<'a> Iterator for FoldRows<'a> {
|
||||
type Item = RowInfo;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut traversed_fold = false;
|
||||
@@ -1166,11 +1196,11 @@ impl<'a> Iterator for FoldBufferRows<'a> {
|
||||
|
||||
if self.cursor.item().is_some() {
|
||||
if traversed_fold {
|
||||
self.input_buffer_rows.seek(self.cursor.start().1.row());
|
||||
self.input_buffer_rows.next();
|
||||
self.input_rows.seek(self.cursor.start().1 .0.row);
|
||||
self.input_rows.next();
|
||||
}
|
||||
*self.fold_point.row_mut() += 1;
|
||||
self.input_buffer_rows.next()
|
||||
self.input_rows.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -1380,7 +1410,10 @@ pub type FoldEdit = Edit<FoldOffset>;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{display_map::inlay_map::InlayMap, MultiBuffer, ToPoint};
|
||||
use crate::{
|
||||
display_map::{diff_map::DiffMap, inlay_map::InlayMap},
|
||||
MultiBuffer, ToPoint,
|
||||
};
|
||||
use collections::HashSet;
|
||||
use rand::prelude::*;
|
||||
use settings::SettingsStore;
|
||||
@@ -1395,8 +1428,8 @@ mod tests {
|
||||
init_test(cx);
|
||||
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
|
||||
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot, vec![]);
|
||||
@@ -1431,8 +1464,14 @@ mod tests {
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer_snapshot.clone(),
|
||||
subscription.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (snapshot3, edits) = map.read(inlay_snapshot, inlay_edits);
|
||||
assert_eq!(snapshot3.text(), "123a⋯c123c⋯eeeee");
|
||||
assert_eq!(
|
||||
@@ -1453,8 +1492,11 @@ mod tests {
|
||||
buffer.edit([(Point::new(2, 6)..Point::new(4, 3), "456")], None, cx);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot, subscription.consume().into_inner(), cx)
|
||||
});
|
||||
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (snapshot4, _) = map.read(inlay_snapshot.clone(), inlay_edits);
|
||||
assert_eq!(snapshot4.text(), "123a⋯c123456eee");
|
||||
|
||||
@@ -1474,8 +1516,8 @@ mod tests {
|
||||
init_test(cx);
|
||||
let buffer = MultiBuffer::build_simple("abcdefghijkl", cx);
|
||||
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
|
||||
{
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
@@ -1521,8 +1563,10 @@ mod tests {
|
||||
buffer.edit([(0..1, "12345")], None, cx);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot, subscription.consume().into_inner(), cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (snapshot, _) = map.read(inlay_snapshot, inlay_edits);
|
||||
assert_eq!(snapshot.text(), "12345⋯fghijkl");
|
||||
}
|
||||
@@ -1531,8 +1575,8 @@ mod tests {
|
||||
#[gpui::test]
|
||||
fn test_overlapping_folds(cx: &mut gpui::AppContext) {
|
||||
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot);
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
writer.fold(vec![
|
||||
@@ -1550,8 +1594,8 @@ mod tests {
|
||||
init_test(cx);
|
||||
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
|
||||
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
@@ -1566,8 +1610,10 @@ mod tests {
|
||||
buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], None, cx);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot, subscription.consume().into_inner(), cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
let (snapshot, _) = map.read(inlay_snapshot, inlay_edits);
|
||||
assert_eq!(snapshot.text(), "aa⋯eeeee");
|
||||
}
|
||||
@@ -1576,7 +1622,8 @@ mod tests {
|
||||
fn test_folds_in_range(cx: &mut gpui::AppContext) {
|
||||
let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
@@ -1618,7 +1665,8 @@ mod tests {
|
||||
MultiBuffer::build_random(&mut rng, cx)
|
||||
};
|
||||
let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut initial_snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
|
||||
@@ -1648,8 +1696,10 @@ mod tests {
|
||||
}),
|
||||
};
|
||||
|
||||
let (inlay_snapshot, new_inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), buffer_edits, cx)
|
||||
});
|
||||
let (inlay_snapshot, new_inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
log::info!("inlay text {:?}", inlay_snapshot.text());
|
||||
|
||||
let inlay_edits = Patch::new(inlay_edits)
|
||||
@@ -1660,8 +1710,8 @@ mod tests {
|
||||
|
||||
let mut expected_text: String = inlay_snapshot.text().to_string();
|
||||
for fold_range in map.merged_folds().into_iter().rev() {
|
||||
let fold_inlay_start = inlay_snapshot.to_inlay_offset(fold_range.start);
|
||||
let fold_inlay_end = inlay_snapshot.to_inlay_offset(fold_range.end);
|
||||
let fold_inlay_start = inlay_snapshot.make_inlay_offset(fold_range.start);
|
||||
let fold_inlay_end = inlay_snapshot.make_inlay_offset(fold_range.end);
|
||||
expected_text.replace_range(fold_inlay_start.0..fold_inlay_end.0, "⋯");
|
||||
}
|
||||
|
||||
@@ -1676,19 +1726,19 @@ mod tests {
|
||||
let mut expected_buffer_rows = Vec::new();
|
||||
for fold_range in map.merged_folds() {
|
||||
let fold_start = inlay_snapshot
|
||||
.to_point(inlay_snapshot.to_inlay_offset(fold_range.start))
|
||||
.to_point(inlay_snapshot.make_inlay_offset(fold_range.start))
|
||||
.row();
|
||||
let fold_end = inlay_snapshot
|
||||
.to_point(inlay_snapshot.to_inlay_offset(fold_range.end))
|
||||
.to_point(inlay_snapshot.make_inlay_offset(fold_range.end))
|
||||
.row();
|
||||
expected_buffer_rows.extend(
|
||||
inlay_snapshot
|
||||
.buffer_rows(prev_row)
|
||||
.row_infos(prev_row)
|
||||
.take((1 + fold_start - prev_row) as usize),
|
||||
);
|
||||
prev_row = 1 + fold_end;
|
||||
}
|
||||
expected_buffer_rows.extend(inlay_snapshot.buffer_rows(prev_row));
|
||||
expected_buffer_rows.extend(inlay_snapshot.row_infos(prev_row));
|
||||
|
||||
assert_eq!(
|
||||
expected_buffer_rows.len(),
|
||||
@@ -1777,7 +1827,7 @@ mod tests {
|
||||
let mut fold_row = 0;
|
||||
while fold_row < expected_buffer_rows.len() as u32 {
|
||||
assert_eq!(
|
||||
snapshot.buffer_rows(fold_row).collect::<Vec<_>>(),
|
||||
snapshot.row_infos(fold_row).collect::<Vec<_>>(),
|
||||
expected_buffer_rows[(fold_row as usize)..],
|
||||
"wrong buffer rows starting at fold row {}",
|
||||
fold_row,
|
||||
@@ -1879,8 +1929,8 @@ mod tests {
|
||||
let text = sample_text(6, 6, 'a') + "\n";
|
||||
let buffer = MultiBuffer::build_simple(&text, cx);
|
||||
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot);
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
@@ -1892,10 +1942,19 @@ mod tests {
|
||||
let (snapshot, _) = map.read(inlay_snapshot, vec![]);
|
||||
assert_eq!(snapshot.text(), "aa⋯cccc\nd⋯eeeee\nffffff\n");
|
||||
assert_eq!(
|
||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
||||
snapshot
|
||||
.row_infos(0)
|
||||
.map(|info| info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
[Some(0), Some(3), Some(5), Some(6)]
|
||||
);
|
||||
assert_eq!(snapshot.buffer_rows(3).collect::<Vec<_>>(), [Some(6)]);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.row_infos(3)
|
||||
.map(|info| info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
[Some(6)]
|
||||
);
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut gpui::AppContext) {
|
||||
@@ -1906,7 +1965,7 @@ mod tests {
|
||||
impl FoldMap {
|
||||
fn merged_folds(&self) -> Vec<Range<usize>> {
|
||||
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let buffer = inlay_snapshot.buffer();
|
||||
let mut folds = self.snapshot.folds.items(buffer);
|
||||
// Ensure sorting doesn't change how folds get merged and displayed.
|
||||
folds.sort_by(|a, b| a.range.cmp(&b.range, buffer));
|
||||
@@ -1942,7 +2001,7 @@ mod tests {
|
||||
match rng.gen_range(0..=100) {
|
||||
0..=39 if !self.snapshot.folds.is_empty() => {
|
||||
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let buffer = inlay_snapshot.buffer();
|
||||
let mut to_unfold = Vec::new();
|
||||
for _ in 0..rng.gen_range(1..=3) {
|
||||
let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
|
||||
@@ -1958,7 +2017,7 @@ mod tests {
|
||||
}
|
||||
_ => {
|
||||
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let buffer = inlay_snapshot.buffer();
|
||||
let mut to_fold = Vec::new();
|
||||
for _ in 0..rng.gen_range(1..=2) {
|
||||
let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{HighlightStyles, InlayId};
|
||||
use crate::{HighlightStyles, InlayId, RowInfo};
|
||||
use collections::BTreeSet;
|
||||
use language::{Chunk, Edit, Point, TextSummary};
|
||||
use multi_buffer::{Anchor, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, ToOffset};
|
||||
use multi_buffer::{Anchor, MultiBufferSnapshot, ToOffset};
|
||||
use std::{
|
||||
cmp,
|
||||
ops::{Add, AddAssign, Range, Sub, SubAssign},
|
||||
@@ -9,7 +9,10 @@ use std::{
|
||||
use sum_tree::{Bias, Cursor, SumTree};
|
||||
use text::{Patch, Rope};
|
||||
|
||||
use super::{custom_highlights::CustomHighlightsChunks, Highlights};
|
||||
use super::{
|
||||
diff_map::{DiffEdit, DiffMapChunks, DiffMapRows, DiffMapSnapshot, DiffOffset, DiffPoint},
|
||||
Highlights,
|
||||
};
|
||||
|
||||
/// Decides where the [`Inlay`]s should be displayed.
|
||||
///
|
||||
@@ -21,7 +24,7 @@ pub struct InlayMap {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InlaySnapshot {
|
||||
pub buffer: MultiBufferSnapshot,
|
||||
pub diff_map_snapshot: DiffMapSnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
pub version: usize,
|
||||
}
|
||||
@@ -172,37 +175,37 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for DiffOffset {
|
||||
fn zero(_cx: &()) -> Self {
|
||||
Default::default()
|
||||
DiffOffset(0)
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
*self += &summary.input.len;
|
||||
self.0 += &summary.input.len;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for DiffPoint {
|
||||
fn zero(_cx: &()) -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
*self += &summary.input.lines;
|
||||
self.0 += &summary.input.lines;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InlayBufferRows<'a> {
|
||||
transforms: Cursor<'a, Transform, (InlayPoint, Point)>,
|
||||
buffer_rows: MultiBufferRows<'a>,
|
||||
transforms: Cursor<'a, Transform, (InlayPoint, DiffPoint)>,
|
||||
diff_rows: DiffMapRows<'a>,
|
||||
inlay_row: u32,
|
||||
max_buffer_row: MultiBufferRow,
|
||||
max_point: DiffPoint,
|
||||
}
|
||||
|
||||
pub struct InlayChunks<'a> {
|
||||
transforms: Cursor<'a, Transform, (InlayOffset, usize)>,
|
||||
buffer_chunks: CustomHighlightsChunks<'a>,
|
||||
transforms: Cursor<'a, Transform, (InlayOffset, DiffOffset)>,
|
||||
diff_map_chunks: DiffMapChunks<'a>,
|
||||
buffer_chunk: Option<Chunk<'a>>,
|
||||
inlay_chunks: Option<text::Chunks<'a>>,
|
||||
inlay_chunk: Option<&'a str>,
|
||||
@@ -214,21 +217,21 @@ pub struct InlayChunks<'a> {
|
||||
}
|
||||
|
||||
impl<'a> InlayChunks<'a> {
|
||||
pub fn offset(&self) -> InlayOffset {
|
||||
self.output_offset
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, new_range: Range<InlayOffset>) {
|
||||
self.transforms.seek(&new_range.start, Bias::Right, &());
|
||||
|
||||
let buffer_range = self.snapshot.to_buffer_offset(new_range.start)
|
||||
..self.snapshot.to_buffer_offset(new_range.end);
|
||||
self.buffer_chunks.seek(buffer_range);
|
||||
let diff_range = self.snapshot.to_diff_offset(new_range.start)
|
||||
..self.snapshot.to_diff_offset(new_range.end);
|
||||
self.diff_map_chunks.seek(diff_range);
|
||||
self.inlay_chunks = None;
|
||||
self.buffer_chunk = None;
|
||||
self.output_offset = new_range.start;
|
||||
self.max_output_offset = new_range.end;
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> InlayOffset {
|
||||
self.output_offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for InlayChunks<'a> {
|
||||
@@ -243,9 +246,9 @@ impl<'a> Iterator for InlayChunks<'a> {
|
||||
Transform::Isomorphic(_) => {
|
||||
let chunk = self
|
||||
.buffer_chunk
|
||||
.get_or_insert_with(|| self.buffer_chunks.next().unwrap());
|
||||
.get_or_insert_with(|| self.diff_map_chunks.next().unwrap());
|
||||
if chunk.text.is_empty() {
|
||||
*chunk = self.buffer_chunks.next().unwrap();
|
||||
*chunk = self.diff_map_chunks.next().unwrap();
|
||||
}
|
||||
|
||||
let (prefix, suffix) = chunk.text.split_at(
|
||||
@@ -344,33 +347,33 @@ impl<'a> InlayBufferRows<'a> {
|
||||
let inlay_point = InlayPoint::new(row, 0);
|
||||
self.transforms.seek(&inlay_point, Bias::Left, &());
|
||||
|
||||
let mut buffer_point = self.transforms.start().1;
|
||||
let buffer_row = MultiBufferRow(if row == 0 {
|
||||
let mut diff_point = self.transforms.start().1;
|
||||
let row = if row == 0 {
|
||||
0
|
||||
} else {
|
||||
match self.transforms.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
buffer_point += inlay_point.0 - self.transforms.start().0 .0;
|
||||
buffer_point.row
|
||||
diff_point.0 += inlay_point.0 - self.transforms.start().0 .0;
|
||||
diff_point.row()
|
||||
}
|
||||
_ => cmp::min(buffer_point.row + 1, self.max_buffer_row.0),
|
||||
_ => cmp::min(diff_point.row() + 1, self.max_point.row()),
|
||||
}
|
||||
});
|
||||
};
|
||||
self.inlay_row = inlay_point.row();
|
||||
self.buffer_rows.seek(buffer_row);
|
||||
self.diff_rows.seek(row);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for InlayBufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
type Item = RowInfo;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let buffer_row = if self.inlay_row == 0 {
|
||||
self.buffer_rows.next().unwrap()
|
||||
let row_info = if self.inlay_row == 0 {
|
||||
self.diff_rows.next().unwrap()
|
||||
} else {
|
||||
match self.transforms.item()? {
|
||||
Transform::Inlay(_) => None,
|
||||
Transform::Isomorphic(_) => self.buffer_rows.next().unwrap(),
|
||||
Transform::Inlay(_) => Default::default(),
|
||||
Transform::Isomorphic(_) => self.diff_rows.next().unwrap(),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -378,7 +381,7 @@ impl<'a> Iterator for InlayBufferRows<'a> {
|
||||
self.transforms
|
||||
.seek_forward(&InlayPoint::new(self.inlay_row, 0), Bias::Left, &());
|
||||
|
||||
Some(buffer_row)
|
||||
Some(row_info)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,11 +396,14 @@ impl InlayPoint {
|
||||
}
|
||||
|
||||
impl InlayMap {
|
||||
pub fn new(buffer: MultiBufferSnapshot) -> (Self, InlaySnapshot) {
|
||||
pub fn new(diff_map_snapshot: DiffMapSnapshot) -> (Self, InlaySnapshot) {
|
||||
let version = 0;
|
||||
let snapshot = InlaySnapshot {
|
||||
buffer: buffer.clone(),
|
||||
transforms: SumTree::from_iter(Some(Transform::Isomorphic(buffer.text_summary())), &()),
|
||||
transforms: SumTree::from_iter(
|
||||
Some(Transform::Isomorphic(diff_map_snapshot.text_summary())),
|
||||
&(),
|
||||
),
|
||||
diff_map_snapshot,
|
||||
version,
|
||||
};
|
||||
|
||||
@@ -412,133 +418,121 @@ impl InlayMap {
|
||||
|
||||
pub fn sync(
|
||||
&mut self,
|
||||
buffer_snapshot: MultiBufferSnapshot,
|
||||
mut buffer_edits: Vec<text::Edit<usize>>,
|
||||
diff_map_snapshot: DiffMapSnapshot,
|
||||
mut diff_edits: Vec<DiffEdit>,
|
||||
) -> (InlaySnapshot, Vec<InlayEdit>) {
|
||||
let snapshot = &mut self.snapshot;
|
||||
|
||||
if buffer_edits.is_empty()
|
||||
&& snapshot.buffer.trailing_excerpt_update_count()
|
||||
!= buffer_snapshot.trailing_excerpt_update_count()
|
||||
if diff_edits.is_empty()
|
||||
&& snapshot.buffer().trailing_excerpt_update_count()
|
||||
!= diff_map_snapshot.buffer().trailing_excerpt_update_count()
|
||||
{
|
||||
buffer_edits.push(Edit {
|
||||
old: snapshot.buffer.len()..snapshot.buffer.len(),
|
||||
new: buffer_snapshot.len()..buffer_snapshot.len(),
|
||||
diff_edits.push(Edit {
|
||||
old: snapshot.diff_map_snapshot.len()..snapshot.diff_map_snapshot.len(),
|
||||
new: diff_map_snapshot.len()..diff_map_snapshot.len(),
|
||||
});
|
||||
}
|
||||
|
||||
if buffer_edits.is_empty() {
|
||||
if snapshot.buffer.edit_count() != buffer_snapshot.edit_count()
|
||||
|| snapshot.buffer.non_text_state_update_count()
|
||||
!= buffer_snapshot.non_text_state_update_count()
|
||||
|| snapshot.buffer.trailing_excerpt_update_count()
|
||||
!= buffer_snapshot.trailing_excerpt_update_count()
|
||||
{
|
||||
snapshot.version += 1;
|
||||
}
|
||||
|
||||
snapshot.buffer = buffer_snapshot;
|
||||
(snapshot.clone(), Vec::new())
|
||||
} else {
|
||||
let mut inlay_edits = Patch::default();
|
||||
let mut new_transforms = SumTree::default();
|
||||
let mut cursor = snapshot.transforms.cursor::<(usize, InlayOffset)>(&());
|
||||
let mut buffer_edits_iter = buffer_edits.iter().peekable();
|
||||
while let Some(buffer_edit) = buffer_edits_iter.next() {
|
||||
new_transforms.append(cursor.slice(&buffer_edit.old.start, Bias::Left, &()), &());
|
||||
if let Some(Transform::Isomorphic(transform)) = cursor.item() {
|
||||
if cursor.end(&()).0 == buffer_edit.old.start {
|
||||
push_isomorphic(&mut new_transforms, transform.clone());
|
||||
cursor.next(&());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all the inlays and transforms contained by the edit.
|
||||
let old_start =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.start - cursor.start().0);
|
||||
cursor.seek(&buffer_edit.old.end, Bias::Right, &());
|
||||
let old_end =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.end - cursor.start().0);
|
||||
|
||||
// Push the unchanged prefix.
|
||||
let prefix_start = new_transforms.summary().input.len;
|
||||
let prefix_end = buffer_edit.new.start;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
let new_start = InlayOffset(new_transforms.summary().output.len);
|
||||
|
||||
let start_ix = match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
.to_offset(&buffer_snapshot)
|
||||
.cmp(&buffer_edit.new.start)
|
||||
.then(std::cmp::Ordering::Greater)
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
};
|
||||
|
||||
for inlay in &self.inlays[start_ix..] {
|
||||
let buffer_offset = inlay.position.to_offset(&buffer_snapshot);
|
||||
if buffer_offset > buffer_edit.new.end {
|
||||
break;
|
||||
}
|
||||
|
||||
let prefix_start = new_transforms.summary().input.len;
|
||||
let prefix_end = buffer_offset;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
|
||||
if inlay.position.is_valid(&buffer_snapshot) {
|
||||
new_transforms.push(Transform::Inlay(inlay.clone()), &());
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the rest of the edit.
|
||||
let transform_start = new_transforms.summary().input.len;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(transform_start..buffer_edit.new.end),
|
||||
);
|
||||
let new_end = InlayOffset(new_transforms.summary().output.len);
|
||||
inlay_edits.push(Edit {
|
||||
old: old_start..old_end,
|
||||
new: new_start..new_end,
|
||||
});
|
||||
|
||||
// If the next edit doesn't intersect the current isomorphic transform, then
|
||||
// we can push its remainder.
|
||||
if buffer_edits_iter
|
||||
.peek()
|
||||
.map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
|
||||
{
|
||||
let transform_start = new_transforms.summary().input.len;
|
||||
let transform_end =
|
||||
buffer_edit.new.end + (cursor.end(&()).0 - buffer_edit.old.end);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(transform_start..transform_end),
|
||||
);
|
||||
let mut inlay_edits = Patch::default();
|
||||
let mut new_transforms = SumTree::default();
|
||||
let mut cursor = snapshot.transforms.cursor::<(DiffOffset, InlayOffset)>(&());
|
||||
let mut diff_edits_iter = diff_edits.iter().peekable();
|
||||
while let Some(diff_edit) = diff_edits_iter.next() {
|
||||
new_transforms.append(cursor.slice(&diff_edit.old.start, Bias::Left, &()), &());
|
||||
if let Some(Transform::Isomorphic(transform)) = cursor.item() {
|
||||
if cursor.end(&()).0 == diff_edit.old.start {
|
||||
push_isomorphic(&mut new_transforms, transform.clone());
|
||||
cursor.next(&());
|
||||
}
|
||||
}
|
||||
|
||||
new_transforms.append(cursor.suffix(&()), &());
|
||||
if new_transforms.is_empty() {
|
||||
new_transforms.push(Transform::Isomorphic(Default::default()), &());
|
||||
// Remove all the inlays and transforms contained by the edit.
|
||||
let old_start =
|
||||
cursor.start().1 + InlayOffset((diff_edit.old.start - cursor.start().0).0);
|
||||
cursor.seek(&diff_edit.old.end, Bias::Right, &());
|
||||
let old_end = cursor.start().1 + InlayOffset((diff_edit.old.end - cursor.start().0).0);
|
||||
|
||||
// Push the unchanged prefix.
|
||||
let prefix_start = DiffOffset(new_transforms.summary().input.len);
|
||||
let prefix_end = diff_edit.new.start;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
diff_map_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
let new_start = InlayOffset(new_transforms.summary().output.len);
|
||||
|
||||
let edit_buffer_range = diff_map_snapshot.to_multibuffer_offset(diff_edit.new.start)
|
||||
..diff_map_snapshot.to_multibuffer_offset(diff_edit.new.end);
|
||||
|
||||
let start_ix = match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
.to_offset(diff_map_snapshot.buffer())
|
||||
.cmp(&edit_buffer_range.start)
|
||||
.then(std::cmp::Ordering::Greater)
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
};
|
||||
|
||||
for inlay in &self.inlays[start_ix..] {
|
||||
let buffer_offset = inlay.position.to_offset(&diff_map_snapshot.buffer);
|
||||
let diff_offset = diff_map_snapshot.to_diff_offset(buffer_offset);
|
||||
if buffer_offset > edit_buffer_range.end {
|
||||
break;
|
||||
}
|
||||
|
||||
let prefix_start = DiffOffset(new_transforms.summary().input.len);
|
||||
let prefix_end = diff_offset;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
diff_map_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
|
||||
if inlay.position.is_valid(&diff_map_snapshot.buffer) {
|
||||
new_transforms.push(Transform::Inlay(inlay.clone()), &());
|
||||
}
|
||||
}
|
||||
|
||||
drop(cursor);
|
||||
snapshot.transforms = new_transforms;
|
||||
snapshot.version += 1;
|
||||
snapshot.buffer = buffer_snapshot;
|
||||
snapshot.check_invariants();
|
||||
// Apply the rest of the edit.
|
||||
let transform_start = DiffOffset(new_transforms.summary().input.len);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
diff_map_snapshot.text_summary_for_range(transform_start..diff_edit.new.end),
|
||||
);
|
||||
let new_end = InlayOffset(new_transforms.summary().output.len);
|
||||
inlay_edits.push(Edit {
|
||||
old: old_start..old_end,
|
||||
new: new_start..new_end,
|
||||
});
|
||||
|
||||
(snapshot.clone(), inlay_edits.into_inner())
|
||||
// If the next edit doesn't intersect the current isomorphic transform, then
|
||||
// we can push its remainder.
|
||||
if diff_edits_iter
|
||||
.peek()
|
||||
.map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
|
||||
{
|
||||
let transform_start = DiffOffset(new_transforms.summary().input.len);
|
||||
let transform_end = diff_edit.new.end + (cursor.end(&()).0 - diff_edit.old.end);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
diff_map_snapshot.text_summary_for_range(transform_start..transform_end),
|
||||
);
|
||||
cursor.next(&());
|
||||
}
|
||||
}
|
||||
|
||||
new_transforms.append(cursor.suffix(&()), &());
|
||||
if new_transforms.is_empty() {
|
||||
new_transforms.push(Transform::Isomorphic(Default::default()), &());
|
||||
}
|
||||
|
||||
drop(cursor);
|
||||
snapshot.transforms = new_transforms;
|
||||
snapshot.version += 1;
|
||||
snapshot.diff_map_snapshot = diff_map_snapshot;
|
||||
snapshot.check_invariants();
|
||||
|
||||
(snapshot.clone(), inlay_edits.into_inner())
|
||||
}
|
||||
|
||||
pub fn splice(
|
||||
@@ -552,7 +546,9 @@ impl InlayMap {
|
||||
self.inlays.retain(|inlay| {
|
||||
let retain = !to_remove.contains(&inlay.id);
|
||||
if !retain {
|
||||
let offset = inlay.position.to_offset(&snapshot.buffer);
|
||||
let offset = snapshot
|
||||
.diff_map_snapshot
|
||||
.to_diff_offset(inlay.position.to_offset(&snapshot.diff_map_snapshot.buffer));
|
||||
edits.insert(offset);
|
||||
}
|
||||
retain
|
||||
@@ -564,11 +560,16 @@ impl InlayMap {
|
||||
continue;
|
||||
}
|
||||
|
||||
let offset = inlay_to_insert.position.to_offset(&snapshot.buffer);
|
||||
match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
let offset = snapshot.diff_map_snapshot.to_diff_offset(
|
||||
inlay_to_insert
|
||||
.position
|
||||
.cmp(&inlay_to_insert.position, &snapshot.buffer)
|
||||
.to_offset(&snapshot.diff_map_snapshot.buffer),
|
||||
);
|
||||
match self.inlays.binary_search_by(|probe| {
|
||||
probe.position.cmp(
|
||||
&inlay_to_insert.position,
|
||||
&snapshot.diff_map_snapshot.buffer,
|
||||
)
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => {
|
||||
self.inlays.insert(ix, inlay_to_insert);
|
||||
@@ -585,7 +586,7 @@ impl InlayMap {
|
||||
new: offset..offset,
|
||||
})
|
||||
.collect();
|
||||
let buffer_snapshot = snapshot.buffer.clone();
|
||||
let buffer_snapshot = snapshot.diff_map_snapshot.clone();
|
||||
let (snapshot, edits) = self.sync(buffer_snapshot, buffer_edits);
|
||||
(snapshot, edits)
|
||||
}
|
||||
@@ -608,7 +609,8 @@ impl InlayMap {
|
||||
let snapshot = &mut self.snapshot;
|
||||
for i in 0..rng.gen_range(1..=5) {
|
||||
if self.inlays.is_empty() || rng.gen() {
|
||||
let position = snapshot.buffer.random_byte_range(0, rng).start;
|
||||
let position = snapshot.buffer().random_byte_range(0, rng).start;
|
||||
let anchor = snapshot.buffer().anchor_at(position, Bias::Left);
|
||||
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
|
||||
let len = if rng.gen_bool(0.01) {
|
||||
0
|
||||
@@ -626,7 +628,7 @@ impl InlayMap {
|
||||
InlayId::InlineCompletion(post_inc(next_inlay_id))
|
||||
};
|
||||
log::info!(
|
||||
"creating inlay {:?} at buffer offset {} with bias {:?} and text {:?}",
|
||||
"creating inlay {:?} at buffer offset {:?} with bias {:?} and text {:?}",
|
||||
inlay_id,
|
||||
position,
|
||||
bias,
|
||||
@@ -635,7 +637,7 @@ impl InlayMap {
|
||||
|
||||
to_insert.push(Inlay {
|
||||
id: inlay_id,
|
||||
position: snapshot.buffer.anchor_at(position, bias),
|
||||
position: anchor,
|
||||
text: text.into(),
|
||||
});
|
||||
} else {
|
||||
@@ -659,16 +661,16 @@ impl InlaySnapshot {
|
||||
pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<(InlayOffset, (InlayPoint, usize))>(&());
|
||||
.cursor::<(InlayOffset, (InlayPoint, DiffOffset))>(&());
|
||||
cursor.seek(&offset, Bias::Right, &());
|
||||
let overshoot = offset.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let buffer_offset_start = cursor.start().1 .1;
|
||||
let buffer_offset_end = buffer_offset_start + overshoot;
|
||||
let buffer_start = self.buffer.offset_to_point(buffer_offset_start);
|
||||
let buffer_end = self.buffer.offset_to_point(buffer_offset_end);
|
||||
InlayPoint(cursor.start().1 .0 .0 + (buffer_end - buffer_start))
|
||||
let buffer_offset_end = buffer_offset_start + DiffOffset(overshoot);
|
||||
let buffer_start = self.diff_map_snapshot.offset_to_point(buffer_offset_start);
|
||||
let buffer_end = self.diff_map_snapshot.offset_to_point(buffer_offset_end);
|
||||
cursor.start().1 .0 + InlayPoint(buffer_end.0 - buffer_start.0)
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text.offset_to_point(overshoot);
|
||||
@@ -689,51 +691,68 @@ impl InlaySnapshot {
|
||||
pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<(InlayPoint, (InlayOffset, Point))>(&());
|
||||
.cursor::<(InlayPoint, (InlayOffset, DiffPoint))>(&());
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let buffer_point_start = cursor.start().1 .1;
|
||||
let buffer_point_end = buffer_point_start + overshoot;
|
||||
let buffer_offset_start = self.buffer.point_to_offset(buffer_point_start);
|
||||
let buffer_offset_end = self.buffer.point_to_offset(buffer_point_end);
|
||||
InlayOffset(cursor.start().1 .0 .0 + (buffer_offset_end - buffer_offset_start))
|
||||
let buffer_point_end = buffer_point_start + DiffPoint(overshoot);
|
||||
let buffer_offset_start =
|
||||
self.diff_map_snapshot.point_to_offset(buffer_point_start);
|
||||
let buffer_offset_end = self.diff_map_snapshot.point_to_offset(buffer_point_end);
|
||||
cursor.start().1 .0 + InlayOffset((buffer_offset_end - buffer_offset_start).0)
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text.point_to_offset(overshoot);
|
||||
InlayOffset(cursor.start().1 .0 .0 + overshoot)
|
||||
cursor.start().1 .0 + InlayOffset(overshoot)
|
||||
}
|
||||
None => self.len(),
|
||||
}
|
||||
}
|
||||
pub fn to_buffer_point(&self, point: InlayPoint) -> Point {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>(&());
|
||||
|
||||
pub fn to_diff_point(&self, point: InlayPoint) -> DiffPoint {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, DiffPoint)>(&());
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
cursor.start().1 + overshoot
|
||||
cursor.start().1 + DiffPoint(overshoot)
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
None => self.buffer.max_point(),
|
||||
None => self.diff_map_snapshot.max_point(),
|
||||
}
|
||||
}
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>(&());
|
||||
|
||||
pub fn to_diff_offset(&self, offset: InlayOffset) -> DiffOffset {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, DiffOffset)>(&());
|
||||
cursor.seek(&offset, Bias::Right, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = offset - cursor.start().0;
|
||||
cursor.start().1 + overshoot.0
|
||||
cursor.start().1 + DiffOffset(overshoot.0)
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
None => self.buffer.len(),
|
||||
None => self.diff_map_snapshot.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_inlay_offset(&self, offset: usize) -> InlayOffset {
|
||||
let mut cursor = self.transforms.cursor::<(usize, InlayOffset)>(&());
|
||||
pub fn buffer(&self) -> &MultiBufferSnapshot {
|
||||
&self.diff_map_snapshot.buffer
|
||||
}
|
||||
|
||||
pub fn to_buffer_point(&self, point: InlayPoint) -> Point {
|
||||
self.diff_map_snapshot
|
||||
.to_multibuffer_point(self.to_diff_point(point))
|
||||
}
|
||||
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
|
||||
self.diff_map_snapshot
|
||||
.to_multibuffer_offset(self.to_diff_offset(offset))
|
||||
}
|
||||
|
||||
pub fn to_inlay_offset(&self, offset: DiffOffset) -> InlayOffset {
|
||||
let mut cursor = self.transforms.cursor::<(DiffOffset, InlayOffset)>(&());
|
||||
cursor.seek(&offset, Bias::Left, &());
|
||||
loop {
|
||||
match cursor.item() {
|
||||
@@ -748,7 +767,7 @@ impl InlaySnapshot {
|
||||
}
|
||||
return cursor.end(&()).1;
|
||||
} else {
|
||||
let overshoot = offset - cursor.start().0;
|
||||
let overshoot = offset.0 - cursor.start().0 .0;
|
||||
return InlayOffset(cursor.start().1 .0 + overshoot);
|
||||
}
|
||||
}
|
||||
@@ -765,8 +784,17 @@ impl InlaySnapshot {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn to_inlay_point(&self, point: Point) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(Point, InlayPoint)>(&());
|
||||
|
||||
pub fn make_inlay_point(&self, multibuffer_point: Point) -> InlayPoint {
|
||||
self.to_inlay_point(self.diff_map_snapshot.to_diff_point(multibuffer_point))
|
||||
}
|
||||
|
||||
pub fn make_inlay_offset(&self, multibuffer_point: usize) -> InlayOffset {
|
||||
self.to_inlay_offset(self.diff_map_snapshot.to_diff_offset(multibuffer_point))
|
||||
}
|
||||
|
||||
pub fn to_inlay_point(&self, point: DiffPoint) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(DiffPoint, InlayPoint)>(&());
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
loop {
|
||||
match cursor.item() {
|
||||
@@ -782,7 +810,7 @@ impl InlaySnapshot {
|
||||
return cursor.end(&()).1;
|
||||
} else {
|
||||
let overshoot = point - cursor.start().0;
|
||||
return InlayPoint(cursor.start().1 .0 + overshoot);
|
||||
return InlayPoint(cursor.start().1 .0 + overshoot.0);
|
||||
}
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
@@ -800,7 +828,7 @@ impl InlaySnapshot {
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, mut point: InlayPoint, mut bias: Bias) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>(&());
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, DiffPoint)>(&());
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
loop {
|
||||
match cursor.item() {
|
||||
@@ -836,10 +864,11 @@ impl InlaySnapshot {
|
||||
}
|
||||
} else {
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
let buffer_point = cursor.start().1 + overshoot;
|
||||
let clipped_buffer_point = self.buffer.clip_point(buffer_point, bias);
|
||||
let clipped_overshoot = clipped_buffer_point - cursor.start().1;
|
||||
let clipped_point = InlayPoint(cursor.start().0 .0 + clipped_overshoot);
|
||||
let diff_point = cursor.start().1 + DiffPoint(overshoot);
|
||||
let clipped_diff_point =
|
||||
self.diff_map_snapshot.clip_point(diff_point, bias);
|
||||
let clipped_overshoot = clipped_diff_point - cursor.start().1;
|
||||
let clipped_point = cursor.start().0 + InlayPoint(clipped_overshoot.0);
|
||||
if clipped_point == point {
|
||||
return clipped_point;
|
||||
} else {
|
||||
@@ -897,17 +926,19 @@ impl InlaySnapshot {
|
||||
pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>(&());
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, DiffOffset)>(&());
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
|
||||
let overshoot = range.start.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let buffer_start = cursor.start().1;
|
||||
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);
|
||||
let suffix_start = buffer_start + DiffOffset(overshoot);
|
||||
let suffix_end = buffer_start
|
||||
+ DiffOffset(cmp::min(cursor.end(&()).0, range.end).0 - cursor.start().0 .0);
|
||||
summary = self
|
||||
.diff_map_snapshot
|
||||
.text_summary_for_range(suffix_start..suffix_end);
|
||||
cursor.next(&());
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
@@ -928,10 +959,10 @@ impl InlaySnapshot {
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let prefix_start = cursor.start().1;
|
||||
let prefix_end = prefix_start + overshoot;
|
||||
let prefix_end = prefix_start + DiffOffset(overshoot);
|
||||
summary += self
|
||||
.buffer
|
||||
.text_summary_for_range::<TextSummary, _>(prefix_start..prefix_end);
|
||||
.diff_map_snapshot
|
||||
.text_summary_for_range(prefix_start..prefix_end);
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let prefix_end = overshoot;
|
||||
@@ -944,30 +975,30 @@ impl InlaySnapshot {
|
||||
summary
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, row: u32) -> InlayBufferRows<'_> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>(&());
|
||||
pub fn row_infos(&self, row: u32) -> InlayBufferRows<'_> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, DiffPoint)>(&());
|
||||
let inlay_point = InlayPoint::new(row, 0);
|
||||
cursor.seek(&inlay_point, Bias::Left, &());
|
||||
|
||||
let max_buffer_row = self.buffer.max_row();
|
||||
let mut buffer_point = cursor.start().1;
|
||||
let buffer_row = if row == 0 {
|
||||
MultiBufferRow(0)
|
||||
let max_point = self.diff_map_snapshot.max_point();
|
||||
let mut diff_point = cursor.start().1;
|
||||
let diff_row = if row == 0 {
|
||||
0
|
||||
} else {
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
buffer_point += inlay_point.0 - cursor.start().0 .0;
|
||||
MultiBufferRow(buffer_point.row)
|
||||
diff_point += DiffPoint(inlay_point.0 - cursor.start().0 .0);
|
||||
diff_point.row()
|
||||
}
|
||||
_ => cmp::min(MultiBufferRow(buffer_point.row + 1), max_buffer_row),
|
||||
_ => cmp::min(diff_point.row() + 1, max_point.row()),
|
||||
}
|
||||
};
|
||||
|
||||
InlayBufferRows {
|
||||
transforms: cursor,
|
||||
inlay_row: inlay_point.row(),
|
||||
buffer_rows: self.buffer.buffer_rows(buffer_row),
|
||||
max_buffer_row,
|
||||
diff_rows: self.diff_map_snapshot.row_infos(diff_row),
|
||||
max_point,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,20 +1018,17 @@ impl InlaySnapshot {
|
||||
language_aware: bool,
|
||||
highlights: Highlights<'a>,
|
||||
) -> InlayChunks<'a> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>(&());
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, DiffOffset)>(&());
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
|
||||
let buffer_range = self.to_buffer_offset(range.start)..self.to_buffer_offset(range.end);
|
||||
let buffer_chunks = CustomHighlightsChunks::new(
|
||||
buffer_range,
|
||||
language_aware,
|
||||
highlights.text_highlights,
|
||||
&self.buffer,
|
||||
);
|
||||
let diff_range = self.to_diff_offset(range.start)..self.to_diff_offset(range.end);
|
||||
let diff_map_chunks =
|
||||
self.diff_map_snapshot
|
||||
.chunks(diff_range, language_aware, highlights.text_highlights);
|
||||
|
||||
InlayChunks {
|
||||
transforms: cursor,
|
||||
buffer_chunks,
|
||||
diff_map_chunks,
|
||||
inlay_chunks: None,
|
||||
inlay_chunk: None,
|
||||
buffer_chunk: None,
|
||||
@@ -1022,7 +1050,10 @@ impl InlaySnapshot {
|
||||
fn check_invariants(&self) {
|
||||
#[cfg(any(debug_assertions, feature = "test-support"))]
|
||||
{
|
||||
assert_eq!(self.transforms.summary().input, self.buffer.text_summary());
|
||||
assert_eq!(
|
||||
self.transforms.summary().input,
|
||||
self.diff_map_snapshot.text_summary()
|
||||
);
|
||||
let mut transforms = self.transforms.iter().peekable();
|
||||
while let Some(transform) = transforms.next() {
|
||||
let transform_is_isomorphic = matches!(transform, Transform::Isomorphic(_));
|
||||
@@ -1063,7 +1094,7 @@ fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
display_map::{InlayHighlights, TextHighlights},
|
||||
display_map::{DiffMap, InlayHighlights, TextHighlights},
|
||||
hover_links::InlayHighlight,
|
||||
InlayId, MultiBuffer,
|
||||
};
|
||||
@@ -1163,7 +1194,8 @@ mod tests {
|
||||
fn test_basic_inlays(cx: &mut AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("abcdefghi", cx);
|
||||
let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (diff_map, diff_map_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_map_snapshot.clone());
|
||||
assert_eq!(inlay_snapshot.text(), "abcdefghi");
|
||||
let mut next_inlay_id = 0;
|
||||
|
||||
@@ -1177,27 +1209,27 @@ mod tests {
|
||||
);
|
||||
assert_eq!(inlay_snapshot.text(), "abc|123|defghi");
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 0)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 0)),
|
||||
InlayPoint::new(0, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 1)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 1)),
|
||||
InlayPoint::new(0, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 2)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 2)),
|
||||
InlayPoint::new(0, 2)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 3)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 3)),
|
||||
InlayPoint::new(0, 3)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 4)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 4)),
|
||||
InlayPoint::new(0, 9)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 5)),
|
||||
inlay_snapshot.make_inlay_point(Point::new(0, 5)),
|
||||
InlayPoint::new(0, 10)
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -1229,18 +1261,26 @@ mod tests {
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(2..3, "x"), (3..3, "y"), (4..4, "z")], None, cx)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abxy|123|dzefghi");
|
||||
|
||||
// An edit surrounding the inlay should invalidate it.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(4..5, "D")], None, cx));
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abxyDzefghi");
|
||||
|
||||
let (inlay_snapshot, _) = inlay_map.splice(
|
||||
@@ -1262,10 +1302,16 @@ mod tests {
|
||||
|
||||
// Edits ending where the inlay starts should not move it if it has a left bias.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(3..3, "JKL")], None, cx));
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let (inlay_snapshot, _) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi");
|
||||
|
||||
assert_eq!(
|
||||
@@ -1450,7 +1496,8 @@ mod tests {
|
||||
#[gpui::test]
|
||||
fn test_inlay_buffer_rows(cx: &mut AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (_diff_map, diff_map_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_map_snapshot);
|
||||
assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
|
||||
let mut next_inlay_id = 0;
|
||||
|
||||
@@ -1476,7 +1523,10 @@ mod tests {
|
||||
);
|
||||
assert_eq!(inlay_snapshot.text(), "|123|\nabc\n|456|def\n|567|\n\nghi");
|
||||
assert_eq!(
|
||||
inlay_snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
||||
inlay_snapshot
|
||||
.row_infos(0)
|
||||
.map(|r| r.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(0), None, Some(1), None, None, Some(2)]
|
||||
);
|
||||
}
|
||||
@@ -1501,7 +1551,8 @@ mod tests {
|
||||
let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let mut next_inlay_id = 0;
|
||||
log::info!("buffer text: {:?}", buffer_snapshot.text());
|
||||
let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_map_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(diff_map_snapshot.clone());
|
||||
for _ in 0..operations {
|
||||
let mut inlay_edits = Patch::default();
|
||||
|
||||
@@ -1524,8 +1575,12 @@ mod tests {
|
||||
}),
|
||||
};
|
||||
|
||||
let (new_diff_snapshot, new_diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer.read(cx).snapshot(cx), buffer_edits, cx)
|
||||
});
|
||||
|
||||
let (new_inlay_snapshot, new_inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
inlay_map.sync(new_diff_snapshot, new_diff_edits);
|
||||
inlay_snapshot = new_inlay_snapshot;
|
||||
inlay_edits = inlay_edits.compose(new_inlay_edits);
|
||||
|
||||
@@ -1547,7 +1602,7 @@ mod tests {
|
||||
}
|
||||
assert_eq!(inlay_snapshot.text(), expected_text.to_string());
|
||||
|
||||
let expected_buffer_rows = inlay_snapshot.buffer_rows(0).collect::<Vec<_>>();
|
||||
let expected_buffer_rows = inlay_snapshot.row_infos(0).collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
expected_buffer_rows.len() as u32,
|
||||
expected_text.max_point().row + 1
|
||||
@@ -1555,7 +1610,7 @@ mod tests {
|
||||
for row_start in 0..expected_buffer_rows.len() {
|
||||
assert_eq!(
|
||||
inlay_snapshot
|
||||
.buffer_rows(row_start as u32)
|
||||
.row_infos(row_start as u32)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[row_start..],
|
||||
"incorrect buffer rows starting at {}",
|
||||
@@ -1673,14 +1728,14 @@ mod tests {
|
||||
assert_eq!(expected_text.len(), inlay_snapshot.len().0);
|
||||
|
||||
let mut buffer_point = Point::default();
|
||||
let mut inlay_point = inlay_snapshot.to_inlay_point(buffer_point);
|
||||
let mut inlay_point = inlay_snapshot.make_inlay_point(buffer_point);
|
||||
let mut buffer_chars = buffer_snapshot.chars_at(0);
|
||||
loop {
|
||||
// Ensure conversion from buffer coordinates to inlay coordinates
|
||||
// is consistent.
|
||||
let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_point(inlay_snapshot.to_inlay_offset(buffer_offset)),
|
||||
inlay_snapshot.to_point(inlay_snapshot.make_inlay_offset(buffer_offset)),
|
||||
inlay_point
|
||||
);
|
||||
|
||||
@@ -1707,7 +1762,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Ensure that moving forward in the buffer always moves the inlay point forward as well.
|
||||
let new_inlay_point = inlay_snapshot.to_inlay_point(buffer_point);
|
||||
let new_inlay_point = inlay_snapshot.make_inlay_point(buffer_point);
|
||||
assert!(new_inlay_point > inlay_point);
|
||||
inlay_point = new_inlay_point;
|
||||
} else {
|
||||
@@ -1767,7 +1822,7 @@ mod tests {
|
||||
// Ensure the clipped points are at valid buffer locations.
|
||||
assert_eq!(
|
||||
inlay_snapshot
|
||||
.to_inlay_point(inlay_snapshot.to_buffer_point(clipped_left_point)),
|
||||
.to_inlay_point(inlay_snapshot.to_diff_point(clipped_left_point)),
|
||||
clipped_left_point,
|
||||
"to_buffer_point({:?}) = {:?}",
|
||||
clipped_left_point,
|
||||
@@ -1775,7 +1830,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot
|
||||
.to_inlay_point(inlay_snapshot.to_buffer_point(clipped_right_point)),
|
||||
.to_inlay_point(inlay_snapshot.to_diff_point(clipped_right_point)),
|
||||
clipped_right_point,
|
||||
"to_buffer_point({:?}) = {:?}",
|
||||
clipped_right_point,
|
||||
|
||||
@@ -164,7 +164,7 @@ pub struct TabSnapshot {
|
||||
|
||||
impl TabSnapshot {
|
||||
pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
|
||||
&self.fold_snapshot.inlay_snapshot.buffer
|
||||
self.fold_snapshot.inlay_snapshot.buffer()
|
||||
}
|
||||
|
||||
pub fn line_len(&self, row: u32) -> u32 {
|
||||
@@ -272,8 +272,8 @@ impl TabSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, row: u32) -> fold_map::FoldBufferRows<'_> {
|
||||
self.fold_snapshot.buffer_rows(row)
|
||||
pub fn rows(&self, row: u32) -> fold_map::FoldRows<'_> {
|
||||
self.fold_snapshot.row_infos(row)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -317,8 +317,7 @@ impl TabSnapshot {
|
||||
}
|
||||
|
||||
pub fn make_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);
|
||||
let fold_point = self.fold_snapshot.make_fold_point(point, bias);
|
||||
self.to_tab_point(fold_point)
|
||||
}
|
||||
|
||||
@@ -602,7 +601,7 @@ impl<'a> Iterator for TabChunks<'a> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
display_map::{fold_map::FoldMap, inlay_map::InlayMap},
|
||||
display_map::{diff_map::DiffMap, fold_map::FoldMap, inlay_map::InlayMap},
|
||||
MultiBuffer,
|
||||
};
|
||||
use rand::{prelude::StdRng, Rng};
|
||||
@@ -610,8 +609,8 @@ mod tests {
|
||||
#[gpui::test]
|
||||
fn test_expand_tabs(cx: &mut gpui::AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("", cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer, cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
@@ -627,8 +626,8 @@ mod tests {
|
||||
let output = "A BC DEF G HI J K L M";
|
||||
|
||||
let buffer = MultiBuffer::build_simple(input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer, cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
@@ -674,8 +673,8 @@ mod tests {
|
||||
let input = "abcdefg⋯hij";
|
||||
|
||||
let buffer = MultiBuffer::build_simple(input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
@@ -688,8 +687,8 @@ mod tests {
|
||||
let input = "\t \thello";
|
||||
|
||||
let buffer = MultiBuffer::build_simple(input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
let (_, inlay_snapshot) = InlayMap::new(diff_snapshot);
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
@@ -749,8 +748,11 @@ mod tests {
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (_, diff_snapshot) = DiffMap::new(buffer.clone(), cx);
|
||||
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot.clone());
|
||||
|
||||
log::info!("DiffMap text: {:?}", diff_snapshot.text());
|
||||
let (mut fold_map, _) = FoldMap::new(inlay_snapshot.clone());
|
||||
fold_map.randomly_mutate(&mut rng);
|
||||
let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::RowInfo;
|
||||
|
||||
use super::{
|
||||
fold_map::FoldBufferRows,
|
||||
fold_map::FoldRows,
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
@@ -60,16 +62,16 @@ pub struct WrapChunks<'a> {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WrapBufferRows<'a> {
|
||||
input_buffer_rows: FoldBufferRows<'a>,
|
||||
input_buffer_row: Option<u32>,
|
||||
pub struct WrapRows<'a> {
|
||||
input_buffer_rows: FoldRows<'a>,
|
||||
input_buffer_row: RowInfo,
|
||||
output_row: u32,
|
||||
soft_wrapped: bool,
|
||||
max_output_row: u32,
|
||||
transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
|
||||
}
|
||||
|
||||
impl<'a> WrapBufferRows<'a> {
|
||||
impl<'a> WrapRows<'a> {
|
||||
pub(crate) fn seek(&mut self, start_row: u32) {
|
||||
self.transforms
|
||||
.seek(&WrapPoint::new(start_row, 0), Bias::Left, &());
|
||||
@@ -717,7 +719,7 @@ impl WrapSnapshot {
|
||||
self.transforms.summary().output.longest_row
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, start_row: u32) -> WrapBufferRows {
|
||||
pub fn row_infos(&self, start_row: u32) -> WrapRows {
|
||||
let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>(&());
|
||||
transforms.seek(&WrapPoint::new(start_row, 0), Bias::Left, &());
|
||||
let mut input_row = transforms.start().1.row();
|
||||
@@ -725,9 +727,9 @@ impl WrapSnapshot {
|
||||
input_row += start_row - transforms.start().0.row();
|
||||
}
|
||||
let soft_wrapped = transforms.item().map_or(false, |t| !t.is_isomorphic());
|
||||
let mut input_buffer_rows = self.tab_snapshot.buffer_rows(input_row);
|
||||
let mut input_buffer_rows = self.tab_snapshot.rows(input_row);
|
||||
let input_buffer_row = input_buffer_rows.next().unwrap();
|
||||
WrapBufferRows {
|
||||
WrapRows {
|
||||
transforms,
|
||||
input_buffer_row,
|
||||
input_buffer_rows,
|
||||
@@ -847,7 +849,7 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
let text = language::Rope::from(self.text().as_str());
|
||||
let mut input_buffer_rows = self.tab_snapshot.buffer_rows(0);
|
||||
let mut input_buffer_rows = self.tab_snapshot.rows(0);
|
||||
let mut expected_buffer_rows = Vec::new();
|
||||
let mut prev_tab_row = 0;
|
||||
for display_row in 0..=self.max_point().row() {
|
||||
@@ -855,7 +857,7 @@ impl WrapSnapshot {
|
||||
if tab_point.row() == prev_tab_row && display_row != 0 {
|
||||
expected_buffer_rows.push(None);
|
||||
} else {
|
||||
expected_buffer_rows.push(input_buffer_rows.next().unwrap());
|
||||
expected_buffer_rows.push(input_buffer_rows.next().unwrap().buffer_row);
|
||||
}
|
||||
|
||||
prev_tab_row = tab_point.row();
|
||||
@@ -864,7 +866,8 @@ impl WrapSnapshot {
|
||||
|
||||
for start_display_row in 0..expected_buffer_rows.len() {
|
||||
assert_eq!(
|
||||
self.buffer_rows(start_display_row as u32)
|
||||
self.row_infos(start_display_row as u32)
|
||||
.map(|row_info| row_info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[start_display_row..],
|
||||
"invalid buffer_rows({}..)",
|
||||
@@ -958,8 +961,8 @@ impl<'a> Iterator for WrapChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for WrapBufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
impl<'a> Iterator for WrapRows<'a> {
|
||||
type Item = RowInfo;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.output_row > self.max_output_row {
|
||||
@@ -979,7 +982,11 @@ impl<'a> Iterator for WrapBufferRows<'a> {
|
||||
self.soft_wrapped = true;
|
||||
}
|
||||
|
||||
Some(if soft_wrapped { None } else { buffer_row })
|
||||
Some(if soft_wrapped {
|
||||
RowInfo::default()
|
||||
} else {
|
||||
buffer_row
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,7 +1168,7 @@ fn consolidate_wrap_edits(edits: Vec<WrapEdit>) -> Vec<WrapEdit> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
display_map::{fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap},
|
||||
display_map::{diff_map::DiffMap, fold_map::FoldMap, inlay_map::InlayMap, tab_map::TabMap},
|
||||
MultiBuffer,
|
||||
};
|
||||
use gpui::{font, px, test::observe};
|
||||
@@ -1209,9 +1216,11 @@ mod tests {
|
||||
});
|
||||
let mut buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (diff_map, diff_snapshot) = cx.update(|cx| DiffMap::new(buffer.clone(), cx));
|
||||
log::info!("DiffMap text: {:?}", diff_snapshot.text());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(diff_snapshot);
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
let (mut tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
|
||||
let tabs_snapshot = tab_map.set_max_expansion_column(32);
|
||||
@@ -1293,8 +1302,10 @@ mod tests {
|
||||
}
|
||||
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
let (diff_snapshot, diff_edits) = diff_map.update(cx, |diff_map, cx| {
|
||||
diff_map.sync(buffer_snapshot.clone(), buffer_edits, cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(diff_snapshot, diff_edits);
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
|
||||
@@ -89,7 +89,7 @@ use gpui::{
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
pub(crate) use hunk_diff::HoveredHunk;
|
||||
use hunk_diff::{diff_hunk_to_display, DiffMap, DiffMapSnapshot};
|
||||
use hunk_diff::{diff_hunk_to_display, DiffMap};
|
||||
use indent_guides::ActiveIndentGuidesState;
|
||||
use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
|
||||
pub use inline_completion::Direction;
|
||||
@@ -725,7 +725,6 @@ pub struct EditorSnapshot {
|
||||
git_blame_gutter_max_author_length: Option<usize>,
|
||||
pub display_snapshot: DisplaySnapshot,
|
||||
pub placeholder_text: Option<Arc<str>>,
|
||||
diff_map: DiffMapSnapshot,
|
||||
is_focused: bool,
|
||||
scroll_anchor: ScrollAnchor,
|
||||
ongoing_scroll: OngoingScroll,
|
||||
@@ -1205,7 +1204,12 @@ impl Editor {
|
||||
|
||||
let mut code_action_providers = Vec::new();
|
||||
if let Some(project) = project.clone() {
|
||||
get_unstaged_changes_for_buffers(&project, buffer.read(cx).all_buffers(), cx);
|
||||
get_unstaged_changes_for_buffers(
|
||||
&project,
|
||||
buffer.read(cx).all_buffers(),
|
||||
display_map.clone(),
|
||||
cx,
|
||||
);
|
||||
code_action_providers.push(Rc::new(project) as Rc<_>);
|
||||
}
|
||||
|
||||
@@ -1568,7 +1572,6 @@ impl Editor {
|
||||
scroll_anchor: self.scroll_manager.anchor(),
|
||||
ongoing_scroll: self.scroll_manager.ongoing_scroll(),
|
||||
placeholder_text: self.placeholder_text.clone(),
|
||||
diff_map: self.diff_map.snapshot(),
|
||||
is_focused: self.focus_handle.is_focused(cx),
|
||||
current_line_highlight: self
|
||||
.current_line_highlight
|
||||
@@ -5082,7 +5085,7 @@ impl Editor {
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn context_menu_visible(&self) -> bool {
|
||||
self.context_menu
|
||||
.borrow()
|
||||
@@ -5918,10 +5921,9 @@ impl Editor {
|
||||
pub fn revert_file(&mut self, _: &RevertFile, cx: &mut ViewContext<Self>) {
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(cx);
|
||||
for hunk in hunks_for_ranges(
|
||||
Some(Point::zero()..snapshot.buffer_snapshot.max_point()).into_iter(),
|
||||
&snapshot,
|
||||
) {
|
||||
for hunk in snapshot
|
||||
.hunks_for_ranges(Some(Point::zero()..snapshot.buffer_snapshot.max_point()).into_iter())
|
||||
{
|
||||
self.prepare_revert_change(&mut revert_changes, &hunk, cx);
|
||||
}
|
||||
if !revert_changes.is_empty() {
|
||||
@@ -5939,7 +5941,12 @@ impl Editor {
|
||||
}
|
||||
|
||||
pub fn revert_selected_hunks(&mut self, _: &RevertSelectedHunks, cx: &mut ViewContext<Self>) {
|
||||
let revert_changes = self.gather_revert_changes(&self.selections.all(cx), cx);
|
||||
let selections = self.selections.all(cx).into_iter().map(|s| s.range());
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(cx);
|
||||
for hunk in &snapshot.hunks_for_ranges(selections) {
|
||||
self.prepare_revert_change(&mut revert_changes, &hunk, cx);
|
||||
}
|
||||
if !revert_changes.is_empty() {
|
||||
self.transact(cx, |editor, cx| {
|
||||
editor.revert(revert_changes, cx);
|
||||
@@ -5976,28 +5983,18 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_revert_changes(
|
||||
&mut self,
|
||||
selections: &[Selection<Point>],
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) -> HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>> {
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(cx);
|
||||
for hunk in hunks_for_selections(&snapshot, selections) {
|
||||
self.prepare_revert_change(&mut revert_changes, &hunk, cx);
|
||||
}
|
||||
revert_changes
|
||||
}
|
||||
|
||||
pub fn prepare_revert_change(
|
||||
&mut self,
|
||||
revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
|
||||
hunk: &MultiBufferDiffHunk,
|
||||
cx: &AppContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<()> {
|
||||
let change_set = self
|
||||
.display_map
|
||||
.read(cx)
|
||||
.diff_base_for(hunk.buffer_id, cx)?;
|
||||
let buffer = self.buffer.read(cx).buffer(hunk.buffer_id)?;
|
||||
let buffer = buffer.read(cx);
|
||||
let change_set = &self.diff_map.diff_bases.get(&hunk.buffer_id)?.change_set;
|
||||
let original_text = change_set
|
||||
.read(cx)
|
||||
.base_text
|
||||
@@ -9213,9 +9210,8 @@ impl Editor {
|
||||
snapshot,
|
||||
position,
|
||||
ix > 0,
|
||||
snapshot.diff_map.diff_hunks_in_range(
|
||||
snapshot.diff_hunks_in_range(
|
||||
position + Point::new(1, 0)..snapshot.buffer_snapshot.max_point(),
|
||||
&snapshot.buffer_snapshot,
|
||||
),
|
||||
cx,
|
||||
) {
|
||||
@@ -9245,9 +9241,7 @@ impl Editor {
|
||||
snapshot,
|
||||
position,
|
||||
ix > 0,
|
||||
snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range_rev(Point::zero()..position, &snapshot.buffer_snapshot),
|
||||
snapshot.diff_hunks_in_range_rev(Point::zero()..position),
|
||||
cx,
|
||||
) {
|
||||
return Some(hunk);
|
||||
@@ -10930,6 +10924,29 @@ impl Editor {
|
||||
self.display_map.read(cx).fold_placeholder.clone()
|
||||
}
|
||||
|
||||
pub fn set_expand_all_diff_hunks(&mut self, cx: &mut AppContext) {
|
||||
self.display_map.update(cx, |display_map, cx| {
|
||||
display_map.set_all_hunks_expanded(cx);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn expand_all_diff_hunks(&mut self, _: &ExpandAllHunkDiffs, cx: &mut ViewContext<Self>) {
|
||||
self.display_map.update(cx, |display_map, cx| {
|
||||
display_map.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn toggle_hunk_diff(&mut self, _: &ToggleHunkDiff, cx: &mut ViewContext<Self>) {
|
||||
let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
|
||||
self.display_map.update(cx, |display_map, cx| {
|
||||
if display_map.has_expanded_diff_hunks_in_ranges(&ranges, cx) {
|
||||
display_map.collapse_diff_hunks(ranges, cx)
|
||||
} else {
|
||||
display_map.expand_diff_hunks(ranges, cx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
|
||||
if hovered != self.gutter_hovered {
|
||||
self.gutter_hovered = hovered;
|
||||
@@ -12233,7 +12250,12 @@ impl Editor {
|
||||
let buffer_id = buffer.read(cx).remote_id();
|
||||
if !self.diff_map.diff_bases.contains_key(&buffer_id) {
|
||||
if let Some(project) = &self.project {
|
||||
get_unstaged_changes_for_buffers(project, [buffer.clone()], cx);
|
||||
get_unstaged_changes_for_buffers(
|
||||
project,
|
||||
[buffer.clone()],
|
||||
self.display_map.clone(),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
cx.emit(EditorEvent::ExcerptsAdded {
|
||||
@@ -12937,7 +12959,8 @@ impl Editor {
|
||||
fn get_unstaged_changes_for_buffers(
|
||||
project: &Model<Project>,
|
||||
buffers: impl IntoIterator<Item = Model<Buffer>>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
display_map: Model<DisplayMap>,
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
let mut tasks = Vec::new();
|
||||
project.update(cx, |project, cx| {
|
||||
@@ -12945,16 +12968,17 @@ fn get_unstaged_changes_for_buffers(
|
||||
tasks.push(project.open_unstaged_changes(buffer.clone(), cx))
|
||||
}
|
||||
});
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
cx.spawn(|mut cx| async move {
|
||||
let change_sets = futures::future::join_all(tasks).await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
for change_set in change_sets {
|
||||
if let Some(change_set) = change_set.log_err() {
|
||||
this.diff_map.add_change_set(change_set, cx);
|
||||
display_map
|
||||
.update(&mut cx, |display_map, cx| {
|
||||
for change_set in change_sets {
|
||||
if let Some(change_set) = change_set.log_err() {
|
||||
display_map.add_change_set(change_set, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
@@ -13242,56 +13266,6 @@ fn test_wrap_with_prefix() {
|
||||
);
|
||||
}
|
||||
|
||||
fn hunks_for_selections(
|
||||
snapshot: &EditorSnapshot,
|
||||
selections: &[Selection<Point>],
|
||||
) -> Vec<MultiBufferDiffHunk> {
|
||||
hunks_for_ranges(
|
||||
selections.iter().map(|selection| selection.range()),
|
||||
snapshot,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn hunks_for_ranges(
|
||||
ranges: impl Iterator<Item = Range<Point>>,
|
||||
snapshot: &EditorSnapshot,
|
||||
) -> Vec<MultiBufferDiffHunk> {
|
||||
let mut hunks = Vec::new();
|
||||
let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
|
||||
HashMap::default();
|
||||
for query_range in ranges {
|
||||
let query_rows =
|
||||
MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
|
||||
for hunk in snapshot.diff_map.diff_hunks_in_range(
|
||||
Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
|
||||
&snapshot.buffer_snapshot,
|
||||
) {
|
||||
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
|
||||
// when the caret is just above or just below the deleted hunk.
|
||||
let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
|
||||
let related_to_selection = if allow_adjacent {
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
|| hunk.row_range.start == query_rows.end
|
||||
|| hunk.row_range.end == query_rows.start
|
||||
} else {
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
};
|
||||
if related_to_selection {
|
||||
if !processed_buffer_rows
|
||||
.entry(hunk.buffer_id)
|
||||
.or_default()
|
||||
.insert(hunk.buffer_range.start..hunk.buffer_range.end)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hunks.push(hunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hunks
|
||||
}
|
||||
|
||||
pub trait CollaborationHub {
|
||||
fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
|
||||
fn user_participant_indices<'a>(
|
||||
@@ -13840,6 +13814,45 @@ impl EditorSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hunks_for_ranges(
|
||||
&self,
|
||||
ranges: impl Iterator<Item = Range<Point>>,
|
||||
) -> Vec<MultiBufferDiffHunk> {
|
||||
let mut hunks = Vec::new();
|
||||
let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
|
||||
HashMap::default();
|
||||
for query_range in ranges {
|
||||
let query_rows =
|
||||
MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
|
||||
for hunk in self.diff_snapshot().diff_hunks_in_range(
|
||||
Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
|
||||
) {
|
||||
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
|
||||
// when the caret is just above or just below the deleted hunk.
|
||||
let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
|
||||
let related_to_selection = if allow_adjacent {
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
|| hunk.row_range.start == query_rows.end
|
||||
|| hunk.row_range.end == query_rows.start
|
||||
} else {
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
};
|
||||
if related_to_selection {
|
||||
if !processed_buffer_rows
|
||||
.entry(hunk.buffer_id)
|
||||
.or_default()
|
||||
.insert(hunk.buffer_range.start..hunk.buffer_range.end)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hunks.push(hunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hunks
|
||||
}
|
||||
|
||||
pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
|
||||
self.display_snapshot.buffer_snapshot.language_at(position)
|
||||
}
|
||||
|
||||
@@ -3359,8 +3359,7 @@ async fn test_custom_newlines_cause_no_false_positive_diffs(
|
||||
let snapshot = editor.snapshot(cx);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len(), &snapshot.buffer_snapshot)
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len())
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::new(),
|
||||
"Should not have any diffs for files with custom newlines"
|
||||
@@ -11655,7 +11654,9 @@ async fn test_multibuffer_reverts(cx: &mut gpui::TestAppContext) {
|
||||
cx,
|
||||
)
|
||||
});
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
});
|
||||
}
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
@@ -12073,12 +12074,34 @@ async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::Test
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
for _ in 0..3 {
|
||||
for _ in 0..2 {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
editor.toggle_hunk_diff(&ToggleHunkDiff, cx);
|
||||
}
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod;
|
||||
+ ˇuse some::modified;
|
||||
|
||||
|
||||
fn main() {
|
||||
- println!("hello");
|
||||
+ println!("hello there");
|
||||
|
||||
+ println!("around the");
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
editor.toggle_hunk_diff(&ToggleHunkDiff, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod;
|
||||
@@ -12164,7 +12187,7 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12209,7 +12232,7 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12292,7 +12315,7 @@ async fn test_fold_unfold_diff_hunk(executor: BackgroundExecutor, cx: &mut gpui:
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -12485,7 +12508,9 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext)
|
||||
cx,
|
||||
)
|
||||
});
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
@@ -12595,14 +12620,16 @@ async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut gpui::TestAppContext
|
||||
let buffer = buffer.read(cx).text_snapshot();
|
||||
let change_set = cx
|
||||
.new_model(|cx| BufferChangeSet::new_with_base_text(base.to_string(), buffer, cx));
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut cx = EditorTestContext::for_editor(editor, cx).await;
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| editor.expand_all_hunk_diffs(&Default::default(), cx));
|
||||
cx.update_editor(|editor, cx| editor.expand_all_diff_hunks(&Default::default(), cx));
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12666,7 +12693,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -12685,7 +12712,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12708,7 +12735,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12732,7 +12759,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12757,7 +12784,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12783,7 +12810,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12804,7 +12831,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
@@ -12857,7 +12884,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -12876,7 +12903,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12899,7 +12926,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12922,7 +12949,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -12946,7 +12973,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
@@ -12999,7 +13026,7 @@ async fn test_edit_after_expanded_modification_hunk(
|
||||
cx.set_diff_base(&diff_base);
|
||||
executor.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -14699,8 +14726,7 @@ fn assert_hunk_revert(
|
||||
let reverted_hunk_statuses = cx.update_editor(|editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
let reverted_hunk_statuses = snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len(), &snapshot.buffer_snapshot)
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len())
|
||||
.map(|hunk| hunk_status(&hunk))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ use crate::{
|
||||
DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings,
|
||||
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
||||
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, InlineCompletion, JumpData, LineDown,
|
||||
LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection,
|
||||
SoftWrap, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT,
|
||||
LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowInfo, RowRangeExt, SelectPhase,
|
||||
Selection, SoftWrap, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT,
|
||||
GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||
};
|
||||
use client::ParticipantIndex;
|
||||
@@ -381,7 +381,7 @@ impl EditorElement {
|
||||
register_action(view, cx, Editor::toggle_git_blame);
|
||||
register_action(view, cx, Editor::toggle_git_blame_inline);
|
||||
register_action(view, cx, Editor::toggle_hunk_diff);
|
||||
register_action(view, cx, Editor::expand_all_hunk_diffs);
|
||||
register_action(view, cx, Editor::expand_all_diff_hunks);
|
||||
register_action(view, cx, |editor, action, cx| {
|
||||
if let Some(task) = editor.format(action, cx) {
|
||||
task.detach_and_log_err(cx);
|
||||
@@ -1196,7 +1196,7 @@ impl EditorElement {
|
||||
let editor = self.editor.read(cx);
|
||||
let is_singleton = editor.is_singleton(cx);
|
||||
// Git
|
||||
(is_singleton && scrollbar_settings.git_diff && !snapshot.diff_map.is_empty())
|
||||
(is_singleton && scrollbar_settings.git_diff && snapshot.has_diff_hunks())
|
||||
||
|
||||
// Buffer Search Results
|
||||
(is_singleton && scrollbar_settings.search_results && editor.has_background_highlights::<BufferSearchHighlights>())
|
||||
@@ -1461,10 +1461,10 @@ impl EditorElement {
|
||||
.unwrap_err();
|
||||
let mut expanded_hunks = expanded_hunks[expanded_hunks_start_ix..].iter().peekable();
|
||||
|
||||
let mut display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)> = editor
|
||||
.diff_map
|
||||
.snapshot
|
||||
.diff_hunks_in_range(buffer_start..buffer_end, &buffer_snapshot)
|
||||
let mut display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)> = snapshot
|
||||
.display_snapshot
|
||||
.diff_snapshot()
|
||||
.diff_hunks_in_range(buffer_start..buffer_end)
|
||||
.filter_map(|hunk| {
|
||||
let display_hunk = diff_hunk_to_display(&hunk, snapshot);
|
||||
|
||||
@@ -1532,7 +1532,7 @@ impl EditorElement {
|
||||
fn layout_inline_blame(
|
||||
&self,
|
||||
display_row: DisplayRow,
|
||||
display_snapshot: &DisplaySnapshot,
|
||||
row_info: &RowInfo,
|
||||
line_layout: &LineWithInvisibles,
|
||||
crease_trailer: Option<&CreaseTrailerLayout>,
|
||||
em_width: Pixels,
|
||||
@@ -1555,13 +1555,10 @@ impl EditorElement {
|
||||
.as_ref()
|
||||
.map(|(w, _)| w.clone());
|
||||
|
||||
let display_point = DisplayPoint::new(display_row, 0);
|
||||
let buffer_row = MultiBufferRow(display_point.to_point(display_snapshot).row);
|
||||
|
||||
let blame = self.editor.read(cx).blame.clone()?;
|
||||
let blame_entry = blame
|
||||
.update(cx, |blame, cx| {
|
||||
blame.blame_for_rows([Some(buffer_row)], cx).next()
|
||||
blame.blame_for_rows(&[*row_info], cx).next()
|
||||
})
|
||||
.flatten()?;
|
||||
|
||||
@@ -1601,7 +1598,7 @@ impl EditorElement {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn layout_blame_entries(
|
||||
&self,
|
||||
buffer_rows: impl Iterator<Item = Option<MultiBufferRow>>,
|
||||
buffer_rows: &[RowInfo],
|
||||
em_width: Pixels,
|
||||
scroll_position: gpui::Point<f32>,
|
||||
line_height: Pixels,
|
||||
@@ -1938,7 +1935,7 @@ impl EditorElement {
|
||||
let end = rows.end.max(relative_to);
|
||||
|
||||
let buffer_rows = snapshot
|
||||
.buffer_rows(start)
|
||||
.row_infos(start)
|
||||
.take(1 + end.minus(start) as usize)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -1946,7 +1943,7 @@ impl EditorElement {
|
||||
let mut delta = 1;
|
||||
let mut i = head_idx + 1;
|
||||
while i < buffer_rows.len() as u32 {
|
||||
if buffer_rows[i as usize].is_some() {
|
||||
if buffer_rows[i as usize].buffer_row.is_some() {
|
||||
if rows.contains(&DisplayRow(i + start.0)) {
|
||||
relative_rows.insert(DisplayRow(i + start.0), delta);
|
||||
}
|
||||
@@ -1956,13 +1953,13 @@ impl EditorElement {
|
||||
}
|
||||
delta = 1;
|
||||
i = head_idx.min(buffer_rows.len() as u32 - 1);
|
||||
while i > 0 && buffer_rows[i as usize].is_none() {
|
||||
while i > 0 && buffer_rows[i as usize].buffer_row.is_none() {
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
if buffer_rows[i as usize].is_some() {
|
||||
if buffer_rows[i as usize].buffer_row.is_some() {
|
||||
if rows.contains(&DisplayRow(i + start.0)) {
|
||||
relative_rows.insert(DisplayRow(i + start.0), delta);
|
||||
}
|
||||
@@ -1976,7 +1973,7 @@ impl EditorElement {
|
||||
fn layout_line_numbers(
|
||||
&self,
|
||||
rows: Range<DisplayRow>,
|
||||
buffer_rows: impl Iterator<Item = Option<MultiBufferRow>>,
|
||||
buffer_rows: &[RowInfo],
|
||||
active_rows: &BTreeMap<DisplayRow, bool>,
|
||||
newest_selection_head: Option<DisplayPoint>,
|
||||
snapshot: &EditorSnapshot,
|
||||
@@ -2018,8 +2015,7 @@ impl EditorElement {
|
||||
buffer_rows
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(ix, multibuffer_row)| {
|
||||
let multibuffer_row = multibuffer_row?;
|
||||
.map(|(ix, row_info)| {
|
||||
let display_row = DisplayRow(rows.start.0 + ix as u32);
|
||||
let color = if active_rows.contains_key(&display_row) {
|
||||
cx.theme().colors().editor_active_line_number
|
||||
@@ -2027,7 +2023,7 @@ impl EditorElement {
|
||||
cx.theme().colors().editor_line_number
|
||||
};
|
||||
line_number.clear();
|
||||
let default_number = multibuffer_row.0 + 1;
|
||||
let default_number = row_info.buffer_row? + 1;
|
||||
let number = relative_rows
|
||||
.get(&DisplayRow(ix as u32 + rows.start.0))
|
||||
.unwrap_or(&default_number);
|
||||
@@ -2052,7 +2048,7 @@ impl EditorElement {
|
||||
fn layout_crease_toggles(
|
||||
&self,
|
||||
rows: Range<DisplayRow>,
|
||||
buffer_rows: impl IntoIterator<Item = Option<MultiBufferRow>>,
|
||||
row_infos: &[RowInfo],
|
||||
active_rows: &BTreeMap<DisplayRow, bool>,
|
||||
snapshot: &EditorSnapshot,
|
||||
cx: &mut WindowContext,
|
||||
@@ -2061,22 +2057,21 @@ impl EditorElement {
|
||||
&& snapshot.mode == EditorMode::Full
|
||||
&& self.editor.read(cx).is_singleton(cx);
|
||||
if include_fold_statuses {
|
||||
buffer_rows
|
||||
row_infos
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(ix, row)| {
|
||||
if let Some(multibuffer_row) = row {
|
||||
let display_row = DisplayRow(rows.start.0 + ix as u32);
|
||||
let active = active_rows.contains_key(&display_row);
|
||||
snapshot.render_crease_toggle(
|
||||
multibuffer_row,
|
||||
active,
|
||||
self.editor.clone(),
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.map(|(ix, info)| {
|
||||
let row = info.buffer_row?;
|
||||
let display_row = DisplayRow(rows.start.0 + ix as u32);
|
||||
let active = active_rows.contains_key(&display_row);
|
||||
|
||||
// todo(max): Retrieve the multibuffer row correctly
|
||||
snapshot.render_crease_toggle(
|
||||
MultiBufferRow(row),
|
||||
active,
|
||||
self.editor.clone(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
@@ -2086,15 +2081,16 @@ impl EditorElement {
|
||||
|
||||
fn layout_crease_trailers(
|
||||
&self,
|
||||
buffer_rows: impl IntoIterator<Item = Option<MultiBufferRow>>,
|
||||
buffer_rows: impl IntoIterator<Item = RowInfo>,
|
||||
snapshot: &EditorSnapshot,
|
||||
cx: &mut WindowContext,
|
||||
) -> Vec<Option<AnyElement>> {
|
||||
buffer_rows
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
if let Some(multibuffer_row) = row {
|
||||
snapshot.render_crease_trailer(multibuffer_row, cx)
|
||||
.map(|row_info| {
|
||||
// FIXME: These are not really MultiBufferRow?!
|
||||
if let Some(row) = row_info.buffer_row {
|
||||
snapshot.render_crease_trailer(MultiBufferRow(row), cx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -4376,32 +4372,29 @@ impl EditorElement {
|
||||
let max_point = snapshot.display_snapshot.buffer_snapshot.max_point();
|
||||
let mut marker_quads = Vec::new();
|
||||
if scrollbar_settings.git_diff {
|
||||
let marker_row_ranges = snapshot
|
||||
.diff_map
|
||||
.diff_hunks(&snapshot.buffer_snapshot)
|
||||
.map(|hunk| {
|
||||
let start_display_row =
|
||||
MultiBufferPoint::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
let mut end_display_row =
|
||||
MultiBufferPoint::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
if end_display_row != start_display_row {
|
||||
end_display_row.0 -= 1;
|
||||
}
|
||||
let color = match hunk_status(&hunk) {
|
||||
DiffHunkStatus::Added => theme.status().created,
|
||||
DiffHunkStatus::Modified => theme.status().modified,
|
||||
DiffHunkStatus::Removed => theme.status().deleted,
|
||||
};
|
||||
ColoredRange {
|
||||
start: start_display_row,
|
||||
end: end_display_row,
|
||||
color,
|
||||
}
|
||||
});
|
||||
let marker_row_ranges = snapshot.diff_hunks().map(|hunk| {
|
||||
let start_display_row =
|
||||
MultiBufferPoint::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
let mut end_display_row =
|
||||
MultiBufferPoint::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
if end_display_row != start_display_row {
|
||||
end_display_row.0 -= 1;
|
||||
}
|
||||
let color = match hunk_status(&hunk) {
|
||||
DiffHunkStatus::Added => theme.status().created,
|
||||
DiffHunkStatus::Modified => theme.status().modified,
|
||||
DiffHunkStatus::Removed => theme.status().deleted,
|
||||
};
|
||||
ColoredRange {
|
||||
start: start_display_row,
|
||||
end: end_display_row,
|
||||
color,
|
||||
}
|
||||
});
|
||||
|
||||
marker_quads.extend(
|
||||
scrollbar_layout
|
||||
@@ -5820,12 +5813,15 @@ impl Element for EditorElement {
|
||||
);
|
||||
let end_row = DisplayRow(end_row);
|
||||
|
||||
let buffer_rows = snapshot
|
||||
.buffer_rows(start_row)
|
||||
let row_infos = snapshot
|
||||
.row_infos(start_row)
|
||||
.take((start_row..end_row).len())
|
||||
.collect::<Vec<_>>();
|
||||
let is_row_soft_wrapped =
|
||||
|row| buffer_rows.get(row).copied().flatten().is_none();
|
||||
.collect::<Vec<RowInfo>>();
|
||||
let is_row_soft_wrapped = |row: usize| {
|
||||
row_infos
|
||||
.get(row)
|
||||
.map_or(true, |info| info.buffer_row.is_none())
|
||||
};
|
||||
|
||||
let start_anchor = if start_row == Default::default() {
|
||||
Anchor::min()
|
||||
@@ -5842,9 +5838,21 @@ impl Element for EditorElement {
|
||||
)
|
||||
};
|
||||
|
||||
let highlighted_rows = self
|
||||
let mut highlighted_rows = self
|
||||
.editor
|
||||
.update(cx, |editor, cx| editor.highlighted_display_rows(cx));
|
||||
|
||||
for (ix, row_info) in row_infos.iter().enumerate() {
|
||||
let color = match row_info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => style.status.created_background,
|
||||
Some(DiffHunkStatus::Removed) => style.status.deleted_background,
|
||||
_ => continue,
|
||||
};
|
||||
highlighted_rows
|
||||
.entry(start_row + DisplayRow(ix as u32))
|
||||
.or_insert(color);
|
||||
}
|
||||
|
||||
let highlighted_ranges = self.editor.read(cx).background_highlights_in_range(
|
||||
start_anchor..end_anchor,
|
||||
&snapshot.display_snapshot,
|
||||
@@ -5884,7 +5892,7 @@ impl Element for EditorElement {
|
||||
|
||||
let line_numbers = self.layout_line_numbers(
|
||||
start_row..end_row,
|
||||
buffer_rows.iter().copied(),
|
||||
&row_infos,
|
||||
&active_rows,
|
||||
newest_selection_head,
|
||||
&snapshot,
|
||||
@@ -5894,14 +5902,14 @@ impl Element for EditorElement {
|
||||
let mut crease_toggles = cx.with_element_namespace("crease_toggles", |cx| {
|
||||
self.layout_crease_toggles(
|
||||
start_row..end_row,
|
||||
buffer_rows.iter().copied(),
|
||||
&row_infos,
|
||||
&active_rows,
|
||||
&snapshot,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let crease_trailers = cx.with_element_namespace("crease_trailers", |cx| {
|
||||
self.layout_crease_trailers(buffer_rows.iter().copied(), &snapshot, cx)
|
||||
self.layout_crease_trailers(row_infos.iter().copied(), &snapshot, cx)
|
||||
});
|
||||
|
||||
let display_hunks = self.layout_gutter_git_hunks(
|
||||
@@ -6042,11 +6050,12 @@ impl Element for EditorElement {
|
||||
let display_row = newest_selection_head.row();
|
||||
if (start_row..end_row).contains(&display_row) {
|
||||
let line_ix = display_row.minus(start_row) as usize;
|
||||
let row_info = &row_infos[line_ix];
|
||||
let line_layout = &line_layouts[line_ix];
|
||||
let crease_trailer_layout = crease_trailers[line_ix].as_ref();
|
||||
inline_blame = self.layout_inline_blame(
|
||||
display_row,
|
||||
&snapshot.display_snapshot,
|
||||
row_info,
|
||||
line_layout,
|
||||
crease_trailer_layout,
|
||||
em_width,
|
||||
@@ -6059,7 +6068,7 @@ impl Element for EditorElement {
|
||||
}
|
||||
|
||||
let blamed_display_rows = self.layout_blame_entries(
|
||||
buffer_rows.into_iter(),
|
||||
&row_infos,
|
||||
em_width,
|
||||
scroll_position,
|
||||
line_height,
|
||||
@@ -6148,22 +6157,6 @@ impl Element for EditorElement {
|
||||
|
||||
let gutter_settings = EditorSettings::get_global(cx).gutter;
|
||||
|
||||
let expanded_add_hunks_by_rows = self.editor.update(cx, |editor, _| {
|
||||
editor
|
||||
.diff_map
|
||||
.hunks(false)
|
||||
.filter(|hunk| hunk.status == DiffHunkStatus::Added)
|
||||
.map(|expanded_hunk| {
|
||||
let start_row = expanded_hunk
|
||||
.hunk_range
|
||||
.start
|
||||
.to_display_point(&snapshot)
|
||||
.row();
|
||||
(start_row, expanded_hunk.clone())
|
||||
})
|
||||
.collect::<HashMap<_, _>>()
|
||||
});
|
||||
|
||||
let rows_with_hunk_bounds = display_hunks
|
||||
.iter()
|
||||
.filter_map(|(hunk, hitbox)| Some((hunk, hitbox.as_ref()?.bounds)))
|
||||
@@ -6206,38 +6199,32 @@ impl Element for EditorElement {
|
||||
if show_code_actions {
|
||||
let newest_selection_point =
|
||||
newest_selection_head.to_point(&snapshot.display_snapshot);
|
||||
let newest_selection_display_row =
|
||||
newest_selection_point.to_display_point(&snapshot).row();
|
||||
if !expanded_add_hunks_by_rows
|
||||
.contains_key(&newest_selection_display_row)
|
||||
if !snapshot
|
||||
.is_line_folded(MultiBufferRow(newest_selection_point.row))
|
||||
{
|
||||
if !snapshot
|
||||
.is_line_folded(MultiBufferRow(newest_selection_point.row))
|
||||
{
|
||||
let buffer = snapshot.buffer_snapshot.buffer_line_for_row(
|
||||
MultiBufferRow(newest_selection_point.row),
|
||||
);
|
||||
if let Some((buffer, range)) = buffer {
|
||||
let buffer_id = buffer.remote_id();
|
||||
let row = range.start.row;
|
||||
let has_test_indicator = self
|
||||
.editor
|
||||
.read(cx)
|
||||
.tasks
|
||||
.contains_key(&(buffer_id, row));
|
||||
let buffer = snapshot.buffer_snapshot.buffer_line_for_row(
|
||||
MultiBufferRow(newest_selection_point.row),
|
||||
);
|
||||
if let Some((buffer, range)) = buffer {
|
||||
let buffer_id = buffer.remote_id();
|
||||
let row = range.start.row;
|
||||
let has_test_indicator = self
|
||||
.editor
|
||||
.read(cx)
|
||||
.tasks
|
||||
.contains_key(&(buffer_id, row));
|
||||
|
||||
if !has_test_indicator {
|
||||
code_actions_indicator = self
|
||||
.layout_code_actions_indicator(
|
||||
line_height,
|
||||
newest_selection_head,
|
||||
scroll_pixel_position,
|
||||
&gutter_dimensions,
|
||||
&gutter_hitbox,
|
||||
&rows_with_hunk_bounds,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
if !has_test_indicator {
|
||||
code_actions_indicator = self
|
||||
.layout_code_actions_indicator(
|
||||
line_height,
|
||||
newest_selection_head,
|
||||
scroll_pixel_position,
|
||||
&gutter_dimensions,
|
||||
&gutter_hitbox,
|
||||
&rows_with_hunk_bounds,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7209,7 +7196,12 @@ mod tests {
|
||||
.update_window(*window, |_, cx| {
|
||||
element.layout_line_numbers(
|
||||
DisplayRow(0)..DisplayRow(6),
|
||||
(0..6).map(MultiBufferRow).map(Some),
|
||||
&(0..6)
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
&Default::default(),
|
||||
Some(DisplayPoint::new(DisplayRow(0), 0)),
|
||||
&snapshot,
|
||||
|
||||
@@ -9,12 +9,13 @@ use git::{
|
||||
use gpui::{Model, ModelContext, Subscription, Task};
|
||||
use http_client::HttpClient;
|
||||
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use project::{Project, ProjectItem};
|
||||
use smallvec::SmallVec;
|
||||
use sum_tree::SumTree;
|
||||
use url::Url;
|
||||
|
||||
use crate::RowInfo;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GitBlameEntry {
|
||||
pub rows: u32,
|
||||
@@ -194,15 +195,15 @@ impl GitBlame {
|
||||
|
||||
pub fn blame_for_rows<'a>(
|
||||
&'a mut self,
|
||||
rows: impl 'a + IntoIterator<Item = Option<MultiBufferRow>>,
|
||||
rows: &'a [RowInfo],
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> impl 'a + Iterator<Item = Option<BlameEntry>> {
|
||||
self.sync(cx);
|
||||
|
||||
let mut cursor = self.entries.cursor::<u32>(&());
|
||||
rows.into_iter().map(move |row| {
|
||||
let row = row?;
|
||||
cursor.seek_forward(&row.0, Bias::Right, &());
|
||||
rows.into_iter().map(move |info| {
|
||||
let row = info.buffer_row?;
|
||||
cursor.seek_forward(&row, Bias::Right, &());
|
||||
cursor.item()?.blame.clone()
|
||||
})
|
||||
}
|
||||
@@ -563,15 +564,38 @@ mod tests {
|
||||
use unindent::Unindent as _;
|
||||
use util::RandomCharIter;
|
||||
|
||||
macro_rules! assert_blame_rows {
|
||||
($blame:expr, $rows:expr, $expected:expr, $cx:expr) => {
|
||||
assert_eq!(
|
||||
$blame
|
||||
.blame_for_rows($rows.map(MultiBufferRow).map(Some), $cx)
|
||||
.collect::<Vec<_>>(),
|
||||
$expected
|
||||
);
|
||||
};
|
||||
// macro_rules! assert_blame_rows {
|
||||
// ($blame:expr, $rows:expr, $expected:expr, $cx:expr) => {
|
||||
// assert_eq!(
|
||||
// $blame
|
||||
// .blame_for_rows($rows.map(MultiBufferRow).map(Some), $cx)
|
||||
// .collect::<Vec<_>>(),
|
||||
// $expected
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
|
||||
#[track_caller]
|
||||
fn assert_blame_rows(
|
||||
blame: &mut GitBlame,
|
||||
rows: Range<u32>,
|
||||
expected: Vec<Option<BlameEntry>>,
|
||||
cx: &mut ModelContext<GitBlame>,
|
||||
) {
|
||||
assert_eq!(
|
||||
blame
|
||||
.blame_for_rows(
|
||||
&rows
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut gpui::TestAppContext) {
|
||||
@@ -634,7 +658,15 @@ mod tests {
|
||||
blame.update(cx, |blame, cx| {
|
||||
assert_eq!(
|
||||
blame
|
||||
.blame_for_rows((0..1).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(0..1)
|
||||
.map(|row| RowInfo {
|
||||
buffer_row: Some(row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![None]
|
||||
);
|
||||
@@ -698,7 +730,15 @@ mod tests {
|
||||
// All lines
|
||||
assert_eq!(
|
||||
blame
|
||||
.blame_for_rows((0..8).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(0..8)
|
||||
.map(|buffer_row| RowInfo {
|
||||
buffer_row: Some(buffer_row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
Some(blame_entry("1b1b1b", 0..1)),
|
||||
@@ -714,7 +754,15 @@ mod tests {
|
||||
// Subset of lines
|
||||
assert_eq!(
|
||||
blame
|
||||
.blame_for_rows((1..4).map(MultiBufferRow).map(Some), cx)
|
||||
.blame_for_rows(
|
||||
&(1..4)
|
||||
.map(|buffer_row| RowInfo {
|
||||
buffer_row: Some(buffer_row),
|
||||
..Default::default()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cx
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
Some(blame_entry("0d0d0d", 1..2)),
|
||||
@@ -725,7 +773,17 @@ mod tests {
|
||||
// Subset of lines, with some not displayed
|
||||
assert_eq!(
|
||||
blame
|
||||
.blame_for_rows(vec![Some(MultiBufferRow(1)), None, None], cx)
|
||||
.blame_for_rows(
|
||||
&[
|
||||
RowInfo {
|
||||
buffer_row: Some(1),
|
||||
..Default::default()
|
||||
},
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
],
|
||||
cx
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(blame_entry("0d0d0d", 1..2)), None, None]
|
||||
);
|
||||
@@ -777,16 +835,16 @@ mod tests {
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
// Sanity check before edits: make sure that we get the same blame entry for all
|
||||
// lines.
|
||||
assert_blame_rows!(
|
||||
assert_blame_rows(
|
||||
blame,
|
||||
(0..4),
|
||||
0..4,
|
||||
vec![
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
],
|
||||
cx
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -795,11 +853,11 @@ mod tests {
|
||||
buffer.edit([(Point::new(0, 0)..Point::new(0, 0), "X")], None, cx);
|
||||
});
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(
|
||||
assert_blame_rows(
|
||||
blame,
|
||||
(0..2),
|
||||
0..2,
|
||||
vec![None, Some(blame_entry("1b1b1b", 0..4))],
|
||||
cx
|
||||
cx,
|
||||
);
|
||||
});
|
||||
// Modify a single line, in the middle of the line
|
||||
@@ -807,21 +865,21 @@ mod tests {
|
||||
buffer.edit([(Point::new(1, 2)..Point::new(1, 2), "X")], None, cx);
|
||||
});
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(
|
||||
assert_blame_rows(
|
||||
blame,
|
||||
(1..4),
|
||||
1..4,
|
||||
vec![
|
||||
None,
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
Some(blame_entry("1b1b1b", 0..4))
|
||||
Some(blame_entry("1b1b1b", 0..4)),
|
||||
],
|
||||
cx
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
// Before we insert a newline at the end, sanity check:
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(blame, (3..4), vec![Some(blame_entry("1b1b1b", 0..4))], cx);
|
||||
assert_blame_rows(blame, 3..4, vec![Some(blame_entry("1b1b1b", 0..4))], cx);
|
||||
});
|
||||
// Insert a newline at the end
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
@@ -829,17 +887,17 @@ mod tests {
|
||||
});
|
||||
// Only the new line is marked as edited:
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(
|
||||
assert_blame_rows(
|
||||
blame,
|
||||
(3..5),
|
||||
3..5,
|
||||
vec![Some(blame_entry("1b1b1b", 0..4)), None],
|
||||
cx
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
// Before we insert a newline at the start, sanity check:
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(blame, (2..3), vec![Some(blame_entry("1b1b1b", 0..4)),], cx);
|
||||
assert_blame_rows(blame, 2..3, vec![Some(blame_entry("1b1b1b", 0..4))], cx);
|
||||
});
|
||||
|
||||
// Usage example
|
||||
@@ -849,11 +907,11 @@ mod tests {
|
||||
});
|
||||
// Only the new line is marked as edited:
|
||||
git_blame.update(cx, |blame, cx| {
|
||||
assert_blame_rows!(
|
||||
assert_blame_rows(
|
||||
blame,
|
||||
(2..4),
|
||||
vec![None, Some(blame_entry("1b1b1b", 0..4)),],
|
||||
cx
|
||||
2..4,
|
||||
vec![None, Some(blame_entry("1b1b1b", 0..4))],
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ impl ProjectDiffEditor {
|
||||
let editor = cx.new_view(|cx| {
|
||||
let mut diff_display_editor =
|
||||
Editor::for_multibuffer(excerpts.clone(), Some(project.clone()), true, cx);
|
||||
diff_display_editor.set_expand_all_diff_hunks();
|
||||
diff_display_editor.set_expand_all_diff_hunks(cx);
|
||||
diff_display_editor
|
||||
});
|
||||
|
||||
@@ -311,9 +311,11 @@ impl ProjectDiffEditor {
|
||||
.update(&mut cx, |project_diff_editor, cx| {
|
||||
project_diff_editor.update_excerpts(id, new_changes, new_entry_order, cx);
|
||||
project_diff_editor.editor.update(cx, |editor, cx| {
|
||||
for change_set in change_sets {
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
}
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
for change_set in change_sets {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
@@ -1193,9 +1195,9 @@ mod tests {
|
||||
cx,
|
||||
)
|
||||
});
|
||||
file_a_editor
|
||||
.diff_map
|
||||
.add_change_set(change_set.clone(), cx);
|
||||
file_a_editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map.add_change_set(change_set.clone(), cx)
|
||||
});
|
||||
project.update(cx, |project, cx| {
|
||||
project.buffer_store().update(cx, |buffer_store, cx| {
|
||||
buffer_store.set_change_set(
|
||||
|
||||
@@ -6,11 +6,10 @@ use gpui::{
|
||||
use language::{Buffer, BufferId, Point};
|
||||
use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, ExcerptRange, MultiBuffer, MultiBufferDiffHunk, MultiBufferRow,
|
||||
MultiBufferSnapshot, ToOffset, ToPoint,
|
||||
MultiBufferSnapshot, ToPoint,
|
||||
};
|
||||
use project::buffer_store::BufferChangeSet;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
use sum_tree::TreeMap;
|
||||
use text::OffsetRangeExt;
|
||||
use ui::{
|
||||
prelude::*, ActiveTheme, ContextMenu, IconButtonShape, InteractiveElement, IntoElement,
|
||||
@@ -20,10 +19,10 @@ use util::RangeExt;
|
||||
use workspace::Item;
|
||||
|
||||
use crate::{
|
||||
editor_settings::CurrentLineHighlight, hunk_status, hunks_for_selections, ApplyAllDiffHunks,
|
||||
ApplyDiffHunk, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, DiffRowHighlight,
|
||||
DisplayRow, DisplaySnapshot, Editor, EditorElement, ExpandAllHunkDiffs, GoToHunk, GoToPrevHunk,
|
||||
RevertFile, RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff,
|
||||
editor_settings::CurrentLineHighlight, hunk_status, ApplyAllDiffHunks, ApplyDiffHunk,
|
||||
BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, DiffRowHighlight, DisplayRow,
|
||||
DisplaySnapshot, Editor, EditorElement, GoToHunk, GoToPrevHunk, RevertFile,
|
||||
RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -37,7 +36,6 @@ pub(super) struct HoveredHunk {
|
||||
pub(super) struct DiffMap {
|
||||
pub(crate) hunks: Vec<ExpandedHunk>,
|
||||
pub(crate) diff_bases: HashMap<BufferId, DiffBaseState>,
|
||||
pub(crate) snapshot: DiffMapSnapshot,
|
||||
hunk_update_tasks: HashMap<Option<BufferId>, Task<()>>,
|
||||
expand_all: bool,
|
||||
}
|
||||
@@ -51,9 +49,6 @@ pub(super) struct ExpandedHunk {
|
||||
pub folded: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct DiffMapSnapshot(TreeMap<BufferId, git::diff::BufferDiff>);
|
||||
|
||||
pub(crate) struct DiffBaseState {
|
||||
pub(crate) change_set: Model<BufferChangeSet>,
|
||||
pub(crate) last_version: Option<usize>,
|
||||
@@ -74,133 +69,7 @@ pub enum DisplayDiffHunk {
|
||||
},
|
||||
}
|
||||
|
||||
impl DiffMap {
|
||||
pub fn snapshot(&self) -> DiffMapSnapshot {
|
||||
self.snapshot.clone()
|
||||
}
|
||||
|
||||
pub fn add_change_set(
|
||||
&mut self,
|
||||
change_set: Model<BufferChangeSet>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let buffer_id = change_set.read(cx).buffer_id;
|
||||
self.snapshot
|
||||
.0
|
||||
.insert(buffer_id, change_set.read(cx).diff_to_buffer.clone());
|
||||
self.diff_bases.insert(
|
||||
buffer_id,
|
||||
DiffBaseState {
|
||||
last_version: None,
|
||||
_subscription: cx.observe(&change_set, move |editor, change_set, cx| {
|
||||
editor
|
||||
.diff_map
|
||||
.snapshot
|
||||
.0
|
||||
.insert(buffer_id, change_set.read(cx).diff_to_buffer.clone());
|
||||
Editor::sync_expanded_diff_hunks(&mut editor.diff_map, buffer_id, cx);
|
||||
}),
|
||||
change_set,
|
||||
},
|
||||
);
|
||||
Editor::sync_expanded_diff_hunks(self, buffer_id, cx);
|
||||
}
|
||||
|
||||
pub fn hunks(&self, include_folded: bool) -> impl Iterator<Item = &ExpandedHunk> {
|
||||
self.hunks
|
||||
.iter()
|
||||
.filter(move |hunk| include_folded || !hunk.folded)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffMapSnapshot {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.values().all(|diff| diff.is_empty())
|
||||
}
|
||||
|
||||
pub fn diff_hunks<'a>(
|
||||
&'a self,
|
||||
buffer_snapshot: &'a MultiBufferSnapshot,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
self.diff_hunks_in_range(0..buffer_snapshot.len(), buffer_snapshot)
|
||||
}
|
||||
|
||||
pub fn diff_hunks_in_range<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
buffer_snapshot: &'a MultiBufferSnapshot,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
let range = range.start.to_offset(buffer_snapshot)..range.end.to_offset(buffer_snapshot);
|
||||
buffer_snapshot
|
||||
.excerpts_for_range(range.clone())
|
||||
.filter_map(move |excerpt| {
|
||||
let buffer = excerpt.buffer();
|
||||
let buffer_id = buffer.remote_id();
|
||||
let diff = self.0.get(&buffer_id)?;
|
||||
let buffer_range = excerpt.map_range_to_buffer(range.clone());
|
||||
let buffer_range =
|
||||
buffer.anchor_before(buffer_range.start)..buffer.anchor_after(buffer_range.end);
|
||||
Some(
|
||||
diff.hunks_intersecting_range(buffer_range, excerpt.buffer())
|
||||
.map(move |hunk| {
|
||||
let start =
|
||||
excerpt.map_point_from_buffer(Point::new(hunk.row_range.start, 0));
|
||||
let end =
|
||||
excerpt.map_point_from_buffer(Point::new(hunk.row_range.end, 0));
|
||||
MultiBufferDiffHunk {
|
||||
row_range: MultiBufferRow(start.row)..MultiBufferRow(end.row),
|
||||
buffer_id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn diff_hunks_in_range_rev<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
buffer_snapshot: &'a MultiBufferSnapshot,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + 'a {
|
||||
let range = range.start.to_offset(buffer_snapshot)..range.end.to_offset(buffer_snapshot);
|
||||
buffer_snapshot
|
||||
.excerpts_for_range_rev(range.clone())
|
||||
.filter_map(move |excerpt| {
|
||||
let buffer = excerpt.buffer();
|
||||
let buffer_id = buffer.remote_id();
|
||||
let diff = self.0.get(&buffer_id)?;
|
||||
let buffer_range = excerpt.map_range_to_buffer(range.clone());
|
||||
let buffer_range =
|
||||
buffer.anchor_before(buffer_range.start)..buffer.anchor_after(buffer_range.end);
|
||||
Some(
|
||||
diff.hunks_intersecting_range_rev(buffer_range, excerpt.buffer())
|
||||
.map(move |hunk| {
|
||||
let start_row = excerpt
|
||||
.map_point_from_buffer(Point::new(hunk.row_range.start, 0))
|
||||
.row;
|
||||
let end_row = excerpt
|
||||
.map_point_from_buffer(Point::new(hunk.row_range.end, 0))
|
||||
.row;
|
||||
MultiBufferDiffHunk {
|
||||
row_range: MultiBufferRow(start_row)..MultiBufferRow(end_row),
|
||||
buffer_id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn set_expand_all_diff_hunks(&mut self) {
|
||||
self.diff_map.expand_all = true;
|
||||
}
|
||||
|
||||
pub(super) fn toggle_hovered_hunk(
|
||||
&mut self,
|
||||
hovered_hunk: &HoveredHunk,
|
||||
@@ -213,47 +82,6 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_hunk_diff(&mut self, _: &ToggleHunkDiff, cx: &mut ViewContext<Self>) {
|
||||
let snapshot = self.snapshot(cx);
|
||||
let selections = self.selections.all(cx);
|
||||
self.toggle_hunks_expanded(hunks_for_selections(&snapshot, &selections), cx);
|
||||
}
|
||||
|
||||
pub fn expand_all_hunk_diffs(&mut self, _: &ExpandAllHunkDiffs, cx: &mut ViewContext<Self>) {
|
||||
let snapshot = self.snapshot(cx);
|
||||
let display_rows_with_expanded_hunks = self
|
||||
.diff_map
|
||||
.hunks(false)
|
||||
.map(|hunk| &hunk.hunk_range)
|
||||
.map(|anchor_range| {
|
||||
(
|
||||
anchor_range
|
||||
.start
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row(),
|
||||
anchor_range
|
||||
.end
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row(),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
let hunks = self
|
||||
.diff_map
|
||||
.snapshot
|
||||
.diff_hunks(&snapshot.display_snapshot.buffer_snapshot)
|
||||
.filter(|hunk| {
|
||||
let hunk_display_row_range = Point::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
..Point::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot);
|
||||
let row_range_end =
|
||||
display_rows_with_expanded_hunks.get(&hunk_display_row_range.start.row());
|
||||
row_range_end.is_none() || row_range_end != Some(&hunk_display_row_range.end.row())
|
||||
});
|
||||
self.toggle_hunks_expanded(hunks.collect(), cx);
|
||||
}
|
||||
|
||||
fn toggle_hunks_expanded(
|
||||
&mut self,
|
||||
hunks_to_toggle: Vec<MultiBufferDiffHunk>,
|
||||
@@ -497,7 +325,8 @@ impl Editor {
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let snapshot = self.snapshot(cx);
|
||||
let hunks = hunks_for_selections(&snapshot, &self.selections.all(cx));
|
||||
let ranges = self.selections.all(cx).into_iter().map(|s| s.range());
|
||||
let hunks = snapshot.hunks_for_ranges(ranges);
|
||||
let mut ranges_by_buffer = HashMap::default();
|
||||
self.transact(cx, |editor, cx| {
|
||||
for hunk in hunks {
|
||||
@@ -521,10 +350,8 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn has_multiple_hunks(&self, cx: &AppContext) -> bool {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let mut hunks = self.diff_map.snapshot.diff_hunks(&snapshot);
|
||||
hunks.nth(1).is_some()
|
||||
fn has_multiple_hunks(&self, cx: &mut WindowContext) -> bool {
|
||||
self.display_map.read(cx).has_multiple_hunks(cx)
|
||||
}
|
||||
|
||||
fn hunk_header_block(
|
||||
@@ -865,23 +692,15 @@ impl Editor {
|
||||
}
|
||||
|
||||
pub(super) fn clear_expanded_diff_hunks(&mut self, cx: &mut ViewContext<'_, Editor>) -> bool {
|
||||
if self.diff_map.expand_all {
|
||||
return false;
|
||||
}
|
||||
self.diff_map.hunk_update_tasks.clear();
|
||||
self.clear_row_highlights::<DiffRowHighlight>();
|
||||
let to_remove = self
|
||||
.diff_map
|
||||
.hunks
|
||||
.drain(..)
|
||||
.flat_map(|expanded_hunk| expanded_hunk.blocks.into_iter())
|
||||
.collect::<HashSet<_>>();
|
||||
if to_remove.is_empty() {
|
||||
false
|
||||
} else {
|
||||
self.remove_blocks(to_remove, None, cx);
|
||||
true
|
||||
}
|
||||
self.display_map.update(cx, |diff_map, cx| {
|
||||
let ranges = vec![Anchor::min()..Anchor::max()];
|
||||
if diff_map.has_expanded_diff_hunks_in_ranges(&ranges, cx) {
|
||||
diff_map.collapse_diff_hunks(ranges, cx);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn sync_expanded_diff_hunks(
|
||||
@@ -909,8 +728,7 @@ impl Editor {
|
||||
.update(&mut cx, |editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
let mut recalculated_hunks = snapshot
|
||||
.diff_map
|
||||
.diff_hunks(&snapshot.buffer_snapshot)
|
||||
.diff_hunks()
|
||||
.filter(|hunk| hunk.buffer_id == buffer_id)
|
||||
.fuse()
|
||||
.peekable();
|
||||
@@ -1418,7 +1236,9 @@ mod tests {
|
||||
cx,
|
||||
)
|
||||
});
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1470,8 +1290,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range(Point::zero()..Point::new(12, 0), &snapshot.buffer_snapshot)
|
||||
.diff_hunks_in_range(Point::zero()..Point::new(12, 0))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.row_range))
|
||||
.collect::<Vec<_>>(),
|
||||
&expected,
|
||||
@@ -1479,11 +1298,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range_rev(
|
||||
Point::zero()..Point::new(12, 0),
|
||||
&snapshot.buffer_snapshot
|
||||
)
|
||||
.diff_hunks_in_range_rev(Point::zero()..Point::new(12, 0))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.row_range))
|
||||
.collect::<Vec<_>>(),
|
||||
expected
|
||||
|
||||
@@ -61,7 +61,7 @@ impl ProposedChangesEditor {
|
||||
let mut this = Self {
|
||||
editor: cx.new_view(|cx| {
|
||||
let mut editor = Editor::for_multibuffer(multibuffer.clone(), project, true, cx);
|
||||
editor.set_expand_all_diff_hunks();
|
||||
editor.set_expand_all_diff_hunks(cx);
|
||||
editor.set_completion_provider(None);
|
||||
editor.clear_code_action_providers();
|
||||
editor.set_semantics_provider(
|
||||
@@ -223,9 +223,11 @@ impl ProposedChangesEditor {
|
||||
self.buffer_entries = buffer_entries;
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.change_selections(None, cx, |selections| selections.refresh());
|
||||
for change_set in new_change_sets {
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
}
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
for change_set in new_change_sets {
|
||||
display_map.add_change_set(change_set, cx)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DiffRowHighlight, DisplayPoint,
|
||||
Editor, MultiBuffer, RowExt,
|
||||
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
|
||||
RowExt,
|
||||
};
|
||||
use collections::BTreeMap;
|
||||
use futures::Future;
|
||||
@@ -11,11 +11,12 @@ use gpui::{
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::{Buffer, BufferSnapshot, LanguageRegistry};
|
||||
use multi_buffer::{ExcerptRange, ToPoint};
|
||||
use multi_buffer::ExcerptRange;
|
||||
use parking_lot::RwLock;
|
||||
use project::{FakeFs, Project};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
path::Path,
|
||||
sync::{
|
||||
@@ -23,6 +24,7 @@ use std::{
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use text::Bias;
|
||||
use util::{
|
||||
assert_set_eq,
|
||||
test::{generate_marked_text, marked_text_ranges},
|
||||
@@ -332,83 +334,51 @@ impl EditorTestContext {
|
||||
///
|
||||
/// Diff hunks are indicated by lines starting with `+` and `-`.
|
||||
#[track_caller]
|
||||
pub fn assert_state_with_diff(&mut self, expected_diff: String) {
|
||||
let has_diff_markers = expected_diff
|
||||
.lines()
|
||||
.any(|line| line.starts_with("+") || line.starts_with("-"));
|
||||
let expected_diff_text = expected_diff
|
||||
.split('\n')
|
||||
.map(|line| {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.is_empty() {
|
||||
String::new()
|
||||
} else if has_diff_markers {
|
||||
line.to_string()
|
||||
} else {
|
||||
format!(" {line}")
|
||||
}
|
||||
})
|
||||
.join("\n");
|
||||
pub fn assert_state_with_diff(&mut self, expected_diff_text: String) {
|
||||
let (snapshot, selections) = self
|
||||
.editor
|
||||
.update(&mut self.cx, |editor, cx| editor.selections.all_display(cx));
|
||||
|
||||
let actual_selections = self.editor_selections();
|
||||
let actual_marked_text =
|
||||
generate_marked_text(&self.buffer_text(), &actual_selections, true);
|
||||
let diff_snapshot = snapshot.diff_snapshot();
|
||||
let diff_offsets = selections
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
let start = snapshot.display_point_to_diff_offset(s.start, Bias::Left).0;
|
||||
let end = snapshot.display_point_to_diff_offset(s.end, Bias::Left).0;
|
||||
cmp::min(start, end)..cmp::max(start, end)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let actual_marked_text = generate_marked_text(&diff_snapshot.text(), &diff_offsets, true);
|
||||
|
||||
// Read the actual diff from the editor's row highlights and block
|
||||
// decorations.
|
||||
let actual_diff = self.editor.update(&mut self.cx, |editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
let insertions = editor
|
||||
.highlighted_rows::<DiffRowHighlight>()
|
||||
.map(|(range, _)| {
|
||||
let start = range.start.to_point(&snapshot.buffer_snapshot);
|
||||
let end = range.end.to_point(&snapshot.buffer_snapshot);
|
||||
start.row..end.row
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let deletions = editor
|
||||
.diff_map
|
||||
.hunks
|
||||
.iter()
|
||||
.filter_map(|hunk| {
|
||||
if hunk.blocks.is_empty() {
|
||||
return None;
|
||||
let line_infos = diff_snapshot.row_infos(0).collect::<Vec<_>>();
|
||||
let has_diff = line_infos.iter().any(|info| info.diff_status.is_some());
|
||||
|
||||
let actual_diff = actual_marked_text
|
||||
.split('\n')
|
||||
.zip(line_infos)
|
||||
.map(|(line, info)| {
|
||||
let mut marker = match info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => "+ ",
|
||||
Some(DiffHunkStatus::Removed) => "- ",
|
||||
Some(DiffHunkStatus::Modified) => unreachable!(),
|
||||
None => {
|
||||
if has_diff {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
let row = hunk
|
||||
.hunk_range
|
||||
.start
|
||||
.to_point(&snapshot.buffer_snapshot)
|
||||
.row;
|
||||
let (_, buffer, _) = editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.excerpt_containing(hunk.hunk_range.start, cx)
|
||||
.expect("no excerpt for expanded buffer's hunk start");
|
||||
let buffer_id = buffer.read(cx).remote_id();
|
||||
let change_set = &editor
|
||||
.diff_map
|
||||
.diff_bases
|
||||
.get(&buffer_id)
|
||||
.expect("should have a diff base for expanded hunk")
|
||||
.change_set;
|
||||
let deleted_text = change_set
|
||||
.read(cx)
|
||||
.base_text
|
||||
.as_ref()
|
||||
.expect("no base text for expanded hunk")
|
||||
.read(cx)
|
||||
.as_rope()
|
||||
.slice(hunk.diff_base_byte_range.clone())
|
||||
.to_string();
|
||||
if let DiffHunkStatus::Modified | DiffHunkStatus::Removed = hunk.status {
|
||||
Some((row, deleted_text))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
format_diff(actual_marked_text, deletions, insertions)
|
||||
});
|
||||
};
|
||||
if line.is_empty() {
|
||||
marker = marker.trim();
|
||||
}
|
||||
format!("{marker}{line}")
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
pretty_assertions::assert_eq!(actual_diff, expected_diff_text, "unexpected diff state");
|
||||
}
|
||||
@@ -503,46 +473,6 @@ impl EditorTestContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn format_diff(
|
||||
text: String,
|
||||
actual_deletions: Vec<(u32, String)>,
|
||||
actual_insertions: Vec<Range<u32>>,
|
||||
) -> String {
|
||||
let mut diff = String::new();
|
||||
for (row, line) in text.split('\n').enumerate() {
|
||||
let row = row as u32;
|
||||
if row > 0 {
|
||||
diff.push('\n');
|
||||
}
|
||||
if let Some(text) = actual_deletions
|
||||
.iter()
|
||||
.find_map(|(deletion_row, deleted_text)| {
|
||||
if *deletion_row == row {
|
||||
Some(deleted_text)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
for line in text.lines() {
|
||||
diff.push('-');
|
||||
if !line.is_empty() {
|
||||
diff.push(' ');
|
||||
diff.push_str(line);
|
||||
}
|
||||
diff.push('\n');
|
||||
}
|
||||
}
|
||||
let marker = if actual_insertions.iter().any(|range| range.contains(&row)) {
|
||||
"+ "
|
||||
} else {
|
||||
" "
|
||||
};
|
||||
diff.push_str(format!("{marker}{line}").trim_end());
|
||||
}
|
||||
diff
|
||||
}
|
||||
|
||||
impl Deref for EditorTestContext {
|
||||
type Target = gpui::VisualTestContext;
|
||||
|
||||
|
||||
@@ -27,11 +27,13 @@ collections.workspace = true
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
futures.workspace = true
|
||||
git.workspace = true
|
||||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
project.workspace = true
|
||||
rand.workspace = true
|
||||
settings.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
2563
crates/multi_buffer/src/diff_map.rs
Normal file
2563
crates/multi_buffer/src/diff_map.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
||||
mod anchor;
|
||||
mod diff_map;
|
||||
|
||||
pub use anchor::{Anchor, AnchorRangeExt, Offset};
|
||||
use anyhow::{anyhow, Result};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeMap, Bound, HashMap, HashSet};
|
||||
pub use diff_map::*;
|
||||
use futures::{channel::mpsc, SinkExt};
|
||||
use gpui::{AppContext, EntityId, EventEmitter, Model, ModelContext, Task};
|
||||
use itertools::Itertools;
|
||||
@@ -69,6 +71,7 @@ pub struct MultiBuffer {
|
||||
history: History,
|
||||
title: Option<String>,
|
||||
capability: Capability,
|
||||
diff_map: Model<DiffMap>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -179,6 +182,7 @@ struct BufferState {
|
||||
pub struct MultiBufferSnapshot {
|
||||
singleton: bool,
|
||||
excerpts: SumTree<Excerpt>,
|
||||
// diff_map_snapshot: DiffMapSnapshot,
|
||||
excerpt_ids: SumTree<ExcerptIdMapping>,
|
||||
trailing_excerpt_update_count: usize,
|
||||
non_text_state_update_count: usize,
|
||||
@@ -1547,6 +1551,36 @@ impl MultiBuffer {
|
||||
excerpts
|
||||
}
|
||||
|
||||
pub fn ranges_for_buffer(
|
||||
&self,
|
||||
buffer_id: BufferId,
|
||||
cx: &AppContext,
|
||||
) -> Vec<(ExcerptId, Range<Point>, Range<text::Anchor>)> {
|
||||
let mut ranges = Vec::new();
|
||||
let snapshot = self.read(cx);
|
||||
for locator in self
|
||||
.buffers
|
||||
.borrow()
|
||||
.get(&buffer_id)
|
||||
.map(|state| &state.excerpts)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, Point)>(&());
|
||||
cursor.seek_forward(&Some(locator), Bias::Left, &());
|
||||
if let Some(excerpt) = cursor.item() {
|
||||
if excerpt.locator == *locator {
|
||||
ranges.push((
|
||||
excerpt.id,
|
||||
cursor.start().1..cursor.end(&()).1,
|
||||
excerpt.range.context.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
ranges
|
||||
}
|
||||
|
||||
pub fn excerpt_ranges_for_buffer(
|
||||
&self,
|
||||
buffer_id: BufferId,
|
||||
@@ -2529,6 +2563,39 @@ impl MultiBufferSnapshot {
|
||||
.eq(needle.bytes())
|
||||
}
|
||||
|
||||
pub fn range_to_buffer_ranges<T: ToOffset>(
|
||||
&self,
|
||||
range: Range<T>,
|
||||
) -> Vec<(BufferSnapshot, Range<usize>, ExcerptId)> {
|
||||
let start = range.start.to_offset(&self);
|
||||
let end = range.end.to_offset(&self);
|
||||
|
||||
let mut result = Vec::new();
|
||||
let mut cursor = self.excerpts.cursor::<usize>(&());
|
||||
cursor.seek(&start, Bias::Right, &());
|
||||
if cursor.item().is_none() {
|
||||
cursor.prev(&());
|
||||
}
|
||||
|
||||
while let Some(excerpt) = cursor.item() {
|
||||
if *cursor.start() > end {
|
||||
break;
|
||||
}
|
||||
|
||||
let mut end_before_newline = cursor.end(&());
|
||||
if excerpt.has_trailing_newline {
|
||||
end_before_newline -= 1;
|
||||
}
|
||||
let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
|
||||
let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
|
||||
let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
|
||||
result.push((excerpt.buffer.clone(), start..end, excerpt.id));
|
||||
cursor.next(&());
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn surrounding_word<T: ToOffset>(
|
||||
&self,
|
||||
start: T,
|
||||
@@ -4080,6 +4147,17 @@ impl MultiBufferSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
|
||||
let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
let locator = self.excerpt_locator_for_id(excerpt_id);
|
||||
if cursor.seek(&Some(locator), Bias::Left, &()) {
|
||||
if let Some(excerpt) = cursor.item() {
|
||||
return Some(excerpt.range.context.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
|
||||
let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
let locator = self.excerpt_locator_for_id(excerpt_id);
|
||||
@@ -4675,6 +4753,10 @@ impl<'a> MultiBufferExcerpt<'a> {
|
||||
self.excerpt_position
|
||||
}
|
||||
|
||||
pub fn end_point(&self) -> Point {
|
||||
self.excerpt_position + self.excerpt.text_summary.lines
|
||||
}
|
||||
|
||||
/// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
|
||||
pub fn map_offset_to_buffer(&self, offset: usize) -> usize {
|
||||
self.excerpt.buffer_start_offset()
|
||||
|
||||
@@ -989,6 +989,14 @@ impl TextSummary {
|
||||
column: self.last_line_len_utf16,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_newline(&mut self) {
|
||||
self.len += 1;
|
||||
self.len_utf16 += OffsetUtf16(self.len_utf16.0 + 1);
|
||||
self.last_line_chars = 0;
|
||||
self.last_line_len_utf16 = 0;
|
||||
self.lines += Point::new(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for TextSummary {
|
||||
|
||||
@@ -42,6 +42,7 @@ where
|
||||
self.0
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn compose(&self, new_edits_iter: impl IntoIterator<Item = Edit<T>>) -> Self {
|
||||
let mut old_edits_iter = self.0.iter().cloned().peekable();
|
||||
let mut new_edits_iter = new_edits_iter.into_iter().peekable();
|
||||
|
||||
Reference in New Issue
Block a user