worktree.rs

   1use super::{
   2    fs::{self, Fs},
   3    ignore::IgnoreStack,
   4};
   5use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
   6use anyhow::{anyhow, Result};
   7use client::{proto, Client, PeerId, TypedEnvelope};
   8use clock::ReplicaId;
   9use futures::{Stream, StreamExt};
  10use fuzzy::CharBag;
  11use gpui::{
  12    executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
  13    Task, UpgradeModelHandle, WeakModelHandle,
  14};
  15use language::{Buffer, History, LanguageRegistry, Operation, Rope};
  16use lazy_static::lazy_static;
  17use lsp::LanguageServer;
  18use parking_lot::Mutex;
  19use postage::{
  20    prelude::{Sink as _, Stream as _},
  21    watch,
  22};
  23use serde::Deserialize;
  24use smol::channel::{self, Sender};
  25use std::{
  26    any::Any,
  27    cmp::{self, Ordering},
  28    collections::HashMap,
  29    convert::{TryFrom, TryInto},
  30    ffi::{OsStr, OsString},
  31    fmt,
  32    future::Future,
  33    ops::Deref,
  34    path::{Path, PathBuf},
  35    sync::{
  36        atomic::{AtomicUsize, Ordering::SeqCst},
  37        Arc,
  38    },
  39    time::{Duration, SystemTime},
  40};
  41use sum_tree::Bias;
  42use sum_tree::{Edit, SeekTarget, SumTree};
  43use util::TryFutureExt;
  44
  45lazy_static! {
  46    static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
  47}
  48
  49#[derive(Clone, Debug)]
  50enum ScanState {
  51    Idle,
  52    Scanning,
  53    Err(Arc<anyhow::Error>),
  54}
  55
  56pub enum Worktree {
  57    Local(LocalWorktree),
  58    Remote(RemoteWorktree),
  59}
  60
  61pub enum Event {
  62    Closed,
  63}
  64
  65impl Entity for Worktree {
  66    type Event = Event;
  67
  68    fn release(&mut self, cx: &mut MutableAppContext) {
  69        match self {
  70            Self::Local(tree) => {
  71                if let Some(worktree_id) = *tree.remote_id.borrow() {
  72                    let rpc = tree.rpc.clone();
  73                    cx.spawn(|_| async move {
  74                        if let Err(err) = rpc.send(proto::CloseWorktree { worktree_id }).await {
  75                            log::error!("error closing worktree: {}", err);
  76                        }
  77                    })
  78                    .detach();
  79                }
  80            }
  81            Self::Remote(tree) => {
  82                let rpc = tree.client.clone();
  83                let worktree_id = tree.remote_id;
  84                cx.spawn(|_| async move {
  85                    if let Err(err) = rpc.send(proto::LeaveWorktree { worktree_id }).await {
  86                        log::error!("error closing worktree: {}", err);
  87                    }
  88                })
  89                .detach();
  90            }
  91        }
  92    }
  93}
  94
  95impl Worktree {
  96    pub async fn open_local(
  97        rpc: Arc<Client>,
  98        path: impl Into<Arc<Path>>,
  99        fs: Arc<dyn Fs>,
 100        languages: Arc<LanguageRegistry>,
 101        cx: &mut AsyncAppContext,
 102    ) -> Result<ModelHandle<Self>> {
 103        let (tree, scan_states_tx) =
 104            LocalWorktree::new(rpc, path, fs.clone(), languages, cx).await?;
 105        tree.update(cx, |tree, cx| {
 106            let tree = tree.as_local_mut().unwrap();
 107            let abs_path = tree.snapshot.abs_path.clone();
 108            let background_snapshot = tree.background_snapshot.clone();
 109            let background = cx.background().clone();
 110            tree._background_scanner_task = Some(cx.background().spawn(async move {
 111                let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
 112                let scanner =
 113                    BackgroundScanner::new(background_snapshot, scan_states_tx, fs, background);
 114                scanner.run(events).await;
 115            }));
 116        });
 117        Ok(tree)
 118    }
 119
 120    pub async fn open_remote(
 121        rpc: Arc<Client>,
 122        id: u64,
 123        languages: Arc<LanguageRegistry>,
 124        cx: &mut AsyncAppContext,
 125    ) -> Result<ModelHandle<Self>> {
 126        let response = rpc.request(proto::JoinWorktree { worktree_id: id }).await?;
 127        Worktree::remote(response, rpc, languages, cx).await
 128    }
 129
 130    async fn remote(
 131        join_response: proto::JoinWorktreeResponse,
 132        rpc: Arc<Client>,
 133        languages: Arc<LanguageRegistry>,
 134        cx: &mut AsyncAppContext,
 135    ) -> Result<ModelHandle<Self>> {
 136        let worktree = join_response
 137            .worktree
 138            .ok_or_else(|| anyhow!("empty worktree"))?;
 139
 140        let remote_id = worktree.id;
 141        let replica_id = join_response.replica_id as ReplicaId;
 142        let peers = join_response.peers;
 143        let root_char_bag: CharBag = worktree
 144            .root_name
 145            .chars()
 146            .map(|c| c.to_ascii_lowercase())
 147            .collect();
 148        let root_name = worktree.root_name.clone();
 149        let (entries_by_path, entries_by_id) = cx
 150            .background()
 151            .spawn(async move {
 152                let mut entries_by_path_edits = Vec::new();
 153                let mut entries_by_id_edits = Vec::new();
 154                for entry in worktree.entries {
 155                    match Entry::try_from((&root_char_bag, entry)) {
 156                        Ok(entry) => {
 157                            entries_by_id_edits.push(Edit::Insert(PathEntry {
 158                                id: entry.id,
 159                                path: entry.path.clone(),
 160                                is_ignored: entry.is_ignored,
 161                                scan_id: 0,
 162                            }));
 163                            entries_by_path_edits.push(Edit::Insert(entry));
 164                        }
 165                        Err(err) => log::warn!("error for remote worktree entry {:?}", err),
 166                    }
 167                }
 168
 169                let mut entries_by_path = SumTree::new();
 170                let mut entries_by_id = SumTree::new();
 171                entries_by_path.edit(entries_by_path_edits, &());
 172                entries_by_id.edit(entries_by_id_edits, &());
 173                (entries_by_path, entries_by_id)
 174            })
 175            .await;
 176
 177        let worktree = cx.update(|cx| {
 178            cx.add_model(|cx: &mut ModelContext<Worktree>| {
 179                let snapshot = Snapshot {
 180                    id: cx.model_id(),
 181                    scan_id: 0,
 182                    abs_path: Path::new("").into(),
 183                    root_name,
 184                    root_char_bag,
 185                    ignores: Default::default(),
 186                    entries_by_path,
 187                    entries_by_id,
 188                    removed_entry_ids: Default::default(),
 189                    next_entry_id: Default::default(),
 190                };
 191
 192                let (updates_tx, mut updates_rx) = postage::mpsc::channel(64);
 193                let (mut snapshot_tx, snapshot_rx) = watch::channel_with(snapshot.clone());
 194
 195                cx.background()
 196                    .spawn(async move {
 197                        while let Some(update) = updates_rx.recv().await {
 198                            let mut snapshot = snapshot_tx.borrow().clone();
 199                            if let Err(error) = snapshot.apply_update(update) {
 200                                log::error!("error applying worktree update: {}", error);
 201                            }
 202                            *snapshot_tx.borrow_mut() = snapshot;
 203                        }
 204                    })
 205                    .detach();
 206
 207                {
 208                    let mut snapshot_rx = snapshot_rx.clone();
 209                    cx.spawn_weak(|this, mut cx| async move {
 210                        while let Some(_) = snapshot_rx.recv().await {
 211                            if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
 212                                this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
 213                            } else {
 214                                break;
 215                            }
 216                        }
 217                    })
 218                    .detach();
 219                }
 220
 221                let _subscriptions = vec![
 222                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_add_peer),
 223                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_remove_peer),
 224                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_update),
 225                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
 226                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
 227                    rpc.subscribe_to_entity(remote_id, cx, Self::handle_unshare),
 228                ];
 229
 230                Worktree::Remote(RemoteWorktree {
 231                    remote_id,
 232                    replica_id,
 233                    snapshot,
 234                    snapshot_rx,
 235                    updates_tx,
 236                    client: rpc.clone(),
 237                    open_buffers: Default::default(),
 238                    peers: peers
 239                        .into_iter()
 240                        .map(|p| (PeerId(p.peer_id), p.replica_id as ReplicaId))
 241                        .collect(),
 242                    queued_operations: Default::default(),
 243                    languages,
 244                    _subscriptions,
 245                })
 246            })
 247        });
 248
 249        Ok(worktree)
 250    }
 251
 252    pub fn as_local(&self) -> Option<&LocalWorktree> {
 253        if let Worktree::Local(worktree) = self {
 254            Some(worktree)
 255        } else {
 256            None
 257        }
 258    }
 259
 260    pub fn as_local_mut(&mut self) -> Option<&mut LocalWorktree> {
 261        if let Worktree::Local(worktree) = self {
 262            Some(worktree)
 263        } else {
 264            None
 265        }
 266    }
 267
 268    pub fn as_remote_mut(&mut self) -> Option<&mut RemoteWorktree> {
 269        if let Worktree::Remote(worktree) = self {
 270            Some(worktree)
 271        } else {
 272            None
 273        }
 274    }
 275
 276    pub fn snapshot(&self) -> Snapshot {
 277        match self {
 278            Worktree::Local(worktree) => worktree.snapshot(),
 279            Worktree::Remote(worktree) => worktree.snapshot(),
 280        }
 281    }
 282
 283    pub fn replica_id(&self) -> ReplicaId {
 284        match self {
 285            Worktree::Local(_) => 0,
 286            Worktree::Remote(worktree) => worktree.replica_id,
 287        }
 288    }
 289
 290    pub fn languages(&self) -> &Arc<LanguageRegistry> {
 291        match self {
 292            Worktree::Local(worktree) => &worktree.languages,
 293            Worktree::Remote(worktree) => &worktree.languages,
 294        }
 295    }
 296
 297    pub fn handle_add_peer(
 298        &mut self,
 299        envelope: TypedEnvelope<proto::AddPeer>,
 300        _: Arc<Client>,
 301        cx: &mut ModelContext<Self>,
 302    ) -> Result<()> {
 303        match self {
 304            Worktree::Local(worktree) => worktree.add_peer(envelope, cx),
 305            Worktree::Remote(worktree) => worktree.add_peer(envelope, cx),
 306        }
 307    }
 308
 309    pub fn handle_remove_peer(
 310        &mut self,
 311        envelope: TypedEnvelope<proto::RemovePeer>,
 312        _: Arc<Client>,
 313        cx: &mut ModelContext<Self>,
 314    ) -> Result<()> {
 315        match self {
 316            Worktree::Local(worktree) => worktree.remove_peer(envelope, cx),
 317            Worktree::Remote(worktree) => worktree.remove_peer(envelope, cx),
 318        }
 319    }
 320
 321    pub fn handle_update(
 322        &mut self,
 323        envelope: TypedEnvelope<proto::UpdateWorktree>,
 324        _: Arc<Client>,
 325        cx: &mut ModelContext<Self>,
 326    ) -> anyhow::Result<()> {
 327        self.as_remote_mut()
 328            .unwrap()
 329            .update_from_remote(envelope, cx)
 330    }
 331
 332    pub fn handle_open_buffer(
 333        &mut self,
 334        envelope: TypedEnvelope<proto::OpenBuffer>,
 335        rpc: Arc<Client>,
 336        cx: &mut ModelContext<Self>,
 337    ) -> anyhow::Result<()> {
 338        let receipt = envelope.receipt();
 339
 340        let response = self
 341            .as_local_mut()
 342            .unwrap()
 343            .open_remote_buffer(envelope, cx);
 344
 345        cx.background()
 346            .spawn(
 347                async move {
 348                    rpc.respond(receipt, response.await?).await?;
 349                    Ok(())
 350                }
 351                .log_err(),
 352            )
 353            .detach();
 354
 355        Ok(())
 356    }
 357
 358    pub fn handle_close_buffer(
 359        &mut self,
 360        envelope: TypedEnvelope<proto::CloseBuffer>,
 361        _: Arc<Client>,
 362        cx: &mut ModelContext<Self>,
 363    ) -> anyhow::Result<()> {
 364        self.as_local_mut()
 365            .unwrap()
 366            .close_remote_buffer(envelope, cx)
 367    }
 368
 369    pub fn peers(&self) -> &HashMap<PeerId, ReplicaId> {
 370        match self {
 371            Worktree::Local(worktree) => &worktree.peers,
 372            Worktree::Remote(worktree) => &worktree.peers,
 373        }
 374    }
 375
 376    pub fn open_buffer(
 377        &mut self,
 378        path: impl AsRef<Path>,
 379        cx: &mut ModelContext<Self>,
 380    ) -> Task<Result<ModelHandle<Buffer>>> {
 381        match self {
 382            Worktree::Local(worktree) => worktree.open_buffer(path.as_ref(), cx),
 383            Worktree::Remote(worktree) => worktree.open_buffer(path.as_ref(), cx),
 384        }
 385    }
 386
 387    #[cfg(feature = "test-support")]
 388    pub fn has_open_buffer(&self, path: impl AsRef<Path>, cx: &AppContext) -> bool {
 389        let mut open_buffers: Box<dyn Iterator<Item = _>> = match self {
 390            Worktree::Local(worktree) => Box::new(worktree.open_buffers.values()),
 391            Worktree::Remote(worktree) => {
 392                Box::new(worktree.open_buffers.values().filter_map(|buf| {
 393                    if let RemoteBuffer::Loaded(buf) = buf {
 394                        Some(buf)
 395                    } else {
 396                        None
 397                    }
 398                }))
 399            }
 400        };
 401
 402        let path = path.as_ref();
 403        open_buffers
 404            .find(|buffer| {
 405                if let Some(file) = buffer.upgrade(cx).and_then(|buffer| buffer.read(cx).file()) {
 406                    file.path().as_ref() == path
 407                } else {
 408                    false
 409                }
 410            })
 411            .is_some()
 412    }
 413
 414    pub fn handle_update_buffer(
 415        &mut self,
 416        envelope: TypedEnvelope<proto::UpdateBuffer>,
 417        _: Arc<Client>,
 418        cx: &mut ModelContext<Self>,
 419    ) -> Result<()> {
 420        let payload = envelope.payload.clone();
 421        let buffer_id = payload.buffer_id as usize;
 422        let ops = payload
 423            .operations
 424            .into_iter()
 425            .map(|op| op.try_into())
 426            .collect::<anyhow::Result<Vec<_>>>()?;
 427
 428        match self {
 429            Worktree::Local(worktree) => {
 430                let buffer = worktree
 431                    .open_buffers
 432                    .get(&buffer_id)
 433                    .and_then(|buf| buf.upgrade(cx))
 434                    .ok_or_else(|| {
 435                        anyhow!("invalid buffer {} in update buffer message", buffer_id)
 436                    })?;
 437                buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
 438            }
 439            Worktree::Remote(worktree) => match worktree.open_buffers.get_mut(&buffer_id) {
 440                Some(RemoteBuffer::Operations(pending_ops)) => pending_ops.extend(ops),
 441                Some(RemoteBuffer::Loaded(buffer)) => {
 442                    if let Some(buffer) = buffer.upgrade(cx) {
 443                        buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
 444                    } else {
 445                        worktree
 446                            .open_buffers
 447                            .insert(buffer_id, RemoteBuffer::Operations(ops));
 448                    }
 449                }
 450                None => {
 451                    worktree
 452                        .open_buffers
 453                        .insert(buffer_id, RemoteBuffer::Operations(ops));
 454                }
 455            },
 456        }
 457
 458        Ok(())
 459    }
 460
 461    pub fn handle_save_buffer(
 462        &mut self,
 463        envelope: TypedEnvelope<proto::SaveBuffer>,
 464        rpc: Arc<Client>,
 465        cx: &mut ModelContext<Self>,
 466    ) -> Result<()> {
 467        let sender_id = envelope.original_sender_id()?;
 468        let buffer = self
 469            .as_local()
 470            .unwrap()
 471            .shared_buffers
 472            .get(&sender_id)
 473            .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
 474            .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
 475
 476        let receipt = envelope.receipt();
 477        let worktree_id = envelope.payload.worktree_id;
 478        let buffer_id = envelope.payload.buffer_id;
 479        let save = cx.spawn(|_, mut cx| async move {
 480            buffer.update(&mut cx, |buffer, cx| buffer.save(cx))?.await
 481        });
 482
 483        cx.background()
 484            .spawn(
 485                async move {
 486                    let (version, mtime) = save.await?;
 487
 488                    rpc.respond(
 489                        receipt,
 490                        proto::BufferSaved {
 491                            worktree_id,
 492                            buffer_id,
 493                            version: (&version).into(),
 494                            mtime: Some(mtime.into()),
 495                        },
 496                    )
 497                    .await?;
 498
 499                    Ok(())
 500                }
 501                .log_err(),
 502            )
 503            .detach();
 504
 505        Ok(())
 506    }
 507
 508    pub fn handle_buffer_saved(
 509        &mut self,
 510        envelope: TypedEnvelope<proto::BufferSaved>,
 511        _: Arc<Client>,
 512        cx: &mut ModelContext<Self>,
 513    ) -> Result<()> {
 514        let payload = envelope.payload.clone();
 515        let worktree = self.as_remote_mut().unwrap();
 516        if let Some(buffer) = worktree
 517            .open_buffers
 518            .get(&(payload.buffer_id as usize))
 519            .and_then(|buf| buf.upgrade(cx))
 520        {
 521            buffer.update(cx, |buffer, cx| {
 522                let version = payload.version.try_into()?;
 523                let mtime = payload
 524                    .mtime
 525                    .ok_or_else(|| anyhow!("missing mtime"))?
 526                    .into();
 527                buffer.did_save(version, mtime, None, cx);
 528                Result::<_, anyhow::Error>::Ok(())
 529            })?;
 530        }
 531        Ok(())
 532    }
 533
 534    pub fn handle_unshare(
 535        &mut self,
 536        _: TypedEnvelope<proto::UnshareWorktree>,
 537        _: Arc<Client>,
 538        cx: &mut ModelContext<Self>,
 539    ) -> Result<()> {
 540        cx.emit(Event::Closed);
 541        Ok(())
 542    }
 543
 544    fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
 545        match self {
 546            Self::Local(worktree) => {
 547                let is_fake_fs = worktree.fs.is_fake();
 548                worktree.snapshot = worktree.background_snapshot.lock().clone();
 549                if worktree.is_scanning() {
 550                    if worktree.poll_task.is_none() {
 551                        worktree.poll_task = Some(cx.spawn(|this, mut cx| async move {
 552                            if is_fake_fs {
 553                                smol::future::yield_now().await;
 554                            } else {
 555                                smol::Timer::after(Duration::from_millis(100)).await;
 556                            }
 557                            this.update(&mut cx, |this, cx| {
 558                                this.as_local_mut().unwrap().poll_task = None;
 559                                this.poll_snapshot(cx);
 560                            })
 561                        }));
 562                    }
 563                } else {
 564                    worktree.poll_task.take();
 565                    self.update_open_buffers(cx);
 566                }
 567            }
 568            Self::Remote(worktree) => {
 569                worktree.snapshot = worktree.snapshot_rx.borrow().clone();
 570                self.update_open_buffers(cx);
 571            }
 572        };
 573
 574        cx.notify();
 575    }
 576
 577    fn update_open_buffers(&mut self, cx: &mut ModelContext<Self>) {
 578        let open_buffers: Box<dyn Iterator<Item = _>> = match &self {
 579            Self::Local(worktree) => Box::new(worktree.open_buffers.iter()),
 580            Self::Remote(worktree) => {
 581                Box::new(worktree.open_buffers.iter().filter_map(|(id, buf)| {
 582                    if let RemoteBuffer::Loaded(buf) = buf {
 583                        Some((id, buf))
 584                    } else {
 585                        None
 586                    }
 587                }))
 588            }
 589        };
 590
 591        let worktree_handle = cx.handle();
 592        let mut buffers_to_delete = Vec::new();
 593        for (buffer_id, buffer) in open_buffers {
 594            if let Some(buffer) = buffer.upgrade(cx) {
 595                buffer.update(cx, |buffer, cx| {
 596                    if let Some(old_file) = buffer.file() {
 597                        let new_file = if let Some(entry) = old_file
 598                            .entry_id()
 599                            .and_then(|entry_id| self.entry_for_id(entry_id))
 600                        {
 601                            File {
 602                                entry_id: Some(entry.id),
 603                                mtime: entry.mtime,
 604                                path: entry.path.clone(),
 605                                worktree: worktree_handle.clone(),
 606                            }
 607                        } else if let Some(entry) = self.entry_for_path(old_file.path().as_ref()) {
 608                            File {
 609                                entry_id: Some(entry.id),
 610                                mtime: entry.mtime,
 611                                path: entry.path.clone(),
 612                                worktree: worktree_handle.clone(),
 613                            }
 614                        } else {
 615                            File {
 616                                entry_id: None,
 617                                path: old_file.path().clone(),
 618                                mtime: old_file.mtime(),
 619                                worktree: worktree_handle.clone(),
 620                            }
 621                        };
 622
 623                        if let Some(task) = buffer.file_updated(Box::new(new_file), cx) {
 624                            task.detach();
 625                        }
 626                    }
 627                });
 628            } else {
 629                buffers_to_delete.push(*buffer_id);
 630            }
 631        }
 632
 633        for buffer_id in buffers_to_delete {
 634            match self {
 635                Self::Local(worktree) => {
 636                    worktree.open_buffers.remove(&buffer_id);
 637                }
 638                Self::Remote(worktree) => {
 639                    worktree.open_buffers.remove(&buffer_id);
 640                }
 641            }
 642        }
 643    }
 644}
 645
 646impl Deref for Worktree {
 647    type Target = Snapshot;
 648
 649    fn deref(&self) -> &Self::Target {
 650        match self {
 651            Worktree::Local(worktree) => &worktree.snapshot,
 652            Worktree::Remote(worktree) => &worktree.snapshot,
 653        }
 654    }
 655}
 656
 657pub struct LocalWorktree {
 658    snapshot: Snapshot,
 659    config: WorktreeConfig,
 660    background_snapshot: Arc<Mutex<Snapshot>>,
 661    last_scan_state_rx: watch::Receiver<ScanState>,
 662    _background_scanner_task: Option<Task<()>>,
 663    _maintain_remote_id_task: Task<Option<()>>,
 664    poll_task: Option<Task<()>>,
 665    remote_id: watch::Receiver<Option<u64>>,
 666    share: Option<ShareState>,
 667    open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
 668    shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
 669    peers: HashMap<PeerId, ReplicaId>,
 670    languages: Arc<LanguageRegistry>,
 671    queued_operations: Vec<(u64, Operation)>,
 672    rpc: Arc<Client>,
 673    fs: Arc<dyn Fs>,
 674    language_server: Arc<LanguageServer>,
 675}
 676
 677#[derive(Default, Deserialize)]
 678struct WorktreeConfig {
 679    collaborators: Vec<String>,
 680}
 681
 682impl LocalWorktree {
 683    async fn new(
 684        rpc: Arc<Client>,
 685        path: impl Into<Arc<Path>>,
 686        fs: Arc<dyn Fs>,
 687        languages: Arc<LanguageRegistry>,
 688        cx: &mut AsyncAppContext,
 689    ) -> Result<(ModelHandle<Worktree>, Sender<ScanState>)> {
 690        let abs_path = path.into();
 691        let path: Arc<Path> = Arc::from(Path::new(""));
 692        let next_entry_id = AtomicUsize::new(0);
 693
 694        // After determining whether the root entry is a file or a directory, populate the
 695        // snapshot's "root name", which will be used for the purpose of fuzzy matching.
 696        let root_name = abs_path
 697            .file_name()
 698            .map_or(String::new(), |f| f.to_string_lossy().to_string());
 699        let root_char_bag = root_name.chars().map(|c| c.to_ascii_lowercase()).collect();
 700        let metadata = fs.metadata(&abs_path).await?;
 701
 702        let mut config = WorktreeConfig::default();
 703        if let Ok(zed_toml) = fs.load(&abs_path.join(".zed.toml")).await {
 704            if let Ok(parsed) = toml::from_str(&zed_toml) {
 705                config = parsed;
 706            }
 707        }
 708
 709        let (scan_states_tx, scan_states_rx) = smol::channel::unbounded();
 710        let (mut last_scan_state_tx, last_scan_state_rx) = watch::channel_with(ScanState::Scanning);
 711        let tree = cx.add_model(move |cx: &mut ModelContext<Worktree>| {
 712            let language_server = LanguageServer::rust(&abs_path, cx).unwrap();
 713            let mut snapshot = Snapshot {
 714                id: cx.model_id(),
 715                scan_id: 0,
 716                abs_path,
 717                root_name: root_name.clone(),
 718                root_char_bag,
 719                ignores: Default::default(),
 720                entries_by_path: Default::default(),
 721                entries_by_id: Default::default(),
 722                removed_entry_ids: Default::default(),
 723                next_entry_id: Arc::new(next_entry_id),
 724            };
 725            if let Some(metadata) = metadata {
 726                snapshot.insert_entry(
 727                    Entry::new(
 728                        path.into(),
 729                        &metadata,
 730                        &snapshot.next_entry_id,
 731                        snapshot.root_char_bag,
 732                    ),
 733                    fs.as_ref(),
 734                );
 735            }
 736
 737            let (mut remote_id_tx, remote_id_rx) = watch::channel();
 738            let _maintain_remote_id_task = cx.spawn_weak({
 739                let rpc = rpc.clone();
 740                move |this, cx| {
 741                    async move {
 742                        let mut status = rpc.status();
 743                        while let Some(status) = status.recv().await {
 744                            if let Some(this) = this.upgrade(&cx) {
 745                                let remote_id = if let client::Status::Connected { .. } = status {
 746                                    let collaborator_logins = this.read_with(&cx, |this, _| {
 747                                        this.as_local().unwrap().config.collaborators.clone()
 748                                    });
 749                                    let response = rpc
 750                                        .request(proto::OpenWorktree {
 751                                            root_name: root_name.clone(),
 752                                            collaborator_logins,
 753                                        })
 754                                        .await?;
 755
 756                                    Some(response.worktree_id)
 757                                } else {
 758                                    None
 759                                };
 760                                if remote_id_tx.send(remote_id).await.is_err() {
 761                                    break;
 762                                }
 763                            }
 764                        }
 765                        Ok(())
 766                    }
 767                    .log_err()
 768                }
 769            });
 770
 771            let tree = Self {
 772                snapshot: snapshot.clone(),
 773                config,
 774                remote_id: remote_id_rx,
 775                background_snapshot: Arc::new(Mutex::new(snapshot)),
 776                last_scan_state_rx,
 777                _background_scanner_task: None,
 778                _maintain_remote_id_task,
 779                share: None,
 780                poll_task: None,
 781                open_buffers: Default::default(),
 782                shared_buffers: Default::default(),
 783                queued_operations: Default::default(),
 784                peers: Default::default(),
 785                languages,
 786                rpc,
 787                fs,
 788                language_server,
 789            };
 790
 791            cx.spawn_weak(|this, mut cx| async move {
 792                while let Ok(scan_state) = scan_states_rx.recv().await {
 793                    if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
 794                        let to_send = handle.update(&mut cx, |this, cx| {
 795                            last_scan_state_tx.blocking_send(scan_state).ok();
 796                            this.poll_snapshot(cx);
 797                            let tree = this.as_local_mut().unwrap();
 798                            if !tree.is_scanning() {
 799                                if let Some(share) = tree.share.as_ref() {
 800                                    return Some((tree.snapshot(), share.snapshots_tx.clone()));
 801                                }
 802                            }
 803                            None
 804                        });
 805
 806                        if let Some((snapshot, snapshots_to_send_tx)) = to_send {
 807                            if let Err(err) = snapshots_to_send_tx.send(snapshot).await {
 808                                log::error!("error submitting snapshot to send {}", err);
 809                            }
 810                        }
 811                    } else {
 812                        break;
 813                    }
 814                }
 815            })
 816            .detach();
 817
 818            Worktree::Local(tree)
 819        });
 820
 821        Ok((tree, scan_states_tx))
 822    }
 823
 824    pub fn open_buffer(
 825        &mut self,
 826        path: &Path,
 827        cx: &mut ModelContext<Worktree>,
 828    ) -> Task<Result<ModelHandle<Buffer>>> {
 829        let handle = cx.handle();
 830
 831        // If there is already a buffer for the given path, then return it.
 832        let mut existing_buffer = None;
 833        self.open_buffers.retain(|_buffer_id, buffer| {
 834            if let Some(buffer) = buffer.upgrade(cx.as_ref()) {
 835                if let Some(file) = buffer.read(cx.as_ref()).file() {
 836                    if file.worktree_id() == handle.id() && file.path().as_ref() == path {
 837                        existing_buffer = Some(buffer);
 838                    }
 839                }
 840                true
 841            } else {
 842                false
 843            }
 844        });
 845
 846        let path = Arc::from(path);
 847        cx.spawn(|this, mut cx| async move {
 848            if let Some(existing_buffer) = existing_buffer {
 849                Ok(existing_buffer)
 850            } else {
 851                let (file, contents) = this
 852                    .update(&mut cx, |this, cx| this.as_local().unwrap().load(&path, cx))
 853                    .await?;
 854                let language = this.read_with(&cx, |this, cx| {
 855                    use language::File;
 856
 857                    this.languages()
 858                        .select_language(file.full_path(cx))
 859                        .cloned()
 860                });
 861                let buffer = cx.add_model(|cx| {
 862                    Buffer::from_history(
 863                        0,
 864                        History::new(contents.into()),
 865                        Some(Box::new(file)),
 866                        language,
 867                        cx,
 868                    )
 869                });
 870                this.update(&mut cx, |this, _| {
 871                    let this = this
 872                        .as_local_mut()
 873                        .ok_or_else(|| anyhow!("must be a local worktree"))?;
 874                    this.open_buffers.insert(buffer.id(), buffer.downgrade());
 875                    Ok(buffer)
 876                })
 877            }
 878        })
 879    }
 880
 881    pub fn open_remote_buffer(
 882        &mut self,
 883        envelope: TypedEnvelope<proto::OpenBuffer>,
 884        cx: &mut ModelContext<Worktree>,
 885    ) -> Task<Result<proto::OpenBufferResponse>> {
 886        let peer_id = envelope.original_sender_id();
 887        let path = Path::new(&envelope.payload.path);
 888
 889        let buffer = self.open_buffer(path, cx);
 890
 891        cx.spawn(|this, mut cx| async move {
 892            let buffer = buffer.await?;
 893            this.update(&mut cx, |this, cx| {
 894                this.as_local_mut()
 895                    .unwrap()
 896                    .shared_buffers
 897                    .entry(peer_id?)
 898                    .or_default()
 899                    .insert(buffer.id() as u64, buffer.clone());
 900
 901                Ok(proto::OpenBufferResponse {
 902                    buffer: Some(buffer.update(cx.as_mut(), |buffer, _| buffer.to_proto())),
 903                })
 904            })
 905        })
 906    }
 907
 908    pub fn close_remote_buffer(
 909        &mut self,
 910        envelope: TypedEnvelope<proto::CloseBuffer>,
 911        cx: &mut ModelContext<Worktree>,
 912    ) -> Result<()> {
 913        if let Some(shared_buffers) = self.shared_buffers.get_mut(&envelope.original_sender_id()?) {
 914            shared_buffers.remove(&envelope.payload.buffer_id);
 915            cx.notify();
 916        }
 917
 918        Ok(())
 919    }
 920
 921    pub fn add_peer(
 922        &mut self,
 923        envelope: TypedEnvelope<proto::AddPeer>,
 924        cx: &mut ModelContext<Worktree>,
 925    ) -> Result<()> {
 926        let peer = envelope
 927            .payload
 928            .peer
 929            .as_ref()
 930            .ok_or_else(|| anyhow!("empty peer"))?;
 931        self.peers
 932            .insert(PeerId(peer.peer_id), peer.replica_id as ReplicaId);
 933        cx.notify();
 934
 935        Ok(())
 936    }
 937
 938    pub fn remove_peer(
 939        &mut self,
 940        envelope: TypedEnvelope<proto::RemovePeer>,
 941        cx: &mut ModelContext<Worktree>,
 942    ) -> Result<()> {
 943        let peer_id = PeerId(envelope.payload.peer_id);
 944        let replica_id = self
 945            .peers
 946            .remove(&peer_id)
 947            .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?;
 948        self.shared_buffers.remove(&peer_id);
 949        for (_, buffer) in &self.open_buffers {
 950            if let Some(buffer) = buffer.upgrade(cx) {
 951                buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
 952            }
 953        }
 954        cx.notify();
 955
 956        Ok(())
 957    }
 958
 959    pub fn scan_complete(&self) -> impl Future<Output = ()> {
 960        let mut scan_state_rx = self.last_scan_state_rx.clone();
 961        async move {
 962            let mut scan_state = Some(scan_state_rx.borrow().clone());
 963            while let Some(ScanState::Scanning) = scan_state {
 964                scan_state = scan_state_rx.recv().await;
 965            }
 966        }
 967    }
 968
 969    pub fn remote_id(&self) -> Option<u64> {
 970        *self.remote_id.borrow()
 971    }
 972
 973    pub fn next_remote_id(&self) -> impl Future<Output = Option<u64>> {
 974        let mut remote_id = self.remote_id.clone();
 975        async move {
 976            while let Some(remote_id) = remote_id.recv().await {
 977                if remote_id.is_some() {
 978                    return remote_id;
 979                }
 980            }
 981            None
 982        }
 983    }
 984
 985    fn is_scanning(&self) -> bool {
 986        if let ScanState::Scanning = *self.last_scan_state_rx.borrow() {
 987            true
 988        } else {
 989            false
 990        }
 991    }
 992
 993    pub fn snapshot(&self) -> Snapshot {
 994        self.snapshot.clone()
 995    }
 996
 997    pub fn abs_path(&self) -> &Path {
 998        self.snapshot.abs_path.as_ref()
 999    }
1000
1001    pub fn contains_abs_path(&self, path: &Path) -> bool {
1002        path.starts_with(&self.snapshot.abs_path)
1003    }
1004
1005    fn absolutize(&self, path: &Path) -> PathBuf {
1006        if path.file_name().is_some() {
1007            self.snapshot.abs_path.join(path)
1008        } else {
1009            self.snapshot.abs_path.to_path_buf()
1010        }
1011    }
1012
1013    fn load(&self, path: &Path, cx: &mut ModelContext<Worktree>) -> Task<Result<(File, String)>> {
1014        let handle = cx.handle();
1015        let path = Arc::from(path);
1016        let abs_path = self.absolutize(&path);
1017        let background_snapshot = self.background_snapshot.clone();
1018        let fs = self.fs.clone();
1019        cx.spawn(|this, mut cx| async move {
1020            let text = fs.load(&abs_path).await?;
1021            // Eagerly populate the snapshot with an updated entry for the loaded file
1022            let entry = refresh_entry(fs.as_ref(), &background_snapshot, path, &abs_path).await?;
1023            this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
1024            Ok((File::new(entry.id, handle, entry.path, entry.mtime), text))
1025        })
1026    }
1027
1028    pub fn save_buffer_as(
1029        &self,
1030        buffer: ModelHandle<Buffer>,
1031        path: impl Into<Arc<Path>>,
1032        text: Rope,
1033        cx: &mut ModelContext<Worktree>,
1034    ) -> Task<Result<File>> {
1035        let save = self.save(path, text, cx);
1036        cx.spawn(|this, mut cx| async move {
1037            let entry = save.await?;
1038            this.update(&mut cx, |this, cx| {
1039                this.as_local_mut()
1040                    .unwrap()
1041                    .open_buffers
1042                    .insert(buffer.id(), buffer.downgrade());
1043                Ok(File::new(entry.id, cx.handle(), entry.path, entry.mtime))
1044            })
1045        })
1046    }
1047
1048    fn save(
1049        &self,
1050        path: impl Into<Arc<Path>>,
1051        text: Rope,
1052        cx: &mut ModelContext<Worktree>,
1053    ) -> Task<Result<Entry>> {
1054        let path = path.into();
1055        let abs_path = self.absolutize(&path);
1056        let background_snapshot = self.background_snapshot.clone();
1057        let fs = self.fs.clone();
1058        let save = cx.background().spawn(async move {
1059            fs.save(&abs_path, &text).await?;
1060            refresh_entry(fs.as_ref(), &background_snapshot, path.clone(), &abs_path).await
1061        });
1062
1063        cx.spawn(|this, mut cx| async move {
1064            let entry = save.await?;
1065            this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
1066            Ok(entry)
1067        })
1068    }
1069
1070    pub fn share(&mut self, cx: &mut ModelContext<Worktree>) -> Task<anyhow::Result<u64>> {
1071        let snapshot = self.snapshot();
1072        let share_request = self.share_request(cx);
1073        let rpc = self.rpc.clone();
1074        cx.spawn(|this, mut cx| async move {
1075            let share_request = if let Some(request) = share_request.await {
1076                request
1077            } else {
1078                return Err(anyhow!("failed to open worktree on the server"));
1079            };
1080
1081            let remote_id = share_request.worktree.as_ref().unwrap().id;
1082            let share_response = rpc.request(share_request).await?;
1083
1084            log::info!("sharing worktree {:?}", share_response);
1085            let (snapshots_to_send_tx, snapshots_to_send_rx) =
1086                smol::channel::unbounded::<Snapshot>();
1087
1088            cx.background()
1089                .spawn({
1090                    let rpc = rpc.clone();
1091                    async move {
1092                        let mut prev_snapshot = snapshot;
1093                        while let Ok(snapshot) = snapshots_to_send_rx.recv().await {
1094                            let message = snapshot.build_update(&prev_snapshot, remote_id, false);
1095                            match rpc.send(message).await {
1096                                Ok(()) => prev_snapshot = snapshot,
1097                                Err(err) => log::error!("error sending snapshot diff {}", err),
1098                            }
1099                        }
1100                    }
1101                })
1102                .detach();
1103
1104            this.update(&mut cx, |worktree, cx| {
1105                let _subscriptions = vec![
1106                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_add_peer),
1107                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_remove_peer),
1108                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_open_buffer),
1109                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_close_buffer),
1110                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_update_buffer),
1111                    rpc.subscribe_to_entity(remote_id, cx, Worktree::handle_save_buffer),
1112                ];
1113
1114                let worktree = worktree.as_local_mut().unwrap();
1115                worktree.share = Some(ShareState {
1116                    snapshots_tx: snapshots_to_send_tx,
1117                    _subscriptions,
1118                });
1119            });
1120
1121            Ok(remote_id)
1122        })
1123    }
1124
1125    pub fn unshare(&mut self, cx: &mut ModelContext<Worktree>) {
1126        self.share.take();
1127        let rpc = self.rpc.clone();
1128        let remote_id = self.remote_id();
1129        cx.foreground()
1130            .spawn(
1131                async move {
1132                    if let Some(worktree_id) = remote_id {
1133                        rpc.send(proto::UnshareWorktree { worktree_id }).await?;
1134                    }
1135                    Ok(())
1136                }
1137                .log_err(),
1138            )
1139            .detach()
1140    }
1141
1142    fn share_request(&self, cx: &mut ModelContext<Worktree>) -> Task<Option<proto::ShareWorktree>> {
1143        let remote_id = self.next_remote_id();
1144        let snapshot = self.snapshot();
1145        let root_name = self.root_name.clone();
1146        cx.background().spawn(async move {
1147            remote_id.await.map(|id| {
1148                let entries = snapshot
1149                    .entries_by_path
1150                    .cursor::<()>()
1151                    .filter(|e| !e.is_ignored)
1152                    .map(Into::into)
1153                    .collect();
1154                proto::ShareWorktree {
1155                    worktree: Some(proto::Worktree {
1156                        id,
1157                        root_name,
1158                        entries,
1159                    }),
1160                }
1161            })
1162        })
1163    }
1164}
1165
1166fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
1167    let contents = smol::block_on(fs.load(&abs_path))?;
1168    let parent = abs_path.parent().unwrap_or(Path::new("/"));
1169    let mut builder = GitignoreBuilder::new(parent);
1170    for line in contents.lines() {
1171        builder.add_line(Some(abs_path.into()), line)?;
1172    }
1173    Ok(builder.build()?)
1174}
1175
1176impl Deref for LocalWorktree {
1177    type Target = Snapshot;
1178
1179    fn deref(&self) -> &Self::Target {
1180        &self.snapshot
1181    }
1182}
1183
1184impl fmt::Debug for LocalWorktree {
1185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1186        self.snapshot.fmt(f)
1187    }
1188}
1189
1190struct ShareState {
1191    snapshots_tx: Sender<Snapshot>,
1192    _subscriptions: Vec<client::Subscription>,
1193}
1194
1195pub struct RemoteWorktree {
1196    remote_id: u64,
1197    snapshot: Snapshot,
1198    snapshot_rx: watch::Receiver<Snapshot>,
1199    client: Arc<Client>,
1200    updates_tx: postage::mpsc::Sender<proto::UpdateWorktree>,
1201    replica_id: ReplicaId,
1202    open_buffers: HashMap<usize, RemoteBuffer>,
1203    peers: HashMap<PeerId, ReplicaId>,
1204    languages: Arc<LanguageRegistry>,
1205    queued_operations: Vec<(u64, Operation)>,
1206    _subscriptions: Vec<client::Subscription>,
1207}
1208
1209impl RemoteWorktree {
1210    pub fn open_buffer(
1211        &mut self,
1212        path: &Path,
1213        cx: &mut ModelContext<Worktree>,
1214    ) -> Task<Result<ModelHandle<Buffer>>> {
1215        let mut existing_buffer = None;
1216        self.open_buffers.retain(|_buffer_id, buffer| {
1217            if let Some(buffer) = buffer.upgrade(cx.as_ref()) {
1218                if let Some(file) = buffer.read(cx.as_ref()).file() {
1219                    if file.worktree_id() == cx.model_id() && file.path().as_ref() == path {
1220                        existing_buffer = Some(buffer);
1221                    }
1222                }
1223                true
1224            } else {
1225                false
1226            }
1227        });
1228
1229        let rpc = self.client.clone();
1230        let replica_id = self.replica_id;
1231        let remote_worktree_id = self.remote_id;
1232        let path = path.to_string_lossy().to_string();
1233        cx.spawn_weak(|this, mut cx| async move {
1234            if let Some(existing_buffer) = existing_buffer {
1235                Ok(existing_buffer)
1236            } else {
1237                let entry = this
1238                    .upgrade(&cx)
1239                    .ok_or_else(|| anyhow!("worktree was closed"))?
1240                    .read_with(&cx, |tree, _| tree.entry_for_path(&path).cloned())
1241                    .ok_or_else(|| anyhow!("file does not exist"))?;
1242                let response = rpc
1243                    .request(proto::OpenBuffer {
1244                        worktree_id: remote_worktree_id as u64,
1245                        path,
1246                    })
1247                    .await?;
1248
1249                let this = this
1250                    .upgrade(&cx)
1251                    .ok_or_else(|| anyhow!("worktree was closed"))?;
1252                let file = File::new(entry.id, this.clone(), entry.path, entry.mtime);
1253                let language = this.read_with(&cx, |this, cx| {
1254                    use language::File;
1255
1256                    this.languages()
1257                        .select_language(file.full_path(cx))
1258                        .cloned()
1259                });
1260                let remote_buffer = response.buffer.ok_or_else(|| anyhow!("empty buffer"))?;
1261                let buffer_id = remote_buffer.id as usize;
1262                let buffer = cx.add_model(|cx| {
1263                    Buffer::from_proto(
1264                        replica_id,
1265                        remote_buffer,
1266                        Some(Box::new(file)),
1267                        language,
1268                        cx,
1269                    )
1270                    .unwrap()
1271                });
1272                this.update(&mut cx, |this, cx| {
1273                    let this = this.as_remote_mut().unwrap();
1274                    if let Some(RemoteBuffer::Operations(pending_ops)) = this
1275                        .open_buffers
1276                        .insert(buffer_id, RemoteBuffer::Loaded(buffer.downgrade()))
1277                    {
1278                        buffer.update(cx, |buf, cx| buf.apply_ops(pending_ops, cx))?;
1279                    }
1280                    Result::<_, anyhow::Error>::Ok(())
1281                })?;
1282                Ok(buffer)
1283            }
1284        })
1285    }
1286
1287    pub fn remote_id(&self) -> u64 {
1288        self.remote_id
1289    }
1290
1291    pub fn close_all_buffers(&mut self, cx: &mut MutableAppContext) {
1292        for (_, buffer) in self.open_buffers.drain() {
1293            if let RemoteBuffer::Loaded(buffer) = buffer {
1294                if let Some(buffer) = buffer.upgrade(cx) {
1295                    buffer.update(cx, |buffer, cx| buffer.close(cx))
1296                }
1297            }
1298        }
1299    }
1300
1301    fn snapshot(&self) -> Snapshot {
1302        self.snapshot.clone()
1303    }
1304
1305    fn update_from_remote(
1306        &mut self,
1307        envelope: TypedEnvelope<proto::UpdateWorktree>,
1308        cx: &mut ModelContext<Worktree>,
1309    ) -> Result<()> {
1310        let mut tx = self.updates_tx.clone();
1311        let payload = envelope.payload.clone();
1312        cx.background()
1313            .spawn(async move {
1314                tx.send(payload).await.expect("receiver runs to completion");
1315            })
1316            .detach();
1317
1318        Ok(())
1319    }
1320
1321    pub fn add_peer(
1322        &mut self,
1323        envelope: TypedEnvelope<proto::AddPeer>,
1324        cx: &mut ModelContext<Worktree>,
1325    ) -> Result<()> {
1326        let peer = envelope
1327            .payload
1328            .peer
1329            .as_ref()
1330            .ok_or_else(|| anyhow!("empty peer"))?;
1331        self.peers
1332            .insert(PeerId(peer.peer_id), peer.replica_id as ReplicaId);
1333        cx.notify();
1334        Ok(())
1335    }
1336
1337    pub fn remove_peer(
1338        &mut self,
1339        envelope: TypedEnvelope<proto::RemovePeer>,
1340        cx: &mut ModelContext<Worktree>,
1341    ) -> Result<()> {
1342        let peer_id = PeerId(envelope.payload.peer_id);
1343        let replica_id = self
1344            .peers
1345            .remove(&peer_id)
1346            .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?;
1347        for (_, buffer) in &self.open_buffers {
1348            if let Some(buffer) = buffer.upgrade(cx) {
1349                buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
1350            }
1351        }
1352        cx.notify();
1353        Ok(())
1354    }
1355}
1356
1357enum RemoteBuffer {
1358    Operations(Vec<Operation>),
1359    Loaded(WeakModelHandle<Buffer>),
1360}
1361
1362impl RemoteBuffer {
1363    fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
1364        match self {
1365            Self::Operations(_) => None,
1366            Self::Loaded(buffer) => buffer.upgrade(cx),
1367        }
1368    }
1369}
1370
1371#[derive(Clone)]
1372pub struct Snapshot {
1373    id: usize,
1374    scan_id: usize,
1375    abs_path: Arc<Path>,
1376    root_name: String,
1377    root_char_bag: CharBag,
1378    ignores: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,
1379    entries_by_path: SumTree<Entry>,
1380    entries_by_id: SumTree<PathEntry>,
1381    removed_entry_ids: HashMap<u64, usize>,
1382    next_entry_id: Arc<AtomicUsize>,
1383}
1384
1385impl Snapshot {
1386    pub fn id(&self) -> usize {
1387        self.id
1388    }
1389
1390    pub fn build_update(
1391        &self,
1392        other: &Self,
1393        worktree_id: u64,
1394        include_ignored: bool,
1395    ) -> proto::UpdateWorktree {
1396        let mut updated_entries = Vec::new();
1397        let mut removed_entries = Vec::new();
1398        let mut self_entries = self
1399            .entries_by_id
1400            .cursor::<()>()
1401            .filter(|e| include_ignored || !e.is_ignored)
1402            .peekable();
1403        let mut other_entries = other
1404            .entries_by_id
1405            .cursor::<()>()
1406            .filter(|e| include_ignored || !e.is_ignored)
1407            .peekable();
1408        loop {
1409            match (self_entries.peek(), other_entries.peek()) {
1410                (Some(self_entry), Some(other_entry)) => {
1411                    match Ord::cmp(&self_entry.id, &other_entry.id) {
1412                        Ordering::Less => {
1413                            let entry = self.entry_for_id(self_entry.id).unwrap().into();
1414                            updated_entries.push(entry);
1415                            self_entries.next();
1416                        }
1417                        Ordering::Equal => {
1418                            if self_entry.scan_id != other_entry.scan_id {
1419                                let entry = self.entry_for_id(self_entry.id).unwrap().into();
1420                                updated_entries.push(entry);
1421                            }
1422
1423                            self_entries.next();
1424                            other_entries.next();
1425                        }
1426                        Ordering::Greater => {
1427                            removed_entries.push(other_entry.id as u64);
1428                            other_entries.next();
1429                        }
1430                    }
1431                }
1432                (Some(self_entry), None) => {
1433                    let entry = self.entry_for_id(self_entry.id).unwrap().into();
1434                    updated_entries.push(entry);
1435                    self_entries.next();
1436                }
1437                (None, Some(other_entry)) => {
1438                    removed_entries.push(other_entry.id as u64);
1439                    other_entries.next();
1440                }
1441                (None, None) => break,
1442            }
1443        }
1444
1445        proto::UpdateWorktree {
1446            updated_entries,
1447            removed_entries,
1448            worktree_id,
1449        }
1450    }
1451
1452    fn apply_update(&mut self, update: proto::UpdateWorktree) -> Result<()> {
1453        self.scan_id += 1;
1454        let scan_id = self.scan_id;
1455
1456        let mut entries_by_path_edits = Vec::new();
1457        let mut entries_by_id_edits = Vec::new();
1458        for entry_id in update.removed_entries {
1459            let entry_id = entry_id as usize;
1460            let entry = self
1461                .entry_for_id(entry_id)
1462                .ok_or_else(|| anyhow!("unknown entry"))?;
1463            entries_by_path_edits.push(Edit::Remove(PathKey(entry.path.clone())));
1464            entries_by_id_edits.push(Edit::Remove(entry.id));
1465        }
1466
1467        for entry in update.updated_entries {
1468            let entry = Entry::try_from((&self.root_char_bag, entry))?;
1469            if let Some(PathEntry { path, .. }) = self.entries_by_id.get(&entry.id, &()) {
1470                entries_by_path_edits.push(Edit::Remove(PathKey(path.clone())));
1471            }
1472            entries_by_id_edits.push(Edit::Insert(PathEntry {
1473                id: entry.id,
1474                path: entry.path.clone(),
1475                is_ignored: entry.is_ignored,
1476                scan_id,
1477            }));
1478            entries_by_path_edits.push(Edit::Insert(entry));
1479        }
1480
1481        self.entries_by_path.edit(entries_by_path_edits, &());
1482        self.entries_by_id.edit(entries_by_id_edits, &());
1483
1484        Ok(())
1485    }
1486
1487    pub fn file_count(&self) -> usize {
1488        self.entries_by_path.summary().file_count
1489    }
1490
1491    pub fn visible_file_count(&self) -> usize {
1492        self.entries_by_path.summary().visible_file_count
1493    }
1494
1495    fn traverse_from_offset(
1496        &self,
1497        include_dirs: bool,
1498        include_ignored: bool,
1499        start_offset: usize,
1500    ) -> Traversal {
1501        let mut cursor = self.entries_by_path.cursor();
1502        cursor.seek(
1503            &TraversalTarget::Count {
1504                count: start_offset,
1505                include_dirs,
1506                include_ignored,
1507            },
1508            Bias::Right,
1509            &(),
1510        );
1511        Traversal {
1512            cursor,
1513            include_dirs,
1514            include_ignored,
1515        }
1516    }
1517
1518    fn traverse_from_path(
1519        &self,
1520        include_dirs: bool,
1521        include_ignored: bool,
1522        path: &Path,
1523    ) -> Traversal {
1524        let mut cursor = self.entries_by_path.cursor();
1525        cursor.seek(&TraversalTarget::Path(path), Bias::Left, &());
1526        Traversal {
1527            cursor,
1528            include_dirs,
1529            include_ignored,
1530        }
1531    }
1532
1533    pub fn files(&self, include_ignored: bool, start: usize) -> Traversal {
1534        self.traverse_from_offset(false, include_ignored, start)
1535    }
1536
1537    pub fn entries(&self, include_ignored: bool) -> Traversal {
1538        self.traverse_from_offset(true, include_ignored, 0)
1539    }
1540
1541    pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
1542        let empty_path = Path::new("");
1543        self.entries_by_path
1544            .cursor::<()>()
1545            .filter(move |entry| entry.path.as_ref() != empty_path)
1546            .map(|entry| &entry.path)
1547    }
1548
1549    fn child_entries<'a>(&'a self, parent_path: &'a Path) -> ChildEntriesIter<'a> {
1550        let mut cursor = self.entries_by_path.cursor();
1551        cursor.seek(&TraversalTarget::Path(parent_path), Bias::Right, &());
1552        let traversal = Traversal {
1553            cursor,
1554            include_dirs: true,
1555            include_ignored: true,
1556        };
1557        ChildEntriesIter {
1558            traversal,
1559            parent_path,
1560        }
1561    }
1562
1563    pub fn root_entry(&self) -> Option<&Entry> {
1564        self.entry_for_path("")
1565    }
1566
1567    pub fn root_name(&self) -> &str {
1568        &self.root_name
1569    }
1570
1571    pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
1572        let path = path.as_ref();
1573        self.traverse_from_path(true, true, path)
1574            .entry()
1575            .and_then(|entry| {
1576                if entry.path.as_ref() == path {
1577                    Some(entry)
1578                } else {
1579                    None
1580                }
1581            })
1582    }
1583
1584    pub fn entry_for_id(&self, id: usize) -> Option<&Entry> {
1585        let entry = self.entries_by_id.get(&id, &())?;
1586        self.entry_for_path(&entry.path)
1587    }
1588
1589    pub fn inode_for_path(&self, path: impl AsRef<Path>) -> Option<u64> {
1590        self.entry_for_path(path.as_ref()).map(|e| e.inode)
1591    }
1592
1593    fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs) -> Entry {
1594        if !entry.is_dir() && entry.path.file_name() == Some(&GITIGNORE) {
1595            let abs_path = self.abs_path.join(&entry.path);
1596            match build_gitignore(&abs_path, fs) {
1597                Ok(ignore) => {
1598                    let ignore_dir_path = entry.path.parent().unwrap();
1599                    self.ignores
1600                        .insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id));
1601                }
1602                Err(error) => {
1603                    log::error!(
1604                        "error loading .gitignore file {:?} - {:?}",
1605                        &entry.path,
1606                        error
1607                    );
1608                }
1609            }
1610        }
1611
1612        self.reuse_entry_id(&mut entry);
1613        self.entries_by_path.insert_or_replace(entry.clone(), &());
1614        self.entries_by_id.insert_or_replace(
1615            PathEntry {
1616                id: entry.id,
1617                path: entry.path.clone(),
1618                is_ignored: entry.is_ignored,
1619                scan_id: self.scan_id,
1620            },
1621            &(),
1622        );
1623        entry
1624    }
1625
1626    fn populate_dir(
1627        &mut self,
1628        parent_path: Arc<Path>,
1629        entries: impl IntoIterator<Item = Entry>,
1630        ignore: Option<Arc<Gitignore>>,
1631    ) {
1632        let mut parent_entry = self
1633            .entries_by_path
1634            .get(&PathKey(parent_path.clone()), &())
1635            .unwrap()
1636            .clone();
1637        if let Some(ignore) = ignore {
1638            self.ignores.insert(parent_path, (ignore, self.scan_id));
1639        }
1640        if matches!(parent_entry.kind, EntryKind::PendingDir) {
1641            parent_entry.kind = EntryKind::Dir;
1642        } else {
1643            unreachable!();
1644        }
1645
1646        let mut entries_by_path_edits = vec![Edit::Insert(parent_entry)];
1647        let mut entries_by_id_edits = Vec::new();
1648
1649        for mut entry in entries {
1650            self.reuse_entry_id(&mut entry);
1651            entries_by_id_edits.push(Edit::Insert(PathEntry {
1652                id: entry.id,
1653                path: entry.path.clone(),
1654                is_ignored: entry.is_ignored,
1655                scan_id: self.scan_id,
1656            }));
1657            entries_by_path_edits.push(Edit::Insert(entry));
1658        }
1659
1660        self.entries_by_path.edit(entries_by_path_edits, &());
1661        self.entries_by_id.edit(entries_by_id_edits, &());
1662    }
1663
1664    fn reuse_entry_id(&mut self, entry: &mut Entry) {
1665        if let Some(removed_entry_id) = self.removed_entry_ids.remove(&entry.inode) {
1666            entry.id = removed_entry_id;
1667        } else if let Some(existing_entry) = self.entry_for_path(&entry.path) {
1668            entry.id = existing_entry.id;
1669        }
1670    }
1671
1672    fn remove_path(&mut self, path: &Path) {
1673        let mut new_entries;
1674        let removed_entries;
1675        {
1676            let mut cursor = self.entries_by_path.cursor::<TraversalProgress>();
1677            new_entries = cursor.slice(&TraversalTarget::Path(path), Bias::Left, &());
1678            removed_entries = cursor.slice(&TraversalTarget::PathSuccessor(path), Bias::Left, &());
1679            new_entries.push_tree(cursor.suffix(&()), &());
1680        }
1681        self.entries_by_path = new_entries;
1682
1683        let mut entries_by_id_edits = Vec::new();
1684        for entry in removed_entries.cursor::<()>() {
1685            let removed_entry_id = self
1686                .removed_entry_ids
1687                .entry(entry.inode)
1688                .or_insert(entry.id);
1689            *removed_entry_id = cmp::max(*removed_entry_id, entry.id);
1690            entries_by_id_edits.push(Edit::Remove(entry.id));
1691        }
1692        self.entries_by_id.edit(entries_by_id_edits, &());
1693
1694        if path.file_name() == Some(&GITIGNORE) {
1695            if let Some((_, scan_id)) = self.ignores.get_mut(path.parent().unwrap()) {
1696                *scan_id = self.scan_id;
1697            }
1698        }
1699    }
1700
1701    fn ignore_stack_for_path(&self, path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
1702        let mut new_ignores = Vec::new();
1703        for ancestor in path.ancestors().skip(1) {
1704            if let Some((ignore, _)) = self.ignores.get(ancestor) {
1705                new_ignores.push((ancestor, Some(ignore.clone())));
1706            } else {
1707                new_ignores.push((ancestor, None));
1708            }
1709        }
1710
1711        let mut ignore_stack = IgnoreStack::none();
1712        for (parent_path, ignore) in new_ignores.into_iter().rev() {
1713            if ignore_stack.is_path_ignored(&parent_path, true) {
1714                ignore_stack = IgnoreStack::all();
1715                break;
1716            } else if let Some(ignore) = ignore {
1717                ignore_stack = ignore_stack.append(Arc::from(parent_path), ignore);
1718            }
1719        }
1720
1721        if ignore_stack.is_path_ignored(path, is_dir) {
1722            ignore_stack = IgnoreStack::all();
1723        }
1724
1725        ignore_stack
1726    }
1727}
1728
1729impl fmt::Debug for Snapshot {
1730    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1731        for entry in self.entries_by_path.cursor::<()>() {
1732            for _ in entry.path.ancestors().skip(1) {
1733                write!(f, " ")?;
1734            }
1735            writeln!(f, "{:?} (inode: {})", entry.path, entry.inode)?;
1736        }
1737        Ok(())
1738    }
1739}
1740
1741#[derive(Clone, PartialEq)]
1742pub struct File {
1743    entry_id: Option<usize>,
1744    worktree: ModelHandle<Worktree>,
1745    pub path: Arc<Path>,
1746    pub mtime: SystemTime,
1747}
1748
1749impl File {
1750    pub fn new(
1751        entry_id: usize,
1752        worktree: ModelHandle<Worktree>,
1753        path: Arc<Path>,
1754        mtime: SystemTime,
1755    ) -> Self {
1756        Self {
1757            entry_id: Some(entry_id),
1758            worktree,
1759            path,
1760            mtime,
1761        }
1762    }
1763}
1764
1765impl language::File for File {
1766    fn worktree_id(&self) -> usize {
1767        self.worktree.id()
1768    }
1769
1770    fn entry_id(&self) -> Option<usize> {
1771        self.entry_id
1772    }
1773
1774    fn mtime(&self) -> SystemTime {
1775        self.mtime
1776    }
1777
1778    fn path(&self) -> &Arc<Path> {
1779        &self.path
1780    }
1781
1782    fn full_path(&self, cx: &AppContext) -> PathBuf {
1783        let worktree = self.worktree.read(cx);
1784        let mut full_path = PathBuf::new();
1785        full_path.push(worktree.root_name());
1786        full_path.push(&self.path);
1787        full_path
1788    }
1789
1790    /// Returns the last component of this handle's absolute path. If this handle refers to the root
1791    /// of its worktree, then this method will return the name of the worktree itself.
1792    fn file_name<'a>(&'a self, cx: &'a AppContext) -> Option<OsString> {
1793        self.path
1794            .file_name()
1795            .or_else(|| Some(OsStr::new(self.worktree.read(cx).root_name())))
1796            .map(Into::into)
1797    }
1798
1799    fn is_deleted(&self) -> bool {
1800        self.entry_id.is_none()
1801    }
1802
1803    fn save(
1804        &self,
1805        buffer_id: u64,
1806        text: Rope,
1807        version: clock::Global,
1808        cx: &mut MutableAppContext,
1809    ) -> Task<Result<(clock::Global, SystemTime)>> {
1810        self.worktree.update(cx, |worktree, cx| match worktree {
1811            Worktree::Local(worktree) => {
1812                let rpc = worktree.rpc.clone();
1813                let worktree_id = *worktree.remote_id.borrow();
1814                let save = worktree.save(self.path.clone(), text, cx);
1815                cx.background().spawn(async move {
1816                    let entry = save.await?;
1817                    if let Some(worktree_id) = worktree_id {
1818                        rpc.send(proto::BufferSaved {
1819                            worktree_id,
1820                            buffer_id,
1821                            version: (&version).into(),
1822                            mtime: Some(entry.mtime.into()),
1823                        })
1824                        .await?;
1825                    }
1826                    Ok((version, entry.mtime))
1827                })
1828            }
1829            Worktree::Remote(worktree) => {
1830                let rpc = worktree.client.clone();
1831                let worktree_id = worktree.remote_id;
1832                cx.foreground().spawn(async move {
1833                    let response = rpc
1834                        .request(proto::SaveBuffer {
1835                            worktree_id,
1836                            buffer_id,
1837                        })
1838                        .await?;
1839                    let version = response.version.try_into()?;
1840                    let mtime = response
1841                        .mtime
1842                        .ok_or_else(|| anyhow!("missing mtime"))?
1843                        .into();
1844                    Ok((version, mtime))
1845                })
1846            }
1847        })
1848    }
1849
1850    fn load_local(&self, cx: &AppContext) -> Option<Task<Result<String>>> {
1851        let worktree = self.worktree.read(cx).as_local()?;
1852        let abs_path = worktree.absolutize(&self.path);
1853        let fs = worktree.fs.clone();
1854        Some(
1855            cx.background()
1856                .spawn(async move { fs.load(&abs_path).await }),
1857        )
1858    }
1859
1860    fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext) {
1861        self.worktree.update(cx, |worktree, cx| {
1862            if let Some((rpc, remote_id)) = match worktree {
1863                Worktree::Local(worktree) => worktree
1864                    .remote_id
1865                    .borrow()
1866                    .map(|id| (worktree.rpc.clone(), id)),
1867                Worktree::Remote(worktree) => Some((worktree.client.clone(), worktree.remote_id)),
1868            } {
1869                cx.spawn(|worktree, mut cx| async move {
1870                    if let Err(error) = rpc
1871                        .request(proto::UpdateBuffer {
1872                            worktree_id: remote_id,
1873                            buffer_id,
1874                            operations: vec![(&operation).into()],
1875                        })
1876                        .await
1877                    {
1878                        worktree.update(&mut cx, |worktree, _| {
1879                            log::error!("error sending buffer operation: {}", error);
1880                            match worktree {
1881                                Worktree::Local(t) => &mut t.queued_operations,
1882                                Worktree::Remote(t) => &mut t.queued_operations,
1883                            }
1884                            .push((buffer_id, operation));
1885                        });
1886                    }
1887                })
1888                .detach();
1889            }
1890        });
1891    }
1892
1893    fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext) {
1894        self.worktree.update(cx, |worktree, cx| {
1895            if let Worktree::Remote(worktree) = worktree {
1896                let worktree_id = worktree.remote_id;
1897                let rpc = worktree.client.clone();
1898                cx.background()
1899                    .spawn(async move {
1900                        if let Err(error) = rpc
1901                            .send(proto::CloseBuffer {
1902                                worktree_id,
1903                                buffer_id,
1904                            })
1905                            .await
1906                        {
1907                            log::error!("error closing remote buffer: {}", error);
1908                        }
1909                    })
1910                    .detach();
1911            }
1912        });
1913    }
1914
1915    fn boxed_clone(&self) -> Box<dyn language::File> {
1916        Box::new(self.clone())
1917    }
1918
1919    fn as_any(&self) -> &dyn Any {
1920        self
1921    }
1922}
1923
1924#[derive(Clone, Debug)]
1925pub struct Entry {
1926    pub id: usize,
1927    pub kind: EntryKind,
1928    pub path: Arc<Path>,
1929    pub inode: u64,
1930    pub mtime: SystemTime,
1931    pub is_symlink: bool,
1932    pub is_ignored: bool,
1933}
1934
1935#[derive(Clone, Debug)]
1936pub enum EntryKind {
1937    PendingDir,
1938    Dir,
1939    File(CharBag),
1940}
1941
1942impl Entry {
1943    fn new(
1944        path: Arc<Path>,
1945        metadata: &fs::Metadata,
1946        next_entry_id: &AtomicUsize,
1947        root_char_bag: CharBag,
1948    ) -> Self {
1949        Self {
1950            id: next_entry_id.fetch_add(1, SeqCst),
1951            kind: if metadata.is_dir {
1952                EntryKind::PendingDir
1953            } else {
1954                EntryKind::File(char_bag_for_path(root_char_bag, &path))
1955            },
1956            path,
1957            inode: metadata.inode,
1958            mtime: metadata.mtime,
1959            is_symlink: metadata.is_symlink,
1960            is_ignored: false,
1961        }
1962    }
1963
1964    pub fn is_dir(&self) -> bool {
1965        matches!(self.kind, EntryKind::Dir | EntryKind::PendingDir)
1966    }
1967
1968    pub fn is_file(&self) -> bool {
1969        matches!(self.kind, EntryKind::File(_))
1970    }
1971}
1972
1973impl sum_tree::Item for Entry {
1974    type Summary = EntrySummary;
1975
1976    fn summary(&self) -> Self::Summary {
1977        let visible_count = if self.is_ignored { 0 } else { 1 };
1978        let file_count;
1979        let visible_file_count;
1980        if self.is_file() {
1981            file_count = 1;
1982            visible_file_count = visible_count;
1983        } else {
1984            file_count = 0;
1985            visible_file_count = 0;
1986        }
1987
1988        EntrySummary {
1989            max_path: self.path.clone(),
1990            count: 1,
1991            visible_count,
1992            file_count,
1993            visible_file_count,
1994        }
1995    }
1996}
1997
1998impl sum_tree::KeyedItem for Entry {
1999    type Key = PathKey;
2000
2001    fn key(&self) -> Self::Key {
2002        PathKey(self.path.clone())
2003    }
2004}
2005
2006#[derive(Clone, Debug)]
2007pub struct EntrySummary {
2008    max_path: Arc<Path>,
2009    count: usize,
2010    visible_count: usize,
2011    file_count: usize,
2012    visible_file_count: usize,
2013}
2014
2015impl Default for EntrySummary {
2016    fn default() -> Self {
2017        Self {
2018            max_path: Arc::from(Path::new("")),
2019            count: 0,
2020            visible_count: 0,
2021            file_count: 0,
2022            visible_file_count: 0,
2023        }
2024    }
2025}
2026
2027impl sum_tree::Summary for EntrySummary {
2028    type Context = ();
2029
2030    fn add_summary(&mut self, rhs: &Self, _: &()) {
2031        self.max_path = rhs.max_path.clone();
2032        self.visible_count += rhs.visible_count;
2033        self.file_count += rhs.file_count;
2034        self.visible_file_count += rhs.visible_file_count;
2035    }
2036}
2037
2038#[derive(Clone, Debug)]
2039struct PathEntry {
2040    id: usize,
2041    path: Arc<Path>,
2042    is_ignored: bool,
2043    scan_id: usize,
2044}
2045
2046impl sum_tree::Item for PathEntry {
2047    type Summary = PathEntrySummary;
2048
2049    fn summary(&self) -> Self::Summary {
2050        PathEntrySummary { max_id: self.id }
2051    }
2052}
2053
2054impl sum_tree::KeyedItem for PathEntry {
2055    type Key = usize;
2056
2057    fn key(&self) -> Self::Key {
2058        self.id
2059    }
2060}
2061
2062#[derive(Clone, Debug, Default)]
2063struct PathEntrySummary {
2064    max_id: usize,
2065}
2066
2067impl sum_tree::Summary for PathEntrySummary {
2068    type Context = ();
2069
2070    fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
2071        self.max_id = summary.max_id;
2072    }
2073}
2074
2075impl<'a> sum_tree::Dimension<'a, PathEntrySummary> for usize {
2076    fn add_summary(&mut self, summary: &'a PathEntrySummary, _: &()) {
2077        *self = summary.max_id;
2078    }
2079}
2080
2081#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
2082pub struct PathKey(Arc<Path>);
2083
2084impl Default for PathKey {
2085    fn default() -> Self {
2086        Self(Path::new("").into())
2087    }
2088}
2089
2090impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
2091    fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
2092        self.0 = summary.max_path.clone();
2093    }
2094}
2095
2096struct BackgroundScanner {
2097    fs: Arc<dyn Fs>,
2098    snapshot: Arc<Mutex<Snapshot>>,
2099    notify: Sender<ScanState>,
2100    executor: Arc<executor::Background>,
2101}
2102
2103impl BackgroundScanner {
2104    fn new(
2105        snapshot: Arc<Mutex<Snapshot>>,
2106        notify: Sender<ScanState>,
2107        fs: Arc<dyn Fs>,
2108        executor: Arc<executor::Background>,
2109    ) -> Self {
2110        Self {
2111            fs,
2112            snapshot,
2113            notify,
2114            executor,
2115        }
2116    }
2117
2118    fn abs_path(&self) -> Arc<Path> {
2119        self.snapshot.lock().abs_path.clone()
2120    }
2121
2122    fn snapshot(&self) -> Snapshot {
2123        self.snapshot.lock().clone()
2124    }
2125
2126    async fn run(mut self, events_rx: impl Stream<Item = Vec<fsevent::Event>>) {
2127        if self.notify.send(ScanState::Scanning).await.is_err() {
2128            return;
2129        }
2130
2131        if let Err(err) = self.scan_dirs().await {
2132            if self
2133                .notify
2134                .send(ScanState::Err(Arc::new(err)))
2135                .await
2136                .is_err()
2137            {
2138                return;
2139            }
2140        }
2141
2142        if self.notify.send(ScanState::Idle).await.is_err() {
2143            return;
2144        }
2145
2146        futures::pin_mut!(events_rx);
2147        while let Some(events) = events_rx.next().await {
2148            if self.notify.send(ScanState::Scanning).await.is_err() {
2149                break;
2150            }
2151
2152            if !self.process_events(events).await {
2153                break;
2154            }
2155
2156            if self.notify.send(ScanState::Idle).await.is_err() {
2157                break;
2158            }
2159        }
2160    }
2161
2162    async fn scan_dirs(&mut self) -> Result<()> {
2163        let root_char_bag;
2164        let next_entry_id;
2165        let is_dir;
2166        {
2167            let snapshot = self.snapshot.lock();
2168            root_char_bag = snapshot.root_char_bag;
2169            next_entry_id = snapshot.next_entry_id.clone();
2170            is_dir = snapshot.root_entry().map_or(false, |e| e.is_dir())
2171        };
2172
2173        if is_dir {
2174            let path: Arc<Path> = Arc::from(Path::new(""));
2175            let abs_path = self.abs_path();
2176            let (tx, rx) = channel::unbounded();
2177            tx.send(ScanJob {
2178                abs_path: abs_path.to_path_buf(),
2179                path,
2180                ignore_stack: IgnoreStack::none(),
2181                scan_queue: tx.clone(),
2182            })
2183            .await
2184            .unwrap();
2185            drop(tx);
2186
2187            self.executor
2188                .scoped(|scope| {
2189                    for _ in 0..self.executor.num_cpus() {
2190                        scope.spawn(async {
2191                            while let Ok(job) = rx.recv().await {
2192                                if let Err(err) = self
2193                                    .scan_dir(root_char_bag, next_entry_id.clone(), &job)
2194                                    .await
2195                                {
2196                                    log::error!("error scanning {:?}: {}", job.abs_path, err);
2197                                }
2198                            }
2199                        });
2200                    }
2201                })
2202                .await;
2203        }
2204
2205        Ok(())
2206    }
2207
2208    async fn scan_dir(
2209        &self,
2210        root_char_bag: CharBag,
2211        next_entry_id: Arc<AtomicUsize>,
2212        job: &ScanJob,
2213    ) -> Result<()> {
2214        let mut new_entries: Vec<Entry> = Vec::new();
2215        let mut new_jobs: Vec<ScanJob> = Vec::new();
2216        let mut ignore_stack = job.ignore_stack.clone();
2217        let mut new_ignore = None;
2218
2219        let mut child_paths = self.fs.read_dir(&job.abs_path).await?;
2220        while let Some(child_abs_path) = child_paths.next().await {
2221            let child_abs_path = match child_abs_path {
2222                Ok(child_abs_path) => child_abs_path,
2223                Err(error) => {
2224                    log::error!("error processing entry {:?}", error);
2225                    continue;
2226                }
2227            };
2228            let child_name = child_abs_path.file_name().unwrap();
2229            let child_path: Arc<Path> = job.path.join(child_name).into();
2230            let child_metadata = match self.fs.metadata(&child_abs_path).await? {
2231                Some(metadata) => metadata,
2232                None => continue,
2233            };
2234
2235            // If we find a .gitignore, add it to the stack of ignores used to determine which paths are ignored
2236            if child_name == *GITIGNORE {
2237                match build_gitignore(&child_abs_path, self.fs.as_ref()) {
2238                    Ok(ignore) => {
2239                        let ignore = Arc::new(ignore);
2240                        ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
2241                        new_ignore = Some(ignore);
2242                    }
2243                    Err(error) => {
2244                        log::error!(
2245                            "error loading .gitignore file {:?} - {:?}",
2246                            child_name,
2247                            error
2248                        );
2249                    }
2250                }
2251
2252                // Update ignore status of any child entries we've already processed to reflect the
2253                // ignore file in the current directory. Because `.gitignore` starts with a `.`,
2254                // there should rarely be too numerous. Update the ignore stack associated with any
2255                // new jobs as well.
2256                let mut new_jobs = new_jobs.iter_mut();
2257                for entry in &mut new_entries {
2258                    entry.is_ignored = ignore_stack.is_path_ignored(&entry.path, entry.is_dir());
2259                    if entry.is_dir() {
2260                        new_jobs.next().unwrap().ignore_stack = if entry.is_ignored {
2261                            IgnoreStack::all()
2262                        } else {
2263                            ignore_stack.clone()
2264                        };
2265                    }
2266                }
2267            }
2268
2269            let mut child_entry = Entry::new(
2270                child_path.clone(),
2271                &child_metadata,
2272                &next_entry_id,
2273                root_char_bag,
2274            );
2275
2276            if child_metadata.is_dir {
2277                let is_ignored = ignore_stack.is_path_ignored(&child_path, true);
2278                child_entry.is_ignored = is_ignored;
2279                new_entries.push(child_entry);
2280                new_jobs.push(ScanJob {
2281                    abs_path: child_abs_path,
2282                    path: child_path,
2283                    ignore_stack: if is_ignored {
2284                        IgnoreStack::all()
2285                    } else {
2286                        ignore_stack.clone()
2287                    },
2288                    scan_queue: job.scan_queue.clone(),
2289                });
2290            } else {
2291                child_entry.is_ignored = ignore_stack.is_path_ignored(&child_path, false);
2292                new_entries.push(child_entry);
2293            };
2294        }
2295
2296        self.snapshot
2297            .lock()
2298            .populate_dir(job.path.clone(), new_entries, new_ignore);
2299        for new_job in new_jobs {
2300            job.scan_queue.send(new_job).await.unwrap();
2301        }
2302
2303        Ok(())
2304    }
2305
2306    async fn process_events(&mut self, mut events: Vec<fsevent::Event>) -> bool {
2307        let mut snapshot = self.snapshot();
2308        snapshot.scan_id += 1;
2309
2310        let root_abs_path = if let Ok(abs_path) = self.fs.canonicalize(&snapshot.abs_path).await {
2311            abs_path
2312        } else {
2313            return false;
2314        };
2315        let root_char_bag = snapshot.root_char_bag;
2316        let next_entry_id = snapshot.next_entry_id.clone();
2317
2318        events.sort_unstable_by(|a, b| a.path.cmp(&b.path));
2319        events.dedup_by(|a, b| a.path.starts_with(&b.path));
2320
2321        for event in &events {
2322            match event.path.strip_prefix(&root_abs_path) {
2323                Ok(path) => snapshot.remove_path(&path),
2324                Err(_) => {
2325                    log::error!(
2326                        "unexpected event {:?} for root path {:?}",
2327                        event.path,
2328                        root_abs_path
2329                    );
2330                    continue;
2331                }
2332            }
2333        }
2334
2335        let (scan_queue_tx, scan_queue_rx) = channel::unbounded();
2336        for event in events {
2337            let path: Arc<Path> = match event.path.strip_prefix(&root_abs_path) {
2338                Ok(path) => Arc::from(path.to_path_buf()),
2339                Err(_) => {
2340                    log::error!(
2341                        "unexpected event {:?} for root path {:?}",
2342                        event.path,
2343                        root_abs_path
2344                    );
2345                    continue;
2346                }
2347            };
2348
2349            match self.fs.metadata(&event.path).await {
2350                Ok(Some(metadata)) => {
2351                    let ignore_stack = snapshot.ignore_stack_for_path(&path, metadata.is_dir);
2352                    let mut fs_entry = Entry::new(
2353                        path.clone(),
2354                        &metadata,
2355                        snapshot.next_entry_id.as_ref(),
2356                        snapshot.root_char_bag,
2357                    );
2358                    fs_entry.is_ignored = ignore_stack.is_all();
2359                    snapshot.insert_entry(fs_entry, self.fs.as_ref());
2360                    if metadata.is_dir {
2361                        scan_queue_tx
2362                            .send(ScanJob {
2363                                abs_path: event.path,
2364                                path,
2365                                ignore_stack,
2366                                scan_queue: scan_queue_tx.clone(),
2367                            })
2368                            .await
2369                            .unwrap();
2370                    }
2371                }
2372                Ok(None) => {}
2373                Err(err) => {
2374                    // TODO - create a special 'error' entry in the entries tree to mark this
2375                    log::error!("error reading file on event {:?}", err);
2376                }
2377            }
2378        }
2379
2380        *self.snapshot.lock() = snapshot;
2381
2382        // Scan any directories that were created as part of this event batch.
2383        drop(scan_queue_tx);
2384        self.executor
2385            .scoped(|scope| {
2386                for _ in 0..self.executor.num_cpus() {
2387                    scope.spawn(async {
2388                        while let Ok(job) = scan_queue_rx.recv().await {
2389                            if let Err(err) = self
2390                                .scan_dir(root_char_bag, next_entry_id.clone(), &job)
2391                                .await
2392                            {
2393                                log::error!("error scanning {:?}: {}", job.abs_path, err);
2394                            }
2395                        }
2396                    });
2397                }
2398            })
2399            .await;
2400
2401        // Attempt to detect renames only over a single batch of file-system events.
2402        self.snapshot.lock().removed_entry_ids.clear();
2403
2404        self.update_ignore_statuses().await;
2405        true
2406    }
2407
2408    async fn update_ignore_statuses(&self) {
2409        let mut snapshot = self.snapshot();
2410
2411        let mut ignores_to_update = Vec::new();
2412        let mut ignores_to_delete = Vec::new();
2413        for (parent_path, (_, scan_id)) in &snapshot.ignores {
2414            if *scan_id == snapshot.scan_id && snapshot.entry_for_path(parent_path).is_some() {
2415                ignores_to_update.push(parent_path.clone());
2416            }
2417
2418            let ignore_path = parent_path.join(&*GITIGNORE);
2419            if snapshot.entry_for_path(ignore_path).is_none() {
2420                ignores_to_delete.push(parent_path.clone());
2421            }
2422        }
2423
2424        for parent_path in ignores_to_delete {
2425            snapshot.ignores.remove(&parent_path);
2426            self.snapshot.lock().ignores.remove(&parent_path);
2427        }
2428
2429        let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded();
2430        ignores_to_update.sort_unstable();
2431        let mut ignores_to_update = ignores_to_update.into_iter().peekable();
2432        while let Some(parent_path) = ignores_to_update.next() {
2433            while ignores_to_update
2434                .peek()
2435                .map_or(false, |p| p.starts_with(&parent_path))
2436            {
2437                ignores_to_update.next().unwrap();
2438            }
2439
2440            let ignore_stack = snapshot.ignore_stack_for_path(&parent_path, true);
2441            ignore_queue_tx
2442                .send(UpdateIgnoreStatusJob {
2443                    path: parent_path,
2444                    ignore_stack,
2445                    ignore_queue: ignore_queue_tx.clone(),
2446                })
2447                .await
2448                .unwrap();
2449        }
2450        drop(ignore_queue_tx);
2451
2452        self.executor
2453            .scoped(|scope| {
2454                for _ in 0..self.executor.num_cpus() {
2455                    scope.spawn(async {
2456                        while let Ok(job) = ignore_queue_rx.recv().await {
2457                            self.update_ignore_status(job, &snapshot).await;
2458                        }
2459                    });
2460                }
2461            })
2462            .await;
2463    }
2464
2465    async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &Snapshot) {
2466        let mut ignore_stack = job.ignore_stack;
2467        if let Some((ignore, _)) = snapshot.ignores.get(&job.path) {
2468            ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
2469        }
2470
2471        let mut entries_by_id_edits = Vec::new();
2472        let mut entries_by_path_edits = Vec::new();
2473        for mut entry in snapshot.child_entries(&job.path).cloned() {
2474            let was_ignored = entry.is_ignored;
2475            entry.is_ignored = ignore_stack.is_path_ignored(&entry.path, entry.is_dir());
2476            if entry.is_dir() {
2477                let child_ignore_stack = if entry.is_ignored {
2478                    IgnoreStack::all()
2479                } else {
2480                    ignore_stack.clone()
2481                };
2482                job.ignore_queue
2483                    .send(UpdateIgnoreStatusJob {
2484                        path: entry.path.clone(),
2485                        ignore_stack: child_ignore_stack,
2486                        ignore_queue: job.ignore_queue.clone(),
2487                    })
2488                    .await
2489                    .unwrap();
2490            }
2491
2492            if entry.is_ignored != was_ignored {
2493                let mut path_entry = snapshot.entries_by_id.get(&entry.id, &()).unwrap().clone();
2494                path_entry.scan_id = snapshot.scan_id;
2495                path_entry.is_ignored = entry.is_ignored;
2496                entries_by_id_edits.push(Edit::Insert(path_entry));
2497                entries_by_path_edits.push(Edit::Insert(entry));
2498            }
2499        }
2500
2501        let mut snapshot = self.snapshot.lock();
2502        snapshot.entries_by_path.edit(entries_by_path_edits, &());
2503        snapshot.entries_by_id.edit(entries_by_id_edits, &());
2504    }
2505}
2506
2507async fn refresh_entry(
2508    fs: &dyn Fs,
2509    snapshot: &Mutex<Snapshot>,
2510    path: Arc<Path>,
2511    abs_path: &Path,
2512) -> Result<Entry> {
2513    let root_char_bag;
2514    let next_entry_id;
2515    {
2516        let snapshot = snapshot.lock();
2517        root_char_bag = snapshot.root_char_bag;
2518        next_entry_id = snapshot.next_entry_id.clone();
2519    }
2520    let entry = Entry::new(
2521        path,
2522        &fs.metadata(abs_path)
2523            .await?
2524            .ok_or_else(|| anyhow!("could not read saved file metadata"))?,
2525        &next_entry_id,
2526        root_char_bag,
2527    );
2528    Ok(snapshot.lock().insert_entry(entry, fs))
2529}
2530
2531fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
2532    let mut result = root_char_bag;
2533    result.extend(
2534        path.to_string_lossy()
2535            .chars()
2536            .map(|c| c.to_ascii_lowercase()),
2537    );
2538    result
2539}
2540
2541struct ScanJob {
2542    abs_path: PathBuf,
2543    path: Arc<Path>,
2544    ignore_stack: Arc<IgnoreStack>,
2545    scan_queue: Sender<ScanJob>,
2546}
2547
2548struct UpdateIgnoreStatusJob {
2549    path: Arc<Path>,
2550    ignore_stack: Arc<IgnoreStack>,
2551    ignore_queue: Sender<UpdateIgnoreStatusJob>,
2552}
2553
2554pub trait WorktreeHandle {
2555    #[cfg(test)]
2556    fn flush_fs_events<'a>(
2557        &self,
2558        cx: &'a gpui::TestAppContext,
2559    ) -> futures::future::LocalBoxFuture<'a, ()>;
2560}
2561
2562impl WorktreeHandle for ModelHandle<Worktree> {
2563    // When the worktree's FS event stream sometimes delivers "redundant" events for FS changes that
2564    // occurred before the worktree was constructed. These events can cause the worktree to perfrom
2565    // extra directory scans, and emit extra scan-state notifications.
2566    //
2567    // This function mutates the worktree's directory and waits for those mutations to be picked up,
2568    // to ensure that all redundant FS events have already been processed.
2569    #[cfg(test)]
2570    fn flush_fs_events<'a>(
2571        &self,
2572        cx: &'a gpui::TestAppContext,
2573    ) -> futures::future::LocalBoxFuture<'a, ()> {
2574        use smol::future::FutureExt;
2575
2576        let filename = "fs-event-sentinel";
2577        let root_path = cx.read(|cx| self.read(cx).abs_path.clone());
2578        let tree = self.clone();
2579        async move {
2580            std::fs::write(root_path.join(filename), "").unwrap();
2581            tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_some())
2582                .await;
2583
2584            std::fs::remove_file(root_path.join(filename)).unwrap();
2585            tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_none())
2586                .await;
2587
2588            cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2589                .await;
2590        }
2591        .boxed_local()
2592    }
2593}
2594
2595#[derive(Clone, Debug)]
2596struct TraversalProgress<'a> {
2597    max_path: &'a Path,
2598    count: usize,
2599    visible_count: usize,
2600    file_count: usize,
2601    visible_file_count: usize,
2602}
2603
2604impl<'a> TraversalProgress<'a> {
2605    fn count(&self, include_dirs: bool, include_ignored: bool) -> usize {
2606        match (include_ignored, include_dirs) {
2607            (true, true) => self.count,
2608            (true, false) => self.file_count,
2609            (false, true) => self.visible_count,
2610            (false, false) => self.visible_file_count,
2611        }
2612    }
2613}
2614
2615impl<'a> sum_tree::Dimension<'a, EntrySummary> for TraversalProgress<'a> {
2616    fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
2617        self.max_path = summary.max_path.as_ref();
2618        self.count += summary.count;
2619        self.visible_count += summary.visible_count;
2620        self.file_count += summary.file_count;
2621        self.visible_file_count += summary.visible_file_count;
2622    }
2623}
2624
2625impl<'a> Default for TraversalProgress<'a> {
2626    fn default() -> Self {
2627        Self {
2628            max_path: Path::new(""),
2629            count: 0,
2630            visible_count: 0,
2631            file_count: 0,
2632            visible_file_count: 0,
2633        }
2634    }
2635}
2636
2637pub struct Traversal<'a> {
2638    cursor: sum_tree::Cursor<'a, Entry, TraversalProgress<'a>>,
2639    include_ignored: bool,
2640    include_dirs: bool,
2641}
2642
2643impl<'a> Traversal<'a> {
2644    pub fn advance(&mut self) -> bool {
2645        self.advance_to_offset(self.offset() + 1)
2646    }
2647
2648    pub fn advance_to_offset(&mut self, offset: usize) -> bool {
2649        self.cursor.seek_forward(
2650            &TraversalTarget::Count {
2651                count: offset,
2652                include_dirs: self.include_dirs,
2653                include_ignored: self.include_ignored,
2654            },
2655            Bias::Right,
2656            &(),
2657        )
2658    }
2659
2660    pub fn advance_to_sibling(&mut self) -> bool {
2661        while let Some(entry) = self.cursor.item() {
2662            self.cursor.seek_forward(
2663                &TraversalTarget::PathSuccessor(&entry.path),
2664                Bias::Left,
2665                &(),
2666            );
2667            if let Some(entry) = self.cursor.item() {
2668                if (self.include_dirs || !entry.is_dir())
2669                    && (self.include_ignored || !entry.is_ignored)
2670                {
2671                    return true;
2672                }
2673            }
2674        }
2675        false
2676    }
2677
2678    pub fn entry(&self) -> Option<&'a Entry> {
2679        self.cursor.item()
2680    }
2681
2682    pub fn offset(&self) -> usize {
2683        self.cursor
2684            .start()
2685            .count(self.include_dirs, self.include_ignored)
2686    }
2687}
2688
2689impl<'a> Iterator for Traversal<'a> {
2690    type Item = &'a Entry;
2691
2692    fn next(&mut self) -> Option<Self::Item> {
2693        if let Some(item) = self.entry() {
2694            self.advance();
2695            Some(item)
2696        } else {
2697            None
2698        }
2699    }
2700}
2701
2702#[derive(Debug)]
2703enum TraversalTarget<'a> {
2704    Path(&'a Path),
2705    PathSuccessor(&'a Path),
2706    Count {
2707        count: usize,
2708        include_ignored: bool,
2709        include_dirs: bool,
2710    },
2711}
2712
2713impl<'a, 'b> SeekTarget<'a, EntrySummary, TraversalProgress<'a>> for TraversalTarget<'b> {
2714    fn cmp(&self, cursor_location: &TraversalProgress<'a>, _: &()) -> Ordering {
2715        match self {
2716            TraversalTarget::Path(path) => path.cmp(&cursor_location.max_path),
2717            TraversalTarget::PathSuccessor(path) => {
2718                if !cursor_location.max_path.starts_with(path) {
2719                    Ordering::Equal
2720                } else {
2721                    Ordering::Greater
2722                }
2723            }
2724            TraversalTarget::Count {
2725                count,
2726                include_dirs,
2727                include_ignored,
2728            } => Ord::cmp(
2729                count,
2730                &cursor_location.count(*include_dirs, *include_ignored),
2731            ),
2732        }
2733    }
2734}
2735
2736struct ChildEntriesIter<'a> {
2737    parent_path: &'a Path,
2738    traversal: Traversal<'a>,
2739}
2740
2741impl<'a> Iterator for ChildEntriesIter<'a> {
2742    type Item = &'a Entry;
2743
2744    fn next(&mut self) -> Option<Self::Item> {
2745        if let Some(item) = self.traversal.entry() {
2746            if item.path.starts_with(&self.parent_path) {
2747                self.traversal.advance_to_sibling();
2748                return Some(item);
2749            }
2750        }
2751        None
2752    }
2753}
2754
2755impl<'a> From<&'a Entry> for proto::Entry {
2756    fn from(entry: &'a Entry) -> Self {
2757        Self {
2758            id: entry.id as u64,
2759            is_dir: entry.is_dir(),
2760            path: entry.path.to_string_lossy().to_string(),
2761            inode: entry.inode,
2762            mtime: Some(entry.mtime.into()),
2763            is_symlink: entry.is_symlink,
2764            is_ignored: entry.is_ignored,
2765        }
2766    }
2767}
2768
2769impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
2770    type Error = anyhow::Error;
2771
2772    fn try_from((root_char_bag, entry): (&'a CharBag, proto::Entry)) -> Result<Self> {
2773        if let Some(mtime) = entry.mtime {
2774            let kind = if entry.is_dir {
2775                EntryKind::Dir
2776            } else {
2777                let mut char_bag = root_char_bag.clone();
2778                char_bag.extend(entry.path.chars().map(|c| c.to_ascii_lowercase()));
2779                EntryKind::File(char_bag)
2780            };
2781            let path: Arc<Path> = Arc::from(Path::new(&entry.path));
2782            Ok(Entry {
2783                id: entry.id as usize,
2784                kind,
2785                path: path.clone(),
2786                inode: entry.inode,
2787                mtime: mtime.into(),
2788                is_symlink: entry.is_symlink,
2789                is_ignored: entry.is_ignored,
2790            })
2791        } else {
2792            Err(anyhow!(
2793                "missing mtime in remote worktree entry {:?}",
2794                entry.path
2795            ))
2796        }
2797    }
2798}
2799
2800#[cfg(test)]
2801mod tests {
2802    use super::*;
2803    use crate::fs::FakeFs;
2804    use anyhow::Result;
2805    use client::test::FakeServer;
2806    use fs::RealFs;
2807    use rand::prelude::*;
2808    use serde_json::json;
2809    use std::{cell::RefCell, rc::Rc};
2810    use std::{
2811        env,
2812        fmt::Write,
2813        time::{SystemTime, UNIX_EPOCH},
2814    };
2815    use util::test::temp_tree;
2816
2817    #[gpui::test]
2818    async fn test_traversal(cx: gpui::TestAppContext) {
2819        let fs = FakeFs::new();
2820        fs.insert_tree(
2821            "/root",
2822            json!({
2823               ".gitignore": "a/b\n",
2824               "a": {
2825                   "b": "",
2826                   "c": "",
2827               }
2828            }),
2829        )
2830        .await;
2831
2832        let tree = Worktree::open_local(
2833            Client::new(),
2834            Arc::from(Path::new("/root")),
2835            Arc::new(fs),
2836            Default::default(),
2837            &mut cx.to_async(),
2838        )
2839        .await
2840        .unwrap();
2841        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2842            .await;
2843
2844        tree.read_with(&cx, |tree, _| {
2845            assert_eq!(
2846                tree.entries(false)
2847                    .map(|entry| entry.path.as_ref())
2848                    .collect::<Vec<_>>(),
2849                vec![
2850                    Path::new(""),
2851                    Path::new(".gitignore"),
2852                    Path::new("a"),
2853                    Path::new("a/c"),
2854                ]
2855            );
2856        })
2857    }
2858
2859    #[gpui::test]
2860    async fn test_save_file(mut cx: gpui::TestAppContext) {
2861        let dir = temp_tree(json!({
2862            "file1": "the old contents",
2863        }));
2864        let tree = Worktree::open_local(
2865            Client::new(),
2866            dir.path(),
2867            Arc::new(RealFs),
2868            Default::default(),
2869            &mut cx.to_async(),
2870        )
2871        .await
2872        .unwrap();
2873        let buffer = tree
2874            .update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
2875            .await
2876            .unwrap();
2877        let save = buffer.update(&mut cx, |buffer, cx| {
2878            buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
2879            buffer.save(cx).unwrap()
2880        });
2881        save.await.unwrap();
2882
2883        let new_text = std::fs::read_to_string(dir.path().join("file1")).unwrap();
2884        assert_eq!(new_text, buffer.read_with(&cx, |buffer, _| buffer.text()));
2885    }
2886
2887    #[gpui::test]
2888    async fn test_save_in_single_file_worktree(mut cx: gpui::TestAppContext) {
2889        let dir = temp_tree(json!({
2890            "file1": "the old contents",
2891        }));
2892        let file_path = dir.path().join("file1");
2893
2894        let tree = Worktree::open_local(
2895            Client::new(),
2896            file_path.clone(),
2897            Arc::new(RealFs),
2898            Default::default(),
2899            &mut cx.to_async(),
2900        )
2901        .await
2902        .unwrap();
2903        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2904            .await;
2905        cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
2906
2907        let buffer = tree
2908            .update(&mut cx, |tree, cx| tree.open_buffer("", cx))
2909            .await
2910            .unwrap();
2911        let save = buffer.update(&mut cx, |buffer, cx| {
2912            buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
2913            buffer.save(cx).unwrap()
2914        });
2915        save.await.unwrap();
2916
2917        let new_text = std::fs::read_to_string(file_path).unwrap();
2918        assert_eq!(new_text, buffer.read_with(&cx, |buffer, _| buffer.text()));
2919    }
2920
2921    #[gpui::test]
2922    async fn test_rescan_and_remote_updates(mut cx: gpui::TestAppContext) {
2923        let dir = temp_tree(json!({
2924            "a": {
2925                "file1": "",
2926                "file2": "",
2927                "file3": "",
2928            },
2929            "b": {
2930                "c": {
2931                    "file4": "",
2932                    "file5": "",
2933                }
2934            }
2935        }));
2936
2937        let user_id = 5;
2938        let mut client = Client::new();
2939        let server = FakeServer::for_client(user_id, &mut client, &cx).await;
2940        let tree = Worktree::open_local(
2941            client,
2942            dir.path(),
2943            Arc::new(RealFs),
2944            Default::default(),
2945            &mut cx.to_async(),
2946        )
2947        .await
2948        .unwrap();
2949
2950        let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
2951            let buffer = tree.update(cx, |tree, cx| tree.open_buffer(path, cx));
2952            async move { buffer.await.unwrap() }
2953        };
2954        let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
2955            tree.read_with(cx, |tree, _| {
2956                tree.entry_for_path(path)
2957                    .expect(&format!("no entry for path {}", path))
2958                    .id
2959            })
2960        };
2961
2962        let buffer2 = buffer_for_path("a/file2", &mut cx).await;
2963        let buffer3 = buffer_for_path("a/file3", &mut cx).await;
2964        let buffer4 = buffer_for_path("b/c/file4", &mut cx).await;
2965        let buffer5 = buffer_for_path("b/c/file5", &mut cx).await;
2966
2967        let file2_id = id_for_path("a/file2", &cx);
2968        let file3_id = id_for_path("a/file3", &cx);
2969        let file4_id = id_for_path("b/c/file4", &cx);
2970
2971        // Wait for the initial scan.
2972        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
2973            .await;
2974
2975        // Create a remote copy of this worktree.
2976        let initial_snapshot = tree.read_with(&cx, |tree, _| tree.snapshot());
2977        let worktree_id = 1;
2978        let share_request = tree.update(&mut cx, |tree, cx| {
2979            tree.as_local().unwrap().share_request(cx)
2980        });
2981        let open_worktree = server.receive::<proto::OpenWorktree>().await.unwrap();
2982        server
2983            .respond(
2984                open_worktree.receipt(),
2985                proto::OpenWorktreeResponse { worktree_id: 1 },
2986            )
2987            .await;
2988
2989        let remote = Worktree::remote(
2990            proto::JoinWorktreeResponse {
2991                worktree: share_request.await.unwrap().worktree,
2992                replica_id: 1,
2993                peers: Vec::new(),
2994            },
2995            Client::new(),
2996            Default::default(),
2997            &mut cx.to_async(),
2998        )
2999        .await
3000        .unwrap();
3001
3002        cx.read(|cx| {
3003            assert!(!buffer2.read(cx).is_dirty());
3004            assert!(!buffer3.read(cx).is_dirty());
3005            assert!(!buffer4.read(cx).is_dirty());
3006            assert!(!buffer5.read(cx).is_dirty());
3007        });
3008
3009        // Rename and delete files and directories.
3010        tree.flush_fs_events(&cx).await;
3011        std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
3012        std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
3013        std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
3014        std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
3015        tree.flush_fs_events(&cx).await;
3016
3017        let expected_paths = vec![
3018            "a",
3019            "a/file1",
3020            "a/file2.new",
3021            "b",
3022            "d",
3023            "d/file3",
3024            "d/file4",
3025        ];
3026
3027        cx.read(|app| {
3028            assert_eq!(
3029                tree.read(app)
3030                    .paths()
3031                    .map(|p| p.to_str().unwrap())
3032                    .collect::<Vec<_>>(),
3033                expected_paths
3034            );
3035
3036            assert_eq!(id_for_path("a/file2.new", &cx), file2_id);
3037            assert_eq!(id_for_path("d/file3", &cx), file3_id);
3038            assert_eq!(id_for_path("d/file4", &cx), file4_id);
3039
3040            assert_eq!(
3041                buffer2.read(app).file().unwrap().path().as_ref(),
3042                Path::new("a/file2.new")
3043            );
3044            assert_eq!(
3045                buffer3.read(app).file().unwrap().path().as_ref(),
3046                Path::new("d/file3")
3047            );
3048            assert_eq!(
3049                buffer4.read(app).file().unwrap().path().as_ref(),
3050                Path::new("d/file4")
3051            );
3052            assert_eq!(
3053                buffer5.read(app).file().unwrap().path().as_ref(),
3054                Path::new("b/c/file5")
3055            );
3056
3057            assert!(!buffer2.read(app).file().unwrap().is_deleted());
3058            assert!(!buffer3.read(app).file().unwrap().is_deleted());
3059            assert!(!buffer4.read(app).file().unwrap().is_deleted());
3060            assert!(buffer5.read(app).file().unwrap().is_deleted());
3061        });
3062
3063        // Update the remote worktree. Check that it becomes consistent with the
3064        // local worktree.
3065        remote.update(&mut cx, |remote, cx| {
3066            let update_message =
3067                tree.read(cx)
3068                    .snapshot()
3069                    .build_update(&initial_snapshot, worktree_id, true);
3070            remote
3071                .as_remote_mut()
3072                .unwrap()
3073                .snapshot
3074                .apply_update(update_message)
3075                .unwrap();
3076
3077            assert_eq!(
3078                remote
3079                    .paths()
3080                    .map(|p| p.to_str().unwrap())
3081                    .collect::<Vec<_>>(),
3082                expected_paths
3083            );
3084        });
3085    }
3086
3087    #[gpui::test]
3088    async fn test_rescan_with_gitignore(cx: gpui::TestAppContext) {
3089        let dir = temp_tree(json!({
3090            ".git": {},
3091            ".gitignore": "ignored-dir\n",
3092            "tracked-dir": {
3093                "tracked-file1": "tracked contents",
3094            },
3095            "ignored-dir": {
3096                "ignored-file1": "ignored contents",
3097            }
3098        }));
3099
3100        let tree = Worktree::open_local(
3101            Client::new(),
3102            dir.path(),
3103            Arc::new(RealFs),
3104            Default::default(),
3105            &mut cx.to_async(),
3106        )
3107        .await
3108        .unwrap();
3109        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3110            .await;
3111        tree.flush_fs_events(&cx).await;
3112        cx.read(|cx| {
3113            let tree = tree.read(cx);
3114            let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap();
3115            let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap();
3116            assert_eq!(tracked.is_ignored, false);
3117            assert_eq!(ignored.is_ignored, true);
3118        });
3119
3120        std::fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap();
3121        std::fs::write(dir.path().join("ignored-dir/ignored-file2"), "").unwrap();
3122        tree.flush_fs_events(&cx).await;
3123        cx.read(|cx| {
3124            let tree = tree.read(cx);
3125            let dot_git = tree.entry_for_path(".git").unwrap();
3126            let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap();
3127            let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap();
3128            assert_eq!(tracked.is_ignored, false);
3129            assert_eq!(ignored.is_ignored, true);
3130            assert_eq!(dot_git.is_ignored, true);
3131        });
3132    }
3133
3134    #[gpui::test]
3135    async fn test_open_and_share_worktree(mut cx: gpui::TestAppContext) {
3136        let user_id = 100;
3137        let mut client = Client::new();
3138        let server = FakeServer::for_client(user_id, &mut client, &cx).await;
3139
3140        let fs = Arc::new(FakeFs::new());
3141        fs.insert_tree(
3142            "/path",
3143            json!({
3144                "to": {
3145                    "the-dir": {
3146                        ".zed.toml": r#"collaborators = ["friend-1", "friend-2"]"#,
3147                        "a.txt": "a-contents",
3148                    },
3149                },
3150            }),
3151        )
3152        .await;
3153
3154        let worktree = Worktree::open_local(
3155            client.clone(),
3156            "/path/to/the-dir".as_ref(),
3157            fs,
3158            Default::default(),
3159            &mut cx.to_async(),
3160        )
3161        .await
3162        .unwrap();
3163
3164        {
3165            let cx = cx.to_async();
3166            client.authenticate_and_connect(&cx).await.unwrap();
3167        }
3168
3169        let open_worktree = server.receive::<proto::OpenWorktree>().await.unwrap();
3170        assert_eq!(
3171            open_worktree.payload,
3172            proto::OpenWorktree {
3173                root_name: "the-dir".to_string(),
3174                collaborator_logins: vec!["friend-1".to_string(), "friend-2".to_string()],
3175            }
3176        );
3177
3178        server
3179            .respond(
3180                open_worktree.receipt(),
3181                proto::OpenWorktreeResponse { worktree_id: 5 },
3182            )
3183            .await;
3184        let remote_id = worktree
3185            .update(&mut cx, |tree, _| tree.as_local().unwrap().next_remote_id())
3186            .await;
3187        assert_eq!(remote_id, Some(5));
3188
3189        cx.update(move |_| drop(worktree));
3190        server.receive::<proto::CloseWorktree>().await.unwrap();
3191    }
3192
3193    #[gpui::test]
3194    async fn test_buffer_is_dirty(mut cx: gpui::TestAppContext) {
3195        use std::fs;
3196
3197        let dir = temp_tree(json!({
3198            "file1": "abc",
3199            "file2": "def",
3200            "file3": "ghi",
3201        }));
3202        let tree = Worktree::open_local(
3203            Client::new(),
3204            dir.path(),
3205            Arc::new(RealFs),
3206            Default::default(),
3207            &mut cx.to_async(),
3208        )
3209        .await
3210        .unwrap();
3211        tree.flush_fs_events(&cx).await;
3212        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3213            .await;
3214
3215        let buffer1 = tree
3216            .update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
3217            .await
3218            .unwrap();
3219        let events = Rc::new(RefCell::new(Vec::new()));
3220
3221        // initially, the buffer isn't dirty.
3222        buffer1.update(&mut cx, |buffer, cx| {
3223            cx.subscribe(&buffer1, {
3224                let events = events.clone();
3225                move |_, _, event, _| events.borrow_mut().push(event.clone())
3226            })
3227            .detach();
3228
3229            assert!(!buffer.is_dirty());
3230            assert!(events.borrow().is_empty());
3231
3232            buffer.edit(vec![1..2], "", cx);
3233        });
3234
3235        // after the first edit, the buffer is dirty, and emits a dirtied event.
3236        buffer1.update(&mut cx, |buffer, cx| {
3237            assert!(buffer.text() == "ac");
3238            assert!(buffer.is_dirty());
3239            assert_eq!(
3240                *events.borrow(),
3241                &[language::Event::Edited, language::Event::Dirtied]
3242            );
3243            events.borrow_mut().clear();
3244            buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
3245        });
3246
3247        // after saving, the buffer is not dirty, and emits a saved event.
3248        buffer1.update(&mut cx, |buffer, cx| {
3249            assert!(!buffer.is_dirty());
3250            assert_eq!(*events.borrow(), &[language::Event::Saved]);
3251            events.borrow_mut().clear();
3252
3253            buffer.edit(vec![1..1], "B", cx);
3254            buffer.edit(vec![2..2], "D", cx);
3255        });
3256
3257        // after editing again, the buffer is dirty, and emits another dirty event.
3258        buffer1.update(&mut cx, |buffer, cx| {
3259            assert!(buffer.text() == "aBDc");
3260            assert!(buffer.is_dirty());
3261            assert_eq!(
3262                *events.borrow(),
3263                &[
3264                    language::Event::Edited,
3265                    language::Event::Dirtied,
3266                    language::Event::Edited
3267                ],
3268            );
3269            events.borrow_mut().clear();
3270
3271            // TODO - currently, after restoring the buffer to its
3272            // previously-saved state, the is still considered dirty.
3273            buffer.edit(vec![1..3], "", cx);
3274            assert!(buffer.text() == "ac");
3275            assert!(buffer.is_dirty());
3276        });
3277
3278        assert_eq!(*events.borrow(), &[language::Event::Edited]);
3279
3280        // When a file is deleted, the buffer is considered dirty.
3281        let events = Rc::new(RefCell::new(Vec::new()));
3282        let buffer2 = tree
3283            .update(&mut cx, |tree, cx| tree.open_buffer("file2", cx))
3284            .await
3285            .unwrap();
3286        buffer2.update(&mut cx, |_, cx| {
3287            cx.subscribe(&buffer2, {
3288                let events = events.clone();
3289                move |_, _, event, _| events.borrow_mut().push(event.clone())
3290            })
3291            .detach();
3292        });
3293
3294        fs::remove_file(dir.path().join("file2")).unwrap();
3295        buffer2.condition(&cx, |b, _| b.is_dirty()).await;
3296        assert_eq!(
3297            *events.borrow(),
3298            &[language::Event::Dirtied, language::Event::FileHandleChanged]
3299        );
3300
3301        // When a file is already dirty when deleted, we don't emit a Dirtied event.
3302        let events = Rc::new(RefCell::new(Vec::new()));
3303        let buffer3 = tree
3304            .update(&mut cx, |tree, cx| tree.open_buffer("file3", cx))
3305            .await
3306            .unwrap();
3307        buffer3.update(&mut cx, |_, cx| {
3308            cx.subscribe(&buffer3, {
3309                let events = events.clone();
3310                move |_, _, event, _| events.borrow_mut().push(event.clone())
3311            })
3312            .detach();
3313        });
3314
3315        tree.flush_fs_events(&cx).await;
3316        buffer3.update(&mut cx, |buffer, cx| {
3317            buffer.edit(Some(0..0), "x", cx);
3318        });
3319        events.borrow_mut().clear();
3320        fs::remove_file(dir.path().join("file3")).unwrap();
3321        buffer3
3322            .condition(&cx, |_, _| !events.borrow().is_empty())
3323            .await;
3324        assert_eq!(*events.borrow(), &[language::Event::FileHandleChanged]);
3325        cx.read(|cx| assert!(buffer3.read(cx).is_dirty()));
3326    }
3327
3328    #[gpui::test]
3329    async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) {
3330        use buffer::{Point, Selection, SelectionGoal, ToPoint};
3331        use std::fs;
3332
3333        let initial_contents = "aaa\nbbbbb\nc\n";
3334        let dir = temp_tree(json!({ "the-file": initial_contents }));
3335        let tree = Worktree::open_local(
3336            Client::new(),
3337            dir.path(),
3338            Arc::new(RealFs),
3339            Default::default(),
3340            &mut cx.to_async(),
3341        )
3342        .await
3343        .unwrap();
3344        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3345            .await;
3346
3347        let abs_path = dir.path().join("the-file");
3348        let buffer = tree
3349            .update(&mut cx, |tree, cx| {
3350                tree.open_buffer(Path::new("the-file"), cx)
3351            })
3352            .await
3353            .unwrap();
3354
3355        // Add a cursor at the start of each row.
3356        let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
3357            assert!(!buffer.is_dirty());
3358            buffer.add_selection_set(
3359                (0..3)
3360                    .map(|row| {
3361                        let anchor = buffer.anchor_at(Point::new(row, 0), Bias::Right);
3362                        Selection {
3363                            id: row as usize,
3364                            start: anchor.clone(),
3365                            end: anchor,
3366                            reversed: false,
3367                            goal: SelectionGoal::None,
3368                        }
3369                    })
3370                    .collect::<Vec<_>>(),
3371                cx,
3372            )
3373        });
3374
3375        // Change the file on disk, adding two new lines of text, and removing
3376        // one line.
3377        buffer.read_with(&cx, |buffer, _| {
3378            assert!(!buffer.is_dirty());
3379            assert!(!buffer.has_conflict());
3380        });
3381        let new_contents = "AAAA\naaa\nBB\nbbbbb\n";
3382        fs::write(&abs_path, new_contents).unwrap();
3383
3384        // Because the buffer was not modified, it is reloaded from disk. Its
3385        // contents are edited according to the diff between the old and new
3386        // file contents.
3387        buffer
3388            .condition(&cx, |buffer, _| buffer.text() != initial_contents)
3389            .await;
3390
3391        buffer.update(&mut cx, |buffer, _| {
3392            assert_eq!(buffer.text(), new_contents);
3393            assert!(!buffer.is_dirty());
3394            assert!(!buffer.has_conflict());
3395
3396            let set = buffer.selection_set(selection_set_id).unwrap();
3397            let cursor_positions = set
3398                .selections
3399                .iter()
3400                .map(|selection| {
3401                    assert_eq!(selection.start, selection.end);
3402                    selection.start.to_point(&*buffer)
3403                })
3404                .collect::<Vec<_>>();
3405            assert_eq!(
3406                cursor_positions,
3407                &[Point::new(1, 0), Point::new(3, 0), Point::new(4, 0),]
3408            );
3409        });
3410
3411        // Modify the buffer
3412        buffer.update(&mut cx, |buffer, cx| {
3413            buffer.edit(vec![0..0], " ", cx);
3414            assert!(buffer.is_dirty());
3415            assert!(!buffer.has_conflict());
3416        });
3417
3418        // Change the file on disk again, adding blank lines to the beginning.
3419        fs::write(&abs_path, "\n\n\nAAAA\naaa\nBB\nbbbbb\n").unwrap();
3420
3421        // Because the buffer is modified, it doesn't reload from disk, but is
3422        // marked as having a conflict.
3423        buffer
3424            .condition(&cx, |buffer, _| buffer.has_conflict())
3425            .await;
3426    }
3427
3428    #[gpui::test(iterations = 100)]
3429    fn test_random(mut rng: StdRng) {
3430        let operations = env::var("OPERATIONS")
3431            .map(|o| o.parse().unwrap())
3432            .unwrap_or(40);
3433        let initial_entries = env::var("INITIAL_ENTRIES")
3434            .map(|o| o.parse().unwrap())
3435            .unwrap_or(20);
3436
3437        let root_dir = tempdir::TempDir::new("worktree-test").unwrap();
3438        for _ in 0..initial_entries {
3439            randomly_mutate_tree(root_dir.path(), 1.0, &mut rng).unwrap();
3440        }
3441        log::info!("Generated initial tree");
3442
3443        let (notify_tx, _notify_rx) = smol::channel::unbounded();
3444        let fs = Arc::new(RealFs);
3445        let next_entry_id = Arc::new(AtomicUsize::new(0));
3446        let mut initial_snapshot = Snapshot {
3447            id: 0,
3448            scan_id: 0,
3449            abs_path: root_dir.path().into(),
3450            entries_by_path: Default::default(),
3451            entries_by_id: Default::default(),
3452            removed_entry_ids: Default::default(),
3453            ignores: Default::default(),
3454            root_name: Default::default(),
3455            root_char_bag: Default::default(),
3456            next_entry_id: next_entry_id.clone(),
3457        };
3458        initial_snapshot.insert_entry(
3459            Entry::new(
3460                Path::new("").into(),
3461                &smol::block_on(fs.metadata(root_dir.path()))
3462                    .unwrap()
3463                    .unwrap(),
3464                &next_entry_id,
3465                Default::default(),
3466            ),
3467            fs.as_ref(),
3468        );
3469        let mut scanner = BackgroundScanner::new(
3470            Arc::new(Mutex::new(initial_snapshot.clone())),
3471            notify_tx,
3472            fs.clone(),
3473            Arc::new(gpui::executor::Background::new()),
3474        );
3475        smol::block_on(scanner.scan_dirs()).unwrap();
3476        scanner.snapshot().check_invariants();
3477
3478        let mut events = Vec::new();
3479        let mut snapshots = Vec::new();
3480        let mut mutations_len = operations;
3481        while mutations_len > 1 {
3482            if !events.is_empty() && rng.gen_bool(0.4) {
3483                let len = rng.gen_range(0..=events.len());
3484                let to_deliver = events.drain(0..len).collect::<Vec<_>>();
3485                log::info!("Delivering events: {:#?}", to_deliver);
3486                smol::block_on(scanner.process_events(to_deliver));
3487                scanner.snapshot().check_invariants();
3488            } else {
3489                events.extend(randomly_mutate_tree(root_dir.path(), 0.6, &mut rng).unwrap());
3490                mutations_len -= 1;
3491            }
3492
3493            if rng.gen_bool(0.2) {
3494                snapshots.push(scanner.snapshot());
3495            }
3496        }
3497        log::info!("Quiescing: {:#?}", events);
3498        smol::block_on(scanner.process_events(events));
3499        scanner.snapshot().check_invariants();
3500
3501        let (notify_tx, _notify_rx) = smol::channel::unbounded();
3502        let mut new_scanner = BackgroundScanner::new(
3503            Arc::new(Mutex::new(initial_snapshot)),
3504            notify_tx,
3505            scanner.fs.clone(),
3506            scanner.executor.clone(),
3507        );
3508        smol::block_on(new_scanner.scan_dirs()).unwrap();
3509        assert_eq!(
3510            scanner.snapshot().to_vec(true),
3511            new_scanner.snapshot().to_vec(true)
3512        );
3513
3514        for mut prev_snapshot in snapshots {
3515            let include_ignored = rng.gen::<bool>();
3516            if !include_ignored {
3517                let mut entries_by_path_edits = Vec::new();
3518                let mut entries_by_id_edits = Vec::new();
3519                for entry in prev_snapshot
3520                    .entries_by_id
3521                    .cursor::<()>()
3522                    .filter(|e| e.is_ignored)
3523                {
3524                    entries_by_path_edits.push(Edit::Remove(PathKey(entry.path.clone())));
3525                    entries_by_id_edits.push(Edit::Remove(entry.id));
3526                }
3527
3528                prev_snapshot
3529                    .entries_by_path
3530                    .edit(entries_by_path_edits, &());
3531                prev_snapshot.entries_by_id.edit(entries_by_id_edits, &());
3532            }
3533
3534            let update = scanner
3535                .snapshot()
3536                .build_update(&prev_snapshot, 0, include_ignored);
3537            prev_snapshot.apply_update(update).unwrap();
3538            assert_eq!(
3539                prev_snapshot.to_vec(true),
3540                scanner.snapshot().to_vec(include_ignored)
3541            );
3542        }
3543    }
3544
3545    fn randomly_mutate_tree(
3546        root_path: &Path,
3547        insertion_probability: f64,
3548        rng: &mut impl Rng,
3549    ) -> Result<Vec<fsevent::Event>> {
3550        let root_path = root_path.canonicalize().unwrap();
3551        let (dirs, files) = read_dir_recursive(root_path.clone());
3552
3553        let mut events = Vec::new();
3554        let mut record_event = |path: PathBuf| {
3555            events.push(fsevent::Event {
3556                event_id: SystemTime::now()
3557                    .duration_since(UNIX_EPOCH)
3558                    .unwrap()
3559                    .as_secs(),
3560                flags: fsevent::StreamFlags::empty(),
3561                path,
3562            });
3563        };
3564
3565        if (files.is_empty() && dirs.len() == 1) || rng.gen_bool(insertion_probability) {
3566            let path = dirs.choose(rng).unwrap();
3567            let new_path = path.join(gen_name(rng));
3568
3569            if rng.gen() {
3570                log::info!("Creating dir {:?}", new_path.strip_prefix(root_path)?);
3571                std::fs::create_dir(&new_path)?;
3572            } else {
3573                log::info!("Creating file {:?}", new_path.strip_prefix(root_path)?);
3574                std::fs::write(&new_path, "")?;
3575            }
3576            record_event(new_path);
3577        } else if rng.gen_bool(0.05) {
3578            let ignore_dir_path = dirs.choose(rng).unwrap();
3579            let ignore_path = ignore_dir_path.join(&*GITIGNORE);
3580
3581            let (subdirs, subfiles) = read_dir_recursive(ignore_dir_path.clone());
3582            let files_to_ignore = {
3583                let len = rng.gen_range(0..=subfiles.len());
3584                subfiles.choose_multiple(rng, len)
3585            };
3586            let dirs_to_ignore = {
3587                let len = rng.gen_range(0..subdirs.len());
3588                subdirs.choose_multiple(rng, len)
3589            };
3590
3591            let mut ignore_contents = String::new();
3592            for path_to_ignore in files_to_ignore.chain(dirs_to_ignore) {
3593                write!(
3594                    ignore_contents,
3595                    "{}\n",
3596                    path_to_ignore
3597                        .strip_prefix(&ignore_dir_path)?
3598                        .to_str()
3599                        .unwrap()
3600                )
3601                .unwrap();
3602            }
3603            log::info!(
3604                "Creating {:?} with contents:\n{}",
3605                ignore_path.strip_prefix(&root_path)?,
3606                ignore_contents
3607            );
3608            std::fs::write(&ignore_path, ignore_contents).unwrap();
3609            record_event(ignore_path);
3610        } else {
3611            let old_path = {
3612                let file_path = files.choose(rng);
3613                let dir_path = dirs[1..].choose(rng);
3614                file_path.into_iter().chain(dir_path).choose(rng).unwrap()
3615            };
3616
3617            let is_rename = rng.gen();
3618            if is_rename {
3619                let new_path_parent = dirs
3620                    .iter()
3621                    .filter(|d| !d.starts_with(old_path))
3622                    .choose(rng)
3623                    .unwrap();
3624
3625                let overwrite_existing_dir =
3626                    !old_path.starts_with(&new_path_parent) && rng.gen_bool(0.3);
3627                let new_path = if overwrite_existing_dir {
3628                    std::fs::remove_dir_all(&new_path_parent).ok();
3629                    new_path_parent.to_path_buf()
3630                } else {
3631                    new_path_parent.join(gen_name(rng))
3632                };
3633
3634                log::info!(
3635                    "Renaming {:?} to {}{:?}",
3636                    old_path.strip_prefix(&root_path)?,
3637                    if overwrite_existing_dir {
3638                        "overwrite "
3639                    } else {
3640                        ""
3641                    },
3642                    new_path.strip_prefix(&root_path)?
3643                );
3644                std::fs::rename(&old_path, &new_path)?;
3645                record_event(old_path.clone());
3646                record_event(new_path);
3647            } else if old_path.is_dir() {
3648                let (dirs, files) = read_dir_recursive(old_path.clone());
3649
3650                log::info!("Deleting dir {:?}", old_path.strip_prefix(&root_path)?);
3651                std::fs::remove_dir_all(&old_path).unwrap();
3652                for file in files {
3653                    record_event(file);
3654                }
3655                for dir in dirs {
3656                    record_event(dir);
3657                }
3658            } else {
3659                log::info!("Deleting file {:?}", old_path.strip_prefix(&root_path)?);
3660                std::fs::remove_file(old_path).unwrap();
3661                record_event(old_path.clone());
3662            }
3663        }
3664
3665        Ok(events)
3666    }
3667
3668    fn read_dir_recursive(path: PathBuf) -> (Vec<PathBuf>, Vec<PathBuf>) {
3669        let child_entries = std::fs::read_dir(&path).unwrap();
3670        let mut dirs = vec![path];
3671        let mut files = Vec::new();
3672        for child_entry in child_entries {
3673            let child_path = child_entry.unwrap().path();
3674            if child_path.is_dir() {
3675                let (child_dirs, child_files) = read_dir_recursive(child_path);
3676                dirs.extend(child_dirs);
3677                files.extend(child_files);
3678            } else {
3679                files.push(child_path);
3680            }
3681        }
3682        (dirs, files)
3683    }
3684
3685    fn gen_name(rng: &mut impl Rng) -> String {
3686        (0..6)
3687            .map(|_| rng.sample(rand::distributions::Alphanumeric))
3688            .map(char::from)
3689            .collect()
3690    }
3691
3692    impl Snapshot {
3693        fn check_invariants(&self) {
3694            let mut files = self.files(true, 0);
3695            let mut visible_files = self.files(false, 0);
3696            for entry in self.entries_by_path.cursor::<()>() {
3697                if entry.is_file() {
3698                    assert_eq!(files.next().unwrap().inode, entry.inode);
3699                    if !entry.is_ignored {
3700                        assert_eq!(visible_files.next().unwrap().inode, entry.inode);
3701                    }
3702                }
3703            }
3704            assert!(files.next().is_none());
3705            assert!(visible_files.next().is_none());
3706
3707            let mut bfs_paths = Vec::new();
3708            let mut stack = vec![Path::new("")];
3709            while let Some(path) = stack.pop() {
3710                bfs_paths.push(path);
3711                let ix = stack.len();
3712                for child_entry in self.child_entries(path) {
3713                    stack.insert(ix, &child_entry.path);
3714                }
3715            }
3716
3717            let dfs_paths = self
3718                .entries_by_path
3719                .cursor::<()>()
3720                .map(|e| e.path.as_ref())
3721                .collect::<Vec<_>>();
3722            assert_eq!(bfs_paths, dfs_paths);
3723
3724            for (ignore_parent_path, _) in &self.ignores {
3725                assert!(self.entry_for_path(ignore_parent_path).is_some());
3726                assert!(self
3727                    .entry_for_path(ignore_parent_path.join(&*GITIGNORE))
3728                    .is_some());
3729            }
3730        }
3731
3732        fn to_vec(&self, include_ignored: bool) -> Vec<(&Path, u64, bool)> {
3733            let mut paths = Vec::new();
3734            for entry in self.entries_by_path.cursor::<()>() {
3735                if include_ignored || !entry.is_ignored {
3736                    paths.push((entry.path.as_ref(), entry.inode, entry.is_ignored));
3737                }
3738            }
3739            paths.sort_by(|a, b| a.0.cmp(&b.0));
3740            paths
3741        }
3742    }
3743}