Compare commits

..

3 Commits

Author SHA1 Message Date
Max Brunsfeld
d1e4c8dec5 zed 0.87.3 2023-05-19 13:18:43 -07:00
Max Brunsfeld
815b80e295 Remove unnescessary double lookup in repo for (#2492)
Release Notes:

* Optimize repository queries (preview only)
2023-05-19 13:18:12 -07:00
Max Brunsfeld
605213708a Optimize retrieving repos for entries when rendering the project panel (#2493)
This fixes slowness in rendering the project panel due to retrieving the
repository for a given entry.

Release Notes:

* Fixed a lag that would occur when lots of files changed on disk while
the project panel was open (preview only).
2023-05-19 13:17:55 -07:00
4 changed files with 67 additions and 25 deletions

2
Cargo.lock generated
View File

@@ -8544,7 +8544,7 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zed"
version = "0.87.2"
version = "0.87.3"
dependencies = [
"activity_indicator",
"anyhow",

View File

@@ -125,7 +125,7 @@ impl Snapshot {
let mut max_len = 0;
let mut current_candidate = None;
for (work_directory, repo) in (&self.repository_entries).iter() {
if repo.contains(self, path) {
if path.starts_with(&work_directory.0) {
if work_directory.0.as_os_str().len() >= max_len {
current_candidate = Some(repo);
max_len = work_directory.0.as_os_str().len();
@@ -169,10 +169,6 @@ impl RepositoryEntry {
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))
}
pub(crate) fn contains(&self, snapshot: &Snapshot, path: &Path) -> bool {
self.work_directory.contains(snapshot, path)
}
pub fn status_for_file(&self, snapshot: &Snapshot, path: &Path) -> Option<GitFileStatus> {
self.work_directory
.relativize(snapshot, path)
@@ -305,14 +301,6 @@ impl AsRef<Path> for RepositoryWorkDirectory {
pub struct WorkDirectoryEntry(ProjectEntryId);
impl WorkDirectoryEntry {
// Note that these paths should be relative to the worktree root.
pub(crate) fn contains(&self, snapshot: &Snapshot, path: &Path) -> bool {
snapshot
.entry_for_id(self.0)
.map(|entry| path.starts_with(&entry.path))
.unwrap_or(false)
}
pub(crate) fn relativize(&self, worktree: &Snapshot, path: &Path) -> Option<RepoPath> {
worktree.entry_for_id(self.0).and_then(|entry| {
path.strip_prefix(&entry.path)
@@ -1643,8 +1631,38 @@ impl Snapshot {
self.traverse_from_offset(true, include_ignored, 0)
}
pub fn repositories(&self) -> impl Iterator<Item = &RepositoryEntry> {
self.repository_entries.values()
pub fn repositories(&self) -> impl Iterator<Item = (&Arc<Path>, &RepositoryEntry)> {
self.repository_entries
.iter()
.map(|(path, entry)| (&path.0, entry))
}
/// Given an ordered iterator of entries, returns an iterator of those entries,
/// along with their containing git repository.
pub fn entries_with_repos<'a>(
&'a self,
entries: impl 'a + Iterator<Item = &'a Entry>,
) -> impl 'a + Iterator<Item = (&'a Entry, Option<&'a RepositoryEntry>)> {
let mut containing_repos = Vec::<(&Arc<Path>, &RepositoryEntry)>::new();
let mut repositories = self.repositories().peekable();
entries.map(move |entry| {
while let Some((repo_path, _)) = containing_repos.last() {
if !entry.path.starts_with(repo_path) {
containing_repos.pop();
} else {
break;
}
}
while let Some((repo_path, _)) = repositories.peek() {
if entry.path.starts_with(repo_path) {
containing_repos.push(repositories.next().unwrap());
} else {
break;
}
}
let repo = containing_repos.last().map(|(_, repo)| *repo);
(entry, repo)
})
}
pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
@@ -4008,6 +4026,7 @@ mod tests {
#[gpui::test]
async fn test_git_repository_for_path(cx: &mut TestAppContext) {
let root = temp_tree(json!({
"c.txt": "",
"dir1": {
".git": {},
"deps": {
@@ -4022,7 +4041,6 @@ mod tests {
"b.txt": ""
}
},
"c.txt": "",
}));
let http_client = FakeHttpClient::with_404_response();
@@ -4062,6 +4080,33 @@ mod tests {
.map(|directory| directory.as_ref().to_owned()),
Some(Path::new("dir1/deps/dep1").to_owned())
);
let entries = tree.files(false, 0);
let paths_with_repos = tree
.entries_with_repos(entries)
.map(|(entry, repo)| {
(
entry.path.as_ref(),
repo.and_then(|repo| {
repo.work_directory(&tree)
.map(|work_directory| work_directory.0.to_path_buf())
}),
)
})
.collect::<Vec<_>>();
assert_eq!(
paths_with_repos,
&[
(Path::new("c.txt"), None),
(
Path::new("dir1/deps/dep1/src/a.txt"),
Some(Path::new("dir1/deps/dep1").into())
),
(Path::new("dir1/src/b.txt"), Some(Path::new("dir1").into())),
]
);
});
let repo_update_events = Arc::new(Mutex::new(vec![]));

View File

@@ -1011,14 +1011,11 @@ impl ProjectPanel {
.unwrap_or(&[]);
let entry_range = range.start.saturating_sub(ix)..end_ix - ix;
for entry in &visible_worktree_entries[entry_range] {
let path = &entry.path;
for (entry, repo) in
snapshot.entries_with_repos(visible_worktree_entries[entry_range].iter())
{
let status = (entry.path.parent().is_some() && !entry.is_ignored)
.then(|| {
snapshot
.repo_for(path)
.and_then(|entry| entry.status_for_path(&snapshot, path))
})
.then(|| repo.and_then(|repo| repo.status_for_path(&snapshot, &entry.path)))
.flatten();
let mut details = EntryDetails {

View File

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.87.2"
version = "0.87.3"
publish = false
[lib]