Fix ordering of multibuffer excerpts (#39476)

The ordering of path-based excerpts in multibuffers regressed with
#38744, because we changed the `path` field of `PathKey` to be a string
(from `std::path::Path`) and used the derived `Ord` implementation,
which doesn't agree with the path-based order of worktree traversals.
This PR fixes that by using `RelPath` for `PathKey`. Instead of using
`File::full_path`, which can be absolute, we always use `File::path` and
distinguish different worktrees using their ID.

Release Notes:

- N/A

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
This commit is contained in:
Cole Miller
2025-10-03 22:17:31 +00:00
committed by GitHub
co-authored by Lukas Wirth
parent 2859cbdba9
commit aced13bc9f
6 changed files with 50 additions and 34 deletions
+17 -8
View File
@@ -49,7 +49,7 @@ use text::{
subscription::{Subscription, Topic},
};
use theme::SyntaxTheme;
use util::post_inc;
use util::{post_inc, rel_path::RelPath};
const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
@@ -161,24 +161,33 @@ impl MultiBufferDiffHunk {
#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
pub struct PathKey {
namespace: u32,
path: Arc<str>,
namespace: Option<u64>,
path: Arc<RelPath>,
}
impl PathKey {
pub fn namespaced(namespace: u32, path: Arc<str>) -> Self {
Self { namespace, path }
pub fn namespaced(namespace: u64, path: Arc<RelPath>) -> Self {
Self {
namespace: Some(namespace),
path,
}
}
pub fn for_buffer(buffer: &Entity<Buffer>, cx: &App) -> Self {
if let Some(file) = buffer.read(cx).file() {
Self::namespaced(1, file.full_path(cx).to_string_lossy().into_owned().into())
Self::namespaced(file.worktree_id(cx).to_proto(), file.path().clone())
} else {
Self::namespaced(0, buffer.entity_id().to_string().into())
Self {
namespace: None,
path: RelPath::unix(&buffer.entity_id().to_string())
.unwrap()
.into_arc(),
}
}
}
pub fn path(&self) -> &Arc<str> {
#[cfg(any(test, feature = "test-support"))]
pub fn path(&self) -> &Arc<RelPath> {
&self.path
}
}
@@ -8,6 +8,7 @@ use rand::prelude::*;
use settings::SettingsStore;
use std::env;
use util::RandomCharIter;
use util::rel_path::rel_path;
use util::test::sample_text;
#[ctor::ctor]
@@ -1524,7 +1525,7 @@ fn test_set_excerpts_for_buffer_ordering(cx: &mut TestAppContext) {
cx,
)
});
let path1: PathKey = PathKey::namespaced(0, "/".into());
let path1: PathKey = PathKey::namespaced(0, rel_path("root").into_arc());
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
multibuffer.update(cx, |multibuffer, cx| {
@@ -1619,7 +1620,7 @@ fn test_set_excerpts_for_buffer(cx: &mut TestAppContext) {
cx,
)
});
let path1: PathKey = PathKey::namespaced(0, "/".into());
let path1: PathKey = PathKey::namespaced(0, rel_path("root").into_arc());
let buf2 = cx.new(|cx| {
Buffer::local(
indoc! {
@@ -1638,7 +1639,7 @@ fn test_set_excerpts_for_buffer(cx: &mut TestAppContext) {
cx,
)
});
let path2 = PathKey::namespaced(1, "/".into());
let path2 = PathKey::namespaced(1, rel_path("root").into_arc());
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
multibuffer.update(cx, |multibuffer, cx| {
@@ -1815,7 +1816,7 @@ fn test_set_excerpts_for_buffer_rename(cx: &mut TestAppContext) {
cx,
)
});
let path: PathKey = PathKey::namespaced(0, "/".into());
let path: PathKey = PathKey::namespaced(0, rel_path("root").into_arc());
let buf2 = cx.new(|cx| {
Buffer::local(
indoc! {