worktree.rs

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