worktree.rs

   1use super::{
   2    fs::{self, Fs},
   3    ignore::IgnoreStack,
   4    DiagnosticSummary,
   5};
   6use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
   7use anyhow::{anyhow, Result};
   8use client::{proto, Client, TypedEnvelope};
   9use clock::ReplicaId;
  10use collections::HashMap;
  11use futures::{Stream, StreamExt};
  12use fuzzy::CharBag;
  13use gpui::{
  14    executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
  15    Task,
  16};
  17use language::{
  18    Anchor, Buffer, Completion, DiagnosticEntry, Language, Operation, PointUtf16, Rope,
  19};
  20use lazy_static::lazy_static;
  21use parking_lot::Mutex;
  22use postage::{
  23    prelude::{Sink as _, Stream as _},
  24    watch,
  25};
  26use serde::Deserialize;
  27use smol::channel::{self, Sender};
  28use std::{
  29    any::Any,
  30    cmp::{self, Ordering},
  31    convert::{TryFrom, TryInto},
  32    ffi::{OsStr, OsString},
  33    fmt,
  34    future::Future,
  35    ops::{Deref, DerefMut},
  36    path::{Path, PathBuf},
  37    sync::{
  38        atomic::{AtomicUsize, Ordering::SeqCst},
  39        Arc,
  40    },
  41    time::{Duration, SystemTime},
  42};
  43use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap};
  44use util::ResultExt;
  45
  46lazy_static! {
  47    static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
  48}
  49
  50#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
  51pub struct WorktreeId(usize);
  52
  53pub enum Worktree {
  54    Local(LocalWorktree),
  55    Remote(RemoteWorktree),
  56}
  57
  58pub struct LocalWorktree {
  59    snapshot: LocalSnapshot,
  60    config: WorktreeConfig,
  61    background_snapshot: Arc<Mutex<LocalSnapshot>>,
  62    last_scan_state_rx: watch::Receiver<ScanState>,
  63    _background_scanner_task: Option<Task<()>>,
  64    poll_task: Option<Task<()>>,
  65    registration: Registration,
  66    share: Option<ShareState>,
  67    diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<PointUtf16>>>,
  68    diagnostic_summaries: TreeMap<PathKey, DiagnosticSummary>,
  69    queued_operations: Vec<(u64, Operation)>,
  70    client: Arc<Client>,
  71    fs: Arc<dyn Fs>,
  72    weak: bool,
  73}
  74
  75pub struct RemoteWorktree {
  76    pub(crate) snapshot: Snapshot,
  77    project_id: u64,
  78    snapshot_rx: watch::Receiver<Snapshot>,
  79    client: Arc<Client>,
  80    updates_tx: postage::mpsc::Sender<proto::UpdateWorktree>,
  81    replica_id: ReplicaId,
  82    queued_operations: Vec<(u64, Operation)>,
  83    diagnostic_summaries: TreeMap<PathKey, DiagnosticSummary>,
  84    weak: bool,
  85}
  86
  87#[derive(Clone)]
  88pub struct Snapshot {
  89    id: WorktreeId,
  90    root_name: String,
  91    root_char_bag: CharBag,
  92    entries_by_path: SumTree<Entry>,
  93    entries_by_id: SumTree<PathEntry>,
  94}
  95
  96#[derive(Clone)]
  97pub struct LocalSnapshot {
  98    abs_path: Arc<Path>,
  99    scan_id: usize,
 100    ignores: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,
 101    removed_entry_ids: HashMap<u64, usize>,
 102    next_entry_id: Arc<AtomicUsize>,
 103    snapshot: Snapshot,
 104}
 105
 106impl Deref for LocalSnapshot {
 107    type Target = Snapshot;
 108
 109    fn deref(&self) -> &Self::Target {
 110        &self.snapshot
 111    }
 112}
 113
 114impl DerefMut for LocalSnapshot {
 115    fn deref_mut(&mut self) -> &mut Self::Target {
 116        &mut self.snapshot
 117    }
 118}
 119
 120#[derive(Clone, Debug)]
 121enum ScanState {
 122    Idle,
 123    Scanning,
 124    Err(Arc<anyhow::Error>),
 125}
 126
 127#[derive(Debug, Eq, PartialEq)]
 128enum Registration {
 129    None,
 130    Pending,
 131    Done { project_id: u64 },
 132}
 133
 134struct ShareState {
 135    project_id: u64,
 136    snapshots_tx: Sender<LocalSnapshot>,
 137    _maintain_remote_snapshot: Option<Task<()>>,
 138}
 139
 140#[derive(Default, Deserialize)]
 141struct WorktreeConfig {
 142    collaborators: Vec<String>,
 143}
 144
 145pub enum Event {
 146    UpdatedEntries,
 147}
 148
 149impl Entity for Worktree {
 150    type Event = Event;
 151
 152    fn release(&mut self, _: &mut MutableAppContext) {
 153        if let Some(worktree) = self.as_local_mut() {
 154            if let Registration::Done { project_id } = worktree.registration {
 155                let client = worktree.client.clone();
 156                let unregister_message = proto::UnregisterWorktree {
 157                    project_id,
 158                    worktree_id: worktree.id().to_proto(),
 159                };
 160                client.send(unregister_message).log_err();
 161            }
 162        }
 163    }
 164}
 165
 166impl Worktree {
 167    pub async fn local(
 168        client: Arc<Client>,
 169        path: impl Into<Arc<Path>>,
 170        weak: bool,
 171        fs: Arc<dyn Fs>,
 172        cx: &mut AsyncAppContext,
 173    ) -> Result<ModelHandle<Self>> {
 174        let (tree, scan_states_tx) = LocalWorktree::new(client, path, weak, fs.clone(), cx).await?;
 175        tree.update(cx, |tree, cx| {
 176            let tree = tree.as_local_mut().unwrap();
 177            let abs_path = tree.abs_path().clone();
 178            let background_snapshot = tree.background_snapshot.clone();
 179            let background = cx.background().clone();
 180            tree._background_scanner_task = Some(cx.background().spawn(async move {
 181                let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
 182                let scanner =
 183                    BackgroundScanner::new(background_snapshot, scan_states_tx, fs, background);
 184                scanner.run(events).await;
 185            }));
 186        });
 187        Ok(tree)
 188    }
 189
 190    pub fn remote(
 191        project_remote_id: u64,
 192        replica_id: ReplicaId,
 193        worktree: proto::Worktree,
 194        client: Arc<Client>,
 195        cx: &mut MutableAppContext,
 196    ) -> (ModelHandle<Self>, Task<()>) {
 197        let remote_id = worktree.id;
 198        let root_char_bag: CharBag = worktree
 199            .root_name
 200            .chars()
 201            .map(|c| c.to_ascii_lowercase())
 202            .collect();
 203        let root_name = worktree.root_name.clone();
 204        let weak = worktree.weak;
 205        let snapshot = Snapshot {
 206            id: WorktreeId(remote_id as usize),
 207            root_name,
 208            root_char_bag,
 209            entries_by_path: Default::default(),
 210            entries_by_id: Default::default(),
 211        };
 212
 213        let (updates_tx, mut updates_rx) = postage::mpsc::channel(64);
 214        let (mut snapshot_tx, snapshot_rx) = watch::channel_with(snapshot.clone());
 215        let worktree_handle = cx.add_model(|_: &mut ModelContext<Worktree>| {
 216            Worktree::Remote(RemoteWorktree {
 217                project_id: project_remote_id,
 218                replica_id,
 219                snapshot: snapshot.clone(),
 220                snapshot_rx: snapshot_rx.clone(),
 221                updates_tx,
 222                client: client.clone(),
 223                queued_operations: Default::default(),
 224                diagnostic_summaries: TreeMap::from_ordered_entries(
 225                    worktree.diagnostic_summaries.into_iter().map(|summary| {
 226                        (
 227                            PathKey(PathBuf::from(summary.path).into()),
 228                            DiagnosticSummary {
 229                                error_count: summary.error_count as usize,
 230                                warning_count: summary.warning_count as usize,
 231                                info_count: summary.info_count as usize,
 232                                hint_count: summary.hint_count as usize,
 233                            },
 234                        )
 235                    }),
 236                ),
 237                weak,
 238            })
 239        });
 240
 241        let deserialize_task = cx.spawn({
 242            let worktree_handle = worktree_handle.clone();
 243            |cx| async move {
 244                let (entries_by_path, entries_by_id) = cx
 245                    .background()
 246                    .spawn(async move {
 247                        let mut entries_by_path_edits = Vec::new();
 248                        let mut entries_by_id_edits = Vec::new();
 249                        for entry in worktree.entries {
 250                            match Entry::try_from((&root_char_bag, entry)) {
 251                                Ok(entry) => {
 252                                    entries_by_id_edits.push(Edit::Insert(PathEntry {
 253                                        id: entry.id,
 254                                        path: entry.path.clone(),
 255                                        is_ignored: entry.is_ignored,
 256                                        scan_id: 0,
 257                                    }));
 258                                    entries_by_path_edits.push(Edit::Insert(entry));
 259                                }
 260                                Err(err) => log::warn!("error for remote worktree entry {:?}", err),
 261                            }
 262                        }
 263
 264                        let mut entries_by_path = SumTree::new();
 265                        let mut entries_by_id = SumTree::new();
 266                        entries_by_path.edit(entries_by_path_edits, &());
 267                        entries_by_id.edit(entries_by_id_edits, &());
 268
 269                        (entries_by_path, entries_by_id)
 270                    })
 271                    .await;
 272
 273                {
 274                    let mut snapshot = snapshot_tx.borrow_mut();
 275                    snapshot.entries_by_path = entries_by_path;
 276                    snapshot.entries_by_id = entries_by_id;
 277                }
 278
 279                cx.background()
 280                    .spawn(async move {
 281                        while let Some(update) = updates_rx.recv().await {
 282                            let mut snapshot = snapshot_tx.borrow().clone();
 283                            if let Err(error) = snapshot.apply_remote_update(update) {
 284                                log::error!("error applying worktree update: {}", error);
 285                            }
 286                            *snapshot_tx.borrow_mut() = snapshot;
 287                        }
 288                    })
 289                    .detach();
 290
 291                {
 292                    let mut snapshot_rx = snapshot_rx.clone();
 293                    let this = worktree_handle.downgrade();
 294                    cx.spawn(|mut cx| async move {
 295                        while let Some(_) = snapshot_rx.recv().await {
 296                            if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
 297                                this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
 298                            } else {
 299                                break;
 300                            }
 301                        }
 302                    })
 303                    .detach();
 304                }
 305            }
 306        });
 307        (worktree_handle, deserialize_task)
 308    }
 309
 310    pub fn as_local(&self) -> Option<&LocalWorktree> {
 311        if let Worktree::Local(worktree) = self {
 312            Some(worktree)
 313        } else {
 314            None
 315        }
 316    }
 317
 318    pub fn as_remote(&self) -> Option<&RemoteWorktree> {
 319        if let Worktree::Remote(worktree) = self {
 320            Some(worktree)
 321        } else {
 322            None
 323        }
 324    }
 325
 326    pub fn as_local_mut(&mut self) -> Option<&mut LocalWorktree> {
 327        if let Worktree::Local(worktree) = self {
 328            Some(worktree)
 329        } else {
 330            None
 331        }
 332    }
 333
 334    pub fn as_remote_mut(&mut self) -> Option<&mut RemoteWorktree> {
 335        if let Worktree::Remote(worktree) = self {
 336            Some(worktree)
 337        } else {
 338            None
 339        }
 340    }
 341
 342    pub fn is_local(&self) -> bool {
 343        matches!(self, Worktree::Local(_))
 344    }
 345
 346    pub fn snapshot(&self) -> Snapshot {
 347        match self {
 348            Worktree::Local(worktree) => worktree.snapshot().snapshot,
 349            Worktree::Remote(worktree) => worktree.snapshot(),
 350        }
 351    }
 352
 353    pub fn is_weak(&self) -> bool {
 354        match self {
 355            Worktree::Local(worktree) => worktree.weak,
 356            Worktree::Remote(worktree) => worktree.weak,
 357        }
 358    }
 359
 360    pub fn replica_id(&self) -> ReplicaId {
 361        match self {
 362            Worktree::Local(_) => 0,
 363            Worktree::Remote(worktree) => worktree.replica_id,
 364        }
 365    }
 366
 367    pub fn diagnostic_summaries<'a>(
 368        &'a self,
 369    ) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + 'a {
 370        match self {
 371            Worktree::Local(worktree) => &worktree.diagnostic_summaries,
 372            Worktree::Remote(worktree) => &worktree.diagnostic_summaries,
 373        }
 374        .iter()
 375        .map(|(path, summary)| (path.0.clone(), summary.clone()))
 376    }
 377
 378    fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
 379        match self {
 380            Self::Local(worktree) => {
 381                let is_fake_fs = worktree.fs.is_fake();
 382                worktree.snapshot = worktree.background_snapshot.lock().clone();
 383                if worktree.is_scanning() {
 384                    if worktree.poll_task.is_none() {
 385                        worktree.poll_task = Some(cx.spawn(|this, mut cx| async move {
 386                            if is_fake_fs {
 387                                smol::future::yield_now().await;
 388                            } else {
 389                                smol::Timer::after(Duration::from_millis(100)).await;
 390                            }
 391                            this.update(&mut cx, |this, cx| {
 392                                this.as_local_mut().unwrap().poll_task = None;
 393                                this.poll_snapshot(cx);
 394                            })
 395                        }));
 396                    }
 397                } else {
 398                    worktree.poll_task.take();
 399                    cx.emit(Event::UpdatedEntries);
 400                }
 401            }
 402            Self::Remote(worktree) => {
 403                worktree.snapshot = worktree.snapshot_rx.borrow().clone();
 404                cx.emit(Event::UpdatedEntries);
 405            }
 406        };
 407
 408        cx.notify();
 409    }
 410
 411    fn send_buffer_update(
 412        &mut self,
 413        buffer_id: u64,
 414        operation: Operation,
 415        cx: &mut ModelContext<Self>,
 416    ) {
 417        if let Some((project_id, rpc)) = match self {
 418            Worktree::Local(worktree) => worktree
 419                .share
 420                .as_ref()
 421                .map(|share| (share.project_id, worktree.client.clone())),
 422            Worktree::Remote(worktree) => Some((worktree.project_id, worktree.client.clone())),
 423        } {
 424            cx.spawn(|worktree, mut cx| async move {
 425                if let Err(error) = rpc
 426                    .request(proto::UpdateBuffer {
 427                        project_id,
 428                        buffer_id,
 429                        operations: vec![language::proto::serialize_operation(&operation)],
 430                    })
 431                    .await
 432                {
 433                    worktree.update(&mut cx, |worktree, _| {
 434                        log::error!("error sending buffer operation: {}", error);
 435                        match worktree {
 436                            Worktree::Local(t) => &mut t.queued_operations,
 437                            Worktree::Remote(t) => &mut t.queued_operations,
 438                        }
 439                        .push((buffer_id, operation));
 440                    });
 441                }
 442            })
 443            .detach();
 444        }
 445    }
 446}
 447
 448impl LocalWorktree {
 449    async fn new(
 450        client: Arc<Client>,
 451        path: impl Into<Arc<Path>>,
 452        weak: bool,
 453        fs: Arc<dyn Fs>,
 454        cx: &mut AsyncAppContext,
 455    ) -> Result<(ModelHandle<Worktree>, Sender<ScanState>)> {
 456        let abs_path = path.into();
 457        let path: Arc<Path> = Arc::from(Path::new(""));
 458        let next_entry_id = AtomicUsize::new(0);
 459
 460        // After determining whether the root entry is a file or a directory, populate the
 461        // snapshot's "root name", which will be used for the purpose of fuzzy matching.
 462        let root_name = abs_path
 463            .file_name()
 464            .map_or(String::new(), |f| f.to_string_lossy().to_string());
 465        let root_char_bag = root_name.chars().map(|c| c.to_ascii_lowercase()).collect();
 466        let metadata = fs.metadata(&abs_path).await?;
 467
 468        let mut config = WorktreeConfig::default();
 469        if let Ok(zed_toml) = fs.load(&abs_path.join(".zed.toml")).await {
 470            if let Ok(parsed) = toml::from_str(&zed_toml) {
 471                config = parsed;
 472            }
 473        }
 474
 475        let (scan_states_tx, scan_states_rx) = smol::channel::unbounded();
 476        let (mut last_scan_state_tx, last_scan_state_rx) = watch::channel_with(ScanState::Scanning);
 477        let tree = cx.add_model(move |cx: &mut ModelContext<Worktree>| {
 478            let mut snapshot = LocalSnapshot {
 479                abs_path,
 480                scan_id: 0,
 481                ignores: Default::default(),
 482                removed_entry_ids: Default::default(),
 483                next_entry_id: Arc::new(next_entry_id),
 484                snapshot: Snapshot {
 485                    id: WorktreeId::from_usize(cx.model_id()),
 486                    root_name: root_name.clone(),
 487                    root_char_bag,
 488                    entries_by_path: Default::default(),
 489                    entries_by_id: Default::default(),
 490                },
 491            };
 492            if let Some(metadata) = metadata {
 493                let entry = Entry::new(
 494                    path.into(),
 495                    &metadata,
 496                    &snapshot.next_entry_id,
 497                    snapshot.root_char_bag,
 498                );
 499                snapshot.insert_entry(entry, fs.as_ref());
 500            }
 501
 502            let tree = Self {
 503                snapshot: snapshot.clone(),
 504                config,
 505                background_snapshot: Arc::new(Mutex::new(snapshot)),
 506                last_scan_state_rx,
 507                _background_scanner_task: None,
 508                registration: Registration::None,
 509                share: None,
 510                poll_task: None,
 511                diagnostics: Default::default(),
 512                diagnostic_summaries: Default::default(),
 513                queued_operations: Default::default(),
 514                client,
 515                fs,
 516                weak,
 517            };
 518
 519            cx.spawn_weak(|this, mut cx| async move {
 520                while let Ok(scan_state) = scan_states_rx.recv().await {
 521                    if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
 522                        let to_send = handle.update(&mut cx, |this, cx| {
 523                            last_scan_state_tx.blocking_send(scan_state).ok();
 524                            this.poll_snapshot(cx);
 525                            let tree = this.as_local_mut().unwrap();
 526                            if !tree.is_scanning() {
 527                                if let Some(share) = tree.share.as_ref() {
 528                                    return Some((tree.snapshot(), share.snapshots_tx.clone()));
 529                                }
 530                            }
 531                            None
 532                        });
 533
 534                        if let Some((snapshot, snapshots_to_send_tx)) = to_send {
 535                            if let Err(err) = snapshots_to_send_tx.send(snapshot).await {
 536                                log::error!("error submitting snapshot to send {}", err);
 537                            }
 538                        }
 539                    } else {
 540                        break;
 541                    }
 542                }
 543            })
 544            .detach();
 545
 546            Worktree::Local(tree)
 547        });
 548
 549        Ok((tree, scan_states_tx))
 550    }
 551
 552    pub fn abs_path(&self) -> &Arc<Path> {
 553        &self.abs_path
 554    }
 555
 556    pub fn contains_abs_path(&self, path: &Path) -> bool {
 557        path.starts_with(&self.abs_path)
 558    }
 559
 560    fn absolutize(&self, path: &Path) -> PathBuf {
 561        if path.file_name().is_some() {
 562            self.abs_path.join(path)
 563        } else {
 564            self.abs_path.to_path_buf()
 565        }
 566    }
 567
 568    pub fn authorized_logins(&self) -> Vec<String> {
 569        self.config.collaborators.clone()
 570    }
 571
 572    pub(crate) fn load_buffer(
 573        &mut self,
 574        path: &Path,
 575        cx: &mut ModelContext<Worktree>,
 576    ) -> Task<Result<ModelHandle<Buffer>>> {
 577        let path = Arc::from(path);
 578        cx.spawn(move |this, mut cx| async move {
 579            let (file, contents) = this
 580                .update(&mut cx, |t, cx| t.as_local().unwrap().load(&path, cx))
 581                .await?;
 582            Ok(cx.add_model(|cx| Buffer::from_file(0, contents, Box::new(file), cx)))
 583        })
 584    }
 585
 586    pub fn diagnostics_for_path(&self, path: &Path) -> Option<Vec<DiagnosticEntry<PointUtf16>>> {
 587        self.diagnostics.get(path).cloned()
 588    }
 589
 590    pub fn update_diagnostics(
 591        &mut self,
 592        worktree_path: Arc<Path>,
 593        diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
 594        _: &mut ModelContext<Worktree>,
 595    ) -> Result<()> {
 596        let summary = DiagnosticSummary::new(&diagnostics);
 597        self.diagnostic_summaries
 598            .insert(PathKey(worktree_path.clone()), summary.clone());
 599        self.diagnostics.insert(worktree_path.clone(), diagnostics);
 600
 601        if let Some(share) = self.share.as_ref() {
 602            self.client
 603                .send(proto::UpdateDiagnosticSummary {
 604                    project_id: share.project_id,
 605                    worktree_id: self.id().to_proto(),
 606                    summary: Some(proto::DiagnosticSummary {
 607                        path: worktree_path.to_string_lossy().to_string(),
 608                        error_count: summary.error_count as u32,
 609                        warning_count: summary.warning_count as u32,
 610                        info_count: summary.info_count as u32,
 611                        hint_count: summary.hint_count as u32,
 612                    }),
 613                })
 614                .log_err();
 615        }
 616
 617        Ok(())
 618    }
 619
 620    pub fn scan_complete(&self) -> impl Future<Output = ()> {
 621        let mut scan_state_rx = self.last_scan_state_rx.clone();
 622        async move {
 623            let mut scan_state = Some(scan_state_rx.borrow().clone());
 624            while let Some(ScanState::Scanning) = scan_state {
 625                scan_state = scan_state_rx.recv().await;
 626            }
 627        }
 628    }
 629
 630    fn is_scanning(&self) -> bool {
 631        if let ScanState::Scanning = *self.last_scan_state_rx.borrow() {
 632            true
 633        } else {
 634            false
 635        }
 636    }
 637
 638    pub fn snapshot(&self) -> LocalSnapshot {
 639        self.snapshot.clone()
 640    }
 641
 642    fn load(&self, path: &Path, cx: &mut ModelContext<Worktree>) -> Task<Result<(File, String)>> {
 643        let handle = cx.handle();
 644        let path = Arc::from(path);
 645        let abs_path = self.absolutize(&path);
 646        let background_snapshot = self.background_snapshot.clone();
 647        let fs = self.fs.clone();
 648        cx.spawn(|this, mut cx| async move {
 649            let text = fs.load(&abs_path).await?;
 650            // Eagerly populate the snapshot with an updated entry for the loaded file
 651            let entry = refresh_entry(fs.as_ref(), &background_snapshot, path, &abs_path).await?;
 652            this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
 653            Ok((
 654                File {
 655                    entry_id: Some(entry.id),
 656                    worktree: handle,
 657                    path: entry.path,
 658                    mtime: entry.mtime,
 659                    is_local: true,
 660                },
 661                text,
 662            ))
 663        })
 664    }
 665
 666    pub fn save_buffer_as(
 667        &self,
 668        buffer_handle: ModelHandle<Buffer>,
 669        path: impl Into<Arc<Path>>,
 670        cx: &mut ModelContext<Worktree>,
 671    ) -> Task<Result<()>> {
 672        let buffer = buffer_handle.read(cx);
 673        let text = buffer.as_rope().clone();
 674        let version = buffer.version();
 675        let save = self.save(path, text, cx);
 676        let handle = cx.handle();
 677        cx.as_mut().spawn(|mut cx| async move {
 678            let entry = save.await?;
 679            let file = File {
 680                entry_id: Some(entry.id),
 681                worktree: handle,
 682                path: entry.path,
 683                mtime: entry.mtime,
 684                is_local: true,
 685            };
 686
 687            buffer_handle.update(&mut cx, |buffer, cx| {
 688                buffer.did_save(version, file.mtime, Some(Box::new(file)), cx);
 689            });
 690
 691            Ok(())
 692        })
 693    }
 694
 695    fn save(
 696        &self,
 697        path: impl Into<Arc<Path>>,
 698        text: Rope,
 699        cx: &mut ModelContext<Worktree>,
 700    ) -> Task<Result<Entry>> {
 701        let path = path.into();
 702        let abs_path = self.absolutize(&path);
 703        let background_snapshot = self.background_snapshot.clone();
 704        let fs = self.fs.clone();
 705        let save = cx.background().spawn(async move {
 706            fs.save(&abs_path, &text).await?;
 707            refresh_entry(fs.as_ref(), &background_snapshot, path.clone(), &abs_path).await
 708        });
 709
 710        cx.spawn(|this, mut cx| async move {
 711            let entry = save.await?;
 712            this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
 713            Ok(entry)
 714        })
 715    }
 716
 717    pub fn register(
 718        &mut self,
 719        project_id: u64,
 720        cx: &mut ModelContext<Worktree>,
 721    ) -> Task<anyhow::Result<()>> {
 722        if self.registration != Registration::None {
 723            return Task::ready(Ok(()));
 724        }
 725
 726        self.registration = Registration::Pending;
 727        let client = self.client.clone();
 728        let register_message = proto::RegisterWorktree {
 729            project_id,
 730            worktree_id: self.id().to_proto(),
 731            root_name: self.root_name().to_string(),
 732            authorized_logins: self.authorized_logins(),
 733        };
 734        cx.spawn(|this, mut cx| async move {
 735            let response = client.request(register_message).await;
 736            this.update(&mut cx, |this, _| {
 737                let worktree = this.as_local_mut().unwrap();
 738                match response {
 739                    Ok(_) => {
 740                        worktree.registration = Registration::Done { project_id };
 741                        Ok(())
 742                    }
 743                    Err(error) => {
 744                        worktree.registration = Registration::None;
 745                        Err(error)
 746                    }
 747                }
 748            })
 749        })
 750    }
 751
 752    pub fn share(
 753        &mut self,
 754        project_id: u64,
 755        cx: &mut ModelContext<Worktree>,
 756    ) -> Task<anyhow::Result<()>> {
 757        if self.share.is_some() {
 758            return Task::ready(Ok(()));
 759        }
 760
 761        let snapshot = self.snapshot();
 762        let rpc = self.client.clone();
 763        let worktree_id = cx.model_id() as u64;
 764        let (snapshots_to_send_tx, snapshots_to_send_rx) =
 765            smol::channel::unbounded::<LocalSnapshot>();
 766        let maintain_remote_snapshot = cx.background().spawn({
 767            let rpc = rpc.clone();
 768            let snapshot = snapshot.clone();
 769            async move {
 770                let mut prev_snapshot = snapshot;
 771                while let Ok(snapshot) = snapshots_to_send_rx.recv().await {
 772                    let message =
 773                        snapshot.build_update(&prev_snapshot, project_id, worktree_id, false);
 774                    match rpc.send(message) {
 775                        Ok(()) => prev_snapshot = snapshot,
 776                        Err(err) => log::error!("error sending snapshot diff {}", err),
 777                    }
 778                }
 779            }
 780        });
 781        self.share = Some(ShareState {
 782            project_id,
 783            snapshots_tx: snapshots_to_send_tx,
 784            _maintain_remote_snapshot: Some(maintain_remote_snapshot),
 785        });
 786
 787        let diagnostic_summaries = self.diagnostic_summaries.clone();
 788        let weak = self.weak;
 789        let share_message = cx.background().spawn(async move {
 790            proto::ShareWorktree {
 791                project_id,
 792                worktree: Some(snapshot.to_proto(&diagnostic_summaries, weak)),
 793            }
 794        });
 795
 796        cx.foreground().spawn(async move {
 797            rpc.request(share_message.await).await?;
 798            Ok(())
 799        })
 800    }
 801
 802    pub fn unshare(&mut self) {
 803        self.share.take();
 804    }
 805
 806    pub fn is_shared(&self) -> bool {
 807        self.share.is_some()
 808    }
 809}
 810
 811impl RemoteWorktree {
 812    fn snapshot(&self) -> Snapshot {
 813        self.snapshot.clone()
 814    }
 815
 816    pub fn update_from_remote(
 817        &mut self,
 818        envelope: TypedEnvelope<proto::UpdateWorktree>,
 819        cx: &mut ModelContext<Worktree>,
 820    ) -> Result<()> {
 821        let mut tx = self.updates_tx.clone();
 822        let payload = envelope.payload.clone();
 823        cx.background()
 824            .spawn(async move {
 825                tx.send(payload).await.expect("receiver runs to completion");
 826            })
 827            .detach();
 828
 829        Ok(())
 830    }
 831
 832    pub fn update_diagnostic_summary(
 833        &mut self,
 834        path: Arc<Path>,
 835        summary: &proto::DiagnosticSummary,
 836    ) {
 837        self.diagnostic_summaries.insert(
 838            PathKey(path.clone()),
 839            DiagnosticSummary {
 840                error_count: summary.error_count as usize,
 841                warning_count: summary.warning_count as usize,
 842                info_count: summary.info_count as usize,
 843                hint_count: summary.hint_count as usize,
 844            },
 845        );
 846    }
 847}
 848
 849impl Snapshot {
 850    pub fn id(&self) -> WorktreeId {
 851        self.id
 852    }
 853
 854    pub(crate) fn to_proto(
 855        &self,
 856        diagnostic_summaries: &TreeMap<PathKey, DiagnosticSummary>,
 857        weak: bool,
 858    ) -> proto::Worktree {
 859        let root_name = self.root_name.clone();
 860        proto::Worktree {
 861            id: self.id.0 as u64,
 862            root_name,
 863            entries: self
 864                .entries_by_path
 865                .iter()
 866                .filter(|e| !e.is_ignored)
 867                .map(Into::into)
 868                .collect(),
 869            diagnostic_summaries: diagnostic_summaries
 870                .iter()
 871                .map(|(path, summary)| summary.to_proto(path.0.clone()))
 872                .collect(),
 873            weak,
 874        }
 875    }
 876
 877    pub(crate) fn build_update(
 878        &self,
 879        other: &Self,
 880        project_id: u64,
 881        worktree_id: u64,
 882        include_ignored: bool,
 883    ) -> proto::UpdateWorktree {
 884        let mut updated_entries = Vec::new();
 885        let mut removed_entries = Vec::new();
 886        let mut self_entries = self
 887            .entries_by_id
 888            .cursor::<()>()
 889            .filter(|e| include_ignored || !e.is_ignored)
 890            .peekable();
 891        let mut other_entries = other
 892            .entries_by_id
 893            .cursor::<()>()
 894            .filter(|e| include_ignored || !e.is_ignored)
 895            .peekable();
 896        loop {
 897            match (self_entries.peek(), other_entries.peek()) {
 898                (Some(self_entry), Some(other_entry)) => {
 899                    match Ord::cmp(&self_entry.id, &other_entry.id) {
 900                        Ordering::Less => {
 901                            let entry = self.entry_for_id(self_entry.id).unwrap().into();
 902                            updated_entries.push(entry);
 903                            self_entries.next();
 904                        }
 905                        Ordering::Equal => {
 906                            if self_entry.scan_id != other_entry.scan_id {
 907                                let entry = self.entry_for_id(self_entry.id).unwrap().into();
 908                                updated_entries.push(entry);
 909                            }
 910
 911                            self_entries.next();
 912                            other_entries.next();
 913                        }
 914                        Ordering::Greater => {
 915                            removed_entries.push(other_entry.id as u64);
 916                            other_entries.next();
 917                        }
 918                    }
 919                }
 920                (Some(self_entry), None) => {
 921                    let entry = self.entry_for_id(self_entry.id).unwrap().into();
 922                    updated_entries.push(entry);
 923                    self_entries.next();
 924                }
 925                (None, Some(other_entry)) => {
 926                    removed_entries.push(other_entry.id as u64);
 927                    other_entries.next();
 928                }
 929                (None, None) => break,
 930            }
 931        }
 932
 933        proto::UpdateWorktree {
 934            project_id,
 935            worktree_id,
 936            root_name: self.root_name().to_string(),
 937            updated_entries,
 938            removed_entries,
 939        }
 940    }
 941
 942    pub(crate) fn apply_remote_update(&mut self, update: proto::UpdateWorktree) -> Result<()> {
 943        let mut entries_by_path_edits = Vec::new();
 944        let mut entries_by_id_edits = Vec::new();
 945        for entry_id in update.removed_entries {
 946            let entry_id = entry_id as usize;
 947            let entry = self
 948                .entry_for_id(entry_id)
 949                .ok_or_else(|| anyhow!("unknown entry"))?;
 950            entries_by_path_edits.push(Edit::Remove(PathKey(entry.path.clone())));
 951            entries_by_id_edits.push(Edit::Remove(entry.id));
 952        }
 953
 954        for entry in update.updated_entries {
 955            let entry = Entry::try_from((&self.root_char_bag, entry))?;
 956            if let Some(PathEntry { path, .. }) = self.entries_by_id.get(&entry.id, &()) {
 957                entries_by_path_edits.push(Edit::Remove(PathKey(path.clone())));
 958            }
 959            entries_by_id_edits.push(Edit::Insert(PathEntry {
 960                id: entry.id,
 961                path: entry.path.clone(),
 962                is_ignored: entry.is_ignored,
 963                scan_id: 0,
 964            }));
 965            entries_by_path_edits.push(Edit::Insert(entry));
 966        }
 967
 968        self.entries_by_path.edit(entries_by_path_edits, &());
 969        self.entries_by_id.edit(entries_by_id_edits, &());
 970
 971        Ok(())
 972    }
 973
 974    pub fn file_count(&self) -> usize {
 975        self.entries_by_path.summary().file_count
 976    }
 977
 978    pub fn visible_file_count(&self) -> usize {
 979        self.entries_by_path.summary().visible_file_count
 980    }
 981
 982    fn traverse_from_offset(
 983        &self,
 984        include_dirs: bool,
 985        include_ignored: bool,
 986        start_offset: usize,
 987    ) -> Traversal {
 988        let mut cursor = self.entries_by_path.cursor();
 989        cursor.seek(
 990            &TraversalTarget::Count {
 991                count: start_offset,
 992                include_dirs,
 993                include_ignored,
 994            },
 995            Bias::Right,
 996            &(),
 997        );
 998        Traversal {
 999            cursor,
1000            include_dirs,
1001            include_ignored,
1002        }
1003    }
1004
1005    fn traverse_from_path(
1006        &self,
1007        include_dirs: bool,
1008        include_ignored: bool,
1009        path: &Path,
1010    ) -> Traversal {
1011        let mut cursor = self.entries_by_path.cursor();
1012        cursor.seek(&TraversalTarget::Path(path), Bias::Left, &());
1013        Traversal {
1014            cursor,
1015            include_dirs,
1016            include_ignored,
1017        }
1018    }
1019
1020    pub fn files(&self, include_ignored: bool, start: usize) -> Traversal {
1021        self.traverse_from_offset(false, include_ignored, start)
1022    }
1023
1024    pub fn entries(&self, include_ignored: bool) -> Traversal {
1025        self.traverse_from_offset(true, include_ignored, 0)
1026    }
1027
1028    pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
1029        let empty_path = Path::new("");
1030        self.entries_by_path
1031            .cursor::<()>()
1032            .filter(move |entry| entry.path.as_ref() != empty_path)
1033            .map(|entry| &entry.path)
1034    }
1035
1036    fn child_entries<'a>(&'a self, parent_path: &'a Path) -> ChildEntriesIter<'a> {
1037        let mut cursor = self.entries_by_path.cursor();
1038        cursor.seek(&TraversalTarget::Path(parent_path), Bias::Right, &());
1039        let traversal = Traversal {
1040            cursor,
1041            include_dirs: true,
1042            include_ignored: true,
1043        };
1044        ChildEntriesIter {
1045            traversal,
1046            parent_path,
1047        }
1048    }
1049
1050    pub fn root_entry(&self) -> Option<&Entry> {
1051        self.entry_for_path("")
1052    }
1053
1054    pub fn root_name(&self) -> &str {
1055        &self.root_name
1056    }
1057
1058    pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
1059        let path = path.as_ref();
1060        self.traverse_from_path(true, true, path)
1061            .entry()
1062            .and_then(|entry| {
1063                if entry.path.as_ref() == path {
1064                    Some(entry)
1065                } else {
1066                    None
1067                }
1068            })
1069    }
1070
1071    pub fn entry_for_id(&self, id: usize) -> Option<&Entry> {
1072        let entry = self.entries_by_id.get(&id, &())?;
1073        self.entry_for_path(&entry.path)
1074    }
1075
1076    pub fn inode_for_path(&self, path: impl AsRef<Path>) -> Option<u64> {
1077        self.entry_for_path(path.as_ref()).map(|e| e.inode)
1078    }
1079}
1080
1081impl LocalSnapshot {
1082    fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs) -> Entry {
1083        if !entry.is_dir() && entry.path.file_name() == Some(&GITIGNORE) {
1084            let abs_path = self.abs_path.join(&entry.path);
1085            match build_gitignore(&abs_path, fs) {
1086                Ok(ignore) => {
1087                    let ignore_dir_path = entry.path.parent().unwrap();
1088                    self.ignores
1089                        .insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id));
1090                }
1091                Err(error) => {
1092                    log::error!(
1093                        "error loading .gitignore file {:?} - {:?}",
1094                        &entry.path,
1095                        error
1096                    );
1097                }
1098            }
1099        }
1100
1101        self.reuse_entry_id(&mut entry);
1102        self.entries_by_path.insert_or_replace(entry.clone(), &());
1103        let scan_id = self.scan_id;
1104        self.entries_by_id.insert_or_replace(
1105            PathEntry {
1106                id: entry.id,
1107                path: entry.path.clone(),
1108                is_ignored: entry.is_ignored,
1109                scan_id,
1110            },
1111            &(),
1112        );
1113        entry
1114    }
1115
1116    fn populate_dir(
1117        &mut self,
1118        parent_path: Arc<Path>,
1119        entries: impl IntoIterator<Item = Entry>,
1120        ignore: Option<Arc<Gitignore>>,
1121    ) {
1122        let mut parent_entry = self
1123            .entries_by_path
1124            .get(&PathKey(parent_path.clone()), &())
1125            .unwrap()
1126            .clone();
1127        if let Some(ignore) = ignore {
1128            self.ignores.insert(parent_path, (ignore, self.scan_id));
1129        }
1130        if matches!(parent_entry.kind, EntryKind::PendingDir) {
1131            parent_entry.kind = EntryKind::Dir;
1132        } else {
1133            unreachable!();
1134        }
1135
1136        let mut entries_by_path_edits = vec![Edit::Insert(parent_entry)];
1137        let mut entries_by_id_edits = Vec::new();
1138
1139        for mut entry in entries {
1140            self.reuse_entry_id(&mut entry);
1141            entries_by_id_edits.push(Edit::Insert(PathEntry {
1142                id: entry.id,
1143                path: entry.path.clone(),
1144                is_ignored: entry.is_ignored,
1145                scan_id: self.scan_id,
1146            }));
1147            entries_by_path_edits.push(Edit::Insert(entry));
1148        }
1149
1150        self.entries_by_path.edit(entries_by_path_edits, &());
1151        self.entries_by_id.edit(entries_by_id_edits, &());
1152    }
1153
1154    fn reuse_entry_id(&mut self, entry: &mut Entry) {
1155        if let Some(removed_entry_id) = self.removed_entry_ids.remove(&entry.inode) {
1156            entry.id = removed_entry_id;
1157        } else if let Some(existing_entry) = self.entry_for_path(&entry.path) {
1158            entry.id = existing_entry.id;
1159        }
1160    }
1161
1162    fn remove_path(&mut self, path: &Path) {
1163        let mut new_entries;
1164        let removed_entries;
1165        {
1166            let mut cursor = self.entries_by_path.cursor::<TraversalProgress>();
1167            new_entries = cursor.slice(&TraversalTarget::Path(path), Bias::Left, &());
1168            removed_entries = cursor.slice(&TraversalTarget::PathSuccessor(path), Bias::Left, &());
1169            new_entries.push_tree(cursor.suffix(&()), &());
1170        }
1171        self.entries_by_path = new_entries;
1172
1173        let mut entries_by_id_edits = Vec::new();
1174        for entry in removed_entries.cursor::<()>() {
1175            let removed_entry_id = self
1176                .removed_entry_ids
1177                .entry(entry.inode)
1178                .or_insert(entry.id);
1179            *removed_entry_id = cmp::max(*removed_entry_id, entry.id);
1180            entries_by_id_edits.push(Edit::Remove(entry.id));
1181        }
1182        self.entries_by_id.edit(entries_by_id_edits, &());
1183
1184        if path.file_name() == Some(&GITIGNORE) {
1185            if let Some((_, scan_id)) = self.ignores.get_mut(path.parent().unwrap()) {
1186                *scan_id = self.scan_id;
1187            }
1188        }
1189    }
1190
1191    fn ignore_stack_for_path(&self, path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
1192        let mut new_ignores = Vec::new();
1193        for ancestor in path.ancestors().skip(1) {
1194            if let Some((ignore, _)) = self.ignores.get(ancestor) {
1195                new_ignores.push((ancestor, Some(ignore.clone())));
1196            } else {
1197                new_ignores.push((ancestor, None));
1198            }
1199        }
1200
1201        let mut ignore_stack = IgnoreStack::none();
1202        for (parent_path, ignore) in new_ignores.into_iter().rev() {
1203            if ignore_stack.is_path_ignored(&parent_path, true) {
1204                ignore_stack = IgnoreStack::all();
1205                break;
1206            } else if let Some(ignore) = ignore {
1207                ignore_stack = ignore_stack.append(Arc::from(parent_path), ignore);
1208            }
1209        }
1210
1211        if ignore_stack.is_path_ignored(path, is_dir) {
1212            ignore_stack = IgnoreStack::all();
1213        }
1214
1215        ignore_stack
1216    }
1217}
1218
1219fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
1220    let contents = smol::block_on(fs.load(&abs_path))?;
1221    let parent = abs_path.parent().unwrap_or(Path::new("/"));
1222    let mut builder = GitignoreBuilder::new(parent);
1223    for line in contents.lines() {
1224        builder.add_line(Some(abs_path.into()), line)?;
1225    }
1226    Ok(builder.build()?)
1227}
1228
1229impl WorktreeId {
1230    pub fn from_usize(handle_id: usize) -> Self {
1231        Self(handle_id)
1232    }
1233
1234    pub(crate) fn from_proto(id: u64) -> Self {
1235        Self(id as usize)
1236    }
1237
1238    pub fn to_proto(&self) -> u64 {
1239        self.0 as u64
1240    }
1241
1242    pub fn to_usize(&self) -> usize {
1243        self.0
1244    }
1245}
1246
1247impl fmt::Display for WorktreeId {
1248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1249        self.0.fmt(f)
1250    }
1251}
1252
1253impl Deref for Worktree {
1254    type Target = Snapshot;
1255
1256    fn deref(&self) -> &Self::Target {
1257        match self {
1258            Worktree::Local(worktree) => &worktree.snapshot,
1259            Worktree::Remote(worktree) => &worktree.snapshot,
1260        }
1261    }
1262}
1263
1264impl Deref for LocalWorktree {
1265    type Target = LocalSnapshot;
1266
1267    fn deref(&self) -> &Self::Target {
1268        &self.snapshot
1269    }
1270}
1271
1272impl Deref for RemoteWorktree {
1273    type Target = Snapshot;
1274
1275    fn deref(&self) -> &Self::Target {
1276        &self.snapshot
1277    }
1278}
1279
1280impl fmt::Debug for LocalWorktree {
1281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1282        self.snapshot.fmt(f)
1283    }
1284}
1285
1286impl fmt::Debug for Snapshot {
1287    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1288        for entry in self.entries_by_path.cursor::<()>() {
1289            for _ in entry.path.ancestors().skip(1) {
1290                write!(f, " ")?;
1291            }
1292            writeln!(f, "{:?} (inode: {})", entry.path, entry.inode)?;
1293        }
1294        Ok(())
1295    }
1296}
1297
1298#[derive(Clone, PartialEq)]
1299pub struct File {
1300    pub worktree: ModelHandle<Worktree>,
1301    pub path: Arc<Path>,
1302    pub mtime: SystemTime,
1303    pub(crate) entry_id: Option<usize>,
1304    pub(crate) is_local: bool,
1305}
1306
1307impl language::File for File {
1308    fn as_local(&self) -> Option<&dyn language::LocalFile> {
1309        if self.is_local {
1310            Some(self)
1311        } else {
1312            None
1313        }
1314    }
1315
1316    fn mtime(&self) -> SystemTime {
1317        self.mtime
1318    }
1319
1320    fn path(&self) -> &Arc<Path> {
1321        &self.path
1322    }
1323
1324    fn full_path(&self, cx: &AppContext) -> PathBuf {
1325        let mut full_path = PathBuf::new();
1326        full_path.push(self.worktree.read(cx).root_name());
1327        full_path.push(&self.path);
1328        full_path
1329    }
1330
1331    /// Returns the last component of this handle's absolute path. If this handle refers to the root
1332    /// of its worktree, then this method will return the name of the worktree itself.
1333    fn file_name(&self, cx: &AppContext) -> OsString {
1334        self.path
1335            .file_name()
1336            .map(|name| name.into())
1337            .unwrap_or_else(|| OsString::from(&self.worktree.read(cx).root_name))
1338    }
1339
1340    fn is_deleted(&self) -> bool {
1341        self.entry_id.is_none()
1342    }
1343
1344    fn save(
1345        &self,
1346        buffer_id: u64,
1347        text: Rope,
1348        version: clock::Global,
1349        cx: &mut MutableAppContext,
1350    ) -> Task<Result<(clock::Global, SystemTime)>> {
1351        self.worktree.update(cx, |worktree, cx| match worktree {
1352            Worktree::Local(worktree) => {
1353                let rpc = worktree.client.clone();
1354                let project_id = worktree.share.as_ref().map(|share| share.project_id);
1355                let save = worktree.save(self.path.clone(), text, cx);
1356                cx.background().spawn(async move {
1357                    let entry = save.await?;
1358                    if let Some(project_id) = project_id {
1359                        rpc.send(proto::BufferSaved {
1360                            project_id,
1361                            buffer_id,
1362                            version: (&version).into(),
1363                            mtime: Some(entry.mtime.into()),
1364                        })?;
1365                    }
1366                    Ok((version, entry.mtime))
1367                })
1368            }
1369            Worktree::Remote(worktree) => {
1370                let rpc = worktree.client.clone();
1371                let project_id = worktree.project_id;
1372                cx.foreground().spawn(async move {
1373                    let response = rpc
1374                        .request(proto::SaveBuffer {
1375                            project_id,
1376                            buffer_id,
1377                        })
1378                        .await?;
1379                    let version = response.version.try_into()?;
1380                    let mtime = response
1381                        .mtime
1382                        .ok_or_else(|| anyhow!("missing mtime"))?
1383                        .into();
1384                    Ok((version, mtime))
1385                })
1386            }
1387        })
1388    }
1389
1390    fn format_remote(
1391        &self,
1392        buffer_id: u64,
1393        cx: &mut MutableAppContext,
1394    ) -> Option<Task<Result<()>>> {
1395        let worktree = self.worktree.read(cx);
1396        let worktree = worktree.as_remote()?;
1397        let rpc = worktree.client.clone();
1398        let project_id = worktree.project_id;
1399        Some(cx.foreground().spawn(async move {
1400            rpc.request(proto::FormatBuffer {
1401                project_id,
1402                buffer_id,
1403            })
1404            .await?;
1405            Ok(())
1406        }))
1407    }
1408
1409    fn completions(
1410        &self,
1411        buffer_id: u64,
1412        position: Anchor,
1413        language: Option<Arc<Language>>,
1414        cx: &mut MutableAppContext,
1415    ) -> Task<Result<Vec<Completion<Anchor>>>> {
1416        let worktree = self.worktree.read(cx);
1417        let worktree = if let Some(worktree) = worktree.as_remote() {
1418            worktree
1419        } else {
1420            return Task::ready(Err(anyhow!(
1421                "remote completions requested on a local worktree"
1422            )));
1423        };
1424        let rpc = worktree.client.clone();
1425        let project_id = worktree.project_id;
1426        cx.foreground().spawn(async move {
1427            let response = rpc
1428                .request(proto::GetCompletions {
1429                    project_id,
1430                    buffer_id,
1431                    position: Some(language::proto::serialize_anchor(&position)),
1432                })
1433                .await?;
1434            response
1435                .completions
1436                .into_iter()
1437                .map(|completion| {
1438                    language::proto::deserialize_completion(completion, language.as_ref())
1439                })
1440                .collect()
1441        })
1442    }
1443
1444    fn apply_additional_edits_for_completion(
1445        &self,
1446        buffer_id: u64,
1447        completion: Completion<Anchor>,
1448        cx: &mut MutableAppContext,
1449    ) -> Task<Result<Vec<clock::Local>>> {
1450        let worktree = self.worktree.read(cx);
1451        let worktree = if let Some(worktree) = worktree.as_remote() {
1452            worktree
1453        } else {
1454            return Task::ready(Err(anyhow!(
1455                "remote additional edits application requested on a local worktree"
1456            )));
1457        };
1458        let rpc = worktree.client.clone();
1459        let project_id = worktree.project_id;
1460        cx.foreground().spawn(async move {
1461            let response = rpc
1462                .request(proto::ApplyCompletionAdditionalEdits {
1463                    project_id,
1464                    buffer_id,
1465                    completion: Some(language::proto::serialize_completion(&completion)),
1466                })
1467                .await?;
1468
1469            Ok(response
1470                .additional_edits
1471                .into_iter()
1472                .map(language::proto::deserialize_edit_id)
1473                .collect())
1474        })
1475    }
1476
1477    fn code_actions(
1478        &self,
1479        buffer_id: u64,
1480        position: Anchor,
1481        cx: &mut MutableAppContext,
1482    ) -> Task<Result<Vec<language::CodeAction<Anchor>>>> {
1483        let worktree = self.worktree.read(cx);
1484        let worktree = if let Some(worktree) = worktree.as_remote() {
1485            worktree
1486        } else {
1487            return Task::ready(Err(anyhow!(
1488                "remote code actions requested on a local worktree"
1489            )));
1490        };
1491        let rpc = worktree.client.clone();
1492        let project_id = worktree.project_id;
1493        cx.foreground().spawn(async move {
1494            let response = rpc
1495                .request(proto::GetCodeActions {
1496                    project_id,
1497                    buffer_id,
1498                    position: Some(language::proto::serialize_anchor(&position)),
1499                })
1500                .await?;
1501            response
1502                .actions
1503                .into_iter()
1504                .map(language::proto::deserialize_code_action)
1505                .collect()
1506        })
1507    }
1508
1509    fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext) {
1510        self.worktree.update(cx, |worktree, cx| {
1511            worktree.send_buffer_update(buffer_id, operation, cx);
1512        });
1513    }
1514
1515    fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext) {
1516        self.worktree.update(cx, |worktree, _| {
1517            if let Worktree::Remote(worktree) = worktree {
1518                worktree
1519                    .client
1520                    .send(proto::CloseBuffer {
1521                        project_id: worktree.project_id,
1522                        buffer_id,
1523                    })
1524                    .log_err();
1525            }
1526        });
1527    }
1528
1529    fn as_any(&self) -> &dyn Any {
1530        self
1531    }
1532
1533    fn to_proto(&self) -> rpc::proto::File {
1534        rpc::proto::File {
1535            worktree_id: self.worktree.id() as u64,
1536            entry_id: self.entry_id.map(|entry_id| entry_id as u64),
1537            path: self.path.to_string_lossy().into(),
1538            mtime: Some(self.mtime.into()),
1539        }
1540    }
1541}
1542
1543impl language::LocalFile for File {
1544    fn abs_path(&self, cx: &AppContext) -> PathBuf {
1545        self.worktree
1546            .read(cx)
1547            .as_local()
1548            .unwrap()
1549            .abs_path
1550            .join(&self.path)
1551    }
1552
1553    fn load(&self, cx: &AppContext) -> Task<Result<String>> {
1554        let worktree = self.worktree.read(cx).as_local().unwrap();
1555        let abs_path = worktree.absolutize(&self.path);
1556        let fs = worktree.fs.clone();
1557        cx.background()
1558            .spawn(async move { fs.load(&abs_path).await })
1559    }
1560
1561    fn buffer_reloaded(
1562        &self,
1563        buffer_id: u64,
1564        version: &clock::Global,
1565        mtime: SystemTime,
1566        cx: &mut MutableAppContext,
1567    ) {
1568        let worktree = self.worktree.read(cx).as_local().unwrap();
1569        if let Some(project_id) = worktree.share.as_ref().map(|share| share.project_id) {
1570            worktree
1571                .client
1572                .send(proto::BufferReloaded {
1573                    project_id,
1574                    buffer_id,
1575                    version: version.into(),
1576                    mtime: Some(mtime.into()),
1577                })
1578                .log_err();
1579        }
1580    }
1581}
1582
1583impl File {
1584    pub fn from_proto(
1585        proto: rpc::proto::File,
1586        worktree: ModelHandle<Worktree>,
1587        cx: &AppContext,
1588    ) -> Result<Self> {
1589        let worktree_id = worktree
1590            .read(cx)
1591            .as_remote()
1592            .ok_or_else(|| anyhow!("not remote"))?
1593            .id();
1594
1595        if worktree_id.to_proto() != proto.worktree_id {
1596            return Err(anyhow!("worktree id does not match file"));
1597        }
1598
1599        Ok(Self {
1600            worktree,
1601            path: Path::new(&proto.path).into(),
1602            mtime: proto.mtime.ok_or_else(|| anyhow!("no timestamp"))?.into(),
1603            entry_id: proto.entry_id.map(|entry_id| entry_id as usize),
1604            is_local: false,
1605        })
1606    }
1607
1608    pub fn from_dyn(file: Option<&dyn language::File>) -> Option<&Self> {
1609        file.and_then(|f| f.as_any().downcast_ref())
1610    }
1611
1612    pub fn worktree_id(&self, cx: &AppContext) -> WorktreeId {
1613        self.worktree.read(cx).id()
1614    }
1615}
1616
1617#[derive(Clone, Debug)]
1618pub struct Entry {
1619    pub id: usize,
1620    pub kind: EntryKind,
1621    pub path: Arc<Path>,
1622    pub inode: u64,
1623    pub mtime: SystemTime,
1624    pub is_symlink: bool,
1625    pub is_ignored: bool,
1626}
1627
1628#[derive(Clone, Debug)]
1629pub enum EntryKind {
1630    PendingDir,
1631    Dir,
1632    File(CharBag),
1633}
1634
1635impl Entry {
1636    fn new(
1637        path: Arc<Path>,
1638        metadata: &fs::Metadata,
1639        next_entry_id: &AtomicUsize,
1640        root_char_bag: CharBag,
1641    ) -> Self {
1642        Self {
1643            id: next_entry_id.fetch_add(1, SeqCst),
1644            kind: if metadata.is_dir {
1645                EntryKind::PendingDir
1646            } else {
1647                EntryKind::File(char_bag_for_path(root_char_bag, &path))
1648            },
1649            path,
1650            inode: metadata.inode,
1651            mtime: metadata.mtime,
1652            is_symlink: metadata.is_symlink,
1653            is_ignored: false,
1654        }
1655    }
1656
1657    pub fn is_dir(&self) -> bool {
1658        matches!(self.kind, EntryKind::Dir | EntryKind::PendingDir)
1659    }
1660
1661    pub fn is_file(&self) -> bool {
1662        matches!(self.kind, EntryKind::File(_))
1663    }
1664}
1665
1666impl sum_tree::Item for Entry {
1667    type Summary = EntrySummary;
1668
1669    fn summary(&self) -> Self::Summary {
1670        let visible_count = if self.is_ignored { 0 } else { 1 };
1671        let file_count;
1672        let visible_file_count;
1673        if self.is_file() {
1674            file_count = 1;
1675            visible_file_count = visible_count;
1676        } else {
1677            file_count = 0;
1678            visible_file_count = 0;
1679        }
1680
1681        EntrySummary {
1682            max_path: self.path.clone(),
1683            count: 1,
1684            visible_count,
1685            file_count,
1686            visible_file_count,
1687        }
1688    }
1689}
1690
1691impl sum_tree::KeyedItem for Entry {
1692    type Key = PathKey;
1693
1694    fn key(&self) -> Self::Key {
1695        PathKey(self.path.clone())
1696    }
1697}
1698
1699#[derive(Clone, Debug)]
1700pub struct EntrySummary {
1701    max_path: Arc<Path>,
1702    count: usize,
1703    visible_count: usize,
1704    file_count: usize,
1705    visible_file_count: usize,
1706}
1707
1708impl Default for EntrySummary {
1709    fn default() -> Self {
1710        Self {
1711            max_path: Arc::from(Path::new("")),
1712            count: 0,
1713            visible_count: 0,
1714            file_count: 0,
1715            visible_file_count: 0,
1716        }
1717    }
1718}
1719
1720impl sum_tree::Summary for EntrySummary {
1721    type Context = ();
1722
1723    fn add_summary(&mut self, rhs: &Self, _: &()) {
1724        self.max_path = rhs.max_path.clone();
1725        self.visible_count += rhs.visible_count;
1726        self.file_count += rhs.file_count;
1727        self.visible_file_count += rhs.visible_file_count;
1728    }
1729}
1730
1731#[derive(Clone, Debug)]
1732struct PathEntry {
1733    id: usize,
1734    path: Arc<Path>,
1735    is_ignored: bool,
1736    scan_id: usize,
1737}
1738
1739impl sum_tree::Item for PathEntry {
1740    type Summary = PathEntrySummary;
1741
1742    fn summary(&self) -> Self::Summary {
1743        PathEntrySummary { max_id: self.id }
1744    }
1745}
1746
1747impl sum_tree::KeyedItem for PathEntry {
1748    type Key = usize;
1749
1750    fn key(&self) -> Self::Key {
1751        self.id
1752    }
1753}
1754
1755#[derive(Clone, Debug, Default)]
1756struct PathEntrySummary {
1757    max_id: usize,
1758}
1759
1760impl sum_tree::Summary for PathEntrySummary {
1761    type Context = ();
1762
1763    fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
1764        self.max_id = summary.max_id;
1765    }
1766}
1767
1768impl<'a> sum_tree::Dimension<'a, PathEntrySummary> for usize {
1769    fn add_summary(&mut self, summary: &'a PathEntrySummary, _: &()) {
1770        *self = summary.max_id;
1771    }
1772}
1773
1774#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
1775pub struct PathKey(Arc<Path>);
1776
1777impl Default for PathKey {
1778    fn default() -> Self {
1779        Self(Path::new("").into())
1780    }
1781}
1782
1783impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
1784    fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
1785        self.0 = summary.max_path.clone();
1786    }
1787}
1788
1789struct BackgroundScanner {
1790    fs: Arc<dyn Fs>,
1791    snapshot: Arc<Mutex<LocalSnapshot>>,
1792    notify: Sender<ScanState>,
1793    executor: Arc<executor::Background>,
1794}
1795
1796impl BackgroundScanner {
1797    fn new(
1798        snapshot: Arc<Mutex<LocalSnapshot>>,
1799        notify: Sender<ScanState>,
1800        fs: Arc<dyn Fs>,
1801        executor: Arc<executor::Background>,
1802    ) -> Self {
1803        Self {
1804            fs,
1805            snapshot,
1806            notify,
1807            executor,
1808        }
1809    }
1810
1811    fn abs_path(&self) -> Arc<Path> {
1812        self.snapshot.lock().abs_path.clone()
1813    }
1814
1815    fn snapshot(&self) -> LocalSnapshot {
1816        self.snapshot.lock().clone()
1817    }
1818
1819    async fn run(mut self, events_rx: impl Stream<Item = Vec<fsevent::Event>>) {
1820        if self.notify.send(ScanState::Scanning).await.is_err() {
1821            return;
1822        }
1823
1824        if let Err(err) = self.scan_dirs().await {
1825            if self
1826                .notify
1827                .send(ScanState::Err(Arc::new(err)))
1828                .await
1829                .is_err()
1830            {
1831                return;
1832            }
1833        }
1834
1835        if self.notify.send(ScanState::Idle).await.is_err() {
1836            return;
1837        }
1838
1839        futures::pin_mut!(events_rx);
1840        while let Some(events) = events_rx.next().await {
1841            if self.notify.send(ScanState::Scanning).await.is_err() {
1842                break;
1843            }
1844
1845            if !self.process_events(events).await {
1846                break;
1847            }
1848
1849            if self.notify.send(ScanState::Idle).await.is_err() {
1850                break;
1851            }
1852        }
1853    }
1854
1855    async fn scan_dirs(&mut self) -> Result<()> {
1856        let root_char_bag;
1857        let next_entry_id;
1858        let is_dir;
1859        {
1860            let snapshot = self.snapshot.lock();
1861            root_char_bag = snapshot.root_char_bag;
1862            next_entry_id = snapshot.next_entry_id.clone();
1863            is_dir = snapshot.root_entry().map_or(false, |e| e.is_dir())
1864        };
1865
1866        if is_dir {
1867            let path: Arc<Path> = Arc::from(Path::new(""));
1868            let abs_path = self.abs_path();
1869            let (tx, rx) = channel::unbounded();
1870            tx.send(ScanJob {
1871                abs_path: abs_path.to_path_buf(),
1872                path,
1873                ignore_stack: IgnoreStack::none(),
1874                scan_queue: tx.clone(),
1875            })
1876            .await
1877            .unwrap();
1878            drop(tx);
1879
1880            self.executor
1881                .scoped(|scope| {
1882                    for _ in 0..self.executor.num_cpus() {
1883                        scope.spawn(async {
1884                            while let Ok(job) = rx.recv().await {
1885                                if let Err(err) = self
1886                                    .scan_dir(root_char_bag, next_entry_id.clone(), &job)
1887                                    .await
1888                                {
1889                                    log::error!("error scanning {:?}: {}", job.abs_path, err);
1890                                }
1891                            }
1892                        });
1893                    }
1894                })
1895                .await;
1896        }
1897
1898        Ok(())
1899    }
1900
1901    async fn scan_dir(
1902        &self,
1903        root_char_bag: CharBag,
1904        next_entry_id: Arc<AtomicUsize>,
1905        job: &ScanJob,
1906    ) -> Result<()> {
1907        let mut new_entries: Vec<Entry> = Vec::new();
1908        let mut new_jobs: Vec<ScanJob> = Vec::new();
1909        let mut ignore_stack = job.ignore_stack.clone();
1910        let mut new_ignore = None;
1911
1912        let mut child_paths = self.fs.read_dir(&job.abs_path).await?;
1913        while let Some(child_abs_path) = child_paths.next().await {
1914            let child_abs_path = match child_abs_path {
1915                Ok(child_abs_path) => child_abs_path,
1916                Err(error) => {
1917                    log::error!("error processing entry {:?}", error);
1918                    continue;
1919                }
1920            };
1921            let child_name = child_abs_path.file_name().unwrap();
1922            let child_path: Arc<Path> = job.path.join(child_name).into();
1923            let child_metadata = match self.fs.metadata(&child_abs_path).await? {
1924                Some(metadata) => metadata,
1925                None => continue,
1926            };
1927
1928            // If we find a .gitignore, add it to the stack of ignores used to determine which paths are ignored
1929            if child_name == *GITIGNORE {
1930                match build_gitignore(&child_abs_path, self.fs.as_ref()) {
1931                    Ok(ignore) => {
1932                        let ignore = Arc::new(ignore);
1933                        ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
1934                        new_ignore = Some(ignore);
1935                    }
1936                    Err(error) => {
1937                        log::error!(
1938                            "error loading .gitignore file {:?} - {:?}",
1939                            child_name,
1940                            error
1941                        );
1942                    }
1943                }
1944
1945                // Update ignore status of any child entries we've already processed to reflect the
1946                // ignore file in the current directory. Because `.gitignore` starts with a `.`,
1947                // there should rarely be too numerous. Update the ignore stack associated with any
1948                // new jobs as well.
1949                let mut new_jobs = new_jobs.iter_mut();
1950                for entry in &mut new_entries {
1951                    entry.is_ignored = ignore_stack.is_path_ignored(&entry.path, entry.is_dir());
1952                    if entry.is_dir() {
1953                        new_jobs.next().unwrap().ignore_stack = if entry.is_ignored {
1954                            IgnoreStack::all()
1955                        } else {
1956                            ignore_stack.clone()
1957                        };
1958                    }
1959                }
1960            }
1961
1962            let mut child_entry = Entry::new(
1963                child_path.clone(),
1964                &child_metadata,
1965                &next_entry_id,
1966                root_char_bag,
1967            );
1968
1969            if child_metadata.is_dir {
1970                let is_ignored = ignore_stack.is_path_ignored(&child_path, true);
1971                child_entry.is_ignored = is_ignored;
1972                new_entries.push(child_entry);
1973                new_jobs.push(ScanJob {
1974                    abs_path: child_abs_path,
1975                    path: child_path,
1976                    ignore_stack: if is_ignored {
1977                        IgnoreStack::all()
1978                    } else {
1979                        ignore_stack.clone()
1980                    },
1981                    scan_queue: job.scan_queue.clone(),
1982                });
1983            } else {
1984                child_entry.is_ignored = ignore_stack.is_path_ignored(&child_path, false);
1985                new_entries.push(child_entry);
1986            };
1987        }
1988
1989        self.snapshot
1990            .lock()
1991            .populate_dir(job.path.clone(), new_entries, new_ignore);
1992        for new_job in new_jobs {
1993            job.scan_queue.send(new_job).await.unwrap();
1994        }
1995
1996        Ok(())
1997    }
1998
1999    async fn process_events(&mut self, mut events: Vec<fsevent::Event>) -> bool {
2000        let mut snapshot = self.snapshot();
2001        snapshot.scan_id += 1;
2002
2003        let root_abs_path = if let Ok(abs_path) = self.fs.canonicalize(&snapshot.abs_path).await {
2004            abs_path
2005        } else {
2006            return false;
2007        };
2008        let root_char_bag = snapshot.root_char_bag;
2009        let next_entry_id = snapshot.next_entry_id.clone();
2010
2011        events.sort_unstable_by(|a, b| a.path.cmp(&b.path));
2012        events.dedup_by(|a, b| a.path.starts_with(&b.path));
2013
2014        for event in &events {
2015            match event.path.strip_prefix(&root_abs_path) {
2016                Ok(path) => snapshot.remove_path(&path),
2017                Err(_) => {
2018                    log::error!(
2019                        "unexpected event {:?} for root path {:?}",
2020                        event.path,
2021                        root_abs_path
2022                    );
2023                    continue;
2024                }
2025            }
2026        }
2027
2028        let (scan_queue_tx, scan_queue_rx) = channel::unbounded();
2029        for event in events {
2030            let path: Arc<Path> = match event.path.strip_prefix(&root_abs_path) {
2031                Ok(path) => Arc::from(path.to_path_buf()),
2032                Err(_) => {
2033                    log::error!(
2034                        "unexpected event {:?} for root path {:?}",
2035                        event.path,
2036                        root_abs_path
2037                    );
2038                    continue;
2039                }
2040            };
2041
2042            match self.fs.metadata(&event.path).await {
2043                Ok(Some(metadata)) => {
2044                    let ignore_stack = snapshot.ignore_stack_for_path(&path, metadata.is_dir);
2045                    let mut fs_entry = Entry::new(
2046                        path.clone(),
2047                        &metadata,
2048                        snapshot.next_entry_id.as_ref(),
2049                        snapshot.root_char_bag,
2050                    );
2051                    fs_entry.is_ignored = ignore_stack.is_all();
2052                    snapshot.insert_entry(fs_entry, self.fs.as_ref());
2053                    if metadata.is_dir {
2054                        scan_queue_tx
2055                            .send(ScanJob {
2056                                abs_path: event.path,
2057                                path,
2058                                ignore_stack,
2059                                scan_queue: scan_queue_tx.clone(),
2060                            })
2061                            .await
2062                            .unwrap();
2063                    }
2064                }
2065                Ok(None) => {}
2066                Err(err) => {
2067                    // TODO - create a special 'error' entry in the entries tree to mark this
2068                    log::error!("error reading file on event {:?}", err);
2069                }
2070            }
2071        }
2072
2073        *self.snapshot.lock() = snapshot;
2074
2075        // Scan any directories that were created as part of this event batch.
2076        drop(scan_queue_tx);
2077        self.executor
2078            .scoped(|scope| {
2079                for _ in 0..self.executor.num_cpus() {
2080                    scope.spawn(async {
2081                        while let Ok(job) = scan_queue_rx.recv().await {
2082                            if let Err(err) = self
2083                                .scan_dir(root_char_bag, next_entry_id.clone(), &job)
2084                                .await
2085                            {
2086                                log::error!("error scanning {:?}: {}", job.abs_path, err);
2087                            }
2088                        }
2089                    });
2090                }
2091            })
2092            .await;
2093
2094        // Attempt to detect renames only over a single batch of file-system events.
2095        self.snapshot.lock().removed_entry_ids.clear();
2096
2097        self.update_ignore_statuses().await;
2098        true
2099    }
2100
2101    async fn update_ignore_statuses(&self) {
2102        let mut snapshot = self.snapshot();
2103
2104        let mut ignores_to_update = Vec::new();
2105        let mut ignores_to_delete = Vec::new();
2106        for (parent_path, (_, scan_id)) in &snapshot.ignores {
2107            if *scan_id == snapshot.scan_id && snapshot.entry_for_path(parent_path).is_some() {
2108                ignores_to_update.push(parent_path.clone());
2109            }
2110
2111            let ignore_path = parent_path.join(&*GITIGNORE);
2112            if snapshot.entry_for_path(ignore_path).is_none() {
2113                ignores_to_delete.push(parent_path.clone());
2114            }
2115        }
2116
2117        for parent_path in ignores_to_delete {
2118            snapshot.ignores.remove(&parent_path);
2119            self.snapshot.lock().ignores.remove(&parent_path);
2120        }
2121
2122        let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded();
2123        ignores_to_update.sort_unstable();
2124        let mut ignores_to_update = ignores_to_update.into_iter().peekable();
2125        while let Some(parent_path) = ignores_to_update.next() {
2126            while ignores_to_update
2127                .peek()
2128                .map_or(false, |p| p.starts_with(&parent_path))
2129            {
2130                ignores_to_update.next().unwrap();
2131            }
2132
2133            let ignore_stack = snapshot.ignore_stack_for_path(&parent_path, true);
2134            ignore_queue_tx
2135                .send(UpdateIgnoreStatusJob {
2136                    path: parent_path,
2137                    ignore_stack,
2138                    ignore_queue: ignore_queue_tx.clone(),
2139                })
2140                .await
2141                .unwrap();
2142        }
2143        drop(ignore_queue_tx);
2144
2145        self.executor
2146            .scoped(|scope| {
2147                for _ in 0..self.executor.num_cpus() {
2148                    scope.spawn(async {
2149                        while let Ok(job) = ignore_queue_rx.recv().await {
2150                            self.update_ignore_status(job, &snapshot).await;
2151                        }
2152                    });
2153                }
2154            })
2155            .await;
2156    }
2157
2158    async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) {
2159        let mut ignore_stack = job.ignore_stack;
2160        if let Some((ignore, _)) = snapshot.ignores.get(&job.path) {
2161            ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
2162        }
2163
2164        let mut entries_by_id_edits = Vec::new();
2165        let mut entries_by_path_edits = Vec::new();
2166        for mut entry in snapshot.child_entries(&job.path).cloned() {
2167            let was_ignored = entry.is_ignored;
2168            entry.is_ignored = ignore_stack.is_path_ignored(&entry.path, entry.is_dir());
2169            if entry.is_dir() {
2170                let child_ignore_stack = if entry.is_ignored {
2171                    IgnoreStack::all()
2172                } else {
2173                    ignore_stack.clone()
2174                };
2175                job.ignore_queue
2176                    .send(UpdateIgnoreStatusJob {
2177                        path: entry.path.clone(),
2178                        ignore_stack: child_ignore_stack,
2179                        ignore_queue: job.ignore_queue.clone(),
2180                    })
2181                    .await
2182                    .unwrap();
2183            }
2184
2185            if entry.is_ignored != was_ignored {
2186                let mut path_entry = snapshot.entries_by_id.get(&entry.id, &()).unwrap().clone();
2187                path_entry.scan_id = snapshot.scan_id;
2188                path_entry.is_ignored = entry.is_ignored;
2189                entries_by_id_edits.push(Edit::Insert(path_entry));
2190                entries_by_path_edits.push(Edit::Insert(entry));
2191            }
2192        }
2193
2194        let mut snapshot = self.snapshot.lock();
2195        snapshot.entries_by_path.edit(entries_by_path_edits, &());
2196        snapshot.entries_by_id.edit(entries_by_id_edits, &());
2197    }
2198}
2199
2200async fn refresh_entry(
2201    fs: &dyn Fs,
2202    snapshot: &Mutex<LocalSnapshot>,
2203    path: Arc<Path>,
2204    abs_path: &Path,
2205) -> Result<Entry> {
2206    let root_char_bag;
2207    let next_entry_id;
2208    {
2209        let snapshot = snapshot.lock();
2210        root_char_bag = snapshot.root_char_bag;
2211        next_entry_id = snapshot.next_entry_id.clone();
2212    }
2213    let entry = Entry::new(
2214        path,
2215        &fs.metadata(abs_path)
2216            .await?
2217            .ok_or_else(|| anyhow!("could not read saved file metadata"))?,
2218        &next_entry_id,
2219        root_char_bag,
2220    );
2221    Ok(snapshot.lock().insert_entry(entry, fs))
2222}
2223
2224fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
2225    let mut result = root_char_bag;
2226    result.extend(
2227        path.to_string_lossy()
2228            .chars()
2229            .map(|c| c.to_ascii_lowercase()),
2230    );
2231    result
2232}
2233
2234struct ScanJob {
2235    abs_path: PathBuf,
2236    path: Arc<Path>,
2237    ignore_stack: Arc<IgnoreStack>,
2238    scan_queue: Sender<ScanJob>,
2239}
2240
2241struct UpdateIgnoreStatusJob {
2242    path: Arc<Path>,
2243    ignore_stack: Arc<IgnoreStack>,
2244    ignore_queue: Sender<UpdateIgnoreStatusJob>,
2245}
2246
2247pub trait WorktreeHandle {
2248    #[cfg(test)]
2249    fn flush_fs_events<'a>(
2250        &self,
2251        cx: &'a gpui::TestAppContext,
2252    ) -> futures::future::LocalBoxFuture<'a, ()>;
2253}
2254
2255impl WorktreeHandle for ModelHandle<Worktree> {
2256    // When the worktree's FS event stream sometimes delivers "redundant" events for FS changes that
2257    // occurred before the worktree was constructed. These events can cause the worktree to perfrom
2258    // extra directory scans, and emit extra scan-state notifications.
2259    //
2260    // This function mutates the worktree's directory and waits for those mutations to be picked up,
2261    // to ensure that all redundant FS events have already been processed.
2262    #[cfg(test)]
2263    fn flush_fs_events<'a>(
2264        &self,
2265        cx: &'a gpui::TestAppContext,
2266    ) -> futures::future::LocalBoxFuture<'a, ()> {
2267        use smol::future::FutureExt;
2268
2269        let filename = "fs-event-sentinel";
2270        let root_path = cx.read(|cx| self.read(cx).as_local().unwrap().abs_path().clone());
2271        let tree = self.clone();
2272        async move {
2273            std::fs::write(root_path.join(filename), "").unwrap();
2274            tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_some())
2275                .await;
2276
2277            std::fs::remove_file(root_path.join(filename)).unwrap();
2278            tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_none())
2279                .await;
2280
2281            cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2282                .await;
2283        }
2284        .boxed_local()
2285    }
2286}
2287
2288#[derive(Clone, Debug)]
2289struct TraversalProgress<'a> {
2290    max_path: &'a Path,
2291    count: usize,
2292    visible_count: usize,
2293    file_count: usize,
2294    visible_file_count: usize,
2295}
2296
2297impl<'a> TraversalProgress<'a> {
2298    fn count(&self, include_dirs: bool, include_ignored: bool) -> usize {
2299        match (include_ignored, include_dirs) {
2300            (true, true) => self.count,
2301            (true, false) => self.file_count,
2302            (false, true) => self.visible_count,
2303            (false, false) => self.visible_file_count,
2304        }
2305    }
2306}
2307
2308impl<'a> sum_tree::Dimension<'a, EntrySummary> for TraversalProgress<'a> {
2309    fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
2310        self.max_path = summary.max_path.as_ref();
2311        self.count += summary.count;
2312        self.visible_count += summary.visible_count;
2313        self.file_count += summary.file_count;
2314        self.visible_file_count += summary.visible_file_count;
2315    }
2316}
2317
2318impl<'a> Default for TraversalProgress<'a> {
2319    fn default() -> Self {
2320        Self {
2321            max_path: Path::new(""),
2322            count: 0,
2323            visible_count: 0,
2324            file_count: 0,
2325            visible_file_count: 0,
2326        }
2327    }
2328}
2329
2330pub struct Traversal<'a> {
2331    cursor: sum_tree::Cursor<'a, Entry, TraversalProgress<'a>>,
2332    include_ignored: bool,
2333    include_dirs: bool,
2334}
2335
2336impl<'a> Traversal<'a> {
2337    pub fn advance(&mut self) -> bool {
2338        self.advance_to_offset(self.offset() + 1)
2339    }
2340
2341    pub fn advance_to_offset(&mut self, offset: usize) -> bool {
2342        self.cursor.seek_forward(
2343            &TraversalTarget::Count {
2344                count: offset,
2345                include_dirs: self.include_dirs,
2346                include_ignored: self.include_ignored,
2347            },
2348            Bias::Right,
2349            &(),
2350        )
2351    }
2352
2353    pub fn advance_to_sibling(&mut self) -> bool {
2354        while let Some(entry) = self.cursor.item() {
2355            self.cursor.seek_forward(
2356                &TraversalTarget::PathSuccessor(&entry.path),
2357                Bias::Left,
2358                &(),
2359            );
2360            if let Some(entry) = self.cursor.item() {
2361                if (self.include_dirs || !entry.is_dir())
2362                    && (self.include_ignored || !entry.is_ignored)
2363                {
2364                    return true;
2365                }
2366            }
2367        }
2368        false
2369    }
2370
2371    pub fn entry(&self) -> Option<&'a Entry> {
2372        self.cursor.item()
2373    }
2374
2375    pub fn offset(&self) -> usize {
2376        self.cursor
2377            .start()
2378            .count(self.include_dirs, self.include_ignored)
2379    }
2380}
2381
2382impl<'a> Iterator for Traversal<'a> {
2383    type Item = &'a Entry;
2384
2385    fn next(&mut self) -> Option<Self::Item> {
2386        if let Some(item) = self.entry() {
2387            self.advance();
2388            Some(item)
2389        } else {
2390            None
2391        }
2392    }
2393}
2394
2395#[derive(Debug)]
2396enum TraversalTarget<'a> {
2397    Path(&'a Path),
2398    PathSuccessor(&'a Path),
2399    Count {
2400        count: usize,
2401        include_ignored: bool,
2402        include_dirs: bool,
2403    },
2404}
2405
2406impl<'a, 'b> SeekTarget<'a, EntrySummary, TraversalProgress<'a>> for TraversalTarget<'b> {
2407    fn cmp(&self, cursor_location: &TraversalProgress<'a>, _: &()) -> Ordering {
2408        match self {
2409            TraversalTarget::Path(path) => path.cmp(&cursor_location.max_path),
2410            TraversalTarget::PathSuccessor(path) => {
2411                if !cursor_location.max_path.starts_with(path) {
2412                    Ordering::Equal
2413                } else {
2414                    Ordering::Greater
2415                }
2416            }
2417            TraversalTarget::Count {
2418                count,
2419                include_dirs,
2420                include_ignored,
2421            } => Ord::cmp(
2422                count,
2423                &cursor_location.count(*include_dirs, *include_ignored),
2424            ),
2425        }
2426    }
2427}
2428
2429struct ChildEntriesIter<'a> {
2430    parent_path: &'a Path,
2431    traversal: Traversal<'a>,
2432}
2433
2434impl<'a> Iterator for ChildEntriesIter<'a> {
2435    type Item = &'a Entry;
2436
2437    fn next(&mut self) -> Option<Self::Item> {
2438        if let Some(item) = self.traversal.entry() {
2439            if item.path.starts_with(&self.parent_path) {
2440                self.traversal.advance_to_sibling();
2441                return Some(item);
2442            }
2443        }
2444        None
2445    }
2446}
2447
2448impl<'a> From<&'a Entry> for proto::Entry {
2449    fn from(entry: &'a Entry) -> Self {
2450        Self {
2451            id: entry.id as u64,
2452            is_dir: entry.is_dir(),
2453            path: entry.path.to_string_lossy().to_string(),
2454            inode: entry.inode,
2455            mtime: Some(entry.mtime.into()),
2456            is_symlink: entry.is_symlink,
2457            is_ignored: entry.is_ignored,
2458        }
2459    }
2460}
2461
2462impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
2463    type Error = anyhow::Error;
2464
2465    fn try_from((root_char_bag, entry): (&'a CharBag, proto::Entry)) -> Result<Self> {
2466        if let Some(mtime) = entry.mtime {
2467            let kind = if entry.is_dir {
2468                EntryKind::Dir
2469            } else {
2470                let mut char_bag = root_char_bag.clone();
2471                char_bag.extend(entry.path.chars().map(|c| c.to_ascii_lowercase()));
2472                EntryKind::File(char_bag)
2473            };
2474            let path: Arc<Path> = Arc::from(Path::new(&entry.path));
2475            Ok(Entry {
2476                id: entry.id as usize,
2477                kind,
2478                path: path.clone(),
2479                inode: entry.inode,
2480                mtime: mtime.into(),
2481                is_symlink: entry.is_symlink,
2482                is_ignored: entry.is_ignored,
2483            })
2484        } else {
2485            Err(anyhow!(
2486                "missing mtime in remote worktree entry {:?}",
2487                entry.path
2488            ))
2489        }
2490    }
2491}
2492
2493#[cfg(test)]
2494mod tests {
2495    use super::*;
2496    use crate::fs::FakeFs;
2497    use anyhow::Result;
2498    use client::test::FakeHttpClient;
2499    use fs::RealFs;
2500    use rand::prelude::*;
2501    use serde_json::json;
2502    use std::{
2503        env,
2504        fmt::Write,
2505        time::{SystemTime, UNIX_EPOCH},
2506    };
2507    use util::test::temp_tree;
2508
2509    #[gpui::test]
2510    async fn test_traversal(cx: gpui::TestAppContext) {
2511        let fs = FakeFs::new(cx.background());
2512        fs.insert_tree(
2513            "/root",
2514            json!({
2515               ".gitignore": "a/b\n",
2516               "a": {
2517                   "b": "",
2518                   "c": "",
2519               }
2520            }),
2521        )
2522        .await;
2523
2524        let http_client = FakeHttpClient::with_404_response();
2525        let client = Client::new(http_client);
2526
2527        let tree = Worktree::local(
2528            client,
2529            Arc::from(Path::new("/root")),
2530            false,
2531            Arc::new(fs),
2532            &mut cx.to_async(),
2533        )
2534        .await
2535        .unwrap();
2536        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2537            .await;
2538
2539        tree.read_with(&cx, |tree, _| {
2540            assert_eq!(
2541                tree.entries(false)
2542                    .map(|entry| entry.path.as_ref())
2543                    .collect::<Vec<_>>(),
2544                vec![
2545                    Path::new(""),
2546                    Path::new(".gitignore"),
2547                    Path::new("a"),
2548                    Path::new("a/c"),
2549                ]
2550            );
2551        })
2552    }
2553
2554    #[gpui::test]
2555    async fn test_rescan_with_gitignore(cx: gpui::TestAppContext) {
2556        let dir = temp_tree(json!({
2557            ".git": {},
2558            ".gitignore": "ignored-dir\n",
2559            "tracked-dir": {
2560                "tracked-file1": "tracked contents",
2561            },
2562            "ignored-dir": {
2563                "ignored-file1": "ignored contents",
2564            }
2565        }));
2566
2567        let http_client = FakeHttpClient::with_404_response();
2568        let client = Client::new(http_client.clone());
2569
2570        let tree = Worktree::local(
2571            client,
2572            dir.path(),
2573            false,
2574            Arc::new(RealFs),
2575            &mut cx.to_async(),
2576        )
2577        .await
2578        .unwrap();
2579        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2580            .await;
2581        tree.flush_fs_events(&cx).await;
2582        cx.read(|cx| {
2583            let tree = tree.read(cx);
2584            let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap();
2585            let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap();
2586            assert_eq!(tracked.is_ignored, false);
2587            assert_eq!(ignored.is_ignored, true);
2588        });
2589
2590        std::fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap();
2591        std::fs::write(dir.path().join("ignored-dir/ignored-file2"), "").unwrap();
2592        tree.flush_fs_events(&cx).await;
2593        cx.read(|cx| {
2594            let tree = tree.read(cx);
2595            let dot_git = tree.entry_for_path(".git").unwrap();
2596            let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap();
2597            let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap();
2598            assert_eq!(tracked.is_ignored, false);
2599            assert_eq!(ignored.is_ignored, true);
2600            assert_eq!(dot_git.is_ignored, true);
2601        });
2602    }
2603
2604    #[gpui::test(iterations = 100)]
2605    fn test_random(mut rng: StdRng) {
2606        let operations = env::var("OPERATIONS")
2607            .map(|o| o.parse().unwrap())
2608            .unwrap_or(40);
2609        let initial_entries = env::var("INITIAL_ENTRIES")
2610            .map(|o| o.parse().unwrap())
2611            .unwrap_or(20);
2612
2613        let root_dir = tempdir::TempDir::new("worktree-test").unwrap();
2614        for _ in 0..initial_entries {
2615            randomly_mutate_tree(root_dir.path(), 1.0, &mut rng).unwrap();
2616        }
2617        log::info!("Generated initial tree");
2618
2619        let (notify_tx, _notify_rx) = smol::channel::unbounded();
2620        let fs = Arc::new(RealFs);
2621        let next_entry_id = Arc::new(AtomicUsize::new(0));
2622        let mut initial_snapshot = LocalSnapshot {
2623            abs_path: root_dir.path().into(),
2624            scan_id: 0,
2625            removed_entry_ids: Default::default(),
2626            ignores: Default::default(),
2627            next_entry_id: next_entry_id.clone(),
2628            snapshot: Snapshot {
2629                id: WorktreeId::from_usize(0),
2630                entries_by_path: Default::default(),
2631                entries_by_id: Default::default(),
2632                root_name: Default::default(),
2633                root_char_bag: Default::default(),
2634            },
2635        };
2636        initial_snapshot.insert_entry(
2637            Entry::new(
2638                Path::new("").into(),
2639                &smol::block_on(fs.metadata(root_dir.path()))
2640                    .unwrap()
2641                    .unwrap(),
2642                &next_entry_id,
2643                Default::default(),
2644            ),
2645            fs.as_ref(),
2646        );
2647        let mut scanner = BackgroundScanner::new(
2648            Arc::new(Mutex::new(initial_snapshot.clone())),
2649            notify_tx,
2650            fs.clone(),
2651            Arc::new(gpui::executor::Background::new()),
2652        );
2653        smol::block_on(scanner.scan_dirs()).unwrap();
2654        scanner.snapshot().check_invariants();
2655
2656        let mut events = Vec::new();
2657        let mut snapshots = Vec::new();
2658        let mut mutations_len = operations;
2659        while mutations_len > 1 {
2660            if !events.is_empty() && rng.gen_bool(0.4) {
2661                let len = rng.gen_range(0..=events.len());
2662                let to_deliver = events.drain(0..len).collect::<Vec<_>>();
2663                log::info!("Delivering events: {:#?}", to_deliver);
2664                smol::block_on(scanner.process_events(to_deliver));
2665                scanner.snapshot().check_invariants();
2666            } else {
2667                events.extend(randomly_mutate_tree(root_dir.path(), 0.6, &mut rng).unwrap());
2668                mutations_len -= 1;
2669            }
2670
2671            if rng.gen_bool(0.2) {
2672                snapshots.push(scanner.snapshot());
2673            }
2674        }
2675        log::info!("Quiescing: {:#?}", events);
2676        smol::block_on(scanner.process_events(events));
2677        scanner.snapshot().check_invariants();
2678
2679        let (notify_tx, _notify_rx) = smol::channel::unbounded();
2680        let mut new_scanner = BackgroundScanner::new(
2681            Arc::new(Mutex::new(initial_snapshot)),
2682            notify_tx,
2683            scanner.fs.clone(),
2684            scanner.executor.clone(),
2685        );
2686        smol::block_on(new_scanner.scan_dirs()).unwrap();
2687        assert_eq!(
2688            scanner.snapshot().to_vec(true),
2689            new_scanner.snapshot().to_vec(true)
2690        );
2691
2692        for mut prev_snapshot in snapshots {
2693            let include_ignored = rng.gen::<bool>();
2694            if !include_ignored {
2695                let mut entries_by_path_edits = Vec::new();
2696                let mut entries_by_id_edits = Vec::new();
2697                for entry in prev_snapshot
2698                    .entries_by_id
2699                    .cursor::<()>()
2700                    .filter(|e| e.is_ignored)
2701                {
2702                    entries_by_path_edits.push(Edit::Remove(PathKey(entry.path.clone())));
2703                    entries_by_id_edits.push(Edit::Remove(entry.id));
2704                }
2705
2706                prev_snapshot
2707                    .entries_by_path
2708                    .edit(entries_by_path_edits, &());
2709                prev_snapshot.entries_by_id.edit(entries_by_id_edits, &());
2710            }
2711
2712            let update = scanner
2713                .snapshot()
2714                .build_update(&prev_snapshot, 0, 0, include_ignored);
2715            prev_snapshot.apply_remote_update(update).unwrap();
2716            assert_eq!(
2717                prev_snapshot.to_vec(true),
2718                scanner.snapshot().to_vec(include_ignored)
2719            );
2720        }
2721    }
2722
2723    fn randomly_mutate_tree(
2724        root_path: &Path,
2725        insertion_probability: f64,
2726        rng: &mut impl Rng,
2727    ) -> Result<Vec<fsevent::Event>> {
2728        let root_path = root_path.canonicalize().unwrap();
2729        let (dirs, files) = read_dir_recursive(root_path.clone());
2730
2731        let mut events = Vec::new();
2732        let mut record_event = |path: PathBuf| {
2733            events.push(fsevent::Event {
2734                event_id: SystemTime::now()
2735                    .duration_since(UNIX_EPOCH)
2736                    .unwrap()
2737                    .as_secs(),
2738                flags: fsevent::StreamFlags::empty(),
2739                path,
2740            });
2741        };
2742
2743        if (files.is_empty() && dirs.len() == 1) || rng.gen_bool(insertion_probability) {
2744            let path = dirs.choose(rng).unwrap();
2745            let new_path = path.join(gen_name(rng));
2746
2747            if rng.gen() {
2748                log::info!("Creating dir {:?}", new_path.strip_prefix(root_path)?);
2749                std::fs::create_dir(&new_path)?;
2750            } else {
2751                log::info!("Creating file {:?}", new_path.strip_prefix(root_path)?);
2752                std::fs::write(&new_path, "")?;
2753            }
2754            record_event(new_path);
2755        } else if rng.gen_bool(0.05) {
2756            let ignore_dir_path = dirs.choose(rng).unwrap();
2757            let ignore_path = ignore_dir_path.join(&*GITIGNORE);
2758
2759            let (subdirs, subfiles) = read_dir_recursive(ignore_dir_path.clone());
2760            let files_to_ignore = {
2761                let len = rng.gen_range(0..=subfiles.len());
2762                subfiles.choose_multiple(rng, len)
2763            };
2764            let dirs_to_ignore = {
2765                let len = rng.gen_range(0..subdirs.len());
2766                subdirs.choose_multiple(rng, len)
2767            };
2768
2769            let mut ignore_contents = String::new();
2770            for path_to_ignore in files_to_ignore.chain(dirs_to_ignore) {
2771                write!(
2772                    ignore_contents,
2773                    "{}\n",
2774                    path_to_ignore
2775                        .strip_prefix(&ignore_dir_path)?
2776                        .to_str()
2777                        .unwrap()
2778                )
2779                .unwrap();
2780            }
2781            log::info!(
2782                "Creating {:?} with contents:\n{}",
2783                ignore_path.strip_prefix(&root_path)?,
2784                ignore_contents
2785            );
2786            std::fs::write(&ignore_path, ignore_contents).unwrap();
2787            record_event(ignore_path);
2788        } else {
2789            let old_path = {
2790                let file_path = files.choose(rng);
2791                let dir_path = dirs[1..].choose(rng);
2792                file_path.into_iter().chain(dir_path).choose(rng).unwrap()
2793            };
2794
2795            let is_rename = rng.gen();
2796            if is_rename {
2797                let new_path_parent = dirs
2798                    .iter()
2799                    .filter(|d| !d.starts_with(old_path))
2800                    .choose(rng)
2801                    .unwrap();
2802
2803                let overwrite_existing_dir =
2804                    !old_path.starts_with(&new_path_parent) && rng.gen_bool(0.3);
2805                let new_path = if overwrite_existing_dir {
2806                    std::fs::remove_dir_all(&new_path_parent).ok();
2807                    new_path_parent.to_path_buf()
2808                } else {
2809                    new_path_parent.join(gen_name(rng))
2810                };
2811
2812                log::info!(
2813                    "Renaming {:?} to {}{:?}",
2814                    old_path.strip_prefix(&root_path)?,
2815                    if overwrite_existing_dir {
2816                        "overwrite "
2817                    } else {
2818                        ""
2819                    },
2820                    new_path.strip_prefix(&root_path)?
2821                );
2822                std::fs::rename(&old_path, &new_path)?;
2823                record_event(old_path.clone());
2824                record_event(new_path);
2825            } else if old_path.is_dir() {
2826                let (dirs, files) = read_dir_recursive(old_path.clone());
2827
2828                log::info!("Deleting dir {:?}", old_path.strip_prefix(&root_path)?);
2829                std::fs::remove_dir_all(&old_path).unwrap();
2830                for file in files {
2831                    record_event(file);
2832                }
2833                for dir in dirs {
2834                    record_event(dir);
2835                }
2836            } else {
2837                log::info!("Deleting file {:?}", old_path.strip_prefix(&root_path)?);
2838                std::fs::remove_file(old_path).unwrap();
2839                record_event(old_path.clone());
2840            }
2841        }
2842
2843        Ok(events)
2844    }
2845
2846    fn read_dir_recursive(path: PathBuf) -> (Vec<PathBuf>, Vec<PathBuf>) {
2847        let child_entries = std::fs::read_dir(&path).unwrap();
2848        let mut dirs = vec![path];
2849        let mut files = Vec::new();
2850        for child_entry in child_entries {
2851            let child_path = child_entry.unwrap().path();
2852            if child_path.is_dir() {
2853                let (child_dirs, child_files) = read_dir_recursive(child_path);
2854                dirs.extend(child_dirs);
2855                files.extend(child_files);
2856            } else {
2857                files.push(child_path);
2858            }
2859        }
2860        (dirs, files)
2861    }
2862
2863    fn gen_name(rng: &mut impl Rng) -> String {
2864        (0..6)
2865            .map(|_| rng.sample(rand::distributions::Alphanumeric))
2866            .map(char::from)
2867            .collect()
2868    }
2869
2870    impl LocalSnapshot {
2871        fn check_invariants(&self) {
2872            let mut files = self.files(true, 0);
2873            let mut visible_files = self.files(false, 0);
2874            for entry in self.entries_by_path.cursor::<()>() {
2875                if entry.is_file() {
2876                    assert_eq!(files.next().unwrap().inode, entry.inode);
2877                    if !entry.is_ignored {
2878                        assert_eq!(visible_files.next().unwrap().inode, entry.inode);
2879                    }
2880                }
2881            }
2882            assert!(files.next().is_none());
2883            assert!(visible_files.next().is_none());
2884
2885            let mut bfs_paths = Vec::new();
2886            let mut stack = vec![Path::new("")];
2887            while let Some(path) = stack.pop() {
2888                bfs_paths.push(path);
2889                let ix = stack.len();
2890                for child_entry in self.child_entries(path) {
2891                    stack.insert(ix, &child_entry.path);
2892                }
2893            }
2894
2895            let dfs_paths = self
2896                .entries_by_path
2897                .cursor::<()>()
2898                .map(|e| e.path.as_ref())
2899                .collect::<Vec<_>>();
2900            assert_eq!(bfs_paths, dfs_paths);
2901
2902            for (ignore_parent_path, _) in &self.ignores {
2903                assert!(self.entry_for_path(ignore_parent_path).is_some());
2904                assert!(self
2905                    .entry_for_path(ignore_parent_path.join(&*GITIGNORE))
2906                    .is_some());
2907            }
2908        }
2909
2910        fn to_vec(&self, include_ignored: bool) -> Vec<(&Path, u64, bool)> {
2911            let mut paths = Vec::new();
2912            for entry in self.entries_by_path.cursor::<()>() {
2913                if include_ignored || !entry.is_ignored {
2914                    paths.push((entry.path.as_ref(), entry.inode, entry.is_ignored));
2915                }
2916            }
2917            paths.sort_by(|a, b| a.0.cmp(&b.0));
2918            paths
2919        }
2920    }
2921}