Compare commits
2 Commits
thread-edi
...
path-based
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
675c3441ee | ||
|
|
38773a9b0b |
@@ -134,7 +134,7 @@ pub use multi_buffer::{
|
|||||||
};
|
};
|
||||||
use multi_buffer::{
|
use multi_buffer::{
|
||||||
ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
|
ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
|
||||||
MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
|
MultiOrSingleBufferOffsetRange, PathKey, ToOffsetUtf16,
|
||||||
};
|
};
|
||||||
use project::{
|
use project::{
|
||||||
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
||||||
@@ -4659,18 +4659,18 @@ impl Editor {
|
|||||||
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
|
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
|
||||||
for (buffer_handle, transaction) in &entries {
|
for (buffer_handle, transaction) in &entries {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
ranges_to_highlight.extend(
|
multibuffer.set_excerpts_for_path(
|
||||||
multibuffer.push_excerpts_with_context_lines(
|
PathKey::for_buffer(&buffer, cx),
|
||||||
buffer_handle.clone(),
|
buffer_handle.clone(),
|
||||||
buffer
|
buffer
|
||||||
.edited_ranges_for_transaction::<usize>(transaction)
|
.edited_ranges_for_transaction::<Point>(transaction)
|
||||||
.collect(),
|
.collect(),
|
||||||
DEFAULT_MULTIBUFFER_CONTEXT,
|
DEFAULT_MULTIBUFFER_CONTEXT,
|
||||||
cx,
|
cx,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
|
multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
|
||||||
|
ranges_to_highlight.extend(multibuffer.primary_excerpt_ranges(cx));
|
||||||
multibuffer
|
multibuffer
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -12328,20 +12328,20 @@ impl Editor {
|
|||||||
// If there are multiple definitions, open them in a multibuffer
|
// If there are multiple definitions, open them in a multibuffer
|
||||||
locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
|
locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
|
||||||
let mut locations = locations.into_iter().peekable();
|
let mut locations = locations.into_iter().peekable();
|
||||||
let mut ranges = Vec::new();
|
|
||||||
let capability = workspace.project().read(cx).capability();
|
let capability = workspace.project().read(cx).capability();
|
||||||
|
|
||||||
|
let mut ranges = Vec::new();
|
||||||
let excerpt_buffer = cx.new(|cx| {
|
let excerpt_buffer = cx.new(|cx| {
|
||||||
let mut multibuffer = MultiBuffer::new(capability);
|
let mut multibuffer = MultiBuffer::new(capability);
|
||||||
while let Some(location) = locations.next() {
|
while let Some(location) = locations.next() {
|
||||||
let buffer = location.buffer.read(cx);
|
let buffer = location.buffer.read(cx);
|
||||||
let mut ranges_for_buffer = Vec::new();
|
let mut ranges_for_buffer = Vec::new();
|
||||||
let range = location.range.to_offset(buffer);
|
let range = location.range.to_point(buffer);
|
||||||
ranges_for_buffer.push(range.clone());
|
ranges_for_buffer.push(range.clone());
|
||||||
|
|
||||||
while let Some(next_location) = locations.peek() {
|
while let Some(next_location) = locations.peek() {
|
||||||
if next_location.buffer == location.buffer {
|
if next_location.buffer == location.buffer {
|
||||||
ranges_for_buffer.push(next_location.range.to_offset(buffer));
|
ranges_for_buffer.push(next_location.range.to_point(buffer));
|
||||||
locations.next();
|
locations.next();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -12349,14 +12349,16 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
|
ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
|
||||||
ranges.extend(multibuffer.push_excerpts_with_context_lines(
|
multibuffer.set_excerpts_for_path(
|
||||||
|
PathKey::for_buffer(&buffer, cx),
|
||||||
location.buffer.clone(),
|
location.buffer.clone(),
|
||||||
ranges_for_buffer,
|
ranges_for_buffer,
|
||||||
DEFAULT_MULTIBUFFER_CONTEXT,
|
DEFAULT_MULTIBUFFER_CONTEXT,
|
||||||
cx,
|
cx,
|
||||||
))
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ranges.extend(multibuffer.primary_excerpt_ranges(cx));
|
||||||
multibuffer.with_title(title)
|
multibuffer.with_title(title)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15648,7 +15648,7 @@ async fn test_display_diff_hunks(cx: &mut TestAppContext) {
|
|||||||
for buffer in &buffers {
|
for buffer in &buffers {
|
||||||
let snapshot = buffer.read(cx).snapshot();
|
let snapshot = buffer.read(cx).snapshot();
|
||||||
multibuffer.set_excerpts_for_path(
|
multibuffer.set_excerpts_for_path(
|
||||||
PathKey::namespaced("", buffer.read(cx).file().unwrap().path().clone()),
|
PathKey::namespaced(0, buffer.read(cx).file().unwrap().path().clone()),
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
vec![text::Anchor::MIN.to_point(&snapshot)..text::Anchor::MAX.to_point(&snapshot)],
|
vec![text::Anchor::MIN.to_point(&snapshot)..text::Anchor::MAX.to_point(&snapshot)],
|
||||||
DEFAULT_MULTIBUFFER_CONTEXT,
|
DEFAULT_MULTIBUFFER_CONTEXT,
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ struct DiffBuffer {
|
|||||||
file_status: FileStatus,
|
file_status: FileStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONFLICT_NAMESPACE: &'static str = "0";
|
const CONFLICT_NAMESPACE: usize = 0;
|
||||||
const TRACKED_NAMESPACE: &'static str = "1";
|
const TRACKED_NAMESPACE: usize = 1;
|
||||||
const NEW_NAMESPACE: &'static str = "2";
|
const NEW_NAMESPACE: usize = 2;
|
||||||
|
|
||||||
impl ProjectDiff {
|
impl ProjectDiff {
|
||||||
pub(crate) fn register(
|
pub(crate) fn register(
|
||||||
|
|||||||
@@ -167,17 +167,27 @@ impl MultiBufferDiffHunk {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
|
#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
|
||||||
pub struct PathKey {
|
pub struct PathKey {
|
||||||
namespace: &'static str,
|
namespace: usize,
|
||||||
path: Arc<Path>,
|
path: Arc<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathKey {
|
impl PathKey {
|
||||||
pub fn namespaced(namespace: &'static str, path: Arc<Path>) -> Self {
|
pub fn namespaced(namespace: usize, path: Arc<Path>) -> Self {
|
||||||
Self { namespace, path }
|
Self { namespace, path }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> &Arc<Path> {
|
pub fn for_buffer(buffer: &Buffer, cx: &App) -> Self {
|
||||||
&self.path
|
if let Some(file) = buffer.file() {
|
||||||
|
Self {
|
||||||
|
namespace: 1 + file.worktree_id(cx).to_usize(),
|
||||||
|
path: file.path().clone(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self {
|
||||||
|
namespace: 0,
|
||||||
|
path: Arc::from(Path::new(&format!("Untitled/{}", buffer.remote_id()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1442,45 +1452,6 @@ impl MultiBuffer {
|
|||||||
self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
|
self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_excerpts_with_context_lines<O>(
|
|
||||||
&mut self,
|
|
||||||
buffer: Entity<Buffer>,
|
|
||||||
ranges: Vec<Range<O>>,
|
|
||||||
context_line_count: u32,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Vec<Range<Anchor>>
|
|
||||||
where
|
|
||||||
O: text::ToPoint + text::ToOffset,
|
|
||||||
{
|
|
||||||
let buffer_id = buffer.read(cx).remote_id();
|
|
||||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
|
||||||
let (excerpt_ranges, range_counts) =
|
|
||||||
build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
|
|
||||||
|
|
||||||
let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
|
|
||||||
|
|
||||||
let mut anchor_ranges = Vec::new();
|
|
||||||
let mut ranges = ranges.into_iter();
|
|
||||||
for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
|
|
||||||
anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
|
|
||||||
let start = Anchor {
|
|
||||||
buffer_id: Some(buffer_id),
|
|
||||||
excerpt_id,
|
|
||||||
text_anchor: buffer_snapshot.anchor_after(range.start),
|
|
||||||
diff_base_anchor: None,
|
|
||||||
};
|
|
||||||
let end = Anchor {
|
|
||||||
buffer_id: Some(buffer_id),
|
|
||||||
excerpt_id,
|
|
||||||
text_anchor: buffer_snapshot.anchor_after(range.end),
|
|
||||||
diff_base_anchor: None,
|
|
||||||
};
|
|
||||||
start..end
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
anchor_ranges
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
|
pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
|
||||||
let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
|
let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
|
||||||
let snapshot = self.snapshot(cx);
|
let snapshot = self.snapshot(cx);
|
||||||
@@ -1554,7 +1525,7 @@ impl MultiBuffer {
|
|||||||
let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new();
|
let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new();
|
||||||
for range in expanded_ranges {
|
for range in expanded_ranges {
|
||||||
if let Some(last_range) = merged_ranges.last_mut() {
|
if let Some(last_range) = merged_ranges.last_mut() {
|
||||||
if last_range.context.end >= range.context.start {
|
if last_range.context.end + Point::new(1, 0) >= range.context.start {
|
||||||
last_range.context.end = range.context.end;
|
last_range.context.end = range.context.end;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2015,6 +1986,19 @@ impl MultiBuffer {
|
|||||||
excerpts
|
excerpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn primary_excerpt_ranges(&self, cx: &App) -> Vec<Range<Anchor>> {
|
||||||
|
self.read(cx)
|
||||||
|
.excerpts()
|
||||||
|
.flat_map(|(excerpt_id, buffer, range)| {
|
||||||
|
Some(Anchor::range_in_buffer(
|
||||||
|
excerpt_id,
|
||||||
|
buffer.remote_id(),
|
||||||
|
range.primary?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn excerpt_ranges_for_buffer(&self, buffer_id: BufferId, cx: &App) -> Vec<Range<Point>> {
|
pub fn excerpt_ranges_for_buffer(&self, buffer_id: BufferId, cx: &App) -> Vec<Range<Point>> {
|
||||||
let snapshot = self.read(cx);
|
let snapshot = self.read(cx);
|
||||||
let buffers = self.buffers.borrow();
|
let buffers = self.buffers.borrow();
|
||||||
|
|||||||
@@ -737,7 +737,8 @@ fn test_expand_excerpts(cx: &mut App) {
|
|||||||
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
||||||
|
|
||||||
multibuffer.update(cx, |multibuffer, cx| {
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
multibuffer.push_excerpts_with_context_lines(
|
multibuffer.set_excerpts_for_path(
|
||||||
|
PathKey::for_buffer(&buffer.read(cx), cx),
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
vec![
|
vec![
|
||||||
// Note that in this test, this first excerpt
|
// Note that in this test, this first excerpt
|
||||||
@@ -782,9 +783,6 @@ fn test_expand_excerpts(cx: &mut App) {
|
|||||||
|
|
||||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||||
|
|
||||||
// Expanding context lines causes the line containing 'fff' to appear in two different excerpts.
|
|
||||||
// We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers
|
|
||||||
// that are tracking excerpt ids.
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.text(),
|
snapshot.text(),
|
||||||
concat!(
|
concat!(
|
||||||
@@ -792,7 +790,6 @@ fn test_expand_excerpts(cx: &mut App) {
|
|||||||
"ccc\n", //
|
"ccc\n", //
|
||||||
"ddd\n", //
|
"ddd\n", //
|
||||||
"eee\n", //
|
"eee\n", //
|
||||||
"fff\n", // End of excerpt
|
|
||||||
"fff\n", //
|
"fff\n", //
|
||||||
"ggg\n", //
|
"ggg\n", //
|
||||||
"hhh\n", //
|
"hhh\n", //
|
||||||
@@ -807,59 +804,6 @@ fn test_expand_excerpts(cx: &mut App) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
|
||||||
fn test_push_excerpts_with_context_lines(cx: &mut App) {
|
|
||||||
let buffer = cx.new(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
|
|
||||||
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
|
||||||
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
|
|
||||||
multibuffer.push_excerpts_with_context_lines(
|
|
||||||
buffer.clone(),
|
|
||||||
vec![
|
|
||||||
// Note that in this test, this first excerpt
|
|
||||||
// does contain a new line
|
|
||||||
Point::new(3, 2)..Point::new(4, 2),
|
|
||||||
Point::new(7, 1)..Point::new(7, 3),
|
|
||||||
Point::new(15, 0)..Point::new(15, 0),
|
|
||||||
],
|
|
||||||
2,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
|
||||||
assert_eq!(
|
|
||||||
snapshot.text(),
|
|
||||||
concat!(
|
|
||||||
"bbb\n", // Preserve newlines
|
|
||||||
"ccc\n", //
|
|
||||||
"ddd\n", //
|
|
||||||
"eee\n", //
|
|
||||||
"fff\n", //
|
|
||||||
"ggg\n", //
|
|
||||||
"hhh\n", //
|
|
||||||
"iii\n", //
|
|
||||||
"jjj\n", //
|
|
||||||
"nnn\n", //
|
|
||||||
"ooo\n", //
|
|
||||||
"ppp\n", //
|
|
||||||
"qqq\n", //
|
|
||||||
"rrr", //
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
anchor_ranges
|
|
||||||
.iter()
|
|
||||||
.map(|range| range.to_point(&snapshot))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
vec![
|
|
||||||
Point::new(2, 2)..Point::new(3, 2),
|
|
||||||
Point::new(6, 1)..Point::new(6, 3),
|
|
||||||
Point::new(11, 0)..Point::new(11, 0)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[gpui::test(iterations = 100)]
|
#[gpui::test(iterations = 100)]
|
||||||
async fn test_push_multiple_excerpts_with_context_lines(cx: &mut TestAppContext) {
|
async fn test_push_multiple_excerpts_with_context_lines(cx: &mut TestAppContext) {
|
||||||
let buffer_1 = cx.new(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
|
let buffer_1 = cx.new(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
|
||||||
@@ -1587,7 +1531,7 @@ fn test_set_excerpts_for_buffer_ordering(cx: &mut TestAppContext) {
|
|||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let path1: PathKey = PathKey::namespaced("0", Path::new("/").into());
|
let path1: PathKey = PathKey::namespaced(0, Path::new("/").into());
|
||||||
|
|
||||||
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
||||||
multibuffer.update(cx, |multibuffer, cx| {
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
@@ -1683,7 +1627,7 @@ fn test_set_excerpts_for_buffer(cx: &mut TestAppContext) {
|
|||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let path1: PathKey = PathKey::namespaced("0", Path::new("/").into());
|
let path1: PathKey = PathKey::namespaced(0, Path::new("/").into());
|
||||||
let buf2 = cx.new(|cx| {
|
let buf2 = cx.new(|cx| {
|
||||||
Buffer::local(
|
Buffer::local(
|
||||||
indoc! {
|
indoc! {
|
||||||
@@ -1702,7 +1646,7 @@ fn test_set_excerpts_for_buffer(cx: &mut TestAppContext) {
|
|||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let path2 = PathKey::namespaced("x", Path::new("/").into());
|
let path2 = PathKey::namespaced(0, Path::new("/").into());
|
||||||
|
|
||||||
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
|
||||||
multibuffer.update(cx, |multibuffer, cx| {
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
|
|||||||
Reference in New Issue
Block a user