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