diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 9e87b0b1bd939015542cd4acaa0860e12255d9a6..0c992486fa369e19f9752419e181e77fe8fcb02a 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -4604,7 +4604,10 @@ impl Project { typ: match change { PathChange::Added => lsp::FileChangeType::CREATED, PathChange::Removed => lsp::FileChangeType::DELETED, - PathChange::Updated => lsp::FileChangeType::CHANGED, + PathChange::Updated + | PathChange::AddedOrUpdated => { + lsp::FileChangeType::CHANGED + } }, }) .collect(), diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index f0bf81e49ee79ff0e5729e311483492938764386..0d3e3b416b03b9d513af047b4e763f8feb880967 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -610,8 +610,6 @@ impl LocalWorktree { } })); - cx.emit(Event::UpdatedEntries(Default::default())); - if !updated_repos.is_empty() { cx.emit(Event::UpdatedGitRepositories(updated_repos)); } @@ -2072,6 +2070,7 @@ pub enum PathChange { Added, Removed, Updated, + AddedOrUpdated, } impl Entry { @@ -2283,21 +2282,37 @@ impl BackgroundScanner { futures::pin_mut!(events_rx); - while let Some(mut events) = events_rx.next().await { + // Process any events that occurred while performing the initial scan. These + // events can't be reported as precisely, because there is no snapshot of the + // worktree before they occurred. + if let Some(mut events) = events_rx.next().await { while let Poll::Ready(Some(additional_events)) = futures::poll!(events_rx.next()) { events.extend(additional_events); } - if self.notify.unbounded_send(ScanState::Updating).is_err() { - break; + return; } - - if !self.process_events(events).await { - break; + if !self.process_events(events, true).await { + return; + } + if self.notify.unbounded_send(ScanState::Idle).is_err() { + return; } + } + // Continue processing events until the worktree is dropped. + while let Some(mut events) = events_rx.next().await { + while let Poll::Ready(Some(additional_events)) = futures::poll!(events_rx.next()) { + events.extend(additional_events); + } + if self.notify.unbounded_send(ScanState::Updating).is_err() { + return; + } + if !self.process_events(events, false).await { + return; + } if self.notify.unbounded_send(ScanState::Idle).is_err() { - break; + return; } } } @@ -2508,7 +2523,11 @@ impl BackgroundScanner { Ok(()) } - async fn process_events(&mut self, mut events: Vec) -> bool { + async fn process_events( + &mut self, + mut events: Vec, + received_before_initialized: bool, + ) -> bool { events.sort_unstable_by(|a, b| a.path.cmp(&b.path)); events.dedup_by(|a, b| a.path.starts_with(&b.path)); @@ -2632,7 +2651,7 @@ impl BackgroundScanner { self.update_ignore_statuses().await; self.update_git_repositories(); - self.build_change_set(prev_snapshot, event_paths); + self.build_change_set(prev_snapshot, event_paths, received_before_initialized); self.snapshot.lock().scan_completed(); true } @@ -2749,7 +2768,12 @@ impl BackgroundScanner { snapshot.entries_by_id.edit(entries_by_id_edits, &()); } - fn build_change_set(&self, old_snapshot: Snapshot, event_paths: Vec>) { + fn build_change_set( + &self, + old_snapshot: Snapshot, + event_paths: Vec>, + received_before_initialized: bool, + ) { let new_snapshot = self.snapshot.lock(); let mut old_paths = old_snapshot.entries_by_path.cursor::(); let mut new_paths = new_snapshot.entries_by_path.cursor::(); @@ -2777,7 +2801,13 @@ impl BackgroundScanner { old_paths.next(&()); } Ordering::Equal => { - if old_entry.mtime != new_entry.mtime { + if received_before_initialized { + // If the worktree was not fully initialized when this event was generated, + // we can't know whether this entry was added during the scan or whether + // it was merely updated. + change_set + .insert(old_entry.path.clone(), PathChange::AddedOrUpdated); + } else if old_entry.mtime != new_entry.mtime { change_set.insert(old_entry.path.clone(), PathChange::Updated); } old_paths.next(&()); @@ -3604,7 +3634,7 @@ mod tests { let len = rng.gen_range(0..=events.len()); let to_deliver = events.drain(0..len).collect::>(); log::info!("Delivering events: {:#?}", to_deliver); - smol::block_on(scanner.process_events(to_deliver)); + smol::block_on(scanner.process_events(to_deliver, false)); scanner.snapshot().check_invariants(); } else { events.extend(randomly_mutate_tree(root_dir.path(), 0.6, &mut rng).unwrap()); @@ -3616,7 +3646,7 @@ mod tests { } } log::info!("Quiescing: {:#?}", events); - smol::block_on(scanner.process_events(events)); + smol::block_on(scanner.process_events(events, false)); scanner.snapshot().check_invariants(); let (notify_tx, _notify_rx) = mpsc::unbounded();