Compare commits

...

53 Commits

Author SHA1 Message Date
Conrad Irwin
df81a91bf9 WIPWIPWIPWIPW 2024-12-17 15:33:38 -07:00
Conrad Irwin
7adcf903cc fix merge conflicts 2024-12-17 14:55:25 -07:00
Conrad Irwin
062b4a2dd8 Merge branch 'main' into new-diff-map 2024-12-17 14:46:59 -07:00
Conrad Irwin
2cca833d7b Add cmp 2024-12-17 12:50:36 -07:00
Conrad Irwin
0b3715ae44 Add DisplayAnchor 2024-12-17 12:25:44 -07:00
Conrad Irwin
2b68817ed8 Fix test_{addition,deletion,modification}_reverts 2024-12-16 23:11:16 -07:00
Conrad Irwin
d1239f6cdb fix test_edits_around_expanded_deletion_hunks 2024-12-16 22:35:09 -07:00
Conrad Irwin
d600c58d3c fix test toggle diff hunks (again) 2024-12-16 22:06:41 -07:00
Conrad Irwin
c160ce6a24 handle diff chunks with no trailing newline 2024-12-16 21:31:41 -07:00
Max Brunsfeld
9450de73b3 Remove more of the old DiffMap 2024-12-16 16:48:03 -08:00
Max Brunsfeld
5cc3bd1585 Fix collapsing of hunks when base text changes
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-16 16:34:33 -08:00
Max Brunsfeld
87d50ee54c Fix handling of modified empty lines in assert_state_with_diff helper 2024-12-16 16:32:27 -08:00
Max Brunsfeld
2f5ea92fe1 Fix bugs in DiffMap::sync
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-16 15:30:45 -08:00
Max Brunsfeld
2625719ca2 Put DiffMap before InlayMap in DisplayMap
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-16 14:58:43 -08:00
Conrad Irwin
88b4628c00 rewrite diff map to not depend on inlay map 2024-12-16 14:38:39 -07:00
Max Brunsfeld
241c7a6645 Extract logic around custom text highlights out of InlayChunks iterator
Co-Authored-By: Conrad <conrad@zed.dev>
Co-Authored-By: Agus <agus@zed.dev>
2024-12-16 11:56:25 -08:00
Max Brunsfeld
f6aa7df14f Make EditorTestContext::assert_state_with_diff use new DiffMap
Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Agus <agus@zed.dev>
2024-12-16 10:34:45 -08:00
Max Brunsfeld
472fee6b62 When buffer is edited, compute DiffMap edits using deltas 2024-12-15 20:30:18 -08:00
Max Brunsfeld
093c3d3652 Add failing unit test for editing inside of an insertion hunk 2024-12-13 17:49:15 -08:00
Max Brunsfeld
1f28437c82 Sync display map immediately when updating diff state 2024-12-13 17:32:39 -08:00
Max Brunsfeld
2266b3cb96 Perform the same range expansion in has_expanded_diff_hunks_in_ranges 2024-12-13 17:26:23 -08:00
Max Brunsfeld
4369890646 Move logic for defining edits outside of recompute_transforms 2024-12-13 17:17:57 -08:00
Max Brunsfeld
82fbe27c08 Fix some problems with expanding and collapsing diff hunks
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-13 16:42:07 -08:00
Conrad Irwin
41c5e45ca2 Fix bugs in DiffMap's handling of edits and diff updates 2024-12-13 12:54:08 -08:00
Max Brunsfeld
243d7c6d5a WIP - Failing diff map test for hunks staying expanded on diff updates 2024-12-12 17:58:10 -08:00
Max Brunsfeld
9025fb226a Update more editor rendering to use the new DiffMap 2024-12-12 17:33:04 -08:00
Max Brunsfeld
07eb573a2c Highlight background of expanded hunks
Co-authored-by: Michael <michael@zed.dev>
2024-12-12 16:51:50 -08:00
Max Brunsfeld
b552e32b18 Replace buffer rows iterators with row info iterators that also give git status
Co-authored-by: Michael <michael@zed.dev>
2024-12-12 16:40:56 -08:00
Max Brunsfeld
9b526a4d42 Start work on providing git statuses for each line of diff map
Co-authored-by: Michael <michael@zed.dev>
2024-12-12 15:50:27 -08:00
Max Brunsfeld
cc4ecacc04 Fix dropping of ChangeSet in DiffMap
Co-authored-by: Michael <michael@zed.dev>
2024-12-12 14:51:19 -08:00
Max Brunsfeld
dc814cb3af Start integrating the new DiffMap into the editor
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-12 14:26:58 -08:00
Max Brunsfeld
ad87dfe908 Get more editor tests passing
Correctly handle multiple edits to DiffMap

Co-authored-by: Conrad <conrad@zed.dev>
2024-12-12 12:52:29 -08:00
Max Brunsfeld
99edc9583c Fix DiffMap::buffer_rows to handle last empty line of buffer
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-12 11:55:37 -08:00
Max Brunsfeld
c015553b1f Get assertions about DiffMap::chunks passing
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-12 10:41:40 -08:00
Max Brunsfeld
e53d8bb8d2 wip 2024-12-12 09:59:37 -08:00
Conrad Irwin
6e724c1168 seek on DiffMapBufferRows 2024-12-11 23:43:29 -07:00
Conrad Irwin
a8a9177878 implement text_summary_for_range 2024-12-11 23:12:58 -07:00
Conrad Irwin
9dc5ebab85 better naming? 2024-12-11 22:13:28 -07:00
Conrad Irwin
2630dfdd23 implement clip_point 2024-12-11 22:04:12 -07:00
Conrad Irwin
20ec116932 Implement to_offset/to_point 2024-12-11 21:33:07 -07:00
Max Brunsfeld
dac0a07770 Merge branch 'main' into new-diff-map 2024-12-11 17:10:46 -08:00
Max Brunsfeld
61e42b986a Integrate DiffMap into the DisplayMap 2024-12-11 17:10:34 -08:00
Max Brunsfeld
a20715d663 Start implementing DiffMap::buffer_rows 2024-12-11 11:36:44 -08:00
Max Brunsfeld
33833533bd Get DiffMap::sync working for a basic test
Co-authored-by: Cole <cole@zed.dev>
2024-12-10 17:19:29 -08:00
Max Brunsfeld
023f9239b4 Restructure DiffMap::sync to prepare for handling buffer edits
Co-authored-by: Cole <cole@zed.dev>
2024-12-10 16:30:47 -08:00
Max Brunsfeld
946ae93f68 Compute diff map edits in a single pass through the old and new trees
Co-authored-by: Cole <cole@zed.dev>
2024-12-09 16:26:16 -08:00
Max Brunsfeld
011880c48c Start work on expanding and collapsing hunks by range
Co-authored-by: Cole <cole@zed.dev>
2024-12-09 11:55:13 -08:00
Max Brunsfeld
440b632b09 Start work on expanding and collapsing hunks 2024-12-05 17:58:53 -08:00
Max Brunsfeld
d0a8b0f8b1 Start work on returning edits from DiffMap::sync
Co-authored-by: Conrad <conrad@zed.dev>
2024-12-05 15:38:55 -08:00
Max Brunsfeld
09082d103e Implement DiffMap::set_all_hunks_expanded
Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
2024-12-05 14:37:16 -08:00
Max Brunsfeld
90c9ad4fd6 Get DiffMapChunks working to some degree
Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
2024-12-05 14:30:59 -08:00
Max Brunsfeld
67ffe999e5 Start work on DiffMapSnapshot::chunks
Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Cole <cole@zed.dev>
2024-12-05 12:39:04 -08:00
Max Brunsfeld
159c2239cc Stub in the structure of a DiffMap to go in the display map stack
Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Cole <cole@zed.dev>
2024-12-04 16:49:53 -08:00
22 changed files with 6509 additions and 1045 deletions

2
Cargo.lock generated
View File

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

View File

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

View File

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

View File

@@ -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 {:?}",

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -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![]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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