project.rs

   1pub mod fs;
   2mod ignore;
   3mod lsp_command;
   4pub mod search;
   5pub mod worktree;
   6
   7use anyhow::{anyhow, Context, Result};
   8use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
   9use clock::ReplicaId;
  10use collections::{hash_map, BTreeMap, HashMap, HashSet};
  11use futures::{future::Shared, Future, FutureExt, StreamExt, TryFutureExt};
  12use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
  13use gpui::{
  14    AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
  15    MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle,
  16};
  17use language::{
  18    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  19    range_from_lsp, Anchor, Bias, Buffer, CodeAction, CodeLabel, Completion, Diagnostic,
  20    DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _, Language, LanguageRegistry,
  21    LocalFile, OffsetRangeExt, Operation, Patch, PointUtf16, TextBufferSnapshot, ToLspPosition,
  22    ToOffset, ToPointUtf16, Transaction,
  23};
  24use lsp::{DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer};
  25use lsp_command::*;
  26use parking_lot::Mutex;
  27use postage::watch;
  28use rand::prelude::*;
  29use search::SearchQuery;
  30use sha2::{Digest, Sha256};
  31use similar::{ChangeTag, TextDiff};
  32use std::{
  33    cell::RefCell,
  34    cmp::{self, Ordering},
  35    convert::TryInto,
  36    hash::Hash,
  37    mem,
  38    ops::Range,
  39    path::{Component, Path, PathBuf},
  40    rc::Rc,
  41    sync::{
  42        atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
  43        Arc,
  44    },
  45    time::Instant,
  46};
  47use util::{post_inc, ResultExt, TryFutureExt as _};
  48
  49pub use fs::*;
  50pub use worktree::*;
  51
  52pub trait Item: Entity {
  53    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
  54}
  55
  56pub struct Project {
  57    worktrees: Vec<WorktreeHandle>,
  58    active_entry: Option<ProjectEntryId>,
  59    languages: Arc<LanguageRegistry>,
  60    language_servers: HashMap<(WorktreeId, Arc<str>), Arc<LanguageServer>>,
  61    started_language_servers: HashMap<(WorktreeId, Arc<str>), Task<Option<Arc<LanguageServer>>>>,
  62    language_server_statuses: BTreeMap<usize, LanguageServerStatus>,
  63    language_server_settings: Arc<Mutex<serde_json::Value>>,
  64    next_language_server_id: usize,
  65    client: Arc<client::Client>,
  66    next_entry_id: Arc<AtomicUsize>,
  67    user_store: ModelHandle<UserStore>,
  68    fs: Arc<dyn Fs>,
  69    client_state: ProjectClientState,
  70    collaborators: HashMap<PeerId, Collaborator>,
  71    subscriptions: Vec<client::Subscription>,
  72    language_servers_with_diagnostics_running: isize,
  73    opened_buffer: (Rc<RefCell<watch::Sender<()>>>, watch::Receiver<()>),
  74    shared_buffers: HashMap<PeerId, HashSet<u64>>,
  75    loading_buffers: HashMap<
  76        ProjectPath,
  77        postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
  78    >,
  79    loading_local_worktrees:
  80        HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>,
  81    opened_buffers: HashMap<u64, OpenBuffer>,
  82    buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
  83    nonce: u128,
  84}
  85
  86enum OpenBuffer {
  87    Strong(ModelHandle<Buffer>),
  88    Weak(WeakModelHandle<Buffer>),
  89    Loading(Vec<Operation>),
  90}
  91
  92enum WorktreeHandle {
  93    Strong(ModelHandle<Worktree>),
  94    Weak(WeakModelHandle<Worktree>),
  95}
  96
  97enum ProjectClientState {
  98    Local {
  99        is_shared: bool,
 100        remote_id_tx: watch::Sender<Option<u64>>,
 101        remote_id_rx: watch::Receiver<Option<u64>>,
 102        _maintain_remote_id_task: Task<Option<()>>,
 103    },
 104    Remote {
 105        sharing_has_stopped: bool,
 106        remote_id: u64,
 107        replica_id: ReplicaId,
 108        _detect_unshare_task: Task<Option<()>>,
 109    },
 110}
 111
 112#[derive(Clone, Debug)]
 113pub struct Collaborator {
 114    pub user: Arc<User>,
 115    pub peer_id: PeerId,
 116    pub replica_id: ReplicaId,
 117}
 118
 119#[derive(Clone, Debug, PartialEq)]
 120pub enum Event {
 121    ActiveEntryChanged(Option<ProjectEntryId>),
 122    WorktreeRemoved(WorktreeId),
 123    DiskBasedDiagnosticsStarted,
 124    DiskBasedDiagnosticsUpdated,
 125    DiskBasedDiagnosticsFinished,
 126    DiagnosticsUpdated(ProjectPath),
 127    RemoteIdChanged(Option<u64>),
 128    CollaboratorLeft(PeerId),
 129}
 130
 131enum LanguageServerEvent {
 132    WorkStart {
 133        token: String,
 134    },
 135    WorkProgress {
 136        token: String,
 137        progress: LanguageServerProgress,
 138    },
 139    WorkEnd {
 140        token: String,
 141    },
 142    DiagnosticsUpdate(lsp::PublishDiagnosticsParams),
 143}
 144
 145pub struct LanguageServerStatus {
 146    pub name: String,
 147    pub pending_work: BTreeMap<String, LanguageServerProgress>,
 148    pending_diagnostic_updates: isize,
 149}
 150
 151#[derive(Clone, Debug)]
 152pub struct LanguageServerProgress {
 153    pub message: Option<String>,
 154    pub percentage: Option<usize>,
 155    pub last_update_at: Instant,
 156}
 157
 158#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
 159pub struct ProjectPath {
 160    pub worktree_id: WorktreeId,
 161    pub path: Arc<Path>,
 162}
 163
 164#[derive(Clone, Debug, Default, PartialEq)]
 165pub struct DiagnosticSummary {
 166    pub error_count: usize,
 167    pub warning_count: usize,
 168    pub info_count: usize,
 169    pub hint_count: usize,
 170}
 171
 172#[derive(Debug)]
 173pub struct Location {
 174    pub buffer: ModelHandle<Buffer>,
 175    pub range: Range<language::Anchor>,
 176}
 177
 178#[derive(Debug)]
 179pub struct DocumentHighlight {
 180    pub range: Range<language::Anchor>,
 181    pub kind: DocumentHighlightKind,
 182}
 183
 184#[derive(Clone, Debug)]
 185pub struct Symbol {
 186    pub source_worktree_id: WorktreeId,
 187    pub worktree_id: WorktreeId,
 188    pub language_name: String,
 189    pub path: PathBuf,
 190    pub label: CodeLabel,
 191    pub name: String,
 192    pub kind: lsp::SymbolKind,
 193    pub range: Range<PointUtf16>,
 194    pub signature: [u8; 32],
 195}
 196
 197#[derive(Default)]
 198pub struct ProjectTransaction(pub HashMap<ModelHandle<Buffer>, language::Transaction>);
 199
 200impl DiagnosticSummary {
 201    fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
 202        let mut this = Self {
 203            error_count: 0,
 204            warning_count: 0,
 205            info_count: 0,
 206            hint_count: 0,
 207        };
 208
 209        for entry in diagnostics {
 210            if entry.diagnostic.is_primary {
 211                match entry.diagnostic.severity {
 212                    DiagnosticSeverity::ERROR => this.error_count += 1,
 213                    DiagnosticSeverity::WARNING => this.warning_count += 1,
 214                    DiagnosticSeverity::INFORMATION => this.info_count += 1,
 215                    DiagnosticSeverity::HINT => this.hint_count += 1,
 216                    _ => {}
 217                }
 218            }
 219        }
 220
 221        this
 222    }
 223
 224    pub fn to_proto(&self, path: &Path) -> proto::DiagnosticSummary {
 225        proto::DiagnosticSummary {
 226            path: path.to_string_lossy().to_string(),
 227            error_count: self.error_count as u32,
 228            warning_count: self.warning_count as u32,
 229            info_count: self.info_count as u32,
 230            hint_count: self.hint_count as u32,
 231        }
 232    }
 233}
 234
 235#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 236pub struct ProjectEntryId(usize);
 237
 238impl ProjectEntryId {
 239    pub fn new(counter: &AtomicUsize) -> Self {
 240        Self(counter.fetch_add(1, SeqCst))
 241    }
 242
 243    pub fn from_proto(id: u64) -> Self {
 244        Self(id as usize)
 245    }
 246
 247    pub fn to_proto(&self) -> u64 {
 248        self.0 as u64
 249    }
 250
 251    pub fn to_usize(&self) -> usize {
 252        self.0
 253    }
 254}
 255
 256impl Project {
 257    pub fn init(client: &Arc<Client>) {
 258        client.add_model_message_handler(Self::handle_add_collaborator);
 259        client.add_model_message_handler(Self::handle_buffer_reloaded);
 260        client.add_model_message_handler(Self::handle_buffer_saved);
 261        client.add_model_message_handler(Self::handle_start_language_server);
 262        client.add_model_message_handler(Self::handle_update_language_server);
 263        client.add_model_message_handler(Self::handle_remove_collaborator);
 264        client.add_model_message_handler(Self::handle_register_worktree);
 265        client.add_model_message_handler(Self::handle_unregister_worktree);
 266        client.add_model_message_handler(Self::handle_unshare_project);
 267        client.add_model_message_handler(Self::handle_update_buffer_file);
 268        client.add_model_message_handler(Self::handle_update_buffer);
 269        client.add_model_message_handler(Self::handle_update_diagnostic_summary);
 270        client.add_model_message_handler(Self::handle_update_worktree);
 271        client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion);
 272        client.add_model_request_handler(Self::handle_apply_code_action);
 273        client.add_model_request_handler(Self::handle_format_buffers);
 274        client.add_model_request_handler(Self::handle_get_code_actions);
 275        client.add_model_request_handler(Self::handle_get_completions);
 276        client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
 277        client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
 278        client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
 279        client.add_model_request_handler(Self::handle_lsp_command::<PrepareRename>);
 280        client.add_model_request_handler(Self::handle_lsp_command::<PerformRename>);
 281        client.add_model_request_handler(Self::handle_search_project);
 282        client.add_model_request_handler(Self::handle_get_project_symbols);
 283        client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
 284        client.add_model_request_handler(Self::handle_open_buffer_by_id);
 285        client.add_model_request_handler(Self::handle_open_buffer_by_path);
 286        client.add_model_request_handler(Self::handle_save_buffer);
 287    }
 288
 289    pub fn local(
 290        client: Arc<Client>,
 291        user_store: ModelHandle<UserStore>,
 292        languages: Arc<LanguageRegistry>,
 293        fs: Arc<dyn Fs>,
 294        cx: &mut MutableAppContext,
 295    ) -> ModelHandle<Self> {
 296        cx.add_model(|cx: &mut ModelContext<Self>| {
 297            let (remote_id_tx, remote_id_rx) = watch::channel();
 298            let _maintain_remote_id_task = cx.spawn_weak({
 299                let rpc = client.clone();
 300                move |this, mut cx| {
 301                    async move {
 302                        let mut status = rpc.status();
 303                        while let Some(status) = status.next().await {
 304                            if let Some(this) = this.upgrade(&cx) {
 305                                if status.is_connected() {
 306                                    this.update(&mut cx, |this, cx| this.register(cx)).await?;
 307                                } else {
 308                                    this.update(&mut cx, |this, cx| this.unregister(cx));
 309                                }
 310                            }
 311                        }
 312                        Ok(())
 313                    }
 314                    .log_err()
 315                }
 316            });
 317
 318            let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
 319            Self {
 320                worktrees: Default::default(),
 321                collaborators: Default::default(),
 322                opened_buffers: Default::default(),
 323                shared_buffers: Default::default(),
 324                loading_buffers: Default::default(),
 325                loading_local_worktrees: Default::default(),
 326                buffer_snapshots: Default::default(),
 327                client_state: ProjectClientState::Local {
 328                    is_shared: false,
 329                    remote_id_tx,
 330                    remote_id_rx,
 331                    _maintain_remote_id_task,
 332                },
 333                opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
 334                subscriptions: Vec::new(),
 335                active_entry: None,
 336                languages,
 337                client,
 338                user_store,
 339                fs,
 340                next_entry_id: Default::default(),
 341                language_servers_with_diagnostics_running: 0,
 342                language_servers: Default::default(),
 343                started_language_servers: Default::default(),
 344                language_server_statuses: Default::default(),
 345                language_server_settings: Default::default(),
 346                next_language_server_id: 0,
 347                nonce: StdRng::from_entropy().gen(),
 348            }
 349        })
 350    }
 351
 352    pub async fn remote(
 353        remote_id: u64,
 354        client: Arc<Client>,
 355        user_store: ModelHandle<UserStore>,
 356        languages: Arc<LanguageRegistry>,
 357        fs: Arc<dyn Fs>,
 358        cx: &mut AsyncAppContext,
 359    ) -> Result<ModelHandle<Self>> {
 360        client.authenticate_and_connect(true, &cx).await?;
 361
 362        let response = client
 363            .request(proto::JoinProject {
 364                project_id: remote_id,
 365            })
 366            .await?;
 367
 368        let replica_id = response.replica_id as ReplicaId;
 369
 370        let mut worktrees = Vec::new();
 371        for worktree in response.worktrees {
 372            let (worktree, load_task) = cx
 373                .update(|cx| Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx));
 374            worktrees.push(worktree);
 375            load_task.detach();
 376        }
 377
 378        let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
 379        let this = cx.add_model(|cx: &mut ModelContext<Self>| {
 380            let mut this = Self {
 381                worktrees: Vec::new(),
 382                loading_buffers: Default::default(),
 383                opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
 384                shared_buffers: Default::default(),
 385                loading_local_worktrees: Default::default(),
 386                active_entry: None,
 387                collaborators: Default::default(),
 388                languages,
 389                user_store: user_store.clone(),
 390                fs,
 391                next_entry_id: Default::default(),
 392                subscriptions: vec![client.add_model_for_remote_entity(remote_id, cx)],
 393                client: client.clone(),
 394                client_state: ProjectClientState::Remote {
 395                    sharing_has_stopped: false,
 396                    remote_id,
 397                    replica_id,
 398                    _detect_unshare_task: cx.spawn_weak(move |this, mut cx| {
 399                        async move {
 400                            let mut status = client.status();
 401                            let is_connected =
 402                                status.next().await.map_or(false, |s| s.is_connected());
 403                            // Even if we're initially connected, any future change of the status means we momentarily disconnected.
 404                            if !is_connected || status.next().await.is_some() {
 405                                if let Some(this) = this.upgrade(&cx) {
 406                                    this.update(&mut cx, |this, cx| this.project_unshared(cx))
 407                                }
 408                            }
 409                            Ok(())
 410                        }
 411                        .log_err()
 412                    }),
 413                },
 414                language_servers_with_diagnostics_running: 0,
 415                language_servers: Default::default(),
 416                started_language_servers: Default::default(),
 417                language_server_settings: Default::default(),
 418                language_server_statuses: response
 419                    .language_servers
 420                    .into_iter()
 421                    .map(|server| {
 422                        (
 423                            server.id as usize,
 424                            LanguageServerStatus {
 425                                name: server.name,
 426                                pending_work: Default::default(),
 427                                pending_diagnostic_updates: 0,
 428                            },
 429                        )
 430                    })
 431                    .collect(),
 432                next_language_server_id: 0,
 433                opened_buffers: Default::default(),
 434                buffer_snapshots: Default::default(),
 435                nonce: StdRng::from_entropy().gen(),
 436            };
 437            for worktree in worktrees {
 438                this.add_worktree(&worktree, cx);
 439            }
 440            this
 441        });
 442
 443        let user_ids = response
 444            .collaborators
 445            .iter()
 446            .map(|peer| peer.user_id)
 447            .collect();
 448        user_store
 449            .update(cx, |user_store, cx| user_store.load_users(user_ids, cx))
 450            .await?;
 451        let mut collaborators = HashMap::default();
 452        for message in response.collaborators {
 453            let collaborator = Collaborator::from_proto(message, &user_store, cx).await?;
 454            collaborators.insert(collaborator.peer_id, collaborator);
 455        }
 456
 457        this.update(cx, |this, _| {
 458            this.collaborators = collaborators;
 459        });
 460
 461        Ok(this)
 462    }
 463
 464    #[cfg(any(test, feature = "test-support"))]
 465    pub fn test(fs: Arc<dyn Fs>, cx: &mut gpui::TestAppContext) -> ModelHandle<Project> {
 466        let languages = Arc::new(LanguageRegistry::test());
 467        let http_client = client::test::FakeHttpClient::with_404_response();
 468        let client = client::Client::new(http_client.clone());
 469        let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
 470        cx.update(|cx| Project::local(client, user_store, languages, fs, cx))
 471    }
 472
 473    pub fn buffer_for_id(&self, remote_id: u64, cx: &AppContext) -> Option<ModelHandle<Buffer>> {
 474        self.opened_buffers
 475            .get(&remote_id)
 476            .and_then(|buffer| buffer.upgrade(cx))
 477    }
 478
 479    #[cfg(any(test, feature = "test-support"))]
 480    pub fn languages(&self) -> &Arc<LanguageRegistry> {
 481        &self.languages
 482    }
 483
 484    #[cfg(any(test, feature = "test-support"))]
 485    pub fn check_invariants(&self, cx: &AppContext) {
 486        if self.is_local() {
 487            let mut worktree_root_paths = HashMap::default();
 488            for worktree in self.worktrees(cx) {
 489                let worktree = worktree.read(cx);
 490                let abs_path = worktree.as_local().unwrap().abs_path().clone();
 491                let prev_worktree_id = worktree_root_paths.insert(abs_path.clone(), worktree.id());
 492                assert_eq!(
 493                    prev_worktree_id,
 494                    None,
 495                    "abs path {:?} for worktree {:?} is not unique ({:?} was already registered with the same path)",
 496                    abs_path,
 497                    worktree.id(),
 498                    prev_worktree_id
 499                )
 500            }
 501        } else {
 502            let replica_id = self.replica_id();
 503            for buffer in self.opened_buffers.values() {
 504                if let Some(buffer) = buffer.upgrade(cx) {
 505                    let buffer = buffer.read(cx);
 506                    assert_eq!(
 507                        buffer.deferred_ops_len(),
 508                        0,
 509                        "replica {}, buffer {} has deferred operations",
 510                        replica_id,
 511                        buffer.remote_id()
 512                    );
 513                }
 514            }
 515        }
 516    }
 517
 518    #[cfg(any(test, feature = "test-support"))]
 519    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
 520        let path = path.into();
 521        if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
 522            self.opened_buffers.iter().any(|(_, buffer)| {
 523                if let Some(buffer) = buffer.upgrade(cx) {
 524                    if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
 525                        if file.worktree == worktree && file.path() == &path.path {
 526                            return true;
 527                        }
 528                    }
 529                }
 530                false
 531            })
 532        } else {
 533            false
 534        }
 535    }
 536
 537    pub fn fs(&self) -> &Arc<dyn Fs> {
 538        &self.fs
 539    }
 540
 541    fn unregister(&mut self, cx: &mut ModelContext<Self>) {
 542        self.unshare(cx);
 543        for worktree in &self.worktrees {
 544            if let Some(worktree) = worktree.upgrade(cx) {
 545                worktree.update(cx, |worktree, _| {
 546                    worktree.as_local_mut().unwrap().unregister();
 547                });
 548            }
 549        }
 550
 551        if let ProjectClientState::Local { remote_id_tx, .. } = &mut self.client_state {
 552            *remote_id_tx.borrow_mut() = None;
 553        }
 554
 555        self.subscriptions.clear();
 556    }
 557
 558    fn register(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 559        self.unregister(cx);
 560
 561        let response = self.client.request(proto::RegisterProject {});
 562        cx.spawn(|this, mut cx| async move {
 563            let remote_id = response.await?.project_id;
 564
 565            let mut registrations = Vec::new();
 566            this.update(&mut cx, |this, cx| {
 567                if let ProjectClientState::Local { remote_id_tx, .. } = &mut this.client_state {
 568                    *remote_id_tx.borrow_mut() = Some(remote_id);
 569                }
 570
 571                cx.emit(Event::RemoteIdChanged(Some(remote_id)));
 572
 573                this.subscriptions
 574                    .push(this.client.add_model_for_remote_entity(remote_id, cx));
 575
 576                for worktree in &this.worktrees {
 577                    if let Some(worktree) = worktree.upgrade(cx) {
 578                        registrations.push(worktree.update(cx, |worktree, cx| {
 579                            let worktree = worktree.as_local_mut().unwrap();
 580                            worktree.register(remote_id, cx)
 581                        }));
 582                    }
 583                }
 584            });
 585
 586            futures::future::try_join_all(registrations).await?;
 587            Ok(())
 588        })
 589    }
 590
 591    pub fn remote_id(&self) -> Option<u64> {
 592        match &self.client_state {
 593            ProjectClientState::Local { remote_id_rx, .. } => *remote_id_rx.borrow(),
 594            ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
 595        }
 596    }
 597
 598    pub fn next_remote_id(&self) -> impl Future<Output = u64> {
 599        let mut id = None;
 600        let mut watch = None;
 601        match &self.client_state {
 602            ProjectClientState::Local { remote_id_rx, .. } => watch = Some(remote_id_rx.clone()),
 603            ProjectClientState::Remote { remote_id, .. } => id = Some(*remote_id),
 604        }
 605
 606        async move {
 607            if let Some(id) = id {
 608                return id;
 609            }
 610            let mut watch = watch.unwrap();
 611            loop {
 612                let id = *watch.borrow();
 613                if let Some(id) = id {
 614                    return id;
 615                }
 616                watch.next().await;
 617            }
 618        }
 619    }
 620
 621    pub fn replica_id(&self) -> ReplicaId {
 622        match &self.client_state {
 623            ProjectClientState::Local { .. } => 0,
 624            ProjectClientState::Remote { replica_id, .. } => *replica_id,
 625        }
 626    }
 627
 628    pub fn collaborators(&self) -> &HashMap<PeerId, Collaborator> {
 629        &self.collaborators
 630    }
 631
 632    pub fn worktrees<'a>(
 633        &'a self,
 634        cx: &'a AppContext,
 635    ) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
 636        self.worktrees
 637            .iter()
 638            .filter_map(move |worktree| worktree.upgrade(cx))
 639    }
 640
 641    pub fn visible_worktrees<'a>(
 642        &'a self,
 643        cx: &'a AppContext,
 644    ) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
 645        self.worktrees.iter().filter_map(|worktree| {
 646            worktree.upgrade(cx).and_then(|worktree| {
 647                if worktree.read(cx).is_visible() {
 648                    Some(worktree)
 649                } else {
 650                    None
 651                }
 652            })
 653        })
 654    }
 655
 656    pub fn worktree_for_id(
 657        &self,
 658        id: WorktreeId,
 659        cx: &AppContext,
 660    ) -> Option<ModelHandle<Worktree>> {
 661        self.worktrees(cx)
 662            .find(|worktree| worktree.read(cx).id() == id)
 663    }
 664
 665    pub fn worktree_for_entry(
 666        &self,
 667        entry_id: ProjectEntryId,
 668        cx: &AppContext,
 669    ) -> Option<ModelHandle<Worktree>> {
 670        self.worktrees(cx)
 671            .find(|worktree| worktree.read(cx).contains_entry(entry_id))
 672    }
 673
 674    pub fn worktree_id_for_entry(
 675        &self,
 676        entry_id: ProjectEntryId,
 677        cx: &AppContext,
 678    ) -> Option<WorktreeId> {
 679        self.worktree_for_entry(entry_id, cx)
 680            .map(|worktree| worktree.read(cx).id())
 681    }
 682
 683    pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 684        let rpc = self.client.clone();
 685        cx.spawn(|this, mut cx| async move {
 686            let project_id = this.update(&mut cx, |this, cx| {
 687                if let ProjectClientState::Local {
 688                    is_shared,
 689                    remote_id_rx,
 690                    ..
 691                } = &mut this.client_state
 692                {
 693                    *is_shared = true;
 694
 695                    for open_buffer in this.opened_buffers.values_mut() {
 696                        match open_buffer {
 697                            OpenBuffer::Strong(_) => {}
 698                            OpenBuffer::Weak(buffer) => {
 699                                if let Some(buffer) = buffer.upgrade(cx) {
 700                                    *open_buffer = OpenBuffer::Strong(buffer);
 701                                }
 702                            }
 703                            OpenBuffer::Loading(_) => unreachable!(),
 704                        }
 705                    }
 706
 707                    for worktree_handle in this.worktrees.iter_mut() {
 708                        match worktree_handle {
 709                            WorktreeHandle::Strong(_) => {}
 710                            WorktreeHandle::Weak(worktree) => {
 711                                if let Some(worktree) = worktree.upgrade(cx) {
 712                                    *worktree_handle = WorktreeHandle::Strong(worktree);
 713                                }
 714                            }
 715                        }
 716                    }
 717
 718                    remote_id_rx
 719                        .borrow()
 720                        .ok_or_else(|| anyhow!("no project id"))
 721                } else {
 722                    Err(anyhow!("can't share a remote project"))
 723                }
 724            })?;
 725
 726            rpc.request(proto::ShareProject { project_id }).await?;
 727
 728            let mut tasks = Vec::new();
 729            this.update(&mut cx, |this, cx| {
 730                for worktree in this.worktrees(cx).collect::<Vec<_>>() {
 731                    worktree.update(cx, |worktree, cx| {
 732                        let worktree = worktree.as_local_mut().unwrap();
 733                        tasks.push(worktree.share(project_id, cx));
 734                    });
 735                }
 736            });
 737            for task in tasks {
 738                task.await?;
 739            }
 740            this.update(&mut cx, |_, cx| cx.notify());
 741            Ok(())
 742        })
 743    }
 744
 745    pub fn unshare(&mut self, cx: &mut ModelContext<Self>) {
 746        let rpc = self.client.clone();
 747
 748        if let ProjectClientState::Local {
 749            is_shared,
 750            remote_id_rx,
 751            ..
 752        } = &mut self.client_state
 753        {
 754            if !*is_shared {
 755                return;
 756            }
 757
 758            *is_shared = false;
 759            self.collaborators.clear();
 760            self.shared_buffers.clear();
 761            for worktree_handle in self.worktrees.iter_mut() {
 762                if let WorktreeHandle::Strong(worktree) = worktree_handle {
 763                    let is_visible = worktree.update(cx, |worktree, _| {
 764                        worktree.as_local_mut().unwrap().unshare();
 765                        worktree.is_visible()
 766                    });
 767                    if !is_visible {
 768                        *worktree_handle = WorktreeHandle::Weak(worktree.downgrade());
 769                    }
 770                }
 771            }
 772
 773            for open_buffer in self.opened_buffers.values_mut() {
 774                match open_buffer {
 775                    OpenBuffer::Strong(buffer) => {
 776                        *open_buffer = OpenBuffer::Weak(buffer.downgrade());
 777                    }
 778                    _ => {}
 779                }
 780            }
 781
 782            if let Some(project_id) = *remote_id_rx.borrow() {
 783                rpc.send(proto::UnshareProject { project_id }).log_err();
 784            }
 785
 786            cx.notify();
 787        } else {
 788            log::error!("attempted to unshare a remote project");
 789        }
 790    }
 791
 792    fn project_unshared(&mut self, cx: &mut ModelContext<Self>) {
 793        if let ProjectClientState::Remote {
 794            sharing_has_stopped,
 795            ..
 796        } = &mut self.client_state
 797        {
 798            *sharing_has_stopped = true;
 799            self.collaborators.clear();
 800            cx.notify();
 801        }
 802    }
 803
 804    pub fn is_read_only(&self) -> bool {
 805        match &self.client_state {
 806            ProjectClientState::Local { .. } => false,
 807            ProjectClientState::Remote {
 808                sharing_has_stopped,
 809                ..
 810            } => *sharing_has_stopped,
 811        }
 812    }
 813
 814    pub fn is_local(&self) -> bool {
 815        match &self.client_state {
 816            ProjectClientState::Local { .. } => true,
 817            ProjectClientState::Remote { .. } => false,
 818        }
 819    }
 820
 821    pub fn is_remote(&self) -> bool {
 822        !self.is_local()
 823    }
 824
 825    pub fn create_buffer(&mut self, cx: &mut ModelContext<Self>) -> Result<ModelHandle<Buffer>> {
 826        if self.is_remote() {
 827            return Err(anyhow!("creating buffers as a guest is not supported yet"));
 828        }
 829
 830        let buffer = cx.add_model(|cx| {
 831            Buffer::new(self.replica_id(), "", cx).with_language(language::PLAIN_TEXT.clone(), cx)
 832        });
 833        self.register_buffer(&buffer, cx)?;
 834        Ok(buffer)
 835    }
 836
 837    pub fn open_path(
 838        &mut self,
 839        path: impl Into<ProjectPath>,
 840        cx: &mut ModelContext<Self>,
 841    ) -> Task<Result<(ProjectEntryId, AnyModelHandle)>> {
 842        let task = self.open_buffer(path, cx);
 843        cx.spawn_weak(|_, cx| async move {
 844            let buffer = task.await?;
 845            let project_entry_id = buffer
 846                .read_with(&cx, |buffer, cx| {
 847                    File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
 848                })
 849                .ok_or_else(|| anyhow!("no project entry"))?;
 850            Ok((project_entry_id, buffer.into()))
 851        })
 852    }
 853
 854    pub fn open_buffer(
 855        &mut self,
 856        path: impl Into<ProjectPath>,
 857        cx: &mut ModelContext<Self>,
 858    ) -> Task<Result<ModelHandle<Buffer>>> {
 859        let project_path = path.into();
 860        let worktree = if let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) {
 861            worktree
 862        } else {
 863            return Task::ready(Err(anyhow!("no such worktree")));
 864        };
 865
 866        // If there is already a buffer for the given path, then return it.
 867        let existing_buffer = self.get_open_buffer(&project_path, cx);
 868        if let Some(existing_buffer) = existing_buffer {
 869            return Task::ready(Ok(existing_buffer));
 870        }
 871
 872        let mut loading_watch = match self.loading_buffers.entry(project_path.clone()) {
 873            // If the given path is already being loaded, then wait for that existing
 874            // task to complete and return the same buffer.
 875            hash_map::Entry::Occupied(e) => e.get().clone(),
 876
 877            // Otherwise, record the fact that this path is now being loaded.
 878            hash_map::Entry::Vacant(entry) => {
 879                let (mut tx, rx) = postage::watch::channel();
 880                entry.insert(rx.clone());
 881
 882                let load_buffer = if worktree.read(cx).is_local() {
 883                    self.open_local_buffer(&project_path.path, &worktree, cx)
 884                } else {
 885                    self.open_remote_buffer(&project_path.path, &worktree, cx)
 886                };
 887
 888                cx.spawn(move |this, mut cx| async move {
 889                    let load_result = load_buffer.await;
 890                    *tx.borrow_mut() = Some(this.update(&mut cx, |this, _| {
 891                        // Record the fact that the buffer is no longer loading.
 892                        this.loading_buffers.remove(&project_path);
 893                        let buffer = load_result.map_err(Arc::new)?;
 894                        Ok(buffer)
 895                    }));
 896                })
 897                .detach();
 898                rx
 899            }
 900        };
 901
 902        cx.foreground().spawn(async move {
 903            loop {
 904                if let Some(result) = loading_watch.borrow().as_ref() {
 905                    match result {
 906                        Ok(buffer) => return Ok(buffer.clone()),
 907                        Err(error) => return Err(anyhow!("{}", error)),
 908                    }
 909                }
 910                loading_watch.next().await;
 911            }
 912        })
 913    }
 914
 915    fn open_local_buffer(
 916        &mut self,
 917        path: &Arc<Path>,
 918        worktree: &ModelHandle<Worktree>,
 919        cx: &mut ModelContext<Self>,
 920    ) -> Task<Result<ModelHandle<Buffer>>> {
 921        let load_buffer = worktree.update(cx, |worktree, cx| {
 922            let worktree = worktree.as_local_mut().unwrap();
 923            worktree.load_buffer(path, cx)
 924        });
 925        cx.spawn(|this, mut cx| async move {
 926            let buffer = load_buffer.await?;
 927            this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
 928            Ok(buffer)
 929        })
 930    }
 931
 932    fn open_remote_buffer(
 933        &mut self,
 934        path: &Arc<Path>,
 935        worktree: &ModelHandle<Worktree>,
 936        cx: &mut ModelContext<Self>,
 937    ) -> Task<Result<ModelHandle<Buffer>>> {
 938        let rpc = self.client.clone();
 939        let project_id = self.remote_id().unwrap();
 940        let remote_worktree_id = worktree.read(cx).id();
 941        let path = path.clone();
 942        let path_string = path.to_string_lossy().to_string();
 943        cx.spawn(|this, mut cx| async move {
 944            let response = rpc
 945                .request(proto::OpenBufferByPath {
 946                    project_id,
 947                    worktree_id: remote_worktree_id.to_proto(),
 948                    path: path_string,
 949                })
 950                .await?;
 951            let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
 952            this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
 953                .await
 954        })
 955    }
 956
 957    fn open_local_buffer_via_lsp(
 958        &mut self,
 959        abs_path: lsp::Url,
 960        lang_name: Arc<str>,
 961        lang_server: Arc<LanguageServer>,
 962        cx: &mut ModelContext<Self>,
 963    ) -> Task<Result<ModelHandle<Buffer>>> {
 964        cx.spawn(|this, mut cx| async move {
 965            let abs_path = abs_path
 966                .to_file_path()
 967                .map_err(|_| anyhow!("can't convert URI to path"))?;
 968            let (worktree, relative_path) = if let Some(result) =
 969                this.read_with(&cx, |this, cx| this.find_local_worktree(&abs_path, cx))
 970            {
 971                result
 972            } else {
 973                let worktree = this
 974                    .update(&mut cx, |this, cx| {
 975                        this.create_local_worktree(&abs_path, false, cx)
 976                    })
 977                    .await?;
 978                this.update(&mut cx, |this, cx| {
 979                    this.language_servers
 980                        .insert((worktree.read(cx).id(), lang_name), lang_server);
 981                });
 982                (worktree, PathBuf::new())
 983            };
 984
 985            let project_path = ProjectPath {
 986                worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()),
 987                path: relative_path.into(),
 988            };
 989            this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
 990                .await
 991        })
 992    }
 993
 994    pub fn open_buffer_by_id(
 995        &mut self,
 996        id: u64,
 997        cx: &mut ModelContext<Self>,
 998    ) -> Task<Result<ModelHandle<Buffer>>> {
 999        if let Some(buffer) = self.buffer_for_id(id, cx) {
1000            Task::ready(Ok(buffer))
1001        } else if self.is_local() {
1002            Task::ready(Err(anyhow!("buffer {} does not exist", id)))
1003        } else if let Some(project_id) = self.remote_id() {
1004            let request = self
1005                .client
1006                .request(proto::OpenBufferById { project_id, id });
1007            cx.spawn(|this, mut cx| async move {
1008                let buffer = request
1009                    .await?
1010                    .buffer
1011                    .ok_or_else(|| anyhow!("invalid buffer"))?;
1012                this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
1013                    .await
1014            })
1015        } else {
1016            Task::ready(Err(anyhow!("cannot open buffer while disconnected")))
1017        }
1018    }
1019
1020    pub fn save_buffer_as(
1021        &mut self,
1022        buffer: ModelHandle<Buffer>,
1023        abs_path: PathBuf,
1024        cx: &mut ModelContext<Project>,
1025    ) -> Task<Result<()>> {
1026        let worktree_task = self.find_or_create_local_worktree(&abs_path, true, cx);
1027        cx.spawn(|this, mut cx| async move {
1028            let (worktree, path) = worktree_task.await?;
1029            worktree
1030                .update(&mut cx, |worktree, cx| {
1031                    worktree
1032                        .as_local_mut()
1033                        .unwrap()
1034                        .save_buffer_as(buffer.clone(), path, cx)
1035                })
1036                .await?;
1037            this.update(&mut cx, |this, cx| {
1038                this.assign_language_to_buffer(&buffer, cx);
1039                this.register_buffer_with_language_server(&buffer, cx);
1040            });
1041            Ok(())
1042        })
1043    }
1044
1045    pub fn get_open_buffer(
1046        &mut self,
1047        path: &ProjectPath,
1048        cx: &mut ModelContext<Self>,
1049    ) -> Option<ModelHandle<Buffer>> {
1050        let worktree = self.worktree_for_id(path.worktree_id, cx)?;
1051        self.opened_buffers.values().find_map(|buffer| {
1052            let buffer = buffer.upgrade(cx)?;
1053            let file = File::from_dyn(buffer.read(cx).file())?;
1054            if file.worktree == worktree && file.path() == &path.path {
1055                Some(buffer)
1056            } else {
1057                None
1058            }
1059        })
1060    }
1061
1062    fn register_buffer(
1063        &mut self,
1064        buffer: &ModelHandle<Buffer>,
1065        cx: &mut ModelContext<Self>,
1066    ) -> Result<()> {
1067        let remote_id = buffer.read(cx).remote_id();
1068        let open_buffer = if self.is_remote() || self.is_shared() {
1069            OpenBuffer::Strong(buffer.clone())
1070        } else {
1071            OpenBuffer::Weak(buffer.downgrade())
1072        };
1073
1074        match self.opened_buffers.insert(remote_id, open_buffer) {
1075            None => {}
1076            Some(OpenBuffer::Loading(operations)) => {
1077                buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?
1078            }
1079            Some(OpenBuffer::Weak(existing_handle)) => {
1080                if existing_handle.upgrade(cx).is_some() {
1081                    Err(anyhow!(
1082                        "already registered buffer with remote id {}",
1083                        remote_id
1084                    ))?
1085                }
1086            }
1087            Some(OpenBuffer::Strong(_)) => Err(anyhow!(
1088                "already registered buffer with remote id {}",
1089                remote_id
1090            ))?,
1091        }
1092        cx.subscribe(buffer, |this, buffer, event, cx| {
1093            this.on_buffer_event(buffer, event, cx);
1094        })
1095        .detach();
1096
1097        self.assign_language_to_buffer(buffer, cx);
1098        self.register_buffer_with_language_server(buffer, cx);
1099
1100        Ok(())
1101    }
1102
1103    fn register_buffer_with_language_server(
1104        &mut self,
1105        buffer_handle: &ModelHandle<Buffer>,
1106        cx: &mut ModelContext<Self>,
1107    ) {
1108        let buffer = buffer_handle.read(cx);
1109        let buffer_id = buffer.remote_id();
1110        if let Some(file) = File::from_dyn(buffer.file()) {
1111            if file.is_local() {
1112                let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1113                let initial_snapshot = buffer.text_snapshot();
1114                let language_server = self.language_server_for_buffer(buffer, cx).cloned();
1115
1116                if let Some(local_worktree) = file.worktree.read(cx).as_local() {
1117                    if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
1118                        self.update_buffer_diagnostics(&buffer_handle, diagnostics, None, cx)
1119                            .log_err();
1120                    }
1121                }
1122
1123                if let Some(server) = language_server {
1124                    server
1125                        .notify::<lsp::notification::DidOpenTextDocument>(
1126                            lsp::DidOpenTextDocumentParams {
1127                                text_document: lsp::TextDocumentItem::new(
1128                                    uri,
1129                                    Default::default(),
1130                                    0,
1131                                    initial_snapshot.text(),
1132                                ),
1133                            }
1134                            .clone(),
1135                        )
1136                        .log_err();
1137                    buffer_handle.update(cx, |buffer, cx| {
1138                        buffer.set_completion_triggers(
1139                            server
1140                                .capabilities()
1141                                .completion_provider
1142                                .as_ref()
1143                                .and_then(|provider| provider.trigger_characters.clone())
1144                                .unwrap_or(Vec::new()),
1145                            cx,
1146                        )
1147                    });
1148                    self.buffer_snapshots
1149                        .insert(buffer_id, vec![(0, initial_snapshot)]);
1150                }
1151
1152                cx.observe_release(buffer_handle, |this, buffer, cx| {
1153                    if let Some(file) = File::from_dyn(buffer.file()) {
1154                        if file.is_local() {
1155                            let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1156                            if let Some(server) = this.language_server_for_buffer(buffer, cx) {
1157                                server
1158                                    .notify::<lsp::notification::DidCloseTextDocument>(
1159                                        lsp::DidCloseTextDocumentParams {
1160                                            text_document: lsp::TextDocumentIdentifier::new(
1161                                                uri.clone(),
1162                                            ),
1163                                        },
1164                                    )
1165                                    .log_err();
1166                            }
1167                        }
1168                    }
1169                })
1170                .detach();
1171            }
1172        }
1173    }
1174
1175    fn on_buffer_event(
1176        &mut self,
1177        buffer: ModelHandle<Buffer>,
1178        event: &BufferEvent,
1179        cx: &mut ModelContext<Self>,
1180    ) -> Option<()> {
1181        match event {
1182            BufferEvent::Operation(operation) => {
1183                let project_id = self.remote_id()?;
1184                let request = self.client.request(proto::UpdateBuffer {
1185                    project_id,
1186                    buffer_id: buffer.read(cx).remote_id(),
1187                    operations: vec![language::proto::serialize_operation(&operation)],
1188                });
1189                cx.background().spawn(request).detach_and_log_err(cx);
1190            }
1191            BufferEvent::Edited { .. } => {
1192                let language_server = self
1193                    .language_server_for_buffer(buffer.read(cx), cx)?
1194                    .clone();
1195                let buffer = buffer.read(cx);
1196                let file = File::from_dyn(buffer.file())?;
1197                let abs_path = file.as_local()?.abs_path(cx);
1198                let uri = lsp::Url::from_file_path(abs_path).unwrap();
1199                let buffer_snapshots = self.buffer_snapshots.entry(buffer.remote_id()).or_default();
1200                let (version, prev_snapshot) = buffer_snapshots.last()?;
1201                let next_snapshot = buffer.text_snapshot();
1202                let next_version = version + 1;
1203
1204                let content_changes = buffer
1205                    .edits_since::<(PointUtf16, usize)>(prev_snapshot.version())
1206                    .map(|edit| {
1207                        let edit_start = edit.new.start.0;
1208                        let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
1209                        let new_text = next_snapshot
1210                            .text_for_range(edit.new.start.1..edit.new.end.1)
1211                            .collect();
1212                        lsp::TextDocumentContentChangeEvent {
1213                            range: Some(lsp::Range::new(
1214                                edit_start.to_lsp_position(),
1215                                edit_end.to_lsp_position(),
1216                            )),
1217                            range_length: None,
1218                            text: new_text,
1219                        }
1220                    })
1221                    .collect();
1222
1223                buffer_snapshots.push((next_version, next_snapshot));
1224
1225                language_server
1226                    .notify::<lsp::notification::DidChangeTextDocument>(
1227                        lsp::DidChangeTextDocumentParams {
1228                            text_document: lsp::VersionedTextDocumentIdentifier::new(
1229                                uri,
1230                                next_version,
1231                            ),
1232                            content_changes,
1233                        },
1234                    )
1235                    .log_err();
1236            }
1237            BufferEvent::Saved => {
1238                let file = File::from_dyn(buffer.read(cx).file())?;
1239                let worktree_id = file.worktree_id(cx);
1240                let abs_path = file.as_local()?.abs_path(cx);
1241                let text_document = lsp::TextDocumentIdentifier {
1242                    uri: lsp::Url::from_file_path(abs_path).unwrap(),
1243                };
1244
1245                for (_, server) in self.language_servers_for_worktree(worktree_id) {
1246                    server
1247                        .notify::<lsp::notification::DidSaveTextDocument>(
1248                            lsp::DidSaveTextDocumentParams {
1249                                text_document: text_document.clone(),
1250                                text: None,
1251                            },
1252                        )
1253                        .log_err();
1254                }
1255            }
1256            _ => {}
1257        }
1258
1259        None
1260    }
1261
1262    fn language_servers_for_worktree(
1263        &self,
1264        worktree_id: WorktreeId,
1265    ) -> impl Iterator<Item = (&str, &Arc<LanguageServer>)> {
1266        self.language_servers.iter().filter_map(
1267            move |((language_server_worktree_id, language_name), server)| {
1268                if *language_server_worktree_id == worktree_id {
1269                    Some((language_name.as_ref(), server))
1270                } else {
1271                    None
1272                }
1273            },
1274        )
1275    }
1276
1277    fn assign_language_to_buffer(
1278        &mut self,
1279        buffer: &ModelHandle<Buffer>,
1280        cx: &mut ModelContext<Self>,
1281    ) -> Option<()> {
1282        // If the buffer has a language, set it and start the language server if we haven't already.
1283        let full_path = buffer.read(cx).file()?.full_path(cx);
1284        let language = self.languages.select_language(&full_path)?;
1285        buffer.update(cx, |buffer, cx| {
1286            buffer.set_language(Some(language.clone()), cx);
1287        });
1288
1289        let file = File::from_dyn(buffer.read(cx).file())?;
1290        let worktree = file.worktree.read(cx).as_local()?;
1291        let worktree_id = worktree.id();
1292        let worktree_abs_path = worktree.abs_path().clone();
1293        self.start_language_server(worktree_id, worktree_abs_path, language, cx);
1294
1295        None
1296    }
1297
1298    fn start_language_server(
1299        &mut self,
1300        worktree_id: WorktreeId,
1301        worktree_path: Arc<Path>,
1302        language: Arc<Language>,
1303        cx: &mut ModelContext<Self>,
1304    ) {
1305        let key = (worktree_id, language.name());
1306        self.started_language_servers
1307            .entry(key.clone())
1308            .or_insert_with(|| {
1309                let server_id = post_inc(&mut self.next_language_server_id);
1310                let language_server = self.languages.start_language_server(
1311                    server_id,
1312                    language.clone(),
1313                    worktree_path,
1314                    self.client.http_client(),
1315                    cx,
1316                );
1317                cx.spawn_weak(|this, mut cx| async move {
1318                    let mut language_server = language_server?.await.log_err()?;
1319                    let this = this.upgrade(&cx)?;
1320                    let (language_server_events_tx, language_server_events_rx) =
1321                        smol::channel::unbounded();
1322
1323                    language_server
1324                        .on_notification::<lsp::notification::PublishDiagnostics, _>({
1325                            let language_server_events_tx = language_server_events_tx.clone();
1326                            move |params| {
1327                                language_server_events_tx
1328                                    .try_send(LanguageServerEvent::DiagnosticsUpdate(params))
1329                                    .ok();
1330                            }
1331                        })
1332                        .detach();
1333
1334                    language_server
1335                        .on_request::<lsp::request::WorkspaceConfiguration, _>({
1336                            let settings = this
1337                                .read_with(&cx, |this, _| this.language_server_settings.clone());
1338                            move |params| {
1339                                let settings = settings.lock();
1340                                Ok(params
1341                                    .items
1342                                    .into_iter()
1343                                    .map(|item| {
1344                                        if let Some(section) = &item.section {
1345                                            settings
1346                                                .get(section)
1347                                                .cloned()
1348                                                .unwrap_or(serde_json::Value::Null)
1349                                        } else {
1350                                            settings.clone()
1351                                        }
1352                                    })
1353                                    .collect())
1354                            }
1355                        })
1356                        .detach();
1357
1358                    language_server
1359                        .on_notification::<lsp::notification::Progress, _>(move |params| {
1360                            let token = match params.token {
1361                                lsp::NumberOrString::String(token) => token,
1362                                lsp::NumberOrString::Number(token) => {
1363                                    log::info!("skipping numeric progress token {}", token);
1364                                    return;
1365                                }
1366                            };
1367
1368                            match params.value {
1369                                lsp::ProgressParamsValue::WorkDone(progress) => match progress {
1370                                    lsp::WorkDoneProgress::Begin(_) => {
1371                                        language_server_events_tx
1372                                            .try_send(LanguageServerEvent::WorkStart { token })
1373                                            .ok();
1374                                    }
1375                                    lsp::WorkDoneProgress::Report(report) => {
1376                                        language_server_events_tx
1377                                            .try_send(LanguageServerEvent::WorkProgress {
1378                                                token,
1379                                                progress: LanguageServerProgress {
1380                                                    message: report.message,
1381                                                    percentage: report
1382                                                        .percentage
1383                                                        .map(|p| p as usize),
1384                                                    last_update_at: Instant::now(),
1385                                                },
1386                                            })
1387                                            .ok();
1388                                    }
1389                                    lsp::WorkDoneProgress::End(_) => {
1390                                        language_server_events_tx
1391                                            .try_send(LanguageServerEvent::WorkEnd { token })
1392                                            .ok();
1393                                    }
1394                                },
1395                            }
1396                        })
1397                        .detach();
1398
1399                    // Process all the LSP events.
1400                    cx.spawn(|mut cx| {
1401                        let this = this.downgrade();
1402                        async move {
1403                            while let Ok(event) = language_server_events_rx.recv().await {
1404                                let this = this.upgrade(&cx)?;
1405                                this.update(&mut cx, |this, cx| {
1406                                    this.on_lsp_event(server_id, event, &language, cx)
1407                                });
1408
1409                                // Don't starve the main thread when lots of events arrive all at once.
1410                                smol::future::yield_now().await;
1411                            }
1412                            Some(())
1413                        }
1414                    })
1415                    .detach();
1416
1417                    let language_server = language_server.initialize().await.log_err()?;
1418                    this.update(&mut cx, |this, cx| {
1419                        this.language_servers
1420                            .insert(key.clone(), language_server.clone());
1421                        this.language_server_statuses.insert(
1422                            server_id,
1423                            LanguageServerStatus {
1424                                name: language_server.name().to_string(),
1425                                pending_work: Default::default(),
1426                                pending_diagnostic_updates: 0,
1427                            },
1428                        );
1429                        language_server
1430                            .notify::<lsp::notification::DidChangeConfiguration>(
1431                                lsp::DidChangeConfigurationParams {
1432                                    settings: this.language_server_settings.lock().clone(),
1433                                },
1434                            )
1435                            .ok();
1436
1437                        if let Some(project_id) = this.remote_id() {
1438                            this.client
1439                                .send(proto::StartLanguageServer {
1440                                    project_id,
1441                                    server: Some(proto::LanguageServer {
1442                                        id: server_id as u64,
1443                                        name: language_server.name().to_string(),
1444                                    }),
1445                                })
1446                                .log_err();
1447                        }
1448
1449                        // Tell the language server about every open buffer in the worktree that matches the language.
1450                        for buffer in this.opened_buffers.values() {
1451                            if let Some(buffer_handle) = buffer.upgrade(cx) {
1452                                let buffer = buffer_handle.read(cx);
1453                                let file = if let Some(file) = File::from_dyn(buffer.file()) {
1454                                    file
1455                                } else {
1456                                    continue;
1457                                };
1458                                let language = if let Some(language) = buffer.language() {
1459                                    language
1460                                } else {
1461                                    continue;
1462                                };
1463                                if (file.worktree.read(cx).id(), language.name()) != key {
1464                                    continue;
1465                                }
1466
1467                                let file = file.as_local()?;
1468                                let versions = this
1469                                    .buffer_snapshots
1470                                    .entry(buffer.remote_id())
1471                                    .or_insert_with(|| vec![(0, buffer.text_snapshot())]);
1472                                let (version, initial_snapshot) = versions.last().unwrap();
1473                                let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1474                                language_server
1475                                    .notify::<lsp::notification::DidOpenTextDocument>(
1476                                        lsp::DidOpenTextDocumentParams {
1477                                            text_document: lsp::TextDocumentItem::new(
1478                                                uri,
1479                                                Default::default(),
1480                                                *version,
1481                                                initial_snapshot.text(),
1482                                            ),
1483                                        },
1484                                    )
1485                                    .log_err()?;
1486                                buffer_handle.update(cx, |buffer, cx| {
1487                                    buffer.set_completion_triggers(
1488                                        language_server
1489                                            .capabilities()
1490                                            .completion_provider
1491                                            .as_ref()
1492                                            .and_then(|provider| {
1493                                                provider.trigger_characters.clone()
1494                                            })
1495                                            .unwrap_or(Vec::new()),
1496                                        cx,
1497                                    )
1498                                });
1499                            }
1500                        }
1501
1502                        cx.notify();
1503                        Some(())
1504                    });
1505
1506                    Some(language_server)
1507                })
1508            });
1509    }
1510
1511    pub fn restart_language_servers_for_buffers(
1512        &mut self,
1513        buffers: impl IntoIterator<Item = ModelHandle<Buffer>>,
1514        cx: &mut ModelContext<Self>,
1515    ) -> Option<()> {
1516        let language_server_lookup_info: HashSet<(WorktreeId, Arc<Path>, PathBuf)> = buffers
1517            .into_iter()
1518            .filter_map(|buffer| {
1519                let file = File::from_dyn(buffer.read(cx).file())?;
1520                let worktree = file.worktree.read(cx).as_local()?;
1521                let worktree_id = worktree.id();
1522                let worktree_abs_path = worktree.abs_path().clone();
1523                let full_path = file.full_path(cx);
1524                Some((worktree_id, worktree_abs_path, full_path))
1525            })
1526            .collect();
1527        for (worktree_id, worktree_abs_path, full_path) in language_server_lookup_info {
1528            let language = self.languages.select_language(&full_path)?;
1529            self.restart_language_server(worktree_id, worktree_abs_path, language, cx);
1530        }
1531
1532        None
1533    }
1534
1535    fn restart_language_server(
1536        &mut self,
1537        worktree_id: WorktreeId,
1538        worktree_path: Arc<Path>,
1539        language: Arc<Language>,
1540        cx: &mut ModelContext<Self>,
1541    ) {
1542        let key = (worktree_id, language.name());
1543        let server_to_shutdown = self.language_servers.remove(&key);
1544        self.started_language_servers.remove(&key);
1545        server_to_shutdown
1546            .as_ref()
1547            .map(|server| self.language_server_statuses.remove(&server.server_id()));
1548        cx.spawn_weak(|this, mut cx| async move {
1549            if let Some(this) = this.upgrade(&cx) {
1550                if let Some(server_to_shutdown) = server_to_shutdown {
1551                    if let Some(shutdown_task) = server_to_shutdown.shutdown() {
1552                        shutdown_task.await;
1553                    }
1554                }
1555
1556                this.update(&mut cx, |this, cx| {
1557                    this.start_language_server(worktree_id, worktree_path, language, cx);
1558                });
1559            }
1560        })
1561        .detach();
1562    }
1563
1564    fn on_lsp_event(
1565        &mut self,
1566        language_server_id: usize,
1567        event: LanguageServerEvent,
1568        language: &Arc<Language>,
1569        cx: &mut ModelContext<Self>,
1570    ) {
1571        let disk_diagnostics_token = language.disk_based_diagnostics_progress_token();
1572        let language_server_status =
1573            if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
1574                status
1575            } else {
1576                return;
1577            };
1578
1579        match event {
1580            LanguageServerEvent::WorkStart { token } => {
1581                if Some(&token) == disk_diagnostics_token {
1582                    language_server_status.pending_diagnostic_updates += 1;
1583                    if language_server_status.pending_diagnostic_updates == 1 {
1584                        self.disk_based_diagnostics_started(cx);
1585                        self.broadcast_language_server_update(
1586                            language_server_id,
1587                            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
1588                                proto::LspDiskBasedDiagnosticsUpdating {},
1589                            ),
1590                        );
1591                    }
1592                } else {
1593                    self.on_lsp_work_start(language_server_id, token.clone(), cx);
1594                    self.broadcast_language_server_update(
1595                        language_server_id,
1596                        proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
1597                            token,
1598                        }),
1599                    );
1600                }
1601            }
1602            LanguageServerEvent::WorkProgress { token, progress } => {
1603                if Some(&token) != disk_diagnostics_token {
1604                    self.on_lsp_work_progress(
1605                        language_server_id,
1606                        token.clone(),
1607                        progress.clone(),
1608                        cx,
1609                    );
1610                    self.broadcast_language_server_update(
1611                        language_server_id,
1612                        proto::update_language_server::Variant::WorkProgress(
1613                            proto::LspWorkProgress {
1614                                token,
1615                                message: progress.message,
1616                                percentage: progress.percentage.map(|p| p as u32),
1617                            },
1618                        ),
1619                    );
1620                }
1621            }
1622            LanguageServerEvent::WorkEnd { token } => {
1623                if Some(&token) == disk_diagnostics_token {
1624                    language_server_status.pending_diagnostic_updates -= 1;
1625                    if language_server_status.pending_diagnostic_updates == 0 {
1626                        self.disk_based_diagnostics_finished(cx);
1627                        self.broadcast_language_server_update(
1628                            language_server_id,
1629                            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
1630                                proto::LspDiskBasedDiagnosticsUpdated {},
1631                            ),
1632                        );
1633                    }
1634                } else {
1635                    self.on_lsp_work_end(language_server_id, token.clone(), cx);
1636                    self.broadcast_language_server_update(
1637                        language_server_id,
1638                        proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
1639                            token,
1640                        }),
1641                    );
1642                }
1643            }
1644            LanguageServerEvent::DiagnosticsUpdate(mut params) => {
1645                language.process_diagnostics(&mut params);
1646
1647                if disk_diagnostics_token.is_none() {
1648                    self.disk_based_diagnostics_started(cx);
1649                    self.broadcast_language_server_update(
1650                        language_server_id,
1651                        proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
1652                            proto::LspDiskBasedDiagnosticsUpdating {},
1653                        ),
1654                    );
1655                }
1656                self.update_diagnostics(
1657                    params,
1658                    language
1659                        .disk_based_diagnostic_sources()
1660                        .unwrap_or(&Default::default()),
1661                    cx,
1662                )
1663                .log_err();
1664                if disk_diagnostics_token.is_none() {
1665                    self.disk_based_diagnostics_finished(cx);
1666                    self.broadcast_language_server_update(
1667                        language_server_id,
1668                        proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
1669                            proto::LspDiskBasedDiagnosticsUpdated {},
1670                        ),
1671                    );
1672                }
1673            }
1674        }
1675    }
1676
1677    fn on_lsp_work_start(
1678        &mut self,
1679        language_server_id: usize,
1680        token: String,
1681        cx: &mut ModelContext<Self>,
1682    ) {
1683        if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
1684            status.pending_work.insert(
1685                token,
1686                LanguageServerProgress {
1687                    message: None,
1688                    percentage: None,
1689                    last_update_at: Instant::now(),
1690                },
1691            );
1692            cx.notify();
1693        }
1694    }
1695
1696    fn on_lsp_work_progress(
1697        &mut self,
1698        language_server_id: usize,
1699        token: String,
1700        progress: LanguageServerProgress,
1701        cx: &mut ModelContext<Self>,
1702    ) {
1703        if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
1704            status.pending_work.insert(token, progress);
1705            cx.notify();
1706        }
1707    }
1708
1709    fn on_lsp_work_end(
1710        &mut self,
1711        language_server_id: usize,
1712        token: String,
1713        cx: &mut ModelContext<Self>,
1714    ) {
1715        if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
1716            status.pending_work.remove(&token);
1717            cx.notify();
1718        }
1719    }
1720
1721    fn broadcast_language_server_update(
1722        &self,
1723        language_server_id: usize,
1724        event: proto::update_language_server::Variant,
1725    ) {
1726        if let Some(project_id) = self.remote_id() {
1727            self.client
1728                .send(proto::UpdateLanguageServer {
1729                    project_id,
1730                    language_server_id: language_server_id as u64,
1731                    variant: Some(event),
1732                })
1733                .log_err();
1734        }
1735    }
1736
1737    pub fn set_language_server_settings(&mut self, settings: serde_json::Value) {
1738        for server in self.language_servers.values() {
1739            server
1740                .notify::<lsp::notification::DidChangeConfiguration>(
1741                    lsp::DidChangeConfigurationParams {
1742                        settings: settings.clone(),
1743                    },
1744                )
1745                .ok();
1746        }
1747        *self.language_server_settings.lock() = settings;
1748    }
1749
1750    pub fn language_server_statuses(
1751        &self,
1752    ) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {
1753        self.language_server_statuses.values()
1754    }
1755
1756    pub fn update_diagnostics(
1757        &mut self,
1758        params: lsp::PublishDiagnosticsParams,
1759        disk_based_sources: &HashSet<String>,
1760        cx: &mut ModelContext<Self>,
1761    ) -> Result<()> {
1762        let abs_path = params
1763            .uri
1764            .to_file_path()
1765            .map_err(|_| anyhow!("URI is not a file"))?;
1766        let mut next_group_id = 0;
1767        let mut diagnostics = Vec::default();
1768        let mut primary_diagnostic_group_ids = HashMap::default();
1769        let mut sources_by_group_id = HashMap::default();
1770        let mut supporting_diagnostics = HashMap::default();
1771        for diagnostic in &params.diagnostics {
1772            let source = diagnostic.source.as_ref();
1773            let code = diagnostic.code.as_ref().map(|code| match code {
1774                lsp::NumberOrString::Number(code) => code.to_string(),
1775                lsp::NumberOrString::String(code) => code.clone(),
1776            });
1777            let range = range_from_lsp(diagnostic.range);
1778            let is_supporting = diagnostic
1779                .related_information
1780                .as_ref()
1781                .map_or(false, |infos| {
1782                    infos.iter().any(|info| {
1783                        primary_diagnostic_group_ids.contains_key(&(
1784                            source,
1785                            code.clone(),
1786                            range_from_lsp(info.location.range),
1787                        ))
1788                    })
1789                });
1790
1791            let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
1792                tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
1793            });
1794
1795            if is_supporting {
1796                supporting_diagnostics.insert(
1797                    (source, code.clone(), range),
1798                    (diagnostic.severity, is_unnecessary),
1799                );
1800            } else {
1801                let group_id = post_inc(&mut next_group_id);
1802                let is_disk_based =
1803                    source.map_or(false, |source| disk_based_sources.contains(source));
1804
1805                sources_by_group_id.insert(group_id, source);
1806                primary_diagnostic_group_ids
1807                    .insert((source, code.clone(), range.clone()), group_id);
1808
1809                diagnostics.push(DiagnosticEntry {
1810                    range,
1811                    diagnostic: Diagnostic {
1812                        code: code.clone(),
1813                        severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
1814                        message: diagnostic.message.clone(),
1815                        group_id,
1816                        is_primary: true,
1817                        is_valid: true,
1818                        is_disk_based,
1819                        is_unnecessary,
1820                    },
1821                });
1822                if let Some(infos) = &diagnostic.related_information {
1823                    for info in infos {
1824                        if info.location.uri == params.uri && !info.message.is_empty() {
1825                            let range = range_from_lsp(info.location.range);
1826                            diagnostics.push(DiagnosticEntry {
1827                                range,
1828                                diagnostic: Diagnostic {
1829                                    code: code.clone(),
1830                                    severity: DiagnosticSeverity::INFORMATION,
1831                                    message: info.message.clone(),
1832                                    group_id,
1833                                    is_primary: false,
1834                                    is_valid: true,
1835                                    is_disk_based,
1836                                    is_unnecessary: false,
1837                                },
1838                            });
1839                        }
1840                    }
1841                }
1842            }
1843        }
1844
1845        for entry in &mut diagnostics {
1846            let diagnostic = &mut entry.diagnostic;
1847            if !diagnostic.is_primary {
1848                let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
1849                if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
1850                    source,
1851                    diagnostic.code.clone(),
1852                    entry.range.clone(),
1853                )) {
1854                    if let Some(severity) = severity {
1855                        diagnostic.severity = severity;
1856                    }
1857                    diagnostic.is_unnecessary = is_unnecessary;
1858                }
1859            }
1860        }
1861
1862        self.update_diagnostic_entries(abs_path, params.version, diagnostics, cx)?;
1863        Ok(())
1864    }
1865
1866    pub fn update_diagnostic_entries(
1867        &mut self,
1868        abs_path: PathBuf,
1869        version: Option<i32>,
1870        diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
1871        cx: &mut ModelContext<Project>,
1872    ) -> Result<(), anyhow::Error> {
1873        let (worktree, relative_path) = self
1874            .find_local_worktree(&abs_path, cx)
1875            .ok_or_else(|| anyhow!("no worktree found for diagnostics"))?;
1876        if !worktree.read(cx).is_visible() {
1877            return Ok(());
1878        }
1879
1880        let project_path = ProjectPath {
1881            worktree_id: worktree.read(cx).id(),
1882            path: relative_path.into(),
1883        };
1884
1885        for buffer in self.opened_buffers.values() {
1886            if let Some(buffer) = buffer.upgrade(cx) {
1887                if buffer
1888                    .read(cx)
1889                    .file()
1890                    .map_or(false, |file| *file.path() == project_path.path)
1891                {
1892                    self.update_buffer_diagnostics(&buffer, diagnostics.clone(), version, cx)?;
1893                    break;
1894                }
1895            }
1896        }
1897        worktree.update(cx, |worktree, cx| {
1898            worktree
1899                .as_local_mut()
1900                .ok_or_else(|| anyhow!("not a local worktree"))?
1901                .update_diagnostics(project_path.path.clone(), diagnostics, cx)
1902        })?;
1903        cx.emit(Event::DiagnosticsUpdated(project_path));
1904        Ok(())
1905    }
1906
1907    fn update_buffer_diagnostics(
1908        &mut self,
1909        buffer: &ModelHandle<Buffer>,
1910        mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
1911        version: Option<i32>,
1912        cx: &mut ModelContext<Self>,
1913    ) -> Result<()> {
1914        fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
1915            Ordering::Equal
1916                .then_with(|| b.is_primary.cmp(&a.is_primary))
1917                .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
1918                .then_with(|| a.severity.cmp(&b.severity))
1919                .then_with(|| a.message.cmp(&b.message))
1920        }
1921
1922        let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx)?;
1923
1924        diagnostics.sort_unstable_by(|a, b| {
1925            Ordering::Equal
1926                .then_with(|| a.range.start.cmp(&b.range.start))
1927                .then_with(|| b.range.end.cmp(&a.range.end))
1928                .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
1929        });
1930
1931        let mut sanitized_diagnostics = Vec::new();
1932        let edits_since_save = Patch::new(
1933            snapshot
1934                .edits_since::<PointUtf16>(buffer.read(cx).saved_version())
1935                .collect(),
1936        );
1937        for entry in diagnostics {
1938            let start;
1939            let end;
1940            if entry.diagnostic.is_disk_based {
1941                // Some diagnostics are based on files on disk instead of buffers'
1942                // current contents. Adjust these diagnostics' ranges to reflect
1943                // any unsaved edits.
1944                start = edits_since_save.old_to_new(entry.range.start);
1945                end = edits_since_save.old_to_new(entry.range.end);
1946            } else {
1947                start = entry.range.start;
1948                end = entry.range.end;
1949            }
1950
1951            let mut range = snapshot.clip_point_utf16(start, Bias::Left)
1952                ..snapshot.clip_point_utf16(end, Bias::Right);
1953
1954            // Expand empty ranges by one character
1955            if range.start == range.end {
1956                range.end.column += 1;
1957                range.end = snapshot.clip_point_utf16(range.end, Bias::Right);
1958                if range.start == range.end && range.end.column > 0 {
1959                    range.start.column -= 1;
1960                    range.start = snapshot.clip_point_utf16(range.start, Bias::Left);
1961                }
1962            }
1963
1964            sanitized_diagnostics.push(DiagnosticEntry {
1965                range,
1966                diagnostic: entry.diagnostic,
1967            });
1968        }
1969        drop(edits_since_save);
1970
1971        let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
1972        buffer.update(cx, |buffer, cx| buffer.update_diagnostics(set, cx));
1973        Ok(())
1974    }
1975
1976    pub fn format(
1977        &self,
1978        buffers: HashSet<ModelHandle<Buffer>>,
1979        push_to_history: bool,
1980        cx: &mut ModelContext<Project>,
1981    ) -> Task<Result<ProjectTransaction>> {
1982        let mut local_buffers = Vec::new();
1983        let mut remote_buffers = None;
1984        for buffer_handle in buffers {
1985            let buffer = buffer_handle.read(cx);
1986            if let Some(file) = File::from_dyn(buffer.file()) {
1987                if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
1988                    if let Some(server) = self.language_server_for_buffer(buffer, cx) {
1989                        local_buffers.push((buffer_handle, buffer_abs_path, server.clone()));
1990                    }
1991                } else {
1992                    remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
1993                }
1994            } else {
1995                return Task::ready(Ok(Default::default()));
1996            }
1997        }
1998
1999        let remote_buffers = self.remote_id().zip(remote_buffers);
2000        let client = self.client.clone();
2001
2002        cx.spawn(|this, mut cx| async move {
2003            let mut project_transaction = ProjectTransaction::default();
2004
2005            if let Some((project_id, remote_buffers)) = remote_buffers {
2006                let response = client
2007                    .request(proto::FormatBuffers {
2008                        project_id,
2009                        buffer_ids: remote_buffers
2010                            .iter()
2011                            .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
2012                            .collect(),
2013                    })
2014                    .await?
2015                    .transaction
2016                    .ok_or_else(|| anyhow!("missing transaction"))?;
2017                project_transaction = this
2018                    .update(&mut cx, |this, cx| {
2019                        this.deserialize_project_transaction(response, push_to_history, cx)
2020                    })
2021                    .await?;
2022            }
2023
2024            for (buffer, buffer_abs_path, language_server) in local_buffers {
2025                let text_document = lsp::TextDocumentIdentifier::new(
2026                    lsp::Url::from_file_path(&buffer_abs_path).unwrap(),
2027                );
2028                let capabilities = &language_server.capabilities();
2029                let lsp_edits = if capabilities
2030                    .document_formatting_provider
2031                    .as_ref()
2032                    .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
2033                {
2034                    language_server
2035                        .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2036                            text_document,
2037                            options: Default::default(),
2038                            work_done_progress_params: Default::default(),
2039                        })
2040                        .await?
2041                } else if capabilities
2042                    .document_range_formatting_provider
2043                    .as_ref()
2044                    .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
2045                {
2046                    let buffer_start = lsp::Position::new(0, 0);
2047                    let buffer_end = buffer
2048                        .read_with(&cx, |buffer, _| buffer.max_point_utf16())
2049                        .to_lsp_position();
2050                    language_server
2051                        .request::<lsp::request::RangeFormatting>(
2052                            lsp::DocumentRangeFormattingParams {
2053                                text_document,
2054                                range: lsp::Range::new(buffer_start, buffer_end),
2055                                options: Default::default(),
2056                                work_done_progress_params: Default::default(),
2057                            },
2058                        )
2059                        .await?
2060                } else {
2061                    continue;
2062                };
2063
2064                if let Some(lsp_edits) = lsp_edits {
2065                    let edits = this
2066                        .update(&mut cx, |this, cx| {
2067                            this.edits_from_lsp(&buffer, lsp_edits, None, cx)
2068                        })
2069                        .await?;
2070                    buffer.update(&mut cx, |buffer, cx| {
2071                        buffer.finalize_last_transaction();
2072                        buffer.start_transaction();
2073                        for (range, text) in edits {
2074                            buffer.edit([range], text, cx);
2075                        }
2076                        if buffer.end_transaction(cx).is_some() {
2077                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
2078                            if !push_to_history {
2079                                buffer.forget_transaction(transaction.id);
2080                            }
2081                            project_transaction.0.insert(cx.handle(), transaction);
2082                        }
2083                    });
2084                }
2085            }
2086
2087            Ok(project_transaction)
2088        })
2089    }
2090
2091    pub fn definition<T: ToPointUtf16>(
2092        &self,
2093        buffer: &ModelHandle<Buffer>,
2094        position: T,
2095        cx: &mut ModelContext<Self>,
2096    ) -> Task<Result<Vec<Location>>> {
2097        let position = position.to_point_utf16(buffer.read(cx));
2098        self.request_lsp(buffer.clone(), GetDefinition { position }, cx)
2099    }
2100
2101    pub fn references<T: ToPointUtf16>(
2102        &self,
2103        buffer: &ModelHandle<Buffer>,
2104        position: T,
2105        cx: &mut ModelContext<Self>,
2106    ) -> Task<Result<Vec<Location>>> {
2107        let position = position.to_point_utf16(buffer.read(cx));
2108        self.request_lsp(buffer.clone(), GetReferences { position }, cx)
2109    }
2110
2111    pub fn document_highlights<T: ToPointUtf16>(
2112        &self,
2113        buffer: &ModelHandle<Buffer>,
2114        position: T,
2115        cx: &mut ModelContext<Self>,
2116    ) -> Task<Result<Vec<DocumentHighlight>>> {
2117        let position = position.to_point_utf16(buffer.read(cx));
2118
2119        self.request_lsp(buffer.clone(), GetDocumentHighlights { position }, cx)
2120    }
2121
2122    pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
2123        if self.is_local() {
2124            let mut language_servers = HashMap::default();
2125            for ((worktree_id, language_name), language_server) in self.language_servers.iter() {
2126                if let Some((worktree, language)) = self
2127                    .worktree_for_id(*worktree_id, cx)
2128                    .and_then(|worktree| worktree.read(cx).as_local())
2129                    .zip(self.languages.get_language(language_name))
2130                {
2131                    language_servers
2132                        .entry(Arc::as_ptr(language_server))
2133                        .or_insert((
2134                            language_server.clone(),
2135                            *worktree_id,
2136                            worktree.abs_path().clone(),
2137                            language.clone(),
2138                        ));
2139                }
2140            }
2141
2142            let mut requests = Vec::new();
2143            for (language_server, _, _, _) in language_servers.values() {
2144                requests.push(language_server.request::<lsp::request::WorkspaceSymbol>(
2145                    lsp::WorkspaceSymbolParams {
2146                        query: query.to_string(),
2147                        ..Default::default()
2148                    },
2149                ));
2150            }
2151
2152            cx.spawn_weak(|this, cx| async move {
2153                let responses = futures::future::try_join_all(requests).await?;
2154
2155                let mut symbols = Vec::new();
2156                if let Some(this) = this.upgrade(&cx) {
2157                    this.read_with(&cx, |this, cx| {
2158                        for ((_, source_worktree_id, worktree_abs_path, language), lsp_symbols) in
2159                            language_servers.into_values().zip(responses)
2160                        {
2161                            symbols.extend(lsp_symbols.into_iter().flatten().filter_map(
2162                                |lsp_symbol| {
2163                                    let abs_path = lsp_symbol.location.uri.to_file_path().ok()?;
2164                                    let mut worktree_id = source_worktree_id;
2165                                    let path;
2166                                    if let Some((worktree, rel_path)) =
2167                                        this.find_local_worktree(&abs_path, cx)
2168                                    {
2169                                        worktree_id = worktree.read(cx).id();
2170                                        path = rel_path;
2171                                    } else {
2172                                        path = relativize_path(&worktree_abs_path, &abs_path);
2173                                    }
2174
2175                                    let label = language
2176                                        .label_for_symbol(&lsp_symbol.name, lsp_symbol.kind)
2177                                        .unwrap_or_else(|| {
2178                                            CodeLabel::plain(lsp_symbol.name.clone(), None)
2179                                        });
2180                                    let signature = this.symbol_signature(worktree_id, &path);
2181
2182                                    Some(Symbol {
2183                                        source_worktree_id,
2184                                        worktree_id,
2185                                        language_name: language.name().to_string(),
2186                                        name: lsp_symbol.name,
2187                                        kind: lsp_symbol.kind,
2188                                        label,
2189                                        path,
2190                                        range: range_from_lsp(lsp_symbol.location.range),
2191                                        signature,
2192                                    })
2193                                },
2194                            ));
2195                        }
2196                    })
2197                }
2198
2199                Ok(symbols)
2200            })
2201        } else if let Some(project_id) = self.remote_id() {
2202            let request = self.client.request(proto::GetProjectSymbols {
2203                project_id,
2204                query: query.to_string(),
2205            });
2206            cx.spawn_weak(|this, cx| async move {
2207                let response = request.await?;
2208                let mut symbols = Vec::new();
2209                if let Some(this) = this.upgrade(&cx) {
2210                    this.read_with(&cx, |this, _| {
2211                        symbols.extend(
2212                            response
2213                                .symbols
2214                                .into_iter()
2215                                .filter_map(|symbol| this.deserialize_symbol(symbol).log_err()),
2216                        );
2217                    })
2218                }
2219                Ok(symbols)
2220            })
2221        } else {
2222            Task::ready(Ok(Default::default()))
2223        }
2224    }
2225
2226    pub fn open_buffer_for_symbol(
2227        &mut self,
2228        symbol: &Symbol,
2229        cx: &mut ModelContext<Self>,
2230    ) -> Task<Result<ModelHandle<Buffer>>> {
2231        if self.is_local() {
2232            let language_server = if let Some(server) = self.language_servers.get(&(
2233                symbol.source_worktree_id,
2234                Arc::from(symbol.language_name.as_str()),
2235            )) {
2236                server.clone()
2237            } else {
2238                return Task::ready(Err(anyhow!(
2239                    "language server for worktree and language not found"
2240                )));
2241            };
2242
2243            let worktree_abs_path = if let Some(worktree_abs_path) = self
2244                .worktree_for_id(symbol.worktree_id, cx)
2245                .and_then(|worktree| worktree.read(cx).as_local())
2246                .map(|local_worktree| local_worktree.abs_path())
2247            {
2248                worktree_abs_path
2249            } else {
2250                return Task::ready(Err(anyhow!("worktree not found for symbol")));
2251            };
2252            let symbol_abs_path = worktree_abs_path.join(&symbol.path);
2253            let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
2254                uri
2255            } else {
2256                return Task::ready(Err(anyhow!("invalid symbol path")));
2257            };
2258
2259            self.open_local_buffer_via_lsp(
2260                symbol_uri,
2261                Arc::from(symbol.language_name.as_str()),
2262                language_server,
2263                cx,
2264            )
2265        } else if let Some(project_id) = self.remote_id() {
2266            let request = self.client.request(proto::OpenBufferForSymbol {
2267                project_id,
2268                symbol: Some(serialize_symbol(symbol)),
2269            });
2270            cx.spawn(|this, mut cx| async move {
2271                let response = request.await?;
2272                let buffer = response.buffer.ok_or_else(|| anyhow!("invalid buffer"))?;
2273                this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
2274                    .await
2275            })
2276        } else {
2277            Task::ready(Err(anyhow!("project does not have a remote id")))
2278        }
2279    }
2280
2281    pub fn completions<T: ToPointUtf16>(
2282        &self,
2283        source_buffer_handle: &ModelHandle<Buffer>,
2284        position: T,
2285        cx: &mut ModelContext<Self>,
2286    ) -> Task<Result<Vec<Completion>>> {
2287        let source_buffer_handle = source_buffer_handle.clone();
2288        let source_buffer = source_buffer_handle.read(cx);
2289        let buffer_id = source_buffer.remote_id();
2290        let language = source_buffer.language().cloned();
2291        let worktree;
2292        let buffer_abs_path;
2293        if let Some(file) = File::from_dyn(source_buffer.file()) {
2294            worktree = file.worktree.clone();
2295            buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
2296        } else {
2297            return Task::ready(Ok(Default::default()));
2298        };
2299
2300        let position = position.to_point_utf16(source_buffer);
2301        let anchor = source_buffer.anchor_after(position);
2302
2303        if worktree.read(cx).as_local().is_some() {
2304            let buffer_abs_path = buffer_abs_path.unwrap();
2305            let lang_server =
2306                if let Some(server) = self.language_server_for_buffer(source_buffer, cx) {
2307                    server.clone()
2308                } else {
2309                    return Task::ready(Ok(Default::default()));
2310                };
2311
2312            cx.spawn(|_, cx| async move {
2313                let completions = lang_server
2314                    .request::<lsp::request::Completion>(lsp::CompletionParams {
2315                        text_document_position: lsp::TextDocumentPositionParams::new(
2316                            lsp::TextDocumentIdentifier::new(
2317                                lsp::Url::from_file_path(buffer_abs_path).unwrap(),
2318                            ),
2319                            position.to_lsp_position(),
2320                        ),
2321                        context: Default::default(),
2322                        work_done_progress_params: Default::default(),
2323                        partial_result_params: Default::default(),
2324                    })
2325                    .await
2326                    .context("lsp completion request failed")?;
2327
2328                let completions = if let Some(completions) = completions {
2329                    match completions {
2330                        lsp::CompletionResponse::Array(completions) => completions,
2331                        lsp::CompletionResponse::List(list) => list.items,
2332                    }
2333                } else {
2334                    Default::default()
2335                };
2336
2337                source_buffer_handle.read_with(&cx, |this, _| {
2338                    Ok(completions
2339                        .into_iter()
2340                        .filter_map(|lsp_completion| {
2341                            let (old_range, new_text) = match lsp_completion.text_edit.as_ref()? {
2342                                lsp::CompletionTextEdit::Edit(edit) => {
2343                                    (range_from_lsp(edit.range), edit.new_text.clone())
2344                                }
2345                                lsp::CompletionTextEdit::InsertAndReplace(_) => {
2346                                    log::info!("unsupported insert/replace completion");
2347                                    return None;
2348                                }
2349                            };
2350
2351                            let clipped_start = this.clip_point_utf16(old_range.start, Bias::Left);
2352                            let clipped_end = this.clip_point_utf16(old_range.end, Bias::Left);
2353                            if clipped_start == old_range.start && clipped_end == old_range.end {
2354                                Some(Completion {
2355                                    old_range: this.anchor_before(old_range.start)
2356                                        ..this.anchor_after(old_range.end),
2357                                    new_text,
2358                                    label: language
2359                                        .as_ref()
2360                                        .and_then(|l| l.label_for_completion(&lsp_completion))
2361                                        .unwrap_or_else(|| {
2362                                            CodeLabel::plain(
2363                                                lsp_completion.label.clone(),
2364                                                lsp_completion.filter_text.as_deref(),
2365                                            )
2366                                        }),
2367                                    lsp_completion,
2368                                })
2369                            } else {
2370                                None
2371                            }
2372                        })
2373                        .collect())
2374                })
2375            })
2376        } else if let Some(project_id) = self.remote_id() {
2377            let rpc = self.client.clone();
2378            let message = proto::GetCompletions {
2379                project_id,
2380                buffer_id,
2381                position: Some(language::proto::serialize_anchor(&anchor)),
2382                version: serialize_version(&source_buffer.version()),
2383            };
2384            cx.spawn_weak(|_, mut cx| async move {
2385                let response = rpc.request(message).await?;
2386
2387                source_buffer_handle
2388                    .update(&mut cx, |buffer, _| {
2389                        buffer.wait_for_version(deserialize_version(response.version))
2390                    })
2391                    .await;
2392
2393                response
2394                    .completions
2395                    .into_iter()
2396                    .map(|completion| {
2397                        language::proto::deserialize_completion(completion, language.as_ref())
2398                    })
2399                    .collect()
2400            })
2401        } else {
2402            Task::ready(Ok(Default::default()))
2403        }
2404    }
2405
2406    pub fn apply_additional_edits_for_completion(
2407        &self,
2408        buffer_handle: ModelHandle<Buffer>,
2409        completion: Completion,
2410        push_to_history: bool,
2411        cx: &mut ModelContext<Self>,
2412    ) -> Task<Result<Option<Transaction>>> {
2413        let buffer = buffer_handle.read(cx);
2414        let buffer_id = buffer.remote_id();
2415
2416        if self.is_local() {
2417            let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
2418                server.clone()
2419            } else {
2420                return Task::ready(Ok(Default::default()));
2421            };
2422
2423            cx.spawn(|this, mut cx| async move {
2424                let resolved_completion = lang_server
2425                    .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
2426                    .await?;
2427                if let Some(edits) = resolved_completion.additional_text_edits {
2428                    let edits = this
2429                        .update(&mut cx, |this, cx| {
2430                            this.edits_from_lsp(&buffer_handle, edits, None, cx)
2431                        })
2432                        .await?;
2433                    buffer_handle.update(&mut cx, |buffer, cx| {
2434                        buffer.finalize_last_transaction();
2435                        buffer.start_transaction();
2436                        for (range, text) in edits {
2437                            buffer.edit([range], text, cx);
2438                        }
2439                        let transaction = if buffer.end_transaction(cx).is_some() {
2440                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
2441                            if !push_to_history {
2442                                buffer.forget_transaction(transaction.id);
2443                            }
2444                            Some(transaction)
2445                        } else {
2446                            None
2447                        };
2448                        Ok(transaction)
2449                    })
2450                } else {
2451                    Ok(None)
2452                }
2453            })
2454        } else if let Some(project_id) = self.remote_id() {
2455            let client = self.client.clone();
2456            cx.spawn(|_, mut cx| async move {
2457                let response = client
2458                    .request(proto::ApplyCompletionAdditionalEdits {
2459                        project_id,
2460                        buffer_id,
2461                        completion: Some(language::proto::serialize_completion(&completion)),
2462                    })
2463                    .await?;
2464
2465                if let Some(transaction) = response.transaction {
2466                    let transaction = language::proto::deserialize_transaction(transaction)?;
2467                    buffer_handle
2468                        .update(&mut cx, |buffer, _| {
2469                            buffer.wait_for_edits(transaction.edit_ids.iter().copied())
2470                        })
2471                        .await;
2472                    if push_to_history {
2473                        buffer_handle.update(&mut cx, |buffer, _| {
2474                            buffer.push_transaction(transaction.clone(), Instant::now());
2475                        });
2476                    }
2477                    Ok(Some(transaction))
2478                } else {
2479                    Ok(None)
2480                }
2481            })
2482        } else {
2483            Task::ready(Err(anyhow!("project does not have a remote id")))
2484        }
2485    }
2486
2487    pub fn code_actions<T: ToOffset>(
2488        &self,
2489        buffer_handle: &ModelHandle<Buffer>,
2490        range: Range<T>,
2491        cx: &mut ModelContext<Self>,
2492    ) -> Task<Result<Vec<CodeAction>>> {
2493        let buffer_handle = buffer_handle.clone();
2494        let buffer = buffer_handle.read(cx);
2495        let buffer_id = buffer.remote_id();
2496        let worktree;
2497        let buffer_abs_path;
2498        if let Some(file) = File::from_dyn(buffer.file()) {
2499            worktree = file.worktree.clone();
2500            buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
2501        } else {
2502            return Task::ready(Ok(Default::default()));
2503        };
2504        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
2505
2506        if worktree.read(cx).as_local().is_some() {
2507            let buffer_abs_path = buffer_abs_path.unwrap();
2508            let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
2509                server.clone()
2510            } else {
2511                return Task::ready(Ok(Default::default()));
2512            };
2513
2514            let lsp_range = lsp::Range::new(
2515                range.start.to_point_utf16(buffer).to_lsp_position(),
2516                range.end.to_point_utf16(buffer).to_lsp_position(),
2517            );
2518            cx.foreground().spawn(async move {
2519                if !lang_server.capabilities().code_action_provider.is_some() {
2520                    return Ok(Default::default());
2521                }
2522
2523                Ok(lang_server
2524                    .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
2525                        text_document: lsp::TextDocumentIdentifier::new(
2526                            lsp::Url::from_file_path(buffer_abs_path).unwrap(),
2527                        ),
2528                        range: lsp_range,
2529                        work_done_progress_params: Default::default(),
2530                        partial_result_params: Default::default(),
2531                        context: lsp::CodeActionContext {
2532                            diagnostics: Default::default(),
2533                            only: Some(vec![
2534                                lsp::CodeActionKind::QUICKFIX,
2535                                lsp::CodeActionKind::REFACTOR,
2536                                lsp::CodeActionKind::REFACTOR_EXTRACT,
2537                            ]),
2538                        },
2539                    })
2540                    .await?
2541                    .unwrap_or_default()
2542                    .into_iter()
2543                    .filter_map(|entry| {
2544                        if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
2545                            Some(CodeAction {
2546                                range: range.clone(),
2547                                lsp_action,
2548                            })
2549                        } else {
2550                            None
2551                        }
2552                    })
2553                    .collect())
2554            })
2555        } else if let Some(project_id) = self.remote_id() {
2556            let rpc = self.client.clone();
2557            let version = buffer.version();
2558            cx.spawn_weak(|_, mut cx| async move {
2559                let response = rpc
2560                    .request(proto::GetCodeActions {
2561                        project_id,
2562                        buffer_id,
2563                        start: Some(language::proto::serialize_anchor(&range.start)),
2564                        end: Some(language::proto::serialize_anchor(&range.end)),
2565                        version: serialize_version(&version),
2566                    })
2567                    .await?;
2568
2569                buffer_handle
2570                    .update(&mut cx, |buffer, _| {
2571                        buffer.wait_for_version(deserialize_version(response.version))
2572                    })
2573                    .await;
2574
2575                response
2576                    .actions
2577                    .into_iter()
2578                    .map(language::proto::deserialize_code_action)
2579                    .collect()
2580            })
2581        } else {
2582            Task::ready(Ok(Default::default()))
2583        }
2584    }
2585
2586    pub fn apply_code_action(
2587        &self,
2588        buffer_handle: ModelHandle<Buffer>,
2589        mut action: CodeAction,
2590        push_to_history: bool,
2591        cx: &mut ModelContext<Self>,
2592    ) -> Task<Result<ProjectTransaction>> {
2593        if self.is_local() {
2594            let buffer = buffer_handle.read(cx);
2595            let lang_name = if let Some(lang) = buffer.language() {
2596                lang.name()
2597            } else {
2598                return Task::ready(Ok(Default::default()));
2599            };
2600            let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
2601                server.clone()
2602            } else {
2603                return Task::ready(Ok(Default::default()));
2604            };
2605            let range = action.range.to_point_utf16(buffer);
2606
2607            cx.spawn(|this, mut cx| async move {
2608                if let Some(lsp_range) = action
2609                    .lsp_action
2610                    .data
2611                    .as_mut()
2612                    .and_then(|d| d.get_mut("codeActionParams"))
2613                    .and_then(|d| d.get_mut("range"))
2614                {
2615                    *lsp_range = serde_json::to_value(&lsp::Range::new(
2616                        range.start.to_lsp_position(),
2617                        range.end.to_lsp_position(),
2618                    ))
2619                    .unwrap();
2620                    action.lsp_action = lang_server
2621                        .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
2622                        .await?;
2623                } else {
2624                    let actions = this
2625                        .update(&mut cx, |this, cx| {
2626                            this.code_actions(&buffer_handle, action.range, cx)
2627                        })
2628                        .await?;
2629                    action.lsp_action = actions
2630                        .into_iter()
2631                        .find(|a| a.lsp_action.title == action.lsp_action.title)
2632                        .ok_or_else(|| anyhow!("code action is outdated"))?
2633                        .lsp_action;
2634                }
2635
2636                if let Some(edit) = action.lsp_action.edit {
2637                    Self::deserialize_workspace_edit(
2638                        this,
2639                        edit,
2640                        push_to_history,
2641                        lang_name,
2642                        lang_server,
2643                        &mut cx,
2644                    )
2645                    .await
2646                } else {
2647                    Ok(ProjectTransaction::default())
2648                }
2649            })
2650        } else if let Some(project_id) = self.remote_id() {
2651            let client = self.client.clone();
2652            let request = proto::ApplyCodeAction {
2653                project_id,
2654                buffer_id: buffer_handle.read(cx).remote_id(),
2655                action: Some(language::proto::serialize_code_action(&action)),
2656            };
2657            cx.spawn(|this, mut cx| async move {
2658                let response = client
2659                    .request(request)
2660                    .await?
2661                    .transaction
2662                    .ok_or_else(|| anyhow!("missing transaction"))?;
2663                this.update(&mut cx, |this, cx| {
2664                    this.deserialize_project_transaction(response, push_to_history, cx)
2665                })
2666                .await
2667            })
2668        } else {
2669            Task::ready(Err(anyhow!("project does not have a remote id")))
2670        }
2671    }
2672
2673    async fn deserialize_workspace_edit(
2674        this: ModelHandle<Self>,
2675        edit: lsp::WorkspaceEdit,
2676        push_to_history: bool,
2677        language_name: Arc<str>,
2678        language_server: Arc<LanguageServer>,
2679        cx: &mut AsyncAppContext,
2680    ) -> Result<ProjectTransaction> {
2681        let fs = this.read_with(cx, |this, _| this.fs.clone());
2682        let mut operations = Vec::new();
2683        if let Some(document_changes) = edit.document_changes {
2684            match document_changes {
2685                lsp::DocumentChanges::Edits(edits) => {
2686                    operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2687                }
2688                lsp::DocumentChanges::Operations(ops) => operations = ops,
2689            }
2690        } else if let Some(changes) = edit.changes {
2691            operations.extend(changes.into_iter().map(|(uri, edits)| {
2692                lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2693                    text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2694                        uri,
2695                        version: None,
2696                    },
2697                    edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
2698                })
2699            }));
2700        }
2701
2702        let mut project_transaction = ProjectTransaction::default();
2703        for operation in operations {
2704            match operation {
2705                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2706                    let abs_path = op
2707                        .uri
2708                        .to_file_path()
2709                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2710
2711                    if let Some(parent_path) = abs_path.parent() {
2712                        fs.create_dir(parent_path).await?;
2713                    }
2714                    if abs_path.ends_with("/") {
2715                        fs.create_dir(&abs_path).await?;
2716                    } else {
2717                        fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
2718                            .await?;
2719                    }
2720                }
2721                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2722                    let source_abs_path = op
2723                        .old_uri
2724                        .to_file_path()
2725                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2726                    let target_abs_path = op
2727                        .new_uri
2728                        .to_file_path()
2729                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2730                    fs.rename(
2731                        &source_abs_path,
2732                        &target_abs_path,
2733                        op.options.map(Into::into).unwrap_or_default(),
2734                    )
2735                    .await?;
2736                }
2737                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2738                    let abs_path = op
2739                        .uri
2740                        .to_file_path()
2741                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2742                    let options = op.options.map(Into::into).unwrap_or_default();
2743                    if abs_path.ends_with("/") {
2744                        fs.remove_dir(&abs_path, options).await?;
2745                    } else {
2746                        fs.remove_file(&abs_path, options).await?;
2747                    }
2748                }
2749                lsp::DocumentChangeOperation::Edit(op) => {
2750                    let buffer_to_edit = this
2751                        .update(cx, |this, cx| {
2752                            this.open_local_buffer_via_lsp(
2753                                op.text_document.uri,
2754                                language_name.clone(),
2755                                language_server.clone(),
2756                                cx,
2757                            )
2758                        })
2759                        .await?;
2760
2761                    let edits = this
2762                        .update(cx, |this, cx| {
2763                            let edits = op.edits.into_iter().map(|edit| match edit {
2764                                lsp::OneOf::Left(edit) => edit,
2765                                lsp::OneOf::Right(edit) => edit.text_edit,
2766                            });
2767                            this.edits_from_lsp(
2768                                &buffer_to_edit,
2769                                edits,
2770                                op.text_document.version,
2771                                cx,
2772                            )
2773                        })
2774                        .await?;
2775
2776                    let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2777                        buffer.finalize_last_transaction();
2778                        buffer.start_transaction();
2779                        for (range, text) in edits {
2780                            buffer.edit([range], text, cx);
2781                        }
2782                        let transaction = if buffer.end_transaction(cx).is_some() {
2783                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
2784                            if !push_to_history {
2785                                buffer.forget_transaction(transaction.id);
2786                            }
2787                            Some(transaction)
2788                        } else {
2789                            None
2790                        };
2791
2792                        transaction
2793                    });
2794                    if let Some(transaction) = transaction {
2795                        project_transaction.0.insert(buffer_to_edit, transaction);
2796                    }
2797                }
2798            }
2799        }
2800
2801        Ok(project_transaction)
2802    }
2803
2804    pub fn prepare_rename<T: ToPointUtf16>(
2805        &self,
2806        buffer: ModelHandle<Buffer>,
2807        position: T,
2808        cx: &mut ModelContext<Self>,
2809    ) -> Task<Result<Option<Range<Anchor>>>> {
2810        let position = position.to_point_utf16(buffer.read(cx));
2811        self.request_lsp(buffer, PrepareRename { position }, cx)
2812    }
2813
2814    pub fn perform_rename<T: ToPointUtf16>(
2815        &self,
2816        buffer: ModelHandle<Buffer>,
2817        position: T,
2818        new_name: String,
2819        push_to_history: bool,
2820        cx: &mut ModelContext<Self>,
2821    ) -> Task<Result<ProjectTransaction>> {
2822        let position = position.to_point_utf16(buffer.read(cx));
2823        self.request_lsp(
2824            buffer,
2825            PerformRename {
2826                position,
2827                new_name,
2828                push_to_history,
2829            },
2830            cx,
2831        )
2832    }
2833
2834    pub fn search(
2835        &self,
2836        query: SearchQuery,
2837        cx: &mut ModelContext<Self>,
2838    ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
2839        if self.is_local() {
2840            let snapshots = self
2841                .visible_worktrees(cx)
2842                .filter_map(|tree| {
2843                    let tree = tree.read(cx).as_local()?;
2844                    Some(tree.snapshot())
2845                })
2846                .collect::<Vec<_>>();
2847
2848            let background = cx.background().clone();
2849            let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
2850            if path_count == 0 {
2851                return Task::ready(Ok(Default::default()));
2852            }
2853            let workers = background.num_cpus().min(path_count);
2854            let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
2855            cx.background()
2856                .spawn({
2857                    let fs = self.fs.clone();
2858                    let background = cx.background().clone();
2859                    let query = query.clone();
2860                    async move {
2861                        let fs = &fs;
2862                        let query = &query;
2863                        let matching_paths_tx = &matching_paths_tx;
2864                        let paths_per_worker = (path_count + workers - 1) / workers;
2865                        let snapshots = &snapshots;
2866                        background
2867                            .scoped(|scope| {
2868                                for worker_ix in 0..workers {
2869                                    let worker_start_ix = worker_ix * paths_per_worker;
2870                                    let worker_end_ix = worker_start_ix + paths_per_worker;
2871                                    scope.spawn(async move {
2872                                        let mut snapshot_start_ix = 0;
2873                                        let mut abs_path = PathBuf::new();
2874                                        for snapshot in snapshots {
2875                                            let snapshot_end_ix =
2876                                                snapshot_start_ix + snapshot.visible_file_count();
2877                                            if worker_end_ix <= snapshot_start_ix {
2878                                                break;
2879                                            } else if worker_start_ix > snapshot_end_ix {
2880                                                snapshot_start_ix = snapshot_end_ix;
2881                                                continue;
2882                                            } else {
2883                                                let start_in_snapshot = worker_start_ix
2884                                                    .saturating_sub(snapshot_start_ix);
2885                                                let end_in_snapshot =
2886                                                    cmp::min(worker_end_ix, snapshot_end_ix)
2887                                                        - snapshot_start_ix;
2888
2889                                                for entry in snapshot
2890                                                    .files(false, start_in_snapshot)
2891                                                    .take(end_in_snapshot - start_in_snapshot)
2892                                                {
2893                                                    if matching_paths_tx.is_closed() {
2894                                                        break;
2895                                                    }
2896
2897                                                    abs_path.clear();
2898                                                    abs_path.push(&snapshot.abs_path());
2899                                                    abs_path.push(&entry.path);
2900                                                    let matches = if let Some(file) =
2901                                                        fs.open_sync(&abs_path).await.log_err()
2902                                                    {
2903                                                        query.detect(file).unwrap_or(false)
2904                                                    } else {
2905                                                        false
2906                                                    };
2907
2908                                                    if matches {
2909                                                        let project_path =
2910                                                            (snapshot.id(), entry.path.clone());
2911                                                        if matching_paths_tx
2912                                                            .send(project_path)
2913                                                            .await
2914                                                            .is_err()
2915                                                        {
2916                                                            break;
2917                                                        }
2918                                                    }
2919                                                }
2920
2921                                                snapshot_start_ix = snapshot_end_ix;
2922                                            }
2923                                        }
2924                                    });
2925                                }
2926                            })
2927                            .await;
2928                    }
2929                })
2930                .detach();
2931
2932            let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
2933            let open_buffers = self
2934                .opened_buffers
2935                .values()
2936                .filter_map(|b| b.upgrade(cx))
2937                .collect::<HashSet<_>>();
2938            cx.spawn(|this, cx| async move {
2939                for buffer in &open_buffers {
2940                    let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
2941                    buffers_tx.send((buffer.clone(), snapshot)).await?;
2942                }
2943
2944                let open_buffers = Rc::new(RefCell::new(open_buffers));
2945                while let Some(project_path) = matching_paths_rx.next().await {
2946                    if buffers_tx.is_closed() {
2947                        break;
2948                    }
2949
2950                    let this = this.clone();
2951                    let open_buffers = open_buffers.clone();
2952                    let buffers_tx = buffers_tx.clone();
2953                    cx.spawn(|mut cx| async move {
2954                        if let Some(buffer) = this
2955                            .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
2956                            .await
2957                            .log_err()
2958                        {
2959                            if open_buffers.borrow_mut().insert(buffer.clone()) {
2960                                let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
2961                                buffers_tx.send((buffer, snapshot)).await?;
2962                            }
2963                        }
2964
2965                        Ok::<_, anyhow::Error>(())
2966                    })
2967                    .detach();
2968                }
2969
2970                Ok::<_, anyhow::Error>(())
2971            })
2972            .detach_and_log_err(cx);
2973
2974            let background = cx.background().clone();
2975            cx.background().spawn(async move {
2976                let query = &query;
2977                let mut matched_buffers = Vec::new();
2978                for _ in 0..workers {
2979                    matched_buffers.push(HashMap::default());
2980                }
2981                background
2982                    .scoped(|scope| {
2983                        for worker_matched_buffers in matched_buffers.iter_mut() {
2984                            let mut buffers_rx = buffers_rx.clone();
2985                            scope.spawn(async move {
2986                                while let Some((buffer, snapshot)) = buffers_rx.next().await {
2987                                    let buffer_matches = query
2988                                        .search(snapshot.as_rope())
2989                                        .await
2990                                        .iter()
2991                                        .map(|range| {
2992                                            snapshot.anchor_before(range.start)
2993                                                ..snapshot.anchor_after(range.end)
2994                                        })
2995                                        .collect::<Vec<_>>();
2996                                    if !buffer_matches.is_empty() {
2997                                        worker_matched_buffers
2998                                            .insert(buffer.clone(), buffer_matches);
2999                                    }
3000                                }
3001                            });
3002                        }
3003                    })
3004                    .await;
3005                Ok(matched_buffers.into_iter().flatten().collect())
3006            })
3007        } else if let Some(project_id) = self.remote_id() {
3008            let request = self.client.request(query.to_proto(project_id));
3009            cx.spawn(|this, mut cx| async move {
3010                let response = request.await?;
3011                let mut result = HashMap::default();
3012                for location in response.locations {
3013                    let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
3014                    let target_buffer = this
3015                        .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
3016                        .await?;
3017                    let start = location
3018                        .start
3019                        .and_then(deserialize_anchor)
3020                        .ok_or_else(|| anyhow!("missing target start"))?;
3021                    let end = location
3022                        .end
3023                        .and_then(deserialize_anchor)
3024                        .ok_or_else(|| anyhow!("missing target end"))?;
3025                    result
3026                        .entry(target_buffer)
3027                        .or_insert(Vec::new())
3028                        .push(start..end)
3029                }
3030                Ok(result)
3031            })
3032        } else {
3033            Task::ready(Ok(Default::default()))
3034        }
3035    }
3036
3037    fn request_lsp<R: LspCommand>(
3038        &self,
3039        buffer_handle: ModelHandle<Buffer>,
3040        request: R,
3041        cx: &mut ModelContext<Self>,
3042    ) -> Task<Result<R::Response>>
3043    where
3044        <R::LspRequest as lsp::request::Request>::Result: Send,
3045    {
3046        let buffer = buffer_handle.read(cx);
3047        if self.is_local() {
3048            let file = File::from_dyn(buffer.file()).and_then(File::as_local);
3049            if let Some((file, language_server)) =
3050                file.zip(self.language_server_for_buffer(buffer, cx).cloned())
3051            {
3052                let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
3053                return cx.spawn(|this, cx| async move {
3054                    if !request.check_capabilities(&language_server.capabilities()) {
3055                        return Ok(Default::default());
3056                    }
3057
3058                    let response = language_server
3059                        .request::<R::LspRequest>(lsp_params)
3060                        .await
3061                        .context("lsp request failed")?;
3062                    request
3063                        .response_from_lsp(response, this, buffer_handle, cx)
3064                        .await
3065                });
3066            }
3067        } else if let Some(project_id) = self.remote_id() {
3068            let rpc = self.client.clone();
3069            let message = request.to_proto(project_id, buffer);
3070            return cx.spawn(|this, cx| async move {
3071                let response = rpc.request(message).await?;
3072                request
3073                    .response_from_proto(response, this, buffer_handle, cx)
3074                    .await
3075            });
3076        }
3077        Task::ready(Ok(Default::default()))
3078    }
3079
3080    pub fn find_or_create_local_worktree(
3081        &mut self,
3082        abs_path: impl AsRef<Path>,
3083        visible: bool,
3084        cx: &mut ModelContext<Self>,
3085    ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
3086        let abs_path = abs_path.as_ref();
3087        if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
3088            Task::ready(Ok((tree.clone(), relative_path.into())))
3089        } else {
3090            let worktree = self.create_local_worktree(abs_path, visible, cx);
3091            cx.foreground()
3092                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
3093        }
3094    }
3095
3096    pub fn find_local_worktree(
3097        &self,
3098        abs_path: &Path,
3099        cx: &AppContext,
3100    ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
3101        for tree in self.worktrees(cx) {
3102            if let Some(relative_path) = tree
3103                .read(cx)
3104                .as_local()
3105                .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
3106            {
3107                return Some((tree.clone(), relative_path.into()));
3108            }
3109        }
3110        None
3111    }
3112
3113    pub fn is_shared(&self) -> bool {
3114        match &self.client_state {
3115            ProjectClientState::Local { is_shared, .. } => *is_shared,
3116            ProjectClientState::Remote { .. } => false,
3117        }
3118    }
3119
3120    fn create_local_worktree(
3121        &mut self,
3122        abs_path: impl AsRef<Path>,
3123        visible: bool,
3124        cx: &mut ModelContext<Self>,
3125    ) -> Task<Result<ModelHandle<Worktree>>> {
3126        let fs = self.fs.clone();
3127        let client = self.client.clone();
3128        let next_entry_id = self.next_entry_id.clone();
3129        let path: Arc<Path> = abs_path.as_ref().into();
3130        let task = self
3131            .loading_local_worktrees
3132            .entry(path.clone())
3133            .or_insert_with(|| {
3134                cx.spawn(|project, mut cx| {
3135                    async move {
3136                        let worktree = Worktree::local(
3137                            client.clone(),
3138                            path.clone(),
3139                            visible,
3140                            fs,
3141                            next_entry_id,
3142                            &mut cx,
3143                        )
3144                        .await;
3145                        project.update(&mut cx, |project, _| {
3146                            project.loading_local_worktrees.remove(&path);
3147                        });
3148                        let worktree = worktree?;
3149
3150                        let (remote_project_id, is_shared) =
3151                            project.update(&mut cx, |project, cx| {
3152                                project.add_worktree(&worktree, cx);
3153                                (project.remote_id(), project.is_shared())
3154                            });
3155
3156                        if let Some(project_id) = remote_project_id {
3157                            if is_shared {
3158                                worktree
3159                                    .update(&mut cx, |worktree, cx| {
3160                                        worktree.as_local_mut().unwrap().share(project_id, cx)
3161                                    })
3162                                    .await?;
3163                            } else {
3164                                worktree
3165                                    .update(&mut cx, |worktree, cx| {
3166                                        worktree.as_local_mut().unwrap().register(project_id, cx)
3167                                    })
3168                                    .await?;
3169                            }
3170                        }
3171
3172                        Ok(worktree)
3173                    }
3174                    .map_err(|err| Arc::new(err))
3175                })
3176                .shared()
3177            })
3178            .clone();
3179        cx.foreground().spawn(async move {
3180            match task.await {
3181                Ok(worktree) => Ok(worktree),
3182                Err(err) => Err(anyhow!("{}", err)),
3183            }
3184        })
3185    }
3186
3187    pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext<Self>) {
3188        self.worktrees.retain(|worktree| {
3189            worktree
3190                .upgrade(cx)
3191                .map_or(false, |w| w.read(cx).id() != id)
3192        });
3193        cx.notify();
3194    }
3195
3196    fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
3197        cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
3198        if worktree.read(cx).is_local() {
3199            cx.subscribe(&worktree, |this, worktree, _, cx| {
3200                this.update_local_worktree_buffers(worktree, cx);
3201            })
3202            .detach();
3203        }
3204
3205        let push_strong_handle = {
3206            let worktree = worktree.read(cx);
3207            self.is_shared() || worktree.is_visible() || worktree.is_remote()
3208        };
3209        if push_strong_handle {
3210            self.worktrees
3211                .push(WorktreeHandle::Strong(worktree.clone()));
3212        } else {
3213            cx.observe_release(&worktree, |this, _, cx| {
3214                this.worktrees
3215                    .retain(|worktree| worktree.upgrade(cx).is_some());
3216                cx.notify();
3217            })
3218            .detach();
3219            self.worktrees
3220                .push(WorktreeHandle::Weak(worktree.downgrade()));
3221        }
3222        cx.notify();
3223    }
3224
3225    fn update_local_worktree_buffers(
3226        &mut self,
3227        worktree_handle: ModelHandle<Worktree>,
3228        cx: &mut ModelContext<Self>,
3229    ) {
3230        let snapshot = worktree_handle.read(cx).snapshot();
3231        let mut buffers_to_delete = Vec::new();
3232        for (buffer_id, buffer) in &self.opened_buffers {
3233            if let Some(buffer) = buffer.upgrade(cx) {
3234                buffer.update(cx, |buffer, cx| {
3235                    if let Some(old_file) = File::from_dyn(buffer.file()) {
3236                        if old_file.worktree != worktree_handle {
3237                            return;
3238                        }
3239
3240                        let new_file = if let Some(entry) = old_file
3241                            .entry_id
3242                            .and_then(|entry_id| snapshot.entry_for_id(entry_id))
3243                        {
3244                            File {
3245                                is_local: true,
3246                                entry_id: Some(entry.id),
3247                                mtime: entry.mtime,
3248                                path: entry.path.clone(),
3249                                worktree: worktree_handle.clone(),
3250                            }
3251                        } else if let Some(entry) =
3252                            snapshot.entry_for_path(old_file.path().as_ref())
3253                        {
3254                            File {
3255                                is_local: true,
3256                                entry_id: Some(entry.id),
3257                                mtime: entry.mtime,
3258                                path: entry.path.clone(),
3259                                worktree: worktree_handle.clone(),
3260                            }
3261                        } else {
3262                            File {
3263                                is_local: true,
3264                                entry_id: None,
3265                                path: old_file.path().clone(),
3266                                mtime: old_file.mtime(),
3267                                worktree: worktree_handle.clone(),
3268                            }
3269                        };
3270
3271                        if let Some(project_id) = self.remote_id() {
3272                            self.client
3273                                .send(proto::UpdateBufferFile {
3274                                    project_id,
3275                                    buffer_id: *buffer_id as u64,
3276                                    file: Some(new_file.to_proto()),
3277                                })
3278                                .log_err();
3279                        }
3280                        buffer.file_updated(Box::new(new_file), cx).detach();
3281                    }
3282                });
3283            } else {
3284                buffers_to_delete.push(*buffer_id);
3285            }
3286        }
3287
3288        for buffer_id in buffers_to_delete {
3289            self.opened_buffers.remove(&buffer_id);
3290        }
3291    }
3292
3293    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
3294        let new_active_entry = entry.and_then(|project_path| {
3295            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
3296            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
3297            Some(entry.id)
3298        });
3299        if new_active_entry != self.active_entry {
3300            self.active_entry = new_active_entry;
3301            cx.emit(Event::ActiveEntryChanged(new_active_entry));
3302        }
3303    }
3304
3305    pub fn is_running_disk_based_diagnostics(&self) -> bool {
3306        self.language_servers_with_diagnostics_running > 0
3307    }
3308
3309    pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
3310        let mut summary = DiagnosticSummary::default();
3311        for (_, path_summary) in self.diagnostic_summaries(cx) {
3312            summary.error_count += path_summary.error_count;
3313            summary.warning_count += path_summary.warning_count;
3314            summary.info_count += path_summary.info_count;
3315            summary.hint_count += path_summary.hint_count;
3316        }
3317        summary
3318    }
3319
3320    pub fn diagnostic_summaries<'a>(
3321        &'a self,
3322        cx: &'a AppContext,
3323    ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
3324        self.worktrees(cx).flat_map(move |worktree| {
3325            let worktree = worktree.read(cx);
3326            let worktree_id = worktree.id();
3327            worktree
3328                .diagnostic_summaries()
3329                .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
3330        })
3331    }
3332
3333    pub fn disk_based_diagnostics_started(&mut self, cx: &mut ModelContext<Self>) {
3334        self.language_servers_with_diagnostics_running += 1;
3335        if self.language_servers_with_diagnostics_running == 1 {
3336            cx.emit(Event::DiskBasedDiagnosticsStarted);
3337        }
3338    }
3339
3340    pub fn disk_based_diagnostics_finished(&mut self, cx: &mut ModelContext<Self>) {
3341        cx.emit(Event::DiskBasedDiagnosticsUpdated);
3342        self.language_servers_with_diagnostics_running -= 1;
3343        if self.language_servers_with_diagnostics_running == 0 {
3344            cx.emit(Event::DiskBasedDiagnosticsFinished);
3345        }
3346    }
3347
3348    pub fn active_entry(&self) -> Option<ProjectEntryId> {
3349        self.active_entry
3350    }
3351
3352    pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
3353        self.worktree_for_id(path.worktree_id, cx)?
3354            .read(cx)
3355            .entry_for_path(&path.path)
3356            .map(|entry| entry.id)
3357    }
3358
3359    pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
3360        let worktree = self.worktree_for_entry(entry_id, cx)?;
3361        let worktree = worktree.read(cx);
3362        let worktree_id = worktree.id();
3363        let path = worktree.entry_for_id(entry_id)?.path.clone();
3364        Some(ProjectPath { worktree_id, path })
3365    }
3366
3367    // RPC message handlers
3368
3369    async fn handle_unshare_project(
3370        this: ModelHandle<Self>,
3371        _: TypedEnvelope<proto::UnshareProject>,
3372        _: Arc<Client>,
3373        mut cx: AsyncAppContext,
3374    ) -> Result<()> {
3375        this.update(&mut cx, |this, cx| this.project_unshared(cx));
3376        Ok(())
3377    }
3378
3379    async fn handle_add_collaborator(
3380        this: ModelHandle<Self>,
3381        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
3382        _: Arc<Client>,
3383        mut cx: AsyncAppContext,
3384    ) -> Result<()> {
3385        let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
3386        let collaborator = envelope
3387            .payload
3388            .collaborator
3389            .take()
3390            .ok_or_else(|| anyhow!("empty collaborator"))?;
3391
3392        let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
3393        this.update(&mut cx, |this, cx| {
3394            this.collaborators
3395                .insert(collaborator.peer_id, collaborator);
3396            cx.notify();
3397        });
3398
3399        Ok(())
3400    }
3401
3402    async fn handle_remove_collaborator(
3403        this: ModelHandle<Self>,
3404        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
3405        _: Arc<Client>,
3406        mut cx: AsyncAppContext,
3407    ) -> Result<()> {
3408        this.update(&mut cx, |this, cx| {
3409            let peer_id = PeerId(envelope.payload.peer_id);
3410            let replica_id = this
3411                .collaborators
3412                .remove(&peer_id)
3413                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
3414                .replica_id;
3415            for (_, buffer) in &this.opened_buffers {
3416                if let Some(buffer) = buffer.upgrade(cx) {
3417                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
3418                }
3419            }
3420            cx.emit(Event::CollaboratorLeft(peer_id));
3421            cx.notify();
3422            Ok(())
3423        })
3424    }
3425
3426    async fn handle_register_worktree(
3427        this: ModelHandle<Self>,
3428        envelope: TypedEnvelope<proto::RegisterWorktree>,
3429        client: Arc<Client>,
3430        mut cx: AsyncAppContext,
3431    ) -> Result<()> {
3432        this.update(&mut cx, |this, cx| {
3433            let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
3434            let replica_id = this.replica_id();
3435            let worktree = proto::Worktree {
3436                id: envelope.payload.worktree_id,
3437                root_name: envelope.payload.root_name,
3438                entries: Default::default(),
3439                diagnostic_summaries: Default::default(),
3440                visible: envelope.payload.visible,
3441            };
3442            let (worktree, load_task) =
3443                Worktree::remote(remote_id, replica_id, worktree, client, cx);
3444            this.add_worktree(&worktree, cx);
3445            load_task.detach();
3446            Ok(())
3447        })
3448    }
3449
3450    async fn handle_unregister_worktree(
3451        this: ModelHandle<Self>,
3452        envelope: TypedEnvelope<proto::UnregisterWorktree>,
3453        _: Arc<Client>,
3454        mut cx: AsyncAppContext,
3455    ) -> Result<()> {
3456        this.update(&mut cx, |this, cx| {
3457            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3458            this.remove_worktree(worktree_id, cx);
3459            Ok(())
3460        })
3461    }
3462
3463    async fn handle_update_worktree(
3464        this: ModelHandle<Self>,
3465        envelope: TypedEnvelope<proto::UpdateWorktree>,
3466        _: Arc<Client>,
3467        mut cx: AsyncAppContext,
3468    ) -> Result<()> {
3469        this.update(&mut cx, |this, cx| {
3470            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3471            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
3472                worktree.update(cx, |worktree, _| {
3473                    let worktree = worktree.as_remote_mut().unwrap();
3474                    worktree.update_from_remote(envelope)
3475                })?;
3476            }
3477            Ok(())
3478        })
3479    }
3480
3481    async fn handle_update_diagnostic_summary(
3482        this: ModelHandle<Self>,
3483        envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
3484        _: Arc<Client>,
3485        mut cx: AsyncAppContext,
3486    ) -> Result<()> {
3487        this.update(&mut cx, |this, cx| {
3488            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3489            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
3490                if let Some(summary) = envelope.payload.summary {
3491                    let project_path = ProjectPath {
3492                        worktree_id,
3493                        path: Path::new(&summary.path).into(),
3494                    };
3495                    worktree.update(cx, |worktree, _| {
3496                        worktree
3497                            .as_remote_mut()
3498                            .unwrap()
3499                            .update_diagnostic_summary(project_path.path.clone(), &summary);
3500                    });
3501                    cx.emit(Event::DiagnosticsUpdated(project_path));
3502                }
3503            }
3504            Ok(())
3505        })
3506    }
3507
3508    async fn handle_start_language_server(
3509        this: ModelHandle<Self>,
3510        envelope: TypedEnvelope<proto::StartLanguageServer>,
3511        _: Arc<Client>,
3512        mut cx: AsyncAppContext,
3513    ) -> Result<()> {
3514        let server = envelope
3515            .payload
3516            .server
3517            .ok_or_else(|| anyhow!("invalid server"))?;
3518        this.update(&mut cx, |this, cx| {
3519            this.language_server_statuses.insert(
3520                server.id as usize,
3521                LanguageServerStatus {
3522                    name: server.name,
3523                    pending_work: Default::default(),
3524                    pending_diagnostic_updates: 0,
3525                },
3526            );
3527            cx.notify();
3528        });
3529        Ok(())
3530    }
3531
3532    async fn handle_update_language_server(
3533        this: ModelHandle<Self>,
3534        envelope: TypedEnvelope<proto::UpdateLanguageServer>,
3535        _: Arc<Client>,
3536        mut cx: AsyncAppContext,
3537    ) -> Result<()> {
3538        let language_server_id = envelope.payload.language_server_id as usize;
3539        match envelope
3540            .payload
3541            .variant
3542            .ok_or_else(|| anyhow!("invalid variant"))?
3543        {
3544            proto::update_language_server::Variant::WorkStart(payload) => {
3545                this.update(&mut cx, |this, cx| {
3546                    this.on_lsp_work_start(language_server_id, payload.token, cx);
3547                })
3548            }
3549            proto::update_language_server::Variant::WorkProgress(payload) => {
3550                this.update(&mut cx, |this, cx| {
3551                    this.on_lsp_work_progress(
3552                        language_server_id,
3553                        payload.token,
3554                        LanguageServerProgress {
3555                            message: payload.message,
3556                            percentage: payload.percentage.map(|p| p as usize),
3557                            last_update_at: Instant::now(),
3558                        },
3559                        cx,
3560                    );
3561                })
3562            }
3563            proto::update_language_server::Variant::WorkEnd(payload) => {
3564                this.update(&mut cx, |this, cx| {
3565                    this.on_lsp_work_end(language_server_id, payload.token, cx);
3566                })
3567            }
3568            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
3569                this.update(&mut cx, |this, cx| {
3570                    this.disk_based_diagnostics_started(cx);
3571                })
3572            }
3573            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
3574                this.update(&mut cx, |this, cx| this.disk_based_diagnostics_finished(cx));
3575            }
3576        }
3577
3578        Ok(())
3579    }
3580
3581    async fn handle_update_buffer(
3582        this: ModelHandle<Self>,
3583        envelope: TypedEnvelope<proto::UpdateBuffer>,
3584        _: Arc<Client>,
3585        mut cx: AsyncAppContext,
3586    ) -> Result<()> {
3587        this.update(&mut cx, |this, cx| {
3588            let payload = envelope.payload.clone();
3589            let buffer_id = payload.buffer_id;
3590            let ops = payload
3591                .operations
3592                .into_iter()
3593                .map(|op| language::proto::deserialize_operation(op))
3594                .collect::<Result<Vec<_>, _>>()?;
3595            match this.opened_buffers.entry(buffer_id) {
3596                hash_map::Entry::Occupied(mut e) => match e.get_mut() {
3597                    OpenBuffer::Strong(buffer) => {
3598                        buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
3599                    }
3600                    OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
3601                    OpenBuffer::Weak(_) => {}
3602                },
3603                hash_map::Entry::Vacant(e) => {
3604                    e.insert(OpenBuffer::Loading(ops));
3605                }
3606            }
3607            Ok(())
3608        })
3609    }
3610
3611    async fn handle_update_buffer_file(
3612        this: ModelHandle<Self>,
3613        envelope: TypedEnvelope<proto::UpdateBufferFile>,
3614        _: Arc<Client>,
3615        mut cx: AsyncAppContext,
3616    ) -> Result<()> {
3617        this.update(&mut cx, |this, cx| {
3618            let payload = envelope.payload.clone();
3619            let buffer_id = payload.buffer_id;
3620            let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
3621            let worktree = this
3622                .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
3623                .ok_or_else(|| anyhow!("no such worktree"))?;
3624            let file = File::from_proto(file, worktree.clone(), cx)?;
3625            let buffer = this
3626                .opened_buffers
3627                .get_mut(&buffer_id)
3628                .and_then(|b| b.upgrade(cx))
3629                .ok_or_else(|| anyhow!("no such buffer"))?;
3630            buffer.update(cx, |buffer, cx| {
3631                buffer.file_updated(Box::new(file), cx).detach();
3632            });
3633            Ok(())
3634        })
3635    }
3636
3637    async fn handle_save_buffer(
3638        this: ModelHandle<Self>,
3639        envelope: TypedEnvelope<proto::SaveBuffer>,
3640        _: Arc<Client>,
3641        mut cx: AsyncAppContext,
3642    ) -> Result<proto::BufferSaved> {
3643        let buffer_id = envelope.payload.buffer_id;
3644        let requested_version = deserialize_version(envelope.payload.version);
3645
3646        let (project_id, buffer) = this.update(&mut cx, |this, cx| {
3647            let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
3648            let buffer = this
3649                .opened_buffers
3650                .get(&buffer_id)
3651                .map(|buffer| buffer.upgrade(cx).unwrap())
3652                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
3653            Ok::<_, anyhow::Error>((project_id, buffer))
3654        })?;
3655        buffer
3656            .update(&mut cx, |buffer, _| {
3657                buffer.wait_for_version(requested_version)
3658            })
3659            .await;
3660
3661        let (saved_version, mtime) = buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
3662        Ok(proto::BufferSaved {
3663            project_id,
3664            buffer_id,
3665            version: serialize_version(&saved_version),
3666            mtime: Some(mtime.into()),
3667        })
3668    }
3669
3670    async fn handle_format_buffers(
3671        this: ModelHandle<Self>,
3672        envelope: TypedEnvelope<proto::FormatBuffers>,
3673        _: Arc<Client>,
3674        mut cx: AsyncAppContext,
3675    ) -> Result<proto::FormatBuffersResponse> {
3676        let sender_id = envelope.original_sender_id()?;
3677        let format = this.update(&mut cx, |this, cx| {
3678            let mut buffers = HashSet::default();
3679            for buffer_id in &envelope.payload.buffer_ids {
3680                buffers.insert(
3681                    this.opened_buffers
3682                        .get(buffer_id)
3683                        .map(|buffer| buffer.upgrade(cx).unwrap())
3684                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
3685                );
3686            }
3687            Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
3688        })?;
3689
3690        let project_transaction = format.await?;
3691        let project_transaction = this.update(&mut cx, |this, cx| {
3692            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
3693        });
3694        Ok(proto::FormatBuffersResponse {
3695            transaction: Some(project_transaction),
3696        })
3697    }
3698
3699    async fn handle_get_completions(
3700        this: ModelHandle<Self>,
3701        envelope: TypedEnvelope<proto::GetCompletions>,
3702        _: Arc<Client>,
3703        mut cx: AsyncAppContext,
3704    ) -> Result<proto::GetCompletionsResponse> {
3705        let position = envelope
3706            .payload
3707            .position
3708            .and_then(language::proto::deserialize_anchor)
3709            .ok_or_else(|| anyhow!("invalid position"))?;
3710        let version = deserialize_version(envelope.payload.version);
3711        let buffer = this.read_with(&cx, |this, cx| {
3712            this.opened_buffers
3713                .get(&envelope.payload.buffer_id)
3714                .map(|buffer| buffer.upgrade(cx).unwrap())
3715                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
3716        })?;
3717        buffer
3718            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
3719            .await;
3720        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
3721        let completions = this
3722            .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
3723            .await?;
3724
3725        Ok(proto::GetCompletionsResponse {
3726            completions: completions
3727                .iter()
3728                .map(language::proto::serialize_completion)
3729                .collect(),
3730            version: serialize_version(&version),
3731        })
3732    }
3733
3734    async fn handle_apply_additional_edits_for_completion(
3735        this: ModelHandle<Self>,
3736        envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
3737        _: Arc<Client>,
3738        mut cx: AsyncAppContext,
3739    ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
3740        let apply_additional_edits = this.update(&mut cx, |this, cx| {
3741            let buffer = this
3742                .opened_buffers
3743                .get(&envelope.payload.buffer_id)
3744                .map(|buffer| buffer.upgrade(cx).unwrap())
3745                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
3746            let language = buffer.read(cx).language();
3747            let completion = language::proto::deserialize_completion(
3748                envelope
3749                    .payload
3750                    .completion
3751                    .ok_or_else(|| anyhow!("invalid completion"))?,
3752                language,
3753            )?;
3754            Ok::<_, anyhow::Error>(
3755                this.apply_additional_edits_for_completion(buffer, completion, false, cx),
3756            )
3757        })?;
3758
3759        Ok(proto::ApplyCompletionAdditionalEditsResponse {
3760            transaction: apply_additional_edits
3761                .await?
3762                .as_ref()
3763                .map(language::proto::serialize_transaction),
3764        })
3765    }
3766
3767    async fn handle_get_code_actions(
3768        this: ModelHandle<Self>,
3769        envelope: TypedEnvelope<proto::GetCodeActions>,
3770        _: Arc<Client>,
3771        mut cx: AsyncAppContext,
3772    ) -> Result<proto::GetCodeActionsResponse> {
3773        let start = envelope
3774            .payload
3775            .start
3776            .and_then(language::proto::deserialize_anchor)
3777            .ok_or_else(|| anyhow!("invalid start"))?;
3778        let end = envelope
3779            .payload
3780            .end
3781            .and_then(language::proto::deserialize_anchor)
3782            .ok_or_else(|| anyhow!("invalid end"))?;
3783        let buffer = this.update(&mut cx, |this, cx| {
3784            this.opened_buffers
3785                .get(&envelope.payload.buffer_id)
3786                .map(|buffer| buffer.upgrade(cx).unwrap())
3787                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
3788        })?;
3789        buffer
3790            .update(&mut cx, |buffer, _| {
3791                buffer.wait_for_version(deserialize_version(envelope.payload.version))
3792            })
3793            .await;
3794
3795        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
3796        let code_actions = this.update(&mut cx, |this, cx| {
3797            Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
3798        })?;
3799
3800        Ok(proto::GetCodeActionsResponse {
3801            actions: code_actions
3802                .await?
3803                .iter()
3804                .map(language::proto::serialize_code_action)
3805                .collect(),
3806            version: serialize_version(&version),
3807        })
3808    }
3809
3810    async fn handle_apply_code_action(
3811        this: ModelHandle<Self>,
3812        envelope: TypedEnvelope<proto::ApplyCodeAction>,
3813        _: Arc<Client>,
3814        mut cx: AsyncAppContext,
3815    ) -> Result<proto::ApplyCodeActionResponse> {
3816        let sender_id = envelope.original_sender_id()?;
3817        let action = language::proto::deserialize_code_action(
3818            envelope
3819                .payload
3820                .action
3821                .ok_or_else(|| anyhow!("invalid action"))?,
3822        )?;
3823        let apply_code_action = this.update(&mut cx, |this, cx| {
3824            let buffer = this
3825                .opened_buffers
3826                .get(&envelope.payload.buffer_id)
3827                .map(|buffer| buffer.upgrade(cx).unwrap())
3828                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
3829            Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
3830        })?;
3831
3832        let project_transaction = apply_code_action.await?;
3833        let project_transaction = this.update(&mut cx, |this, cx| {
3834            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
3835        });
3836        Ok(proto::ApplyCodeActionResponse {
3837            transaction: Some(project_transaction),
3838        })
3839    }
3840
3841    async fn handle_lsp_command<T: LspCommand>(
3842        this: ModelHandle<Self>,
3843        envelope: TypedEnvelope<T::ProtoRequest>,
3844        _: Arc<Client>,
3845        mut cx: AsyncAppContext,
3846    ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
3847    where
3848        <T::LspRequest as lsp::request::Request>::Result: Send,
3849    {
3850        let sender_id = envelope.original_sender_id()?;
3851        let buffer_id = T::buffer_id_from_proto(&envelope.payload);
3852        let buffer_handle = this.read_with(&cx, |this, _| {
3853            this.opened_buffers
3854                .get(&buffer_id)
3855                .and_then(|buffer| buffer.upgrade(&cx))
3856                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
3857        })?;
3858        let request = T::from_proto(
3859            envelope.payload,
3860            this.clone(),
3861            buffer_handle.clone(),
3862            cx.clone(),
3863        )
3864        .await?;
3865        let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
3866        let response = this
3867            .update(&mut cx, |this, cx| {
3868                this.request_lsp(buffer_handle, request, cx)
3869            })
3870            .await?;
3871        this.update(&mut cx, |this, cx| {
3872            Ok(T::response_to_proto(
3873                response,
3874                this,
3875                sender_id,
3876                &buffer_version,
3877                cx,
3878            ))
3879        })
3880    }
3881
3882    async fn handle_get_project_symbols(
3883        this: ModelHandle<Self>,
3884        envelope: TypedEnvelope<proto::GetProjectSymbols>,
3885        _: Arc<Client>,
3886        mut cx: AsyncAppContext,
3887    ) -> Result<proto::GetProjectSymbolsResponse> {
3888        let symbols = this
3889            .update(&mut cx, |this, cx| {
3890                this.symbols(&envelope.payload.query, cx)
3891            })
3892            .await?;
3893
3894        Ok(proto::GetProjectSymbolsResponse {
3895            symbols: symbols.iter().map(serialize_symbol).collect(),
3896        })
3897    }
3898
3899    async fn handle_search_project(
3900        this: ModelHandle<Self>,
3901        envelope: TypedEnvelope<proto::SearchProject>,
3902        _: Arc<Client>,
3903        mut cx: AsyncAppContext,
3904    ) -> Result<proto::SearchProjectResponse> {
3905        let peer_id = envelope.original_sender_id()?;
3906        let query = SearchQuery::from_proto(envelope.payload)?;
3907        let result = this
3908            .update(&mut cx, |this, cx| this.search(query, cx))
3909            .await?;
3910
3911        this.update(&mut cx, |this, cx| {
3912            let mut locations = Vec::new();
3913            for (buffer, ranges) in result {
3914                for range in ranges {
3915                    let start = serialize_anchor(&range.start);
3916                    let end = serialize_anchor(&range.end);
3917                    let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
3918                    locations.push(proto::Location {
3919                        buffer: Some(buffer),
3920                        start: Some(start),
3921                        end: Some(end),
3922                    });
3923                }
3924            }
3925            Ok(proto::SearchProjectResponse { locations })
3926        })
3927    }
3928
3929    async fn handle_open_buffer_for_symbol(
3930        this: ModelHandle<Self>,
3931        envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
3932        _: Arc<Client>,
3933        mut cx: AsyncAppContext,
3934    ) -> Result<proto::OpenBufferForSymbolResponse> {
3935        let peer_id = envelope.original_sender_id()?;
3936        let symbol = envelope
3937            .payload
3938            .symbol
3939            .ok_or_else(|| anyhow!("invalid symbol"))?;
3940        let symbol = this.read_with(&cx, |this, _| {
3941            let symbol = this.deserialize_symbol(symbol)?;
3942            let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
3943            if signature == symbol.signature {
3944                Ok(symbol)
3945            } else {
3946                Err(anyhow!("invalid symbol signature"))
3947            }
3948        })?;
3949        let buffer = this
3950            .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
3951            .await?;
3952
3953        Ok(proto::OpenBufferForSymbolResponse {
3954            buffer: Some(this.update(&mut cx, |this, cx| {
3955                this.serialize_buffer_for_peer(&buffer, peer_id, cx)
3956            })),
3957        })
3958    }
3959
3960    fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
3961        let mut hasher = Sha256::new();
3962        hasher.update(worktree_id.to_proto().to_be_bytes());
3963        hasher.update(path.to_string_lossy().as_bytes());
3964        hasher.update(self.nonce.to_be_bytes());
3965        hasher.finalize().as_slice().try_into().unwrap()
3966    }
3967
3968    async fn handle_open_buffer_by_id(
3969        this: ModelHandle<Self>,
3970        envelope: TypedEnvelope<proto::OpenBufferById>,
3971        _: Arc<Client>,
3972        mut cx: AsyncAppContext,
3973    ) -> Result<proto::OpenBufferResponse> {
3974        let peer_id = envelope.original_sender_id()?;
3975        let buffer = this
3976            .update(&mut cx, |this, cx| {
3977                this.open_buffer_by_id(envelope.payload.id, cx)
3978            })
3979            .await?;
3980        this.update(&mut cx, |this, cx| {
3981            Ok(proto::OpenBufferResponse {
3982                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
3983            })
3984        })
3985    }
3986
3987    async fn handle_open_buffer_by_path(
3988        this: ModelHandle<Self>,
3989        envelope: TypedEnvelope<proto::OpenBufferByPath>,
3990        _: Arc<Client>,
3991        mut cx: AsyncAppContext,
3992    ) -> Result<proto::OpenBufferResponse> {
3993        let peer_id = envelope.original_sender_id()?;
3994        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3995        let open_buffer = this.update(&mut cx, |this, cx| {
3996            this.open_buffer(
3997                ProjectPath {
3998                    worktree_id,
3999                    path: PathBuf::from(envelope.payload.path).into(),
4000                },
4001                cx,
4002            )
4003        });
4004
4005        let buffer = open_buffer.await?;
4006        this.update(&mut cx, |this, cx| {
4007            Ok(proto::OpenBufferResponse {
4008                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
4009            })
4010        })
4011    }
4012
4013    fn serialize_project_transaction_for_peer(
4014        &mut self,
4015        project_transaction: ProjectTransaction,
4016        peer_id: PeerId,
4017        cx: &AppContext,
4018    ) -> proto::ProjectTransaction {
4019        let mut serialized_transaction = proto::ProjectTransaction {
4020            buffers: Default::default(),
4021            transactions: Default::default(),
4022        };
4023        for (buffer, transaction) in project_transaction.0 {
4024            serialized_transaction
4025                .buffers
4026                .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
4027            serialized_transaction
4028                .transactions
4029                .push(language::proto::serialize_transaction(&transaction));
4030        }
4031        serialized_transaction
4032    }
4033
4034    fn deserialize_project_transaction(
4035        &mut self,
4036        message: proto::ProjectTransaction,
4037        push_to_history: bool,
4038        cx: &mut ModelContext<Self>,
4039    ) -> Task<Result<ProjectTransaction>> {
4040        cx.spawn(|this, mut cx| async move {
4041            let mut project_transaction = ProjectTransaction::default();
4042            for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
4043                let buffer = this
4044                    .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4045                    .await?;
4046                let transaction = language::proto::deserialize_transaction(transaction)?;
4047                project_transaction.0.insert(buffer, transaction);
4048            }
4049
4050            for (buffer, transaction) in &project_transaction.0 {
4051                buffer
4052                    .update(&mut cx, |buffer, _| {
4053                        buffer.wait_for_edits(transaction.edit_ids.iter().copied())
4054                    })
4055                    .await;
4056
4057                if push_to_history {
4058                    buffer.update(&mut cx, |buffer, _| {
4059                        buffer.push_transaction(transaction.clone(), Instant::now());
4060                    });
4061                }
4062            }
4063
4064            Ok(project_transaction)
4065        })
4066    }
4067
4068    fn serialize_buffer_for_peer(
4069        &mut self,
4070        buffer: &ModelHandle<Buffer>,
4071        peer_id: PeerId,
4072        cx: &AppContext,
4073    ) -> proto::Buffer {
4074        let buffer_id = buffer.read(cx).remote_id();
4075        let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
4076        if shared_buffers.insert(buffer_id) {
4077            proto::Buffer {
4078                variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
4079            }
4080        } else {
4081            proto::Buffer {
4082                variant: Some(proto::buffer::Variant::Id(buffer_id)),
4083            }
4084        }
4085    }
4086
4087    fn deserialize_buffer(
4088        &mut self,
4089        buffer: proto::Buffer,
4090        cx: &mut ModelContext<Self>,
4091    ) -> Task<Result<ModelHandle<Buffer>>> {
4092        let replica_id = self.replica_id();
4093
4094        let opened_buffer_tx = self.opened_buffer.0.clone();
4095        let mut opened_buffer_rx = self.opened_buffer.1.clone();
4096        cx.spawn(|this, mut cx| async move {
4097            match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
4098                proto::buffer::Variant::Id(id) => {
4099                    let buffer = loop {
4100                        let buffer = this.read_with(&cx, |this, cx| {
4101                            this.opened_buffers
4102                                .get(&id)
4103                                .and_then(|buffer| buffer.upgrade(cx))
4104                        });
4105                        if let Some(buffer) = buffer {
4106                            break buffer;
4107                        }
4108                        opened_buffer_rx
4109                            .next()
4110                            .await
4111                            .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
4112                    };
4113                    Ok(buffer)
4114                }
4115                proto::buffer::Variant::State(mut buffer) => {
4116                    let mut buffer_worktree = None;
4117                    let mut buffer_file = None;
4118                    if let Some(file) = buffer.file.take() {
4119                        this.read_with(&cx, |this, cx| {
4120                            let worktree_id = WorktreeId::from_proto(file.worktree_id);
4121                            let worktree =
4122                                this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
4123                                    anyhow!("no worktree found for id {}", file.worktree_id)
4124                                })?;
4125                            buffer_file =
4126                                Some(Box::new(File::from_proto(file, worktree.clone(), cx)?)
4127                                    as Box<dyn language::File>);
4128                            buffer_worktree = Some(worktree);
4129                            Ok::<_, anyhow::Error>(())
4130                        })?;
4131                    }
4132
4133                    let buffer = cx.add_model(|cx| {
4134                        Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
4135                    });
4136
4137                    this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
4138
4139                    *opened_buffer_tx.borrow_mut().borrow_mut() = ();
4140                    Ok(buffer)
4141                }
4142            }
4143        })
4144    }
4145
4146    fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
4147        let language = self
4148            .languages
4149            .get_language(&serialized_symbol.language_name);
4150        let start = serialized_symbol
4151            .start
4152            .ok_or_else(|| anyhow!("invalid start"))?;
4153        let end = serialized_symbol
4154            .end
4155            .ok_or_else(|| anyhow!("invalid end"))?;
4156        let kind = unsafe { mem::transmute(serialized_symbol.kind) };
4157        Ok(Symbol {
4158            source_worktree_id: WorktreeId::from_proto(serialized_symbol.source_worktree_id),
4159            worktree_id: WorktreeId::from_proto(serialized_symbol.worktree_id),
4160            language_name: serialized_symbol.language_name.clone(),
4161            label: language
4162                .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
4163                .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
4164            name: serialized_symbol.name,
4165            path: PathBuf::from(serialized_symbol.path),
4166            range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
4167            kind,
4168            signature: serialized_symbol
4169                .signature
4170                .try_into()
4171                .map_err(|_| anyhow!("invalid signature"))?,
4172        })
4173    }
4174
4175    async fn handle_buffer_saved(
4176        this: ModelHandle<Self>,
4177        envelope: TypedEnvelope<proto::BufferSaved>,
4178        _: Arc<Client>,
4179        mut cx: AsyncAppContext,
4180    ) -> Result<()> {
4181        let version = deserialize_version(envelope.payload.version);
4182        let mtime = envelope
4183            .payload
4184            .mtime
4185            .ok_or_else(|| anyhow!("missing mtime"))?
4186            .into();
4187
4188        this.update(&mut cx, |this, cx| {
4189            let buffer = this
4190                .opened_buffers
4191                .get(&envelope.payload.buffer_id)
4192                .and_then(|buffer| buffer.upgrade(cx));
4193            if let Some(buffer) = buffer {
4194                buffer.update(cx, |buffer, cx| {
4195                    buffer.did_save(version, mtime, None, cx);
4196                });
4197            }
4198            Ok(())
4199        })
4200    }
4201
4202    async fn handle_buffer_reloaded(
4203        this: ModelHandle<Self>,
4204        envelope: TypedEnvelope<proto::BufferReloaded>,
4205        _: Arc<Client>,
4206        mut cx: AsyncAppContext,
4207    ) -> Result<()> {
4208        let payload = envelope.payload.clone();
4209        let version = deserialize_version(payload.version);
4210        let mtime = payload
4211            .mtime
4212            .ok_or_else(|| anyhow!("missing mtime"))?
4213            .into();
4214        this.update(&mut cx, |this, cx| {
4215            let buffer = this
4216                .opened_buffers
4217                .get(&payload.buffer_id)
4218                .and_then(|buffer| buffer.upgrade(cx));
4219            if let Some(buffer) = buffer {
4220                buffer.update(cx, |buffer, cx| {
4221                    buffer.did_reload(version, mtime, cx);
4222                });
4223            }
4224            Ok(())
4225        })
4226    }
4227
4228    pub fn match_paths<'a>(
4229        &self,
4230        query: &'a str,
4231        include_ignored: bool,
4232        smart_case: bool,
4233        max_results: usize,
4234        cancel_flag: &'a AtomicBool,
4235        cx: &AppContext,
4236    ) -> impl 'a + Future<Output = Vec<PathMatch>> {
4237        let worktrees = self
4238            .worktrees(cx)
4239            .filter(|worktree| worktree.read(cx).is_visible())
4240            .collect::<Vec<_>>();
4241        let include_root_name = worktrees.len() > 1;
4242        let candidate_sets = worktrees
4243            .into_iter()
4244            .map(|worktree| CandidateSet {
4245                snapshot: worktree.read(cx).snapshot(),
4246                include_ignored,
4247                include_root_name,
4248            })
4249            .collect::<Vec<_>>();
4250
4251        let background = cx.background().clone();
4252        async move {
4253            fuzzy::match_paths(
4254                candidate_sets.as_slice(),
4255                query,
4256                smart_case,
4257                max_results,
4258                cancel_flag,
4259                background,
4260            )
4261            .await
4262        }
4263    }
4264
4265    fn edits_from_lsp(
4266        &mut self,
4267        buffer: &ModelHandle<Buffer>,
4268        lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
4269        version: Option<i32>,
4270        cx: &mut ModelContext<Self>,
4271    ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
4272        let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
4273        cx.background().spawn(async move {
4274            let snapshot = snapshot?;
4275            let mut lsp_edits = lsp_edits
4276                .into_iter()
4277                .map(|edit| (range_from_lsp(edit.range), edit.new_text))
4278                .peekable();
4279
4280            let mut edits = Vec::new();
4281            while let Some((mut range, mut new_text)) = lsp_edits.next() {
4282                // Combine any LSP edits that are adjacent.
4283                //
4284                // Also, combine LSP edits that are separated from each other by only
4285                // a newline. This is important because for some code actions,
4286                // Rust-analyzer rewrites the entire buffer via a series of edits that
4287                // are separated by unchanged newline characters.
4288                //
4289                // In order for the diffing logic below to work properly, any edits that
4290                // cancel each other out must be combined into one.
4291                while let Some((next_range, next_text)) = lsp_edits.peek() {
4292                    if next_range.start > range.end {
4293                        if next_range.start.row > range.end.row + 1
4294                            || next_range.start.column > 0
4295                            || snapshot.clip_point_utf16(
4296                                PointUtf16::new(range.end.row, u32::MAX),
4297                                Bias::Left,
4298                            ) > range.end
4299                        {
4300                            break;
4301                        }
4302                        new_text.push('\n');
4303                    }
4304                    range.end = next_range.end;
4305                    new_text.push_str(&next_text);
4306                    lsp_edits.next();
4307                }
4308
4309                if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
4310                    || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
4311                {
4312                    return Err(anyhow!("invalid edits received from language server"));
4313                }
4314
4315                // For multiline edits, perform a diff of the old and new text so that
4316                // we can identify the changes more precisely, preserving the locations
4317                // of any anchors positioned in the unchanged regions.
4318                if range.end.row > range.start.row {
4319                    let mut offset = range.start.to_offset(&snapshot);
4320                    let old_text = snapshot.text_for_range(range).collect::<String>();
4321
4322                    let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
4323                    let mut moved_since_edit = true;
4324                    for change in diff.iter_all_changes() {
4325                        let tag = change.tag();
4326                        let value = change.value();
4327                        match tag {
4328                            ChangeTag::Equal => {
4329                                offset += value.len();
4330                                moved_since_edit = true;
4331                            }
4332                            ChangeTag::Delete => {
4333                                let start = snapshot.anchor_after(offset);
4334                                let end = snapshot.anchor_before(offset + value.len());
4335                                if moved_since_edit {
4336                                    edits.push((start..end, String::new()));
4337                                } else {
4338                                    edits.last_mut().unwrap().0.end = end;
4339                                }
4340                                offset += value.len();
4341                                moved_since_edit = false;
4342                            }
4343                            ChangeTag::Insert => {
4344                                if moved_since_edit {
4345                                    let anchor = snapshot.anchor_after(offset);
4346                                    edits.push((anchor.clone()..anchor, value.to_string()));
4347                                } else {
4348                                    edits.last_mut().unwrap().1.push_str(value);
4349                                }
4350                                moved_since_edit = false;
4351                            }
4352                        }
4353                    }
4354                } else if range.end == range.start {
4355                    let anchor = snapshot.anchor_after(range.start);
4356                    edits.push((anchor.clone()..anchor, new_text));
4357                } else {
4358                    let edit_start = snapshot.anchor_after(range.start);
4359                    let edit_end = snapshot.anchor_before(range.end);
4360                    edits.push((edit_start..edit_end, new_text));
4361                }
4362            }
4363
4364            Ok(edits)
4365        })
4366    }
4367
4368    fn buffer_snapshot_for_lsp_version(
4369        &mut self,
4370        buffer: &ModelHandle<Buffer>,
4371        version: Option<i32>,
4372        cx: &AppContext,
4373    ) -> Result<TextBufferSnapshot> {
4374        const OLD_VERSIONS_TO_RETAIN: i32 = 10;
4375
4376        if let Some(version) = version {
4377            let buffer_id = buffer.read(cx).remote_id();
4378            let snapshots = self
4379                .buffer_snapshots
4380                .get_mut(&buffer_id)
4381                .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
4382            let mut found_snapshot = None;
4383            snapshots.retain(|(snapshot_version, snapshot)| {
4384                if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
4385                    false
4386                } else {
4387                    if *snapshot_version == version {
4388                        found_snapshot = Some(snapshot.clone());
4389                    }
4390                    true
4391                }
4392            });
4393
4394            found_snapshot.ok_or_else(|| {
4395                anyhow!(
4396                    "snapshot not found for buffer {} at version {}",
4397                    buffer_id,
4398                    version
4399                )
4400            })
4401        } else {
4402            Ok((buffer.read(cx)).text_snapshot())
4403        }
4404    }
4405
4406    fn language_server_for_buffer(
4407        &self,
4408        buffer: &Buffer,
4409        cx: &AppContext,
4410    ) -> Option<&Arc<LanguageServer>> {
4411        if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
4412            let worktree_id = file.worktree_id(cx);
4413            self.language_servers.get(&(worktree_id, language.name()))
4414        } else {
4415            None
4416        }
4417    }
4418}
4419
4420impl WorktreeHandle {
4421    pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
4422        match self {
4423            WorktreeHandle::Strong(handle) => Some(handle.clone()),
4424            WorktreeHandle::Weak(handle) => handle.upgrade(cx),
4425        }
4426    }
4427}
4428
4429impl OpenBuffer {
4430    pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
4431        match self {
4432            OpenBuffer::Strong(handle) => Some(handle.clone()),
4433            OpenBuffer::Weak(handle) => handle.upgrade(cx),
4434            OpenBuffer::Loading(_) => None,
4435        }
4436    }
4437}
4438
4439struct CandidateSet {
4440    snapshot: Snapshot,
4441    include_ignored: bool,
4442    include_root_name: bool,
4443}
4444
4445impl<'a> PathMatchCandidateSet<'a> for CandidateSet {
4446    type Candidates = CandidateSetIter<'a>;
4447
4448    fn id(&self) -> usize {
4449        self.snapshot.id().to_usize()
4450    }
4451
4452    fn len(&self) -> usize {
4453        if self.include_ignored {
4454            self.snapshot.file_count()
4455        } else {
4456            self.snapshot.visible_file_count()
4457        }
4458    }
4459
4460    fn prefix(&self) -> Arc<str> {
4461        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
4462            self.snapshot.root_name().into()
4463        } else if self.include_root_name {
4464            format!("{}/", self.snapshot.root_name()).into()
4465        } else {
4466            "".into()
4467        }
4468    }
4469
4470    fn candidates(&'a self, start: usize) -> Self::Candidates {
4471        CandidateSetIter {
4472            traversal: self.snapshot.files(self.include_ignored, start),
4473        }
4474    }
4475}
4476
4477struct CandidateSetIter<'a> {
4478    traversal: Traversal<'a>,
4479}
4480
4481impl<'a> Iterator for CandidateSetIter<'a> {
4482    type Item = PathMatchCandidate<'a>;
4483
4484    fn next(&mut self) -> Option<Self::Item> {
4485        self.traversal.next().map(|entry| {
4486            if let EntryKind::File(char_bag) = entry.kind {
4487                PathMatchCandidate {
4488                    path: &entry.path,
4489                    char_bag,
4490                }
4491            } else {
4492                unreachable!()
4493            }
4494        })
4495    }
4496}
4497
4498impl Entity for Project {
4499    type Event = Event;
4500
4501    fn release(&mut self, _: &mut gpui::MutableAppContext) {
4502        match &self.client_state {
4503            ProjectClientState::Local { remote_id_rx, .. } => {
4504                if let Some(project_id) = *remote_id_rx.borrow() {
4505                    self.client
4506                        .send(proto::UnregisterProject { project_id })
4507                        .log_err();
4508                }
4509            }
4510            ProjectClientState::Remote { remote_id, .. } => {
4511                self.client
4512                    .send(proto::LeaveProject {
4513                        project_id: *remote_id,
4514                    })
4515                    .log_err();
4516            }
4517        }
4518    }
4519
4520    fn app_will_quit(
4521        &mut self,
4522        _: &mut MutableAppContext,
4523    ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
4524        let shutdown_futures = self
4525            .language_servers
4526            .drain()
4527            .filter_map(|(_, server)| server.shutdown())
4528            .collect::<Vec<_>>();
4529        Some(
4530            async move {
4531                futures::future::join_all(shutdown_futures).await;
4532            }
4533            .boxed(),
4534        )
4535    }
4536}
4537
4538impl Collaborator {
4539    fn from_proto(
4540        message: proto::Collaborator,
4541        user_store: &ModelHandle<UserStore>,
4542        cx: &mut AsyncAppContext,
4543    ) -> impl Future<Output = Result<Self>> {
4544        let user = user_store.update(cx, |user_store, cx| {
4545            user_store.fetch_user(message.user_id, cx)
4546        });
4547
4548        async move {
4549            Ok(Self {
4550                peer_id: PeerId(message.peer_id),
4551                user: user.await?,
4552                replica_id: message.replica_id as ReplicaId,
4553            })
4554        }
4555    }
4556}
4557
4558impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
4559    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
4560        Self {
4561            worktree_id,
4562            path: path.as_ref().into(),
4563        }
4564    }
4565}
4566
4567impl From<lsp::CreateFileOptions> for fs::CreateOptions {
4568    fn from(options: lsp::CreateFileOptions) -> Self {
4569        Self {
4570            overwrite: options.overwrite.unwrap_or(false),
4571            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
4572        }
4573    }
4574}
4575
4576impl From<lsp::RenameFileOptions> for fs::RenameOptions {
4577    fn from(options: lsp::RenameFileOptions) -> Self {
4578        Self {
4579            overwrite: options.overwrite.unwrap_or(false),
4580            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
4581        }
4582    }
4583}
4584
4585impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
4586    fn from(options: lsp::DeleteFileOptions) -> Self {
4587        Self {
4588            recursive: options.recursive.unwrap_or(false),
4589            ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
4590        }
4591    }
4592}
4593
4594fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
4595    proto::Symbol {
4596        source_worktree_id: symbol.source_worktree_id.to_proto(),
4597        worktree_id: symbol.worktree_id.to_proto(),
4598        language_name: symbol.language_name.clone(),
4599        name: symbol.name.clone(),
4600        kind: unsafe { mem::transmute(symbol.kind) },
4601        path: symbol.path.to_string_lossy().to_string(),
4602        start: Some(proto::Point {
4603            row: symbol.range.start.row,
4604            column: symbol.range.start.column,
4605        }),
4606        end: Some(proto::Point {
4607            row: symbol.range.end.row,
4608            column: symbol.range.end.column,
4609        }),
4610        signature: symbol.signature.to_vec(),
4611    }
4612}
4613
4614fn relativize_path(base: &Path, path: &Path) -> PathBuf {
4615    let mut path_components = path.components();
4616    let mut base_components = base.components();
4617    let mut components: Vec<Component> = Vec::new();
4618    loop {
4619        match (path_components.next(), base_components.next()) {
4620            (None, None) => break,
4621            (Some(a), None) => {
4622                components.push(a);
4623                components.extend(path_components.by_ref());
4624                break;
4625            }
4626            (None, _) => components.push(Component::ParentDir),
4627            (Some(a), Some(b)) if components.is_empty() && a == b => (),
4628            (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
4629            (Some(a), Some(_)) => {
4630                components.push(Component::ParentDir);
4631                for _ in base_components {
4632                    components.push(Component::ParentDir);
4633                }
4634                components.push(a);
4635                components.extend(path_components.by_ref());
4636                break;
4637            }
4638        }
4639    }
4640    components.iter().map(|c| c.as_os_str()).collect()
4641}
4642
4643impl Item for Buffer {
4644    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
4645        File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
4646    }
4647}
4648
4649#[cfg(test)]
4650mod tests {
4651    use super::{Event, *};
4652    use fs::RealFs;
4653    use futures::StreamExt;
4654    use gpui::test::subscribe;
4655    use language::{
4656        tree_sitter_rust, Diagnostic, LanguageConfig, LanguageServerConfig, OffsetRangeExt, Point,
4657        ToPoint,
4658    };
4659    use lsp::Url;
4660    use serde_json::json;
4661    use std::{cell::RefCell, os::unix, path::PathBuf, rc::Rc};
4662    use unindent::Unindent as _;
4663    use util::test::temp_tree;
4664    use worktree::WorktreeHandle as _;
4665
4666    #[gpui::test]
4667    async fn test_populate_and_search(cx: &mut gpui::TestAppContext) {
4668        let dir = temp_tree(json!({
4669            "root": {
4670                "apple": "",
4671                "banana": {
4672                    "carrot": {
4673                        "date": "",
4674                        "endive": "",
4675                    }
4676                },
4677                "fennel": {
4678                    "grape": "",
4679                }
4680            }
4681        }));
4682
4683        let root_link_path = dir.path().join("root_link");
4684        unix::fs::symlink(&dir.path().join("root"), &root_link_path).unwrap();
4685        unix::fs::symlink(
4686            &dir.path().join("root/fennel"),
4687            &dir.path().join("root/finnochio"),
4688        )
4689        .unwrap();
4690
4691        let project = Project::test(Arc::new(RealFs), cx);
4692
4693        let (tree, _) = project
4694            .update(cx, |project, cx| {
4695                project.find_or_create_local_worktree(&root_link_path, true, cx)
4696            })
4697            .await
4698            .unwrap();
4699
4700        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
4701            .await;
4702        cx.read(|cx| {
4703            let tree = tree.read(cx);
4704            assert_eq!(tree.file_count(), 5);
4705            assert_eq!(
4706                tree.inode_for_path("fennel/grape"),
4707                tree.inode_for_path("finnochio/grape")
4708            );
4709        });
4710
4711        let cancel_flag = Default::default();
4712        let results = project
4713            .read_with(cx, |project, cx| {
4714                project.match_paths("bna", false, false, 10, &cancel_flag, cx)
4715            })
4716            .await;
4717        assert_eq!(
4718            results
4719                .into_iter()
4720                .map(|result| result.path)
4721                .collect::<Vec<Arc<Path>>>(),
4722            vec![
4723                PathBuf::from("banana/carrot/date").into(),
4724                PathBuf::from("banana/carrot/endive").into(),
4725            ]
4726        );
4727    }
4728
4729    #[gpui::test]
4730    async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
4731        cx.foreground().forbid_parking();
4732
4733        let (mut rust_lsp_config, mut fake_rust_servers) = LanguageServerConfig::fake();
4734        let (mut json_lsp_config, mut fake_json_servers) = LanguageServerConfig::fake();
4735        rust_lsp_config.set_fake_capabilities(lsp::ServerCapabilities {
4736            completion_provider: Some(lsp::CompletionOptions {
4737                trigger_characters: Some(vec![".".to_string(), "::".to_string()]),
4738                ..Default::default()
4739            }),
4740            ..Default::default()
4741        });
4742        json_lsp_config.set_fake_capabilities(lsp::ServerCapabilities {
4743            completion_provider: Some(lsp::CompletionOptions {
4744                trigger_characters: Some(vec![":".to_string()]),
4745                ..Default::default()
4746            }),
4747            ..Default::default()
4748        });
4749
4750        let rust_language = Arc::new(Language::new(
4751            LanguageConfig {
4752                name: "Rust".into(),
4753                path_suffixes: vec!["rs".to_string()],
4754                language_server: Some(rust_lsp_config),
4755                ..Default::default()
4756            },
4757            Some(tree_sitter_rust::language()),
4758        ));
4759        let json_language = Arc::new(Language::new(
4760            LanguageConfig {
4761                name: "JSON".into(),
4762                path_suffixes: vec!["json".to_string()],
4763                language_server: Some(json_lsp_config),
4764                ..Default::default()
4765            },
4766            None,
4767        ));
4768
4769        let fs = FakeFs::new(cx.background());
4770        fs.insert_tree(
4771            "/the-root",
4772            json!({
4773                "test.rs": "const A: i32 = 1;",
4774                "test2.rs": "",
4775                "Cargo.toml": "a = 1",
4776                "package.json": "{\"a\": 1}",
4777            }),
4778        )
4779        .await;
4780
4781        let project = Project::test(fs, cx);
4782        project.update(cx, |project, _| {
4783            project.languages.add(rust_language);
4784            project.languages.add(json_language);
4785        });
4786
4787        let worktree_id = project
4788            .update(cx, |project, cx| {
4789                project.find_or_create_local_worktree("/the-root", true, cx)
4790            })
4791            .await
4792            .unwrap()
4793            .0
4794            .read_with(cx, |tree, _| tree.id());
4795
4796        // Open a buffer without an associated language server.
4797        let toml_buffer = project
4798            .update(cx, |project, cx| {
4799                project.open_buffer((worktree_id, "Cargo.toml"), cx)
4800            })
4801            .await
4802            .unwrap();
4803
4804        // Open a buffer with an associated language server.
4805        let rust_buffer = project
4806            .update(cx, |project, cx| {
4807                project.open_buffer((worktree_id, "test.rs"), cx)
4808            })
4809            .await
4810            .unwrap();
4811
4812        // A server is started up, and it is notified about Rust files.
4813        let mut fake_rust_server = fake_rust_servers.next().await.unwrap();
4814        assert_eq!(
4815            fake_rust_server
4816                .receive_notification::<lsp::notification::DidOpenTextDocument>()
4817                .await
4818                .text_document,
4819            lsp::TextDocumentItem {
4820                uri: lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
4821                version: 0,
4822                text: "const A: i32 = 1;".to_string(),
4823                language_id: Default::default()
4824            }
4825        );
4826
4827        // The buffer is configured based on the language server's capabilities.
4828        rust_buffer.read_with(cx, |buffer, _| {
4829            assert_eq!(
4830                buffer.completion_triggers(),
4831                &[".".to_string(), "::".to_string()]
4832            );
4833        });
4834        toml_buffer.read_with(cx, |buffer, _| {
4835            assert!(buffer.completion_triggers().is_empty());
4836        });
4837
4838        // Edit a buffer. The changes are reported to the language server.
4839        rust_buffer.update(cx, |buffer, cx| buffer.edit([16..16], "2", cx));
4840        assert_eq!(
4841            fake_rust_server
4842                .receive_notification::<lsp::notification::DidChangeTextDocument>()
4843                .await
4844                .text_document,
4845            lsp::VersionedTextDocumentIdentifier::new(
4846                lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
4847                1
4848            )
4849        );
4850
4851        // Open a third buffer with a different associated language server.
4852        let json_buffer = project
4853            .update(cx, |project, cx| {
4854                project.open_buffer((worktree_id, "package.json"), cx)
4855            })
4856            .await
4857            .unwrap();
4858
4859        // Another language server is started up, and it is notified about
4860        // all three open buffers.
4861        let mut fake_json_server = fake_json_servers.next().await.unwrap();
4862        assert_eq!(
4863            fake_json_server
4864                .receive_notification::<lsp::notification::DidOpenTextDocument>()
4865                .await
4866                .text_document,
4867            lsp::TextDocumentItem {
4868                uri: lsp::Url::from_file_path("/the-root/package.json").unwrap(),
4869                version: 0,
4870                text: "{\"a\": 1}".to_string(),
4871                language_id: Default::default()
4872            }
4873        );
4874
4875        // This buffer is configured based on the second language server's
4876        // capabilities.
4877        json_buffer.read_with(cx, |buffer, _| {
4878            assert_eq!(buffer.completion_triggers(), &[":".to_string()]);
4879        });
4880
4881        // When opening another buffer whose language server is already running,
4882        // it is also configured based on the existing language server's capabilities.
4883        let rust_buffer2 = project
4884            .update(cx, |project, cx| {
4885                project.open_buffer((worktree_id, "test2.rs"), cx)
4886            })
4887            .await
4888            .unwrap();
4889        rust_buffer2.read_with(cx, |buffer, _| {
4890            assert_eq!(
4891                buffer.completion_triggers(),
4892                &[".".to_string(), "::".to_string()]
4893            );
4894        });
4895
4896        // Changes are reported only to servers matching the buffer's language.
4897        toml_buffer.update(cx, |buffer, cx| buffer.edit([5..5], "23", cx));
4898        rust_buffer2.update(cx, |buffer, cx| buffer.edit([0..0], "let x = 1;", cx));
4899        assert_eq!(
4900            fake_rust_server
4901                .receive_notification::<lsp::notification::DidChangeTextDocument>()
4902                .await
4903                .text_document,
4904            lsp::VersionedTextDocumentIdentifier::new(
4905                lsp::Url::from_file_path("/the-root/test2.rs").unwrap(),
4906                1
4907            )
4908        );
4909
4910        // Save notifications are reported to all servers.
4911        toml_buffer
4912            .update(cx, |buffer, cx| buffer.save(cx))
4913            .await
4914            .unwrap();
4915        assert_eq!(
4916            fake_rust_server
4917                .receive_notification::<lsp::notification::DidSaveTextDocument>()
4918                .await
4919                .text_document,
4920            lsp::TextDocumentIdentifier::new(
4921                lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
4922            )
4923        );
4924        assert_eq!(
4925            fake_json_server
4926                .receive_notification::<lsp::notification::DidSaveTextDocument>()
4927                .await
4928                .text_document,
4929            lsp::TextDocumentIdentifier::new(
4930                lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
4931            )
4932        );
4933
4934        // Close notifications are reported only to servers matching the buffer's language.
4935        cx.update(|_| drop(json_buffer));
4936        let close_message = lsp::DidCloseTextDocumentParams {
4937            text_document: lsp::TextDocumentIdentifier::new(
4938                lsp::Url::from_file_path("/the-root/package.json").unwrap(),
4939            ),
4940        };
4941        assert_eq!(
4942            fake_json_server
4943                .receive_notification::<lsp::notification::DidCloseTextDocument>()
4944                .await,
4945            close_message,
4946        );
4947    }
4948
4949    #[gpui::test]
4950    async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
4951        cx.foreground().forbid_parking();
4952
4953        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
4954        let progress_token = language_server_config
4955            .disk_based_diagnostics_progress_token
4956            .clone()
4957            .unwrap();
4958
4959        let language = Arc::new(Language::new(
4960            LanguageConfig {
4961                name: "Rust".into(),
4962                path_suffixes: vec!["rs".to_string()],
4963                language_server: Some(language_server_config),
4964                ..Default::default()
4965            },
4966            Some(tree_sitter_rust::language()),
4967        ));
4968
4969        let fs = FakeFs::new(cx.background());
4970        fs.insert_tree(
4971            "/dir",
4972            json!({
4973                "a.rs": "fn a() { A }",
4974                "b.rs": "const y: i32 = 1",
4975            }),
4976        )
4977        .await;
4978
4979        let project = Project::test(fs, cx);
4980        project.update(cx, |project, _| project.languages.add(language));
4981
4982        let (tree, _) = project
4983            .update(cx, |project, cx| {
4984                project.find_or_create_local_worktree("/dir", true, cx)
4985            })
4986            .await
4987            .unwrap();
4988        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
4989
4990        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
4991            .await;
4992
4993        // Cause worktree to start the fake language server
4994        let _buffer = project
4995            .update(cx, |project, cx| {
4996                project.open_buffer((worktree_id, Path::new("b.rs")), cx)
4997            })
4998            .await
4999            .unwrap();
5000
5001        let mut events = subscribe(&project, cx);
5002
5003        let mut fake_server = fake_servers.next().await.unwrap();
5004        fake_server.start_progress(&progress_token).await;
5005        assert_eq!(
5006            events.next().await.unwrap(),
5007            Event::DiskBasedDiagnosticsStarted
5008        );
5009
5010        fake_server.start_progress(&progress_token).await;
5011        fake_server.end_progress(&progress_token).await;
5012        fake_server.start_progress(&progress_token).await;
5013
5014        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5015            lsp::PublishDiagnosticsParams {
5016                uri: Url::from_file_path("/dir/a.rs").unwrap(),
5017                version: None,
5018                diagnostics: vec![lsp::Diagnostic {
5019                    range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5020                    severity: Some(lsp::DiagnosticSeverity::ERROR),
5021                    message: "undefined variable 'A'".to_string(),
5022                    ..Default::default()
5023                }],
5024            },
5025        );
5026        assert_eq!(
5027            events.next().await.unwrap(),
5028            Event::DiagnosticsUpdated((worktree_id, Path::new("a.rs")).into())
5029        );
5030
5031        fake_server.end_progress(&progress_token).await;
5032        fake_server.end_progress(&progress_token).await;
5033        assert_eq!(
5034            events.next().await.unwrap(),
5035            Event::DiskBasedDiagnosticsUpdated
5036        );
5037        assert_eq!(
5038            events.next().await.unwrap(),
5039            Event::DiskBasedDiagnosticsFinished
5040        );
5041
5042        let buffer = project
5043            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
5044            .await
5045            .unwrap();
5046
5047        buffer.read_with(cx, |buffer, _| {
5048            let snapshot = buffer.snapshot();
5049            let diagnostics = snapshot
5050                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
5051                .collect::<Vec<_>>();
5052            assert_eq!(
5053                diagnostics,
5054                &[DiagnosticEntry {
5055                    range: Point::new(0, 9)..Point::new(0, 10),
5056                    diagnostic: Diagnostic {
5057                        severity: lsp::DiagnosticSeverity::ERROR,
5058                        message: "undefined variable 'A'".to_string(),
5059                        group_id: 0,
5060                        is_primary: true,
5061                        ..Default::default()
5062                    }
5063                }]
5064            )
5065        });
5066    }
5067
5068    #[gpui::test]
5069    async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
5070        cx.foreground().forbid_parking();
5071
5072        let (mut lsp_config, mut fake_servers) = LanguageServerConfig::fake();
5073        lsp_config
5074            .disk_based_diagnostic_sources
5075            .insert("disk".to_string());
5076        let language = Arc::new(Language::new(
5077            LanguageConfig {
5078                name: "Rust".into(),
5079                path_suffixes: vec!["rs".to_string()],
5080                language_server: Some(lsp_config),
5081                ..Default::default()
5082            },
5083            Some(tree_sitter_rust::language()),
5084        ));
5085
5086        let text = "
5087            fn a() { A }
5088            fn b() { BB }
5089            fn c() { CCC }
5090        "
5091        .unindent();
5092
5093        let fs = FakeFs::new(cx.background());
5094        fs.insert_tree("/dir", json!({ "a.rs": text })).await;
5095
5096        let project = Project::test(fs, cx);
5097        project.update(cx, |project, _| project.languages.add(language));
5098
5099        let worktree_id = project
5100            .update(cx, |project, cx| {
5101                project.find_or_create_local_worktree("/dir", true, cx)
5102            })
5103            .await
5104            .unwrap()
5105            .0
5106            .read_with(cx, |tree, _| tree.id());
5107
5108        let buffer = project
5109            .update(cx, |project, cx| {
5110                project.open_buffer((worktree_id, "a.rs"), cx)
5111            })
5112            .await
5113            .unwrap();
5114
5115        let mut fake_server = fake_servers.next().await.unwrap();
5116        let open_notification = fake_server
5117            .receive_notification::<lsp::notification::DidOpenTextDocument>()
5118            .await;
5119
5120        // Edit the buffer, moving the content down
5121        buffer.update(cx, |buffer, cx| buffer.edit([0..0], "\n\n", cx));
5122        let change_notification_1 = fake_server
5123            .receive_notification::<lsp::notification::DidChangeTextDocument>()
5124            .await;
5125        assert!(
5126            change_notification_1.text_document.version > open_notification.text_document.version
5127        );
5128
5129        // Report some diagnostics for the initial version of the buffer
5130        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5131            lsp::PublishDiagnosticsParams {
5132                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5133                version: Some(open_notification.text_document.version),
5134                diagnostics: vec![
5135                    lsp::Diagnostic {
5136                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5137                        severity: Some(DiagnosticSeverity::ERROR),
5138                        message: "undefined variable 'A'".to_string(),
5139                        source: Some("disk".to_string()),
5140                        ..Default::default()
5141                    },
5142                    lsp::Diagnostic {
5143                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
5144                        severity: Some(DiagnosticSeverity::ERROR),
5145                        message: "undefined variable 'BB'".to_string(),
5146                        source: Some("disk".to_string()),
5147                        ..Default::default()
5148                    },
5149                    lsp::Diagnostic {
5150                        range: lsp::Range::new(lsp::Position::new(2, 9), lsp::Position::new(2, 12)),
5151                        severity: Some(DiagnosticSeverity::ERROR),
5152                        source: Some("disk".to_string()),
5153                        message: "undefined variable 'CCC'".to_string(),
5154                        ..Default::default()
5155                    },
5156                ],
5157            },
5158        );
5159
5160        // The diagnostics have moved down since they were created.
5161        buffer.next_notification(cx).await;
5162        buffer.read_with(cx, |buffer, _| {
5163            assert_eq!(
5164                buffer
5165                    .snapshot()
5166                    .diagnostics_in_range::<_, Point>(Point::new(3, 0)..Point::new(5, 0), false)
5167                    .collect::<Vec<_>>(),
5168                &[
5169                    DiagnosticEntry {
5170                        range: Point::new(3, 9)..Point::new(3, 11),
5171                        diagnostic: Diagnostic {
5172                            severity: DiagnosticSeverity::ERROR,
5173                            message: "undefined variable 'BB'".to_string(),
5174                            is_disk_based: true,
5175                            group_id: 1,
5176                            is_primary: true,
5177                            ..Default::default()
5178                        },
5179                    },
5180                    DiagnosticEntry {
5181                        range: Point::new(4, 9)..Point::new(4, 12),
5182                        diagnostic: Diagnostic {
5183                            severity: DiagnosticSeverity::ERROR,
5184                            message: "undefined variable 'CCC'".to_string(),
5185                            is_disk_based: true,
5186                            group_id: 2,
5187                            is_primary: true,
5188                            ..Default::default()
5189                        }
5190                    }
5191                ]
5192            );
5193            assert_eq!(
5194                chunks_with_diagnostics(buffer, 0..buffer.len()),
5195                [
5196                    ("\n\nfn a() { ".to_string(), None),
5197                    ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
5198                    (" }\nfn b() { ".to_string(), None),
5199                    ("BB".to_string(), Some(DiagnosticSeverity::ERROR)),
5200                    (" }\nfn c() { ".to_string(), None),
5201                    ("CCC".to_string(), Some(DiagnosticSeverity::ERROR)),
5202                    (" }\n".to_string(), None),
5203                ]
5204            );
5205            assert_eq!(
5206                chunks_with_diagnostics(buffer, Point::new(3, 10)..Point::new(4, 11)),
5207                [
5208                    ("B".to_string(), Some(DiagnosticSeverity::ERROR)),
5209                    (" }\nfn c() { ".to_string(), None),
5210                    ("CC".to_string(), Some(DiagnosticSeverity::ERROR)),
5211                ]
5212            );
5213        });
5214
5215        // Ensure overlapping diagnostics are highlighted correctly.
5216        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5217            lsp::PublishDiagnosticsParams {
5218                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5219                version: Some(open_notification.text_document.version),
5220                diagnostics: vec![
5221                    lsp::Diagnostic {
5222                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5223                        severity: Some(DiagnosticSeverity::ERROR),
5224                        message: "undefined variable 'A'".to_string(),
5225                        source: Some("disk".to_string()),
5226                        ..Default::default()
5227                    },
5228                    lsp::Diagnostic {
5229                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 12)),
5230                        severity: Some(DiagnosticSeverity::WARNING),
5231                        message: "unreachable statement".to_string(),
5232                        source: Some("disk".to_string()),
5233                        ..Default::default()
5234                    },
5235                ],
5236            },
5237        );
5238
5239        buffer.next_notification(cx).await;
5240        buffer.read_with(cx, |buffer, _| {
5241            assert_eq!(
5242                buffer
5243                    .snapshot()
5244                    .diagnostics_in_range::<_, Point>(Point::new(2, 0)..Point::new(3, 0), false)
5245                    .collect::<Vec<_>>(),
5246                &[
5247                    DiagnosticEntry {
5248                        range: Point::new(2, 9)..Point::new(2, 12),
5249                        diagnostic: Diagnostic {
5250                            severity: DiagnosticSeverity::WARNING,
5251                            message: "unreachable statement".to_string(),
5252                            is_disk_based: true,
5253                            group_id: 1,
5254                            is_primary: true,
5255                            ..Default::default()
5256                        }
5257                    },
5258                    DiagnosticEntry {
5259                        range: Point::new(2, 9)..Point::new(2, 10),
5260                        diagnostic: Diagnostic {
5261                            severity: DiagnosticSeverity::ERROR,
5262                            message: "undefined variable 'A'".to_string(),
5263                            is_disk_based: true,
5264                            group_id: 0,
5265                            is_primary: true,
5266                            ..Default::default()
5267                        },
5268                    }
5269                ]
5270            );
5271            assert_eq!(
5272                chunks_with_diagnostics(buffer, Point::new(2, 0)..Point::new(3, 0)),
5273                [
5274                    ("fn a() { ".to_string(), None),
5275                    ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
5276                    (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
5277                    ("\n".to_string(), None),
5278                ]
5279            );
5280            assert_eq!(
5281                chunks_with_diagnostics(buffer, Point::new(2, 10)..Point::new(3, 0)),
5282                [
5283                    (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
5284                    ("\n".to_string(), None),
5285                ]
5286            );
5287        });
5288
5289        // Keep editing the buffer and ensure disk-based diagnostics get translated according to the
5290        // changes since the last save.
5291        buffer.update(cx, |buffer, cx| {
5292            buffer.edit(Some(Point::new(2, 0)..Point::new(2, 0)), "    ", cx);
5293            buffer.edit(Some(Point::new(2, 8)..Point::new(2, 10)), "(x: usize)", cx);
5294            buffer.edit(Some(Point::new(3, 10)..Point::new(3, 10)), "xxx", cx);
5295        });
5296        let change_notification_2 = fake_server
5297            .receive_notification::<lsp::notification::DidChangeTextDocument>()
5298            .await;
5299        assert!(
5300            change_notification_2.text_document.version
5301                > change_notification_1.text_document.version
5302        );
5303
5304        // Handle out-of-order diagnostics
5305        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5306            lsp::PublishDiagnosticsParams {
5307                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5308                version: Some(change_notification_2.text_document.version),
5309                diagnostics: vec![
5310                    lsp::Diagnostic {
5311                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
5312                        severity: Some(DiagnosticSeverity::ERROR),
5313                        message: "undefined variable 'BB'".to_string(),
5314                        source: Some("disk".to_string()),
5315                        ..Default::default()
5316                    },
5317                    lsp::Diagnostic {
5318                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5319                        severity: Some(DiagnosticSeverity::WARNING),
5320                        message: "undefined variable 'A'".to_string(),
5321                        source: Some("disk".to_string()),
5322                        ..Default::default()
5323                    },
5324                ],
5325            },
5326        );
5327
5328        buffer.next_notification(cx).await;
5329        buffer.read_with(cx, |buffer, _| {
5330            assert_eq!(
5331                buffer
5332                    .snapshot()
5333                    .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
5334                    .collect::<Vec<_>>(),
5335                &[
5336                    DiagnosticEntry {
5337                        range: Point::new(2, 21)..Point::new(2, 22),
5338                        diagnostic: Diagnostic {
5339                            severity: DiagnosticSeverity::WARNING,
5340                            message: "undefined variable 'A'".to_string(),
5341                            is_disk_based: true,
5342                            group_id: 1,
5343                            is_primary: true,
5344                            ..Default::default()
5345                        }
5346                    },
5347                    DiagnosticEntry {
5348                        range: Point::new(3, 9)..Point::new(3, 14),
5349                        diagnostic: Diagnostic {
5350                            severity: DiagnosticSeverity::ERROR,
5351                            message: "undefined variable 'BB'".to_string(),
5352                            is_disk_based: true,
5353                            group_id: 0,
5354                            is_primary: true,
5355                            ..Default::default()
5356                        },
5357                    }
5358                ]
5359            );
5360        });
5361    }
5362
5363    #[gpui::test]
5364    async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
5365        cx.foreground().forbid_parking();
5366
5367        let text = concat!(
5368            "let one = ;\n", //
5369            "let two = \n",
5370            "let three = 3;\n",
5371        );
5372
5373        let fs = FakeFs::new(cx.background());
5374        fs.insert_tree("/dir", json!({ "a.rs": text })).await;
5375
5376        let project = Project::test(fs, cx);
5377        let worktree_id = project
5378            .update(cx, |project, cx| {
5379                project.find_or_create_local_worktree("/dir", true, cx)
5380            })
5381            .await
5382            .unwrap()
5383            .0
5384            .read_with(cx, |tree, _| tree.id());
5385
5386        let buffer = project
5387            .update(cx, |project, cx| {
5388                project.open_buffer((worktree_id, "a.rs"), cx)
5389            })
5390            .await
5391            .unwrap();
5392
5393        project.update(cx, |project, cx| {
5394            project
5395                .update_buffer_diagnostics(
5396                    &buffer,
5397                    vec![
5398                        DiagnosticEntry {
5399                            range: PointUtf16::new(0, 10)..PointUtf16::new(0, 10),
5400                            diagnostic: Diagnostic {
5401                                severity: DiagnosticSeverity::ERROR,
5402                                message: "syntax error 1".to_string(),
5403                                ..Default::default()
5404                            },
5405                        },
5406                        DiagnosticEntry {
5407                            range: PointUtf16::new(1, 10)..PointUtf16::new(1, 10),
5408                            diagnostic: Diagnostic {
5409                                severity: DiagnosticSeverity::ERROR,
5410                                message: "syntax error 2".to_string(),
5411                                ..Default::default()
5412                            },
5413                        },
5414                    ],
5415                    None,
5416                    cx,
5417                )
5418                .unwrap();
5419        });
5420
5421        // An empty range is extended forward to include the following character.
5422        // At the end of a line, an empty range is extended backward to include
5423        // the preceding character.
5424        buffer.read_with(cx, |buffer, _| {
5425            let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len());
5426            assert_eq!(
5427                chunks
5428                    .iter()
5429                    .map(|(s, d)| (s.as_str(), *d))
5430                    .collect::<Vec<_>>(),
5431                &[
5432                    ("let one = ", None),
5433                    (";", Some(DiagnosticSeverity::ERROR)),
5434                    ("\nlet two =", None),
5435                    (" ", Some(DiagnosticSeverity::ERROR)),
5436                    ("\nlet three = 3;\n", None)
5437                ]
5438            );
5439        });
5440    }
5441
5442    #[gpui::test]
5443    async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
5444        cx.foreground().forbid_parking();
5445
5446        let (lsp_config, mut fake_servers) = LanguageServerConfig::fake();
5447        let language = Arc::new(Language::new(
5448            LanguageConfig {
5449                name: "Rust".into(),
5450                path_suffixes: vec!["rs".to_string()],
5451                language_server: Some(lsp_config),
5452                ..Default::default()
5453            },
5454            Some(tree_sitter_rust::language()),
5455        ));
5456
5457        let text = "
5458            fn a() {
5459                f1();
5460            }
5461            fn b() {
5462                f2();
5463            }
5464            fn c() {
5465                f3();
5466            }
5467        "
5468        .unindent();
5469
5470        let fs = FakeFs::new(cx.background());
5471        fs.insert_tree(
5472            "/dir",
5473            json!({
5474                "a.rs": text.clone(),
5475            }),
5476        )
5477        .await;
5478
5479        let project = Project::test(fs, cx);
5480        project.update(cx, |project, _| project.languages.add(language));
5481
5482        let worktree_id = project
5483            .update(cx, |project, cx| {
5484                project.find_or_create_local_worktree("/dir", true, cx)
5485            })
5486            .await
5487            .unwrap()
5488            .0
5489            .read_with(cx, |tree, _| tree.id());
5490
5491        let buffer = project
5492            .update(cx, |project, cx| {
5493                project.open_buffer((worktree_id, "a.rs"), cx)
5494            })
5495            .await
5496            .unwrap();
5497
5498        let mut fake_server = fake_servers.next().await.unwrap();
5499        let lsp_document_version = fake_server
5500            .receive_notification::<lsp::notification::DidOpenTextDocument>()
5501            .await
5502            .text_document
5503            .version;
5504
5505        // Simulate editing the buffer after the language server computes some edits.
5506        buffer.update(cx, |buffer, cx| {
5507            buffer.edit(
5508                [Point::new(0, 0)..Point::new(0, 0)],
5509                "// above first function\n",
5510                cx,
5511            );
5512            buffer.edit(
5513                [Point::new(2, 0)..Point::new(2, 0)],
5514                "    // inside first function\n",
5515                cx,
5516            );
5517            buffer.edit(
5518                [Point::new(6, 4)..Point::new(6, 4)],
5519                "// inside second function ",
5520                cx,
5521            );
5522
5523            assert_eq!(
5524                buffer.text(),
5525                "
5526                    // above first function
5527                    fn a() {
5528                        // inside first function
5529                        f1();
5530                    }
5531                    fn b() {
5532                        // inside second function f2();
5533                    }
5534                    fn c() {
5535                        f3();
5536                    }
5537                "
5538                .unindent()
5539            );
5540        });
5541
5542        let edits = project
5543            .update(cx, |project, cx| {
5544                project.edits_from_lsp(
5545                    &buffer,
5546                    vec![
5547                        // replace body of first function
5548                        lsp::TextEdit {
5549                            range: lsp::Range::new(
5550                                lsp::Position::new(0, 0),
5551                                lsp::Position::new(3, 0),
5552                            ),
5553                            new_text: "
5554                                fn a() {
5555                                    f10();
5556                                }
5557                            "
5558                            .unindent(),
5559                        },
5560                        // edit inside second function
5561                        lsp::TextEdit {
5562                            range: lsp::Range::new(
5563                                lsp::Position::new(4, 6),
5564                                lsp::Position::new(4, 6),
5565                            ),
5566                            new_text: "00".into(),
5567                        },
5568                        // edit inside third function via two distinct edits
5569                        lsp::TextEdit {
5570                            range: lsp::Range::new(
5571                                lsp::Position::new(7, 5),
5572                                lsp::Position::new(7, 5),
5573                            ),
5574                            new_text: "4000".into(),
5575                        },
5576                        lsp::TextEdit {
5577                            range: lsp::Range::new(
5578                                lsp::Position::new(7, 5),
5579                                lsp::Position::new(7, 6),
5580                            ),
5581                            new_text: "".into(),
5582                        },
5583                    ],
5584                    Some(lsp_document_version),
5585                    cx,
5586                )
5587            })
5588            .await
5589            .unwrap();
5590
5591        buffer.update(cx, |buffer, cx| {
5592            for (range, new_text) in edits {
5593                buffer.edit([range], new_text, cx);
5594            }
5595            assert_eq!(
5596                buffer.text(),
5597                "
5598                    // above first function
5599                    fn a() {
5600                        // inside first function
5601                        f10();
5602                    }
5603                    fn b() {
5604                        // inside second function f200();
5605                    }
5606                    fn c() {
5607                        f4000();
5608                    }
5609                "
5610                .unindent()
5611            );
5612        });
5613    }
5614
5615    #[gpui::test]
5616    async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestAppContext) {
5617        cx.foreground().forbid_parking();
5618
5619        let text = "
5620            use a::b;
5621            use a::c;
5622
5623            fn f() {
5624                b();
5625                c();
5626            }
5627        "
5628        .unindent();
5629
5630        let fs = FakeFs::new(cx.background());
5631        fs.insert_tree(
5632            "/dir",
5633            json!({
5634                "a.rs": text.clone(),
5635            }),
5636        )
5637        .await;
5638
5639        let project = Project::test(fs, cx);
5640        let worktree_id = project
5641            .update(cx, |project, cx| {
5642                project.find_or_create_local_worktree("/dir", true, cx)
5643            })
5644            .await
5645            .unwrap()
5646            .0
5647            .read_with(cx, |tree, _| tree.id());
5648
5649        let buffer = project
5650            .update(cx, |project, cx| {
5651                project.open_buffer((worktree_id, "a.rs"), cx)
5652            })
5653            .await
5654            .unwrap();
5655
5656        // Simulate the language server sending us a small edit in the form of a very large diff.
5657        // Rust-analyzer does this when performing a merge-imports code action.
5658        let edits = project
5659            .update(cx, |project, cx| {
5660                project.edits_from_lsp(
5661                    &buffer,
5662                    [
5663                        // Replace the first use statement without editing the semicolon.
5664                        lsp::TextEdit {
5665                            range: lsp::Range::new(
5666                                lsp::Position::new(0, 4),
5667                                lsp::Position::new(0, 8),
5668                            ),
5669                            new_text: "a::{b, c}".into(),
5670                        },
5671                        // Reinsert the remainder of the file between the semicolon and the final
5672                        // newline of the file.
5673                        lsp::TextEdit {
5674                            range: lsp::Range::new(
5675                                lsp::Position::new(0, 9),
5676                                lsp::Position::new(0, 9),
5677                            ),
5678                            new_text: "\n\n".into(),
5679                        },
5680                        lsp::TextEdit {
5681                            range: lsp::Range::new(
5682                                lsp::Position::new(0, 9),
5683                                lsp::Position::new(0, 9),
5684                            ),
5685                            new_text: "
5686                                fn f() {
5687                                    b();
5688                                    c();
5689                                }"
5690                            .unindent(),
5691                        },
5692                        // Delete everything after the first newline of the file.
5693                        lsp::TextEdit {
5694                            range: lsp::Range::new(
5695                                lsp::Position::new(1, 0),
5696                                lsp::Position::new(7, 0),
5697                            ),
5698                            new_text: "".into(),
5699                        },
5700                    ],
5701                    None,
5702                    cx,
5703                )
5704            })
5705            .await
5706            .unwrap();
5707
5708        buffer.update(cx, |buffer, cx| {
5709            let edits = edits
5710                .into_iter()
5711                .map(|(range, text)| {
5712                    (
5713                        range.start.to_point(&buffer)..range.end.to_point(&buffer),
5714                        text,
5715                    )
5716                })
5717                .collect::<Vec<_>>();
5718
5719            assert_eq!(
5720                edits,
5721                [
5722                    (Point::new(0, 4)..Point::new(0, 8), "a::{b, c}".into()),
5723                    (Point::new(1, 0)..Point::new(2, 0), "".into())
5724                ]
5725            );
5726
5727            for (range, new_text) in edits {
5728                buffer.edit([range], new_text, cx);
5729            }
5730            assert_eq!(
5731                buffer.text(),
5732                "
5733                    use a::{b, c};
5734
5735                    fn f() {
5736                        b();
5737                        c();
5738                    }
5739                "
5740                .unindent()
5741            );
5742        });
5743    }
5744
5745    fn chunks_with_diagnostics<T: ToOffset + ToPoint>(
5746        buffer: &Buffer,
5747        range: Range<T>,
5748    ) -> Vec<(String, Option<DiagnosticSeverity>)> {
5749        let mut chunks: Vec<(String, Option<DiagnosticSeverity>)> = Vec::new();
5750        for chunk in buffer.snapshot().chunks(range, true) {
5751            if chunks.last().map_or(false, |prev_chunk| {
5752                prev_chunk.1 == chunk.diagnostic_severity
5753            }) {
5754                chunks.last_mut().unwrap().0.push_str(chunk.text);
5755            } else {
5756                chunks.push((chunk.text.to_string(), chunk.diagnostic_severity));
5757            }
5758        }
5759        chunks
5760    }
5761
5762    #[gpui::test]
5763    async fn test_search_worktree_without_files(cx: &mut gpui::TestAppContext) {
5764        let dir = temp_tree(json!({
5765            "root": {
5766                "dir1": {},
5767                "dir2": {
5768                    "dir3": {}
5769                }
5770            }
5771        }));
5772
5773        let project = Project::test(Arc::new(RealFs), cx);
5774        let (tree, _) = project
5775            .update(cx, |project, cx| {
5776                project.find_or_create_local_worktree(&dir.path(), true, cx)
5777            })
5778            .await
5779            .unwrap();
5780
5781        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
5782            .await;
5783
5784        let cancel_flag = Default::default();
5785        let results = project
5786            .read_with(cx, |project, cx| {
5787                project.match_paths("dir", false, false, 10, &cancel_flag, cx)
5788            })
5789            .await;
5790
5791        assert!(results.is_empty());
5792    }
5793
5794    #[gpui::test]
5795    async fn test_definition(cx: &mut gpui::TestAppContext) {
5796        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
5797        let language = Arc::new(Language::new(
5798            LanguageConfig {
5799                name: "Rust".into(),
5800                path_suffixes: vec!["rs".to_string()],
5801                language_server: Some(language_server_config),
5802                ..Default::default()
5803            },
5804            Some(tree_sitter_rust::language()),
5805        ));
5806
5807        let fs = FakeFs::new(cx.background());
5808        fs.insert_tree(
5809            "/dir",
5810            json!({
5811                "a.rs": "const fn a() { A }",
5812                "b.rs": "const y: i32 = crate::a()",
5813            }),
5814        )
5815        .await;
5816
5817        let project = Project::test(fs, cx);
5818        project.update(cx, |project, _| {
5819            Arc::get_mut(&mut project.languages).unwrap().add(language);
5820        });
5821
5822        let (tree, _) = project
5823            .update(cx, |project, cx| {
5824                project.find_or_create_local_worktree("/dir/b.rs", true, cx)
5825            })
5826            .await
5827            .unwrap();
5828        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
5829        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
5830            .await;
5831
5832        let buffer = project
5833            .update(cx, |project, cx| {
5834                project.open_buffer(
5835                    ProjectPath {
5836                        worktree_id,
5837                        path: Path::new("").into(),
5838                    },
5839                    cx,
5840                )
5841            })
5842            .await
5843            .unwrap();
5844
5845        let mut fake_server = fake_servers.next().await.unwrap();
5846        fake_server.handle_request::<lsp::request::GotoDefinition, _, _>(|params, _| async move {
5847            let params = params.text_document_position_params;
5848            assert_eq!(
5849                params.text_document.uri.to_file_path().unwrap(),
5850                Path::new("/dir/b.rs"),
5851            );
5852            assert_eq!(params.position, lsp::Position::new(0, 22));
5853
5854            Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location::new(
5855                lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5856                lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5857            )))
5858        });
5859
5860        let mut definitions = project
5861            .update(cx, |project, cx| project.definition(&buffer, 22, cx))
5862            .await
5863            .unwrap();
5864
5865        assert_eq!(definitions.len(), 1);
5866        let definition = definitions.pop().unwrap();
5867        cx.update(|cx| {
5868            let target_buffer = definition.buffer.read(cx);
5869            assert_eq!(
5870                target_buffer
5871                    .file()
5872                    .unwrap()
5873                    .as_local()
5874                    .unwrap()
5875                    .abs_path(cx),
5876                Path::new("/dir/a.rs"),
5877            );
5878            assert_eq!(definition.range.to_offset(target_buffer), 9..10);
5879            assert_eq!(
5880                list_worktrees(&project, cx),
5881                [("/dir/b.rs".as_ref(), true), ("/dir/a.rs".as_ref(), false)]
5882            );
5883
5884            drop(definition);
5885        });
5886        cx.read(|cx| {
5887            assert_eq!(list_worktrees(&project, cx), [("/dir/b.rs".as_ref(), true)]);
5888        });
5889
5890        fn list_worktrees<'a>(
5891            project: &'a ModelHandle<Project>,
5892            cx: &'a AppContext,
5893        ) -> Vec<(&'a Path, bool)> {
5894            project
5895                .read(cx)
5896                .worktrees(cx)
5897                .map(|worktree| {
5898                    let worktree = worktree.read(cx);
5899                    (
5900                        worktree.as_local().unwrap().abs_path().as_ref(),
5901                        worktree.is_visible(),
5902                    )
5903                })
5904                .collect::<Vec<_>>()
5905        }
5906    }
5907
5908    #[gpui::test]
5909    async fn test_save_file(cx: &mut gpui::TestAppContext) {
5910        let fs = FakeFs::new(cx.background());
5911        fs.insert_tree(
5912            "/dir",
5913            json!({
5914                "file1": "the old contents",
5915            }),
5916        )
5917        .await;
5918
5919        let project = Project::test(fs.clone(), cx);
5920        let worktree_id = project
5921            .update(cx, |p, cx| {
5922                p.find_or_create_local_worktree("/dir", true, cx)
5923            })
5924            .await
5925            .unwrap()
5926            .0
5927            .read_with(cx, |tree, _| tree.id());
5928
5929        let buffer = project
5930            .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
5931            .await
5932            .unwrap();
5933        buffer
5934            .update(cx, |buffer, cx| {
5935                assert_eq!(buffer.text(), "the old contents");
5936                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
5937                buffer.save(cx)
5938            })
5939            .await
5940            .unwrap();
5941
5942        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
5943        assert_eq!(new_text, buffer.read_with(cx, |buffer, _| buffer.text()));
5944    }
5945
5946    #[gpui::test]
5947    async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
5948        let fs = FakeFs::new(cx.background());
5949        fs.insert_tree(
5950            "/dir",
5951            json!({
5952                "file1": "the old contents",
5953            }),
5954        )
5955        .await;
5956
5957        let project = Project::test(fs.clone(), cx);
5958        let worktree_id = project
5959            .update(cx, |p, cx| {
5960                p.find_or_create_local_worktree("/dir/file1", true, cx)
5961            })
5962            .await
5963            .unwrap()
5964            .0
5965            .read_with(cx, |tree, _| tree.id());
5966
5967        let buffer = project
5968            .update(cx, |p, cx| p.open_buffer((worktree_id, ""), cx))
5969            .await
5970            .unwrap();
5971        buffer
5972            .update(cx, |buffer, cx| {
5973                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
5974                buffer.save(cx)
5975            })
5976            .await
5977            .unwrap();
5978
5979        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
5980        assert_eq!(new_text, buffer.read_with(cx, |buffer, _| buffer.text()));
5981    }
5982
5983    #[gpui::test]
5984    async fn test_save_as(cx: &mut gpui::TestAppContext) {
5985        let fs = FakeFs::new(cx.background());
5986        fs.insert_tree("/dir", json!({})).await;
5987
5988        let project = Project::test(fs.clone(), cx);
5989        let (worktree, _) = project
5990            .update(cx, |project, cx| {
5991                project.find_or_create_local_worktree("/dir", true, cx)
5992            })
5993            .await
5994            .unwrap();
5995        let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
5996
5997        let buffer = project.update(cx, |project, cx| project.create_buffer(cx).unwrap());
5998        buffer.update(cx, |buffer, cx| {
5999            buffer.edit([0..0], "abc", cx);
6000            assert!(buffer.is_dirty());
6001            assert!(!buffer.has_conflict());
6002        });
6003        project
6004            .update(cx, |project, cx| {
6005                project.save_buffer_as(buffer.clone(), "/dir/file1".into(), cx)
6006            })
6007            .await
6008            .unwrap();
6009        assert_eq!(fs.load(Path::new("/dir/file1")).await.unwrap(), "abc");
6010        buffer.read_with(cx, |buffer, cx| {
6011            assert_eq!(buffer.file().unwrap().full_path(cx), Path::new("dir/file1"));
6012            assert!(!buffer.is_dirty());
6013            assert!(!buffer.has_conflict());
6014        });
6015
6016        let opened_buffer = project
6017            .update(cx, |project, cx| {
6018                project.open_buffer((worktree_id, "file1"), cx)
6019            })
6020            .await
6021            .unwrap();
6022        assert_eq!(opened_buffer, buffer);
6023    }
6024
6025    #[gpui::test(retries = 5)]
6026    async fn test_rescan_and_remote_updates(cx: &mut gpui::TestAppContext) {
6027        let dir = temp_tree(json!({
6028            "a": {
6029                "file1": "",
6030                "file2": "",
6031                "file3": "",
6032            },
6033            "b": {
6034                "c": {
6035                    "file4": "",
6036                    "file5": "",
6037                }
6038            }
6039        }));
6040
6041        let project = Project::test(Arc::new(RealFs), cx);
6042        let rpc = project.read_with(cx, |p, _| p.client.clone());
6043
6044        let (tree, _) = project
6045            .update(cx, |p, cx| {
6046                p.find_or_create_local_worktree(dir.path(), true, cx)
6047            })
6048            .await
6049            .unwrap();
6050        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6051
6052        let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
6053            let buffer = project.update(cx, |p, cx| p.open_buffer((worktree_id, path), cx));
6054            async move { buffer.await.unwrap() }
6055        };
6056        let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
6057            tree.read_with(cx, |tree, _| {
6058                tree.entry_for_path(path)
6059                    .expect(&format!("no entry for path {}", path))
6060                    .id
6061            })
6062        };
6063
6064        let buffer2 = buffer_for_path("a/file2", cx).await;
6065        let buffer3 = buffer_for_path("a/file3", cx).await;
6066        let buffer4 = buffer_for_path("b/c/file4", cx).await;
6067        let buffer5 = buffer_for_path("b/c/file5", cx).await;
6068
6069        let file2_id = id_for_path("a/file2", &cx);
6070        let file3_id = id_for_path("a/file3", &cx);
6071        let file4_id = id_for_path("b/c/file4", &cx);
6072
6073        // Wait for the initial scan.
6074        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6075            .await;
6076
6077        // Create a remote copy of this worktree.
6078        let initial_snapshot = tree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot());
6079        let (remote, load_task) = cx.update(|cx| {
6080            Worktree::remote(
6081                1,
6082                1,
6083                initial_snapshot.to_proto(&Default::default(), true),
6084                rpc.clone(),
6085                cx,
6086            )
6087        });
6088        load_task.await;
6089
6090        cx.read(|cx| {
6091            assert!(!buffer2.read(cx).is_dirty());
6092            assert!(!buffer3.read(cx).is_dirty());
6093            assert!(!buffer4.read(cx).is_dirty());
6094            assert!(!buffer5.read(cx).is_dirty());
6095        });
6096
6097        // Rename and delete files and directories.
6098        tree.flush_fs_events(&cx).await;
6099        std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
6100        std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
6101        std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
6102        std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
6103        tree.flush_fs_events(&cx).await;
6104
6105        let expected_paths = vec![
6106            "a",
6107            "a/file1",
6108            "a/file2.new",
6109            "b",
6110            "d",
6111            "d/file3",
6112            "d/file4",
6113        ];
6114
6115        cx.read(|app| {
6116            assert_eq!(
6117                tree.read(app)
6118                    .paths()
6119                    .map(|p| p.to_str().unwrap())
6120                    .collect::<Vec<_>>(),
6121                expected_paths
6122            );
6123
6124            assert_eq!(id_for_path("a/file2.new", &cx), file2_id);
6125            assert_eq!(id_for_path("d/file3", &cx), file3_id);
6126            assert_eq!(id_for_path("d/file4", &cx), file4_id);
6127
6128            assert_eq!(
6129                buffer2.read(app).file().unwrap().path().as_ref(),
6130                Path::new("a/file2.new")
6131            );
6132            assert_eq!(
6133                buffer3.read(app).file().unwrap().path().as_ref(),
6134                Path::new("d/file3")
6135            );
6136            assert_eq!(
6137                buffer4.read(app).file().unwrap().path().as_ref(),
6138                Path::new("d/file4")
6139            );
6140            assert_eq!(
6141                buffer5.read(app).file().unwrap().path().as_ref(),
6142                Path::new("b/c/file5")
6143            );
6144
6145            assert!(!buffer2.read(app).file().unwrap().is_deleted());
6146            assert!(!buffer3.read(app).file().unwrap().is_deleted());
6147            assert!(!buffer4.read(app).file().unwrap().is_deleted());
6148            assert!(buffer5.read(app).file().unwrap().is_deleted());
6149        });
6150
6151        // Update the remote worktree. Check that it becomes consistent with the
6152        // local worktree.
6153        remote.update(cx, |remote, cx| {
6154            let update_message = tree.read(cx).as_local().unwrap().snapshot().build_update(
6155                &initial_snapshot,
6156                1,
6157                1,
6158                true,
6159            );
6160            remote
6161                .as_remote_mut()
6162                .unwrap()
6163                .snapshot
6164                .apply_remote_update(update_message)
6165                .unwrap();
6166
6167            assert_eq!(
6168                remote
6169                    .paths()
6170                    .map(|p| p.to_str().unwrap())
6171                    .collect::<Vec<_>>(),
6172                expected_paths
6173            );
6174        });
6175    }
6176
6177    #[gpui::test]
6178    async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
6179        let fs = FakeFs::new(cx.background());
6180        fs.insert_tree(
6181            "/the-dir",
6182            json!({
6183                "a.txt": "a-contents",
6184                "b.txt": "b-contents",
6185            }),
6186        )
6187        .await;
6188
6189        let project = Project::test(fs.clone(), cx);
6190        let worktree_id = project
6191            .update(cx, |p, cx| {
6192                p.find_or_create_local_worktree("/the-dir", true, cx)
6193            })
6194            .await
6195            .unwrap()
6196            .0
6197            .read_with(cx, |tree, _| tree.id());
6198
6199        // Spawn multiple tasks to open paths, repeating some paths.
6200        let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| {
6201            (
6202                p.open_buffer((worktree_id, "a.txt"), cx),
6203                p.open_buffer((worktree_id, "b.txt"), cx),
6204                p.open_buffer((worktree_id, "a.txt"), cx),
6205            )
6206        });
6207
6208        let buffer_a_1 = buffer_a_1.await.unwrap();
6209        let buffer_a_2 = buffer_a_2.await.unwrap();
6210        let buffer_b = buffer_b.await.unwrap();
6211        assert_eq!(buffer_a_1.read_with(cx, |b, _| b.text()), "a-contents");
6212        assert_eq!(buffer_b.read_with(cx, |b, _| b.text()), "b-contents");
6213
6214        // There is only one buffer per path.
6215        let buffer_a_id = buffer_a_1.id();
6216        assert_eq!(buffer_a_2.id(), buffer_a_id);
6217
6218        // Open the same path again while it is still open.
6219        drop(buffer_a_1);
6220        let buffer_a_3 = project
6221            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
6222            .await
6223            .unwrap();
6224
6225        // There's still only one buffer per path.
6226        assert_eq!(buffer_a_3.id(), buffer_a_id);
6227    }
6228
6229    #[gpui::test]
6230    async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
6231        use std::fs;
6232
6233        let dir = temp_tree(json!({
6234            "file1": "abc",
6235            "file2": "def",
6236            "file3": "ghi",
6237        }));
6238
6239        let project = Project::test(Arc::new(RealFs), cx);
6240        let (worktree, _) = project
6241            .update(cx, |p, cx| {
6242                p.find_or_create_local_worktree(dir.path(), true, cx)
6243            })
6244            .await
6245            .unwrap();
6246        let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
6247
6248        worktree.flush_fs_events(&cx).await;
6249        worktree
6250            .read_with(cx, |t, _| t.as_local().unwrap().scan_complete())
6251            .await;
6252
6253        let buffer1 = project
6254            .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
6255            .await
6256            .unwrap();
6257        let events = Rc::new(RefCell::new(Vec::new()));
6258
6259        // initially, the buffer isn't dirty.
6260        buffer1.update(cx, |buffer, cx| {
6261            cx.subscribe(&buffer1, {
6262                let events = events.clone();
6263                move |_, _, event, _| match event {
6264                    BufferEvent::Operation(_) => {}
6265                    _ => events.borrow_mut().push(event.clone()),
6266                }
6267            })
6268            .detach();
6269
6270            assert!(!buffer.is_dirty());
6271            assert!(events.borrow().is_empty());
6272
6273            buffer.edit(vec![1..2], "", cx);
6274        });
6275
6276        // after the first edit, the buffer is dirty, and emits a dirtied event.
6277        buffer1.update(cx, |buffer, cx| {
6278            assert!(buffer.text() == "ac");
6279            assert!(buffer.is_dirty());
6280            assert_eq!(
6281                *events.borrow(),
6282                &[language::Event::Edited, language::Event::Dirtied]
6283            );
6284            events.borrow_mut().clear();
6285            buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
6286        });
6287
6288        // after saving, the buffer is not dirty, and emits a saved event.
6289        buffer1.update(cx, |buffer, cx| {
6290            assert!(!buffer.is_dirty());
6291            assert_eq!(*events.borrow(), &[language::Event::Saved]);
6292            events.borrow_mut().clear();
6293
6294            buffer.edit(vec![1..1], "B", cx);
6295            buffer.edit(vec![2..2], "D", cx);
6296        });
6297
6298        // after editing again, the buffer is dirty, and emits another dirty event.
6299        buffer1.update(cx, |buffer, cx| {
6300            assert!(buffer.text() == "aBDc");
6301            assert!(buffer.is_dirty());
6302            assert_eq!(
6303                *events.borrow(),
6304                &[
6305                    language::Event::Edited,
6306                    language::Event::Dirtied,
6307                    language::Event::Edited,
6308                ],
6309            );
6310            events.borrow_mut().clear();
6311
6312            // TODO - currently, after restoring the buffer to its
6313            // previously-saved state, the is still considered dirty.
6314            buffer.edit([1..3], "", cx);
6315            assert!(buffer.text() == "ac");
6316            assert!(buffer.is_dirty());
6317        });
6318
6319        assert_eq!(*events.borrow(), &[language::Event::Edited]);
6320
6321        // When a file is deleted, the buffer is considered dirty.
6322        let events = Rc::new(RefCell::new(Vec::new()));
6323        let buffer2 = project
6324            .update(cx, |p, cx| p.open_buffer((worktree_id, "file2"), cx))
6325            .await
6326            .unwrap();
6327        buffer2.update(cx, |_, cx| {
6328            cx.subscribe(&buffer2, {
6329                let events = events.clone();
6330                move |_, _, event, _| events.borrow_mut().push(event.clone())
6331            })
6332            .detach();
6333        });
6334
6335        fs::remove_file(dir.path().join("file2")).unwrap();
6336        buffer2.condition(&cx, |b, _| b.is_dirty()).await;
6337        assert_eq!(
6338            *events.borrow(),
6339            &[language::Event::Dirtied, language::Event::FileHandleChanged]
6340        );
6341
6342        // When a file is already dirty when deleted, we don't emit a Dirtied event.
6343        let events = Rc::new(RefCell::new(Vec::new()));
6344        let buffer3 = project
6345            .update(cx, |p, cx| p.open_buffer((worktree_id, "file3"), cx))
6346            .await
6347            .unwrap();
6348        buffer3.update(cx, |_, cx| {
6349            cx.subscribe(&buffer3, {
6350                let events = events.clone();
6351                move |_, _, event, _| events.borrow_mut().push(event.clone())
6352            })
6353            .detach();
6354        });
6355
6356        worktree.flush_fs_events(&cx).await;
6357        buffer3.update(cx, |buffer, cx| {
6358            buffer.edit(Some(0..0), "x", cx);
6359        });
6360        events.borrow_mut().clear();
6361        fs::remove_file(dir.path().join("file3")).unwrap();
6362        buffer3
6363            .condition(&cx, |_, _| !events.borrow().is_empty())
6364            .await;
6365        assert_eq!(*events.borrow(), &[language::Event::FileHandleChanged]);
6366        cx.read(|cx| assert!(buffer3.read(cx).is_dirty()));
6367    }
6368
6369    #[gpui::test]
6370    async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
6371        use std::fs;
6372
6373        let initial_contents = "aaa\nbbbbb\nc\n";
6374        let dir = temp_tree(json!({ "the-file": initial_contents }));
6375
6376        let project = Project::test(Arc::new(RealFs), cx);
6377        let (worktree, _) = project
6378            .update(cx, |p, cx| {
6379                p.find_or_create_local_worktree(dir.path(), true, cx)
6380            })
6381            .await
6382            .unwrap();
6383        let worktree_id = worktree.read_with(cx, |tree, _| tree.id());
6384
6385        worktree
6386            .read_with(cx, |t, _| t.as_local().unwrap().scan_complete())
6387            .await;
6388
6389        let abs_path = dir.path().join("the-file");
6390        let buffer = project
6391            .update(cx, |p, cx| p.open_buffer((worktree_id, "the-file"), cx))
6392            .await
6393            .unwrap();
6394
6395        // TODO
6396        // Add a cursor on each row.
6397        // let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
6398        //     assert!(!buffer.is_dirty());
6399        //     buffer.add_selection_set(
6400        //         &(0..3)
6401        //             .map(|row| Selection {
6402        //                 id: row as usize,
6403        //                 start: Point::new(row, 1),
6404        //                 end: Point::new(row, 1),
6405        //                 reversed: false,
6406        //                 goal: SelectionGoal::None,
6407        //             })
6408        //             .collect::<Vec<_>>(),
6409        //         cx,
6410        //     )
6411        // });
6412
6413        // Change the file on disk, adding two new lines of text, and removing
6414        // one line.
6415        buffer.read_with(cx, |buffer, _| {
6416            assert!(!buffer.is_dirty());
6417            assert!(!buffer.has_conflict());
6418        });
6419        let new_contents = "AAAA\naaa\nBB\nbbbbb\n";
6420        fs::write(&abs_path, new_contents).unwrap();
6421
6422        // Because the buffer was not modified, it is reloaded from disk. Its
6423        // contents are edited according to the diff between the old and new
6424        // file contents.
6425        buffer
6426            .condition(&cx, |buffer, _| buffer.text() == new_contents)
6427            .await;
6428
6429        buffer.update(cx, |buffer, _| {
6430            assert_eq!(buffer.text(), new_contents);
6431            assert!(!buffer.is_dirty());
6432            assert!(!buffer.has_conflict());
6433
6434            // TODO
6435            // let cursor_positions = buffer
6436            //     .selection_set(selection_set_id)
6437            //     .unwrap()
6438            //     .selections::<Point>(&*buffer)
6439            //     .map(|selection| {
6440            //         assert_eq!(selection.start, selection.end);
6441            //         selection.start
6442            //     })
6443            //     .collect::<Vec<_>>();
6444            // assert_eq!(
6445            //     cursor_positions,
6446            //     [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
6447            // );
6448        });
6449
6450        // Modify the buffer
6451        buffer.update(cx, |buffer, cx| {
6452            buffer.edit(vec![0..0], " ", cx);
6453            assert!(buffer.is_dirty());
6454            assert!(!buffer.has_conflict());
6455        });
6456
6457        // Change the file on disk again, adding blank lines to the beginning.
6458        fs::write(&abs_path, "\n\n\nAAAA\naaa\nBB\nbbbbb\n").unwrap();
6459
6460        // Because the buffer is modified, it doesn't reload from disk, but is
6461        // marked as having a conflict.
6462        buffer
6463            .condition(&cx, |buffer, _| buffer.has_conflict())
6464            .await;
6465    }
6466
6467    #[gpui::test]
6468    async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
6469        cx.foreground().forbid_parking();
6470
6471        let fs = FakeFs::new(cx.background());
6472        fs.insert_tree(
6473            "/the-dir",
6474            json!({
6475                "a.rs": "
6476                    fn foo(mut v: Vec<usize>) {
6477                        for x in &v {
6478                            v.push(1);
6479                        }
6480                    }
6481                "
6482                .unindent(),
6483            }),
6484        )
6485        .await;
6486
6487        let project = Project::test(fs.clone(), cx);
6488        let (worktree, _) = project
6489            .update(cx, |p, cx| {
6490                p.find_or_create_local_worktree("/the-dir", true, cx)
6491            })
6492            .await
6493            .unwrap();
6494        let worktree_id = worktree.read_with(cx, |tree, _| tree.id());
6495
6496        let buffer = project
6497            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
6498            .await
6499            .unwrap();
6500
6501        let buffer_uri = Url::from_file_path("/the-dir/a.rs").unwrap();
6502        let message = lsp::PublishDiagnosticsParams {
6503            uri: buffer_uri.clone(),
6504            diagnostics: vec![
6505                lsp::Diagnostic {
6506                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
6507                    severity: Some(DiagnosticSeverity::WARNING),
6508                    message: "error 1".to_string(),
6509                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
6510                        location: lsp::Location {
6511                            uri: buffer_uri.clone(),
6512                            range: lsp::Range::new(
6513                                lsp::Position::new(1, 8),
6514                                lsp::Position::new(1, 9),
6515                            ),
6516                        },
6517                        message: "error 1 hint 1".to_string(),
6518                    }]),
6519                    ..Default::default()
6520                },
6521                lsp::Diagnostic {
6522                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
6523                    severity: Some(DiagnosticSeverity::HINT),
6524                    message: "error 1 hint 1".to_string(),
6525                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
6526                        location: lsp::Location {
6527                            uri: buffer_uri.clone(),
6528                            range: lsp::Range::new(
6529                                lsp::Position::new(1, 8),
6530                                lsp::Position::new(1, 9),
6531                            ),
6532                        },
6533                        message: "original diagnostic".to_string(),
6534                    }]),
6535                    ..Default::default()
6536                },
6537                lsp::Diagnostic {
6538                    range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 17)),
6539                    severity: Some(DiagnosticSeverity::ERROR),
6540                    message: "error 2".to_string(),
6541                    related_information: Some(vec![
6542                        lsp::DiagnosticRelatedInformation {
6543                            location: lsp::Location {
6544                                uri: buffer_uri.clone(),
6545                                range: lsp::Range::new(
6546                                    lsp::Position::new(1, 13),
6547                                    lsp::Position::new(1, 15),
6548                                ),
6549                            },
6550                            message: "error 2 hint 1".to_string(),
6551                        },
6552                        lsp::DiagnosticRelatedInformation {
6553                            location: lsp::Location {
6554                                uri: buffer_uri.clone(),
6555                                range: lsp::Range::new(
6556                                    lsp::Position::new(1, 13),
6557                                    lsp::Position::new(1, 15),
6558                                ),
6559                            },
6560                            message: "error 2 hint 2".to_string(),
6561                        },
6562                    ]),
6563                    ..Default::default()
6564                },
6565                lsp::Diagnostic {
6566                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
6567                    severity: Some(DiagnosticSeverity::HINT),
6568                    message: "error 2 hint 1".to_string(),
6569                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
6570                        location: lsp::Location {
6571                            uri: buffer_uri.clone(),
6572                            range: lsp::Range::new(
6573                                lsp::Position::new(2, 8),
6574                                lsp::Position::new(2, 17),
6575                            ),
6576                        },
6577                        message: "original diagnostic".to_string(),
6578                    }]),
6579                    ..Default::default()
6580                },
6581                lsp::Diagnostic {
6582                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
6583                    severity: Some(DiagnosticSeverity::HINT),
6584                    message: "error 2 hint 2".to_string(),
6585                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
6586                        location: lsp::Location {
6587                            uri: buffer_uri.clone(),
6588                            range: lsp::Range::new(
6589                                lsp::Position::new(2, 8),
6590                                lsp::Position::new(2, 17),
6591                            ),
6592                        },
6593                        message: "original diagnostic".to_string(),
6594                    }]),
6595                    ..Default::default()
6596                },
6597            ],
6598            version: None,
6599        };
6600
6601        project
6602            .update(cx, |p, cx| {
6603                p.update_diagnostics(message, &Default::default(), cx)
6604            })
6605            .unwrap();
6606        let buffer = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6607
6608        assert_eq!(
6609            buffer
6610                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
6611                .collect::<Vec<_>>(),
6612            &[
6613                DiagnosticEntry {
6614                    range: Point::new(1, 8)..Point::new(1, 9),
6615                    diagnostic: Diagnostic {
6616                        severity: DiagnosticSeverity::WARNING,
6617                        message: "error 1".to_string(),
6618                        group_id: 0,
6619                        is_primary: true,
6620                        ..Default::default()
6621                    }
6622                },
6623                DiagnosticEntry {
6624                    range: Point::new(1, 8)..Point::new(1, 9),
6625                    diagnostic: Diagnostic {
6626                        severity: DiagnosticSeverity::HINT,
6627                        message: "error 1 hint 1".to_string(),
6628                        group_id: 0,
6629                        is_primary: false,
6630                        ..Default::default()
6631                    }
6632                },
6633                DiagnosticEntry {
6634                    range: Point::new(1, 13)..Point::new(1, 15),
6635                    diagnostic: Diagnostic {
6636                        severity: DiagnosticSeverity::HINT,
6637                        message: "error 2 hint 1".to_string(),
6638                        group_id: 1,
6639                        is_primary: false,
6640                        ..Default::default()
6641                    }
6642                },
6643                DiagnosticEntry {
6644                    range: Point::new(1, 13)..Point::new(1, 15),
6645                    diagnostic: Diagnostic {
6646                        severity: DiagnosticSeverity::HINT,
6647                        message: "error 2 hint 2".to_string(),
6648                        group_id: 1,
6649                        is_primary: false,
6650                        ..Default::default()
6651                    }
6652                },
6653                DiagnosticEntry {
6654                    range: Point::new(2, 8)..Point::new(2, 17),
6655                    diagnostic: Diagnostic {
6656                        severity: DiagnosticSeverity::ERROR,
6657                        message: "error 2".to_string(),
6658                        group_id: 1,
6659                        is_primary: true,
6660                        ..Default::default()
6661                    }
6662                }
6663            ]
6664        );
6665
6666        assert_eq!(
6667            buffer.diagnostic_group::<Point>(0).collect::<Vec<_>>(),
6668            &[
6669                DiagnosticEntry {
6670                    range: Point::new(1, 8)..Point::new(1, 9),
6671                    diagnostic: Diagnostic {
6672                        severity: DiagnosticSeverity::WARNING,
6673                        message: "error 1".to_string(),
6674                        group_id: 0,
6675                        is_primary: true,
6676                        ..Default::default()
6677                    }
6678                },
6679                DiagnosticEntry {
6680                    range: Point::new(1, 8)..Point::new(1, 9),
6681                    diagnostic: Diagnostic {
6682                        severity: DiagnosticSeverity::HINT,
6683                        message: "error 1 hint 1".to_string(),
6684                        group_id: 0,
6685                        is_primary: false,
6686                        ..Default::default()
6687                    }
6688                },
6689            ]
6690        );
6691        assert_eq!(
6692            buffer.diagnostic_group::<Point>(1).collect::<Vec<_>>(),
6693            &[
6694                DiagnosticEntry {
6695                    range: Point::new(1, 13)..Point::new(1, 15),
6696                    diagnostic: Diagnostic {
6697                        severity: DiagnosticSeverity::HINT,
6698                        message: "error 2 hint 1".to_string(),
6699                        group_id: 1,
6700                        is_primary: false,
6701                        ..Default::default()
6702                    }
6703                },
6704                DiagnosticEntry {
6705                    range: Point::new(1, 13)..Point::new(1, 15),
6706                    diagnostic: Diagnostic {
6707                        severity: DiagnosticSeverity::HINT,
6708                        message: "error 2 hint 2".to_string(),
6709                        group_id: 1,
6710                        is_primary: false,
6711                        ..Default::default()
6712                    }
6713                },
6714                DiagnosticEntry {
6715                    range: Point::new(2, 8)..Point::new(2, 17),
6716                    diagnostic: Diagnostic {
6717                        severity: DiagnosticSeverity::ERROR,
6718                        message: "error 2".to_string(),
6719                        group_id: 1,
6720                        is_primary: true,
6721                        ..Default::default()
6722                    }
6723                }
6724            ]
6725        );
6726    }
6727
6728    #[gpui::test]
6729    async fn test_rename(cx: &mut gpui::TestAppContext) {
6730        cx.foreground().forbid_parking();
6731
6732        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
6733        let language = Arc::new(Language::new(
6734            LanguageConfig {
6735                name: "Rust".into(),
6736                path_suffixes: vec!["rs".to_string()],
6737                language_server: Some(language_server_config),
6738                ..Default::default()
6739            },
6740            Some(tree_sitter_rust::language()),
6741        ));
6742
6743        let fs = FakeFs::new(cx.background());
6744        fs.insert_tree(
6745            "/dir",
6746            json!({
6747                "one.rs": "const ONE: usize = 1;",
6748                "two.rs": "const TWO: usize = one::ONE + one::ONE;"
6749            }),
6750        )
6751        .await;
6752
6753        let project = Project::test(fs.clone(), cx);
6754        project.update(cx, |project, _| {
6755            Arc::get_mut(&mut project.languages).unwrap().add(language);
6756        });
6757
6758        let (tree, _) = project
6759            .update(cx, |project, cx| {
6760                project.find_or_create_local_worktree("/dir", true, cx)
6761            })
6762            .await
6763            .unwrap();
6764        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6765        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6766            .await;
6767
6768        let buffer = project
6769            .update(cx, |project, cx| {
6770                project.open_buffer((worktree_id, Path::new("one.rs")), cx)
6771            })
6772            .await
6773            .unwrap();
6774
6775        let mut fake_server = fake_servers.next().await.unwrap();
6776
6777        let response = project.update(cx, |project, cx| {
6778            project.prepare_rename(buffer.clone(), 7, cx)
6779        });
6780        fake_server
6781            .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
6782                assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
6783                assert_eq!(params.position, lsp::Position::new(0, 7));
6784                Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
6785                    lsp::Position::new(0, 6),
6786                    lsp::Position::new(0, 9),
6787                )))
6788            })
6789            .next()
6790            .await
6791            .unwrap();
6792        let range = response.await.unwrap().unwrap();
6793        let range = buffer.read_with(cx, |buffer, _| range.to_offset(buffer));
6794        assert_eq!(range, 6..9);
6795
6796        let response = project.update(cx, |project, cx| {
6797            project.perform_rename(buffer.clone(), 7, "THREE".to_string(), true, cx)
6798        });
6799        fake_server
6800            .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
6801                assert_eq!(
6802                    params.text_document_position.text_document.uri.as_str(),
6803                    "file:///dir/one.rs"
6804                );
6805                assert_eq!(
6806                    params.text_document_position.position,
6807                    lsp::Position::new(0, 7)
6808                );
6809                assert_eq!(params.new_name, "THREE");
6810                Some(lsp::WorkspaceEdit {
6811                    changes: Some(
6812                        [
6813                            (
6814                                lsp::Url::from_file_path("/dir/one.rs").unwrap(),
6815                                vec![lsp::TextEdit::new(
6816                                    lsp::Range::new(
6817                                        lsp::Position::new(0, 6),
6818                                        lsp::Position::new(0, 9),
6819                                    ),
6820                                    "THREE".to_string(),
6821                                )],
6822                            ),
6823                            (
6824                                lsp::Url::from_file_path("/dir/two.rs").unwrap(),
6825                                vec![
6826                                    lsp::TextEdit::new(
6827                                        lsp::Range::new(
6828                                            lsp::Position::new(0, 24),
6829                                            lsp::Position::new(0, 27),
6830                                        ),
6831                                        "THREE".to_string(),
6832                                    ),
6833                                    lsp::TextEdit::new(
6834                                        lsp::Range::new(
6835                                            lsp::Position::new(0, 35),
6836                                            lsp::Position::new(0, 38),
6837                                        ),
6838                                        "THREE".to_string(),
6839                                    ),
6840                                ],
6841                            ),
6842                        ]
6843                        .into_iter()
6844                        .collect(),
6845                    ),
6846                    ..Default::default()
6847                })
6848            })
6849            .next()
6850            .await
6851            .unwrap();
6852        let mut transaction = response.await.unwrap().0;
6853        assert_eq!(transaction.len(), 2);
6854        assert_eq!(
6855            transaction
6856                .remove_entry(&buffer)
6857                .unwrap()
6858                .0
6859                .read_with(cx, |buffer, _| buffer.text()),
6860            "const THREE: usize = 1;"
6861        );
6862        assert_eq!(
6863            transaction
6864                .into_keys()
6865                .next()
6866                .unwrap()
6867                .read_with(cx, |buffer, _| buffer.text()),
6868            "const TWO: usize = one::THREE + one::THREE;"
6869        );
6870    }
6871
6872    #[gpui::test]
6873    async fn test_search(cx: &mut gpui::TestAppContext) {
6874        let fs = FakeFs::new(cx.background());
6875        fs.insert_tree(
6876            "/dir",
6877            json!({
6878                "one.rs": "const ONE: usize = 1;",
6879                "two.rs": "const TWO: usize = one::ONE + one::ONE;",
6880                "three.rs": "const THREE: usize = one::ONE + two::TWO;",
6881                "four.rs": "const FOUR: usize = one::ONE + three::THREE;",
6882            }),
6883        )
6884        .await;
6885        let project = Project::test(fs.clone(), cx);
6886        let (tree, _) = project
6887            .update(cx, |project, cx| {
6888                project.find_or_create_local_worktree("/dir", true, cx)
6889            })
6890            .await
6891            .unwrap();
6892        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6893        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6894            .await;
6895
6896        assert_eq!(
6897            search(&project, SearchQuery::text("TWO", false, true), cx)
6898                .await
6899                .unwrap(),
6900            HashMap::from_iter([
6901                ("two.rs".to_string(), vec![6..9]),
6902                ("three.rs".to_string(), vec![37..40])
6903            ])
6904        );
6905
6906        let buffer_4 = project
6907            .update(cx, |project, cx| {
6908                project.open_buffer((worktree_id, "four.rs"), cx)
6909            })
6910            .await
6911            .unwrap();
6912        buffer_4.update(cx, |buffer, cx| {
6913            buffer.edit([20..28, 31..43], "two::TWO", cx);
6914        });
6915
6916        assert_eq!(
6917            search(&project, SearchQuery::text("TWO", false, true), cx)
6918                .await
6919                .unwrap(),
6920            HashMap::from_iter([
6921                ("two.rs".to_string(), vec![6..9]),
6922                ("three.rs".to_string(), vec![37..40]),
6923                ("four.rs".to_string(), vec![25..28, 36..39])
6924            ])
6925        );
6926
6927        async fn search(
6928            project: &ModelHandle<Project>,
6929            query: SearchQuery,
6930            cx: &mut gpui::TestAppContext,
6931        ) -> Result<HashMap<String, Vec<Range<usize>>>> {
6932            let results = project
6933                .update(cx, |project, cx| project.search(query, cx))
6934                .await?;
6935
6936            Ok(results
6937                .into_iter()
6938                .map(|(buffer, ranges)| {
6939                    buffer.read_with(cx, |buffer, _| {
6940                        let path = buffer.file().unwrap().path().to_string_lossy().to_string();
6941                        let ranges = ranges
6942                            .into_iter()
6943                            .map(|range| range.to_offset(buffer))
6944                            .collect::<Vec<_>>();
6945                        (path, ranges)
6946                    })
6947                })
6948                .collect())
6949        }
6950    }
6951}