From a898acf6b591a3ba1444279440a2b1292116120c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 21 Apr 2021 12:29:16 -0600 Subject: [PATCH] WIP Co-Authored-By: Max Brunsfeld --- zed/src/worktree.rs | 195 +++++++++++++++----------------------------- 1 file changed, 64 insertions(+), 131 deletions(-) diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 781770c22b..63a84f8367 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -317,10 +317,10 @@ impl Snapshot { self.entries.edit(edits); } - fn populate_dir<'a>( + fn populate_dir( &mut self, parent_inode: u64, - children: impl IntoIterator, + children: impl IntoIterator, Entry)>, ) { let mut edits = Vec::new(); @@ -359,7 +359,7 @@ impl Snapshot { // For any children that were re-parented, remove them from their old parents for (parent_inode, to_remove) in old_children { - let mut parent = self.entries.get(&parent_inode).unwrap().clone(); + let parent = self.entries.get(&parent_inode).unwrap().clone(); self.remove_children(parent, &mut edits, |inode| to_remove.contains(&inode)); } @@ -383,7 +383,7 @@ impl Snapshot { } } - fn clear_descendants(&mut self, mut inode: u64, edits: &mut Vec>) { + fn clear_descendants(&mut self, inode: u64, edits: &mut Vec>) { let mut stack = vec![inode]; while let Some(inode) = stack.pop() { if let Entry::Dir { children, .. } = self.entries.get(&inode).unwrap() { @@ -414,61 +414,6 @@ impl Snapshot { edits.push(Edit::Insert(parent)); } - fn insert_entry_old(&mut self, path: &Path, entry: Entry) { - let mut edits = Vec::new(); - edits.push(Edit::Insert(entry.clone())); - if let Some(parent) = entry.parent() { - if let Some(mut parent_entry) = self.entries.get(&parent).cloned() { - if let Entry::Dir { children, .. } = &mut parent_entry { - let name = Arc::from(path.file_name().unwrap()); - *children = children - .into_iter() - .cloned() - .chain(Some((entry.inode(), name))) - .collect::>() - .into(); - edits.push(Edit::Insert(parent_entry)); - } else { - unreachable!(); - } - } - } - self.entries.edit(edits); - } - - fn remove_subtree(&mut self, subtree_inode: u64) { - let entry = self.entries.get(&subtree_inode).unwrap(); - - let mut edits = Vec::new(); - - // Update the parent entry to not include this subtree as one of its children. - if let Some(parent_inode) = entry.parent() { - let mut parent_entry = self.entries.get(&parent_inode).unwrap().clone(); - if let Entry::Dir { children, .. } = &mut parent_entry { - *children = children - .into_iter() - .filter(|(child_inode, _)| *child_inode != subtree_inode) - .cloned() - .collect::>() - .into(); - } else { - unreachable!("parent was not a directory"); - } - edits.push(Edit::Insert(parent_entry)); - } - - // Remove all descendant entries for this subtree. - let mut stack = vec![subtree_inode]; - while let Some(inode) = stack.pop() { - edits.push(Edit::Remove(inode)); - if let Entry::Dir { children, .. } = self.entries.get(&inode).unwrap() { - stack.extend(children.iter().map(|(child_inode, _)| *child_inode)); - } - } - - self.entries.edit(edits); - } - fn fmt_entry( &self, f: &mut fmt::Formatter<'_>, @@ -702,8 +647,12 @@ impl BackgroundScanner { children: Arc::from([]), pending: true, }; - self.insert_entries(Some(dir_entry.clone())); - self.snapshot.lock().root_inode = Some(inode); + + { + let mut snapshot = self.snapshot.lock(); + snapshot.insert_entry(None, dir_entry); + snapshot.root_inode = Some(inode); + } let (tx, rx) = crossbeam_channel::unbounded(); @@ -711,7 +660,6 @@ impl BackgroundScanner { inode, path: path.clone(), relative_path, - dir_entry, ignore: Some(ignore), scan_queue: tx.clone(), })) @@ -735,14 +683,18 @@ impl BackgroundScanner { }); results.into_iter().collect::>()?; } else { - self.insert_entries(Some(Entry::File { - parent: None, - path: PathEntry::new(inode, &relative_path, is_ignored), - inode, - is_symlink, - is_ignored, - })); - self.snapshot.lock().root_inode = Some(inode); + let mut snapshot = self.snapshot.lock(); + snapshot.insert_entry( + None, + Entry::File { + parent: None, + path: PathEntry::new(inode, &relative_path, is_ignored), + inode, + is_symlink, + is_ignored, + }, + ); + snapshot.root_inode = Some(inode); } Ok(()) @@ -750,49 +702,47 @@ impl BackgroundScanner { fn scan_dir(&self, job: ScanJob) -> io::Result<()> { let scan_queue = job.scan_queue; - let mut dir_entry = job.dir_entry; - let mut new_children = Vec::new(); let mut new_entries = Vec::new(); let mut new_jobs = Vec::new(); for child_entry in fs::read_dir(&job.path)? { let child_entry = child_entry?; - let name: Arc = child_entry.file_name().into(); - let relative_path = job.relative_path.join(name.as_ref()); - let metadata = child_entry.metadata()?; - let ino = metadata.ino(); - let is_symlink = metadata.file_type().is_symlink(); - let path = job.path.join(name.as_ref()); + let child_name: Arc = child_entry.file_name().into(); + let child_relative_path = job.relative_path.join(child_name.as_ref()); + let child_metadata = child_entry.metadata()?; + let child_inode = child_metadata.ino(); + let child_is_symlink = child_metadata.file_type().is_symlink(); + let child_path = job.path.join(child_name.as_ref()); - new_children.push((ino, name.clone())); - if metadata.is_dir() { + if child_metadata.is_dir() { let mut is_ignored = true; let mut ignore = None; if let Some(parent_ignore) = job.ignore.as_ref() { - let child_ignore = parent_ignore.add_child(&path).unwrap(); - is_ignored = - child_ignore.matched(&path, true).is_ignore() || name.as_ref() == ".git"; + let child_ignore = parent_ignore.add_child(&child_path).unwrap(); + is_ignored = child_ignore.matched(&child_path, true).is_ignore() + || child_name.as_ref() == ".git"; if !is_ignored { ignore = Some(child_ignore); } } - let dir_entry = Entry::Dir { - parent: Some(job.inode), - inode: ino, - is_symlink, - is_ignored, - children: Arc::from([]), - pending: true, - }; - new_entries.push(dir_entry.clone()); + new_entries.push(( + child_name, + Entry::Dir { + parent: Some(job.inode), + inode: child_inode, + is_symlink: child_is_symlink, + is_ignored, + children: Arc::from([]), + pending: true, + }, + )); new_jobs.push(ScanJob { - inode: ino, - path: Arc::from(path), - relative_path, - dir_entry, + inode: child_inode, + path: Arc::from(child_path), + relative_path: child_relative_path, ignore, scan_queue: scan_queue.clone(), }); @@ -800,29 +750,21 @@ impl BackgroundScanner { let is_ignored = job .ignore .as_ref() - .map_or(true, |i| i.matched(&path, false).is_ignore()); - new_entries.push(Entry::File { - parent: Some(job.inode), - path: PathEntry::new(ino, &relative_path, is_ignored), - inode: ino, - is_symlink, - is_ignored, - }); + .map_or(true, |i| i.matched(&child_path, false).is_ignore()); + new_entries.push(( + child_name, + Entry::File { + parent: Some(job.inode), + path: PathEntry::new(child_inode, &child_relative_path, is_ignored), + inode: child_inode, + is_symlink: child_is_symlink, + is_ignored, + }, + )); }; } - if let Entry::Dir { - children, pending, .. - } = &mut dir_entry - { - *children = Arc::from(new_children); - *pending = false; - } else { - unreachable!() - } - new_entries.push(dir_entry); - - self.insert_entries(new_entries); + self.snapshot.lock().populate_dir(job.inode, new_entries); for new_job in new_jobs { scan_queue.send(Ok(new_job)).unwrap(); } @@ -854,24 +796,23 @@ impl BackgroundScanner { paths.next(); } - if let Some(inode) = snapshot.inode_for_path(&relative_path) { - snapshot.remove_subtree(inode); - } + snapshot.remove_path(&relative_path); match self.fs_entry_for_path(&root_path, &path) { Ok(Some((fs_entry, ignore))) => { - snapshot.insert_entry_old(&path, fs_entry.clone()); + let is_dir = fs_entry.is_dir(); + let inode = fs_entry.inode(); - if fs_entry.is_dir() { + snapshot.insert_entry(path.file_name(), fs_entry); + if is_dir { scan_queue_tx .send(Ok(ScanJob { - inode: fs_entry.inode(), + inode, path: Arc::from(path), relative_path: snapshot .root_name() .map_or(PathBuf::new(), PathBuf::from) .join(relative_path), - dir_entry: fs_entry, ignore: Some(ignore), scan_queue: scan_queue_tx.clone(), })) @@ -964,20 +905,12 @@ impl BackgroundScanner { Ok(Some((entry, ignore))) } - - fn insert_entries(&self, entries: impl IntoIterator) { - self.snapshot - .lock() - .entries - .edit(entries.into_iter().map(Edit::Insert).collect::>()); - } } struct ScanJob { inode: u64, path: Arc, relative_path: PathBuf, - dir_entry: Entry, ignore: Option, scan_queue: crossbeam_channel::Sender>, }