worktree.rs

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