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