project.rs

   1pub mod fs;
   2mod ignore;
   3mod lsp_command;
   4pub mod worktree;
   5
   6use anyhow::{anyhow, Context, Result};
   7use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
   8use clock::ReplicaId;
   9use collections::{hash_map, HashMap, HashSet};
  10use futures::{future::Shared, Future, FutureExt, StreamExt};
  11use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
  12use gpui::{
  13    AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
  14    UpgradeModelHandle, WeakModelHandle,
  15};
  16use grep::{matcher::Matcher, searcher::Searcher};
  17use language::{
  18    range_from_lsp, Anchor, AnchorRangeExt, Bias, Buffer, CodeAction, CodeLabel, Completion,
  19    Diagnostic, DiagnosticEntry, File as _, Language, LanguageRegistry, Operation, PointUtf16,
  20    ToLspPosition, ToOffset, ToPointUtf16, Transaction,
  21};
  22use lsp::{DiagnosticSeverity, DocumentHighlightKind, LanguageServer};
  23use lsp_command::*;
  24use postage::{broadcast, prelude::Stream, sink::Sink, watch};
  25use rand::prelude::*;
  26use sha2::{Digest, Sha256};
  27use smol::block_on;
  28use std::{
  29    cell::RefCell,
  30    convert::TryInto,
  31    hash::Hash,
  32    mem,
  33    ops::Range,
  34    path::{Component, Path, PathBuf},
  35    rc::Rc,
  36    sync::{atomic::AtomicBool, Arc},
  37    time::Instant,
  38};
  39use util::{post_inc, ResultExt, TryFutureExt as _};
  40
  41pub use fs::*;
  42pub use worktree::*;
  43
  44pub struct Project {
  45    worktrees: Vec<WorktreeHandle>,
  46    active_entry: Option<ProjectEntry>,
  47    languages: Arc<LanguageRegistry>,
  48    language_servers: HashMap<(WorktreeId, String), Arc<LanguageServer>>,
  49    started_language_servers:
  50        HashMap<(WorktreeId, String), Shared<Task<Option<Arc<LanguageServer>>>>>,
  51    client: Arc<client::Client>,
  52    user_store: ModelHandle<UserStore>,
  53    fs: Arc<dyn Fs>,
  54    client_state: ProjectClientState,
  55    collaborators: HashMap<PeerId, Collaborator>,
  56    subscriptions: Vec<client::Subscription>,
  57    language_servers_with_diagnostics_running: isize,
  58    opened_buffer: broadcast::Sender<()>,
  59    loading_buffers: HashMap<
  60        ProjectPath,
  61        postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
  62    >,
  63    buffers_state: Rc<RefCell<ProjectBuffers>>,
  64    shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
  65    nonce: u128,
  66}
  67
  68#[derive(Default)]
  69struct ProjectBuffers {
  70    buffer_request_count: usize,
  71    preserved_buffers: Vec<ModelHandle<Buffer>>,
  72    open_buffers: HashMap<u64, OpenBuffer>,
  73}
  74
  75enum OpenBuffer {
  76    Loaded(WeakModelHandle<Buffer>),
  77    Loading(Vec<Operation>),
  78}
  79
  80enum WorktreeHandle {
  81    Strong(ModelHandle<Worktree>),
  82    Weak(WeakModelHandle<Worktree>),
  83}
  84
  85enum ProjectClientState {
  86    Local {
  87        is_shared: bool,
  88        remote_id_tx: watch::Sender<Option<u64>>,
  89        remote_id_rx: watch::Receiver<Option<u64>>,
  90        _maintain_remote_id_task: Task<Option<()>>,
  91    },
  92    Remote {
  93        sharing_has_stopped: bool,
  94        remote_id: u64,
  95        replica_id: ReplicaId,
  96    },
  97}
  98
  99#[derive(Clone, Debug)]
 100pub struct Collaborator {
 101    pub user: Arc<User>,
 102    pub peer_id: PeerId,
 103    pub replica_id: ReplicaId,
 104}
 105
 106#[derive(Clone, Debug, PartialEq)]
 107pub enum Event {
 108    ActiveEntryChanged(Option<ProjectEntry>),
 109    WorktreeRemoved(WorktreeId),
 110    DiskBasedDiagnosticsStarted,
 111    DiskBasedDiagnosticsUpdated,
 112    DiskBasedDiagnosticsFinished,
 113    DiagnosticsUpdated(ProjectPath),
 114}
 115
 116#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
 117pub struct ProjectPath {
 118    pub worktree_id: WorktreeId,
 119    pub path: Arc<Path>,
 120}
 121
 122#[derive(Clone, Debug, Default, PartialEq)]
 123pub struct DiagnosticSummary {
 124    pub error_count: usize,
 125    pub warning_count: usize,
 126    pub info_count: usize,
 127    pub hint_count: usize,
 128}
 129
 130#[derive(Debug)]
 131pub struct Location {
 132    pub buffer: ModelHandle<Buffer>,
 133    pub range: Range<language::Anchor>,
 134}
 135
 136#[derive(Debug)]
 137pub struct DocumentHighlight {
 138    pub range: Range<language::Anchor>,
 139    pub kind: DocumentHighlightKind,
 140}
 141
 142#[derive(Clone, Debug)]
 143pub struct Symbol {
 144    pub source_worktree_id: WorktreeId,
 145    pub worktree_id: WorktreeId,
 146    pub language_name: String,
 147    pub path: PathBuf,
 148    pub label: CodeLabel,
 149    pub name: String,
 150    pub kind: lsp::SymbolKind,
 151    pub range: Range<PointUtf16>,
 152    pub signature: [u8; 32],
 153}
 154
 155pub struct BufferRequestHandle(Rc<RefCell<ProjectBuffers>>);
 156
 157#[derive(Default)]
 158pub struct ProjectTransaction(pub HashMap<ModelHandle<Buffer>, language::Transaction>);
 159
 160impl DiagnosticSummary {
 161    fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
 162        let mut this = Self {
 163            error_count: 0,
 164            warning_count: 0,
 165            info_count: 0,
 166            hint_count: 0,
 167        };
 168
 169        for entry in diagnostics {
 170            if entry.diagnostic.is_primary {
 171                match entry.diagnostic.severity {
 172                    DiagnosticSeverity::ERROR => this.error_count += 1,
 173                    DiagnosticSeverity::WARNING => this.warning_count += 1,
 174                    DiagnosticSeverity::INFORMATION => this.info_count += 1,
 175                    DiagnosticSeverity::HINT => this.hint_count += 1,
 176                    _ => {}
 177                }
 178            }
 179        }
 180
 181        this
 182    }
 183
 184    pub fn to_proto(&self, path: &Path) -> proto::DiagnosticSummary {
 185        proto::DiagnosticSummary {
 186            path: path.to_string_lossy().to_string(),
 187            error_count: self.error_count as u32,
 188            warning_count: self.warning_count as u32,
 189            info_count: self.info_count as u32,
 190            hint_count: self.hint_count as u32,
 191        }
 192    }
 193}
 194
 195#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 196pub struct ProjectEntry {
 197    pub worktree_id: WorktreeId,
 198    pub entry_id: usize,
 199}
 200
 201impl Project {
 202    pub fn init(client: &Arc<Client>) {
 203        client.add_entity_message_handler(Self::handle_add_collaborator);
 204        client.add_entity_message_handler(Self::handle_buffer_reloaded);
 205        client.add_entity_message_handler(Self::handle_buffer_saved);
 206        client.add_entity_message_handler(Self::handle_close_buffer);
 207        client.add_entity_message_handler(Self::handle_disk_based_diagnostics_updated);
 208        client.add_entity_message_handler(Self::handle_disk_based_diagnostics_updating);
 209        client.add_entity_message_handler(Self::handle_remove_collaborator);
 210        client.add_entity_message_handler(Self::handle_register_worktree);
 211        client.add_entity_message_handler(Self::handle_unregister_worktree);
 212        client.add_entity_message_handler(Self::handle_unshare_project);
 213        client.add_entity_message_handler(Self::handle_update_buffer_file);
 214        client.add_entity_message_handler(Self::handle_update_buffer);
 215        client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
 216        client.add_entity_message_handler(Self::handle_update_worktree);
 217        client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
 218        client.add_entity_request_handler(Self::handle_apply_code_action);
 219        client.add_entity_request_handler(Self::handle_format_buffers);
 220        client.add_entity_request_handler(Self::handle_get_code_actions);
 221        client.add_entity_request_handler(Self::handle_get_completions);
 222        client.add_entity_request_handler(Self::handle_lsp_command::<GetDefinition>);
 223        client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
 224        client.add_entity_request_handler(Self::handle_lsp_command::<GetReferences>);
 225        client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
 226        client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
 227        client.add_entity_request_handler(Self::handle_get_project_symbols);
 228        client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
 229        client.add_entity_request_handler(Self::handle_open_buffer);
 230        client.add_entity_request_handler(Self::handle_save_buffer);
 231    }
 232
 233    pub fn local(
 234        client: Arc<Client>,
 235        user_store: ModelHandle<UserStore>,
 236        languages: Arc<LanguageRegistry>,
 237        fs: Arc<dyn Fs>,
 238        cx: &mut MutableAppContext,
 239    ) -> ModelHandle<Self> {
 240        cx.add_model(|cx: &mut ModelContext<Self>| {
 241            let (remote_id_tx, remote_id_rx) = watch::channel();
 242            let _maintain_remote_id_task = cx.spawn_weak({
 243                let rpc = client.clone();
 244                move |this, mut cx| {
 245                    async move {
 246                        let mut status = rpc.status();
 247                        while let Some(status) = status.recv().await {
 248                            if let Some(this) = this.upgrade(&cx) {
 249                                let remote_id = if let client::Status::Connected { .. } = status {
 250                                    let response = rpc.request(proto::RegisterProject {}).await?;
 251                                    Some(response.project_id)
 252                                } else {
 253                                    None
 254                                };
 255
 256                                if let Some(project_id) = remote_id {
 257                                    let mut registrations = Vec::new();
 258                                    this.update(&mut cx, |this, cx| {
 259                                        for worktree in this.worktrees(cx).collect::<Vec<_>>() {
 260                                            registrations.push(worktree.update(
 261                                                cx,
 262                                                |worktree, cx| {
 263                                                    let worktree = worktree.as_local_mut().unwrap();
 264                                                    worktree.register(project_id, cx)
 265                                                },
 266                                            ));
 267                                        }
 268                                    });
 269                                    for registration in registrations {
 270                                        registration.await?;
 271                                    }
 272                                }
 273                                this.update(&mut cx, |this, cx| this.set_remote_id(remote_id, cx));
 274                            }
 275                        }
 276                        Ok(())
 277                    }
 278                    .log_err()
 279                }
 280            });
 281
 282            Self {
 283                worktrees: Default::default(),
 284                collaborators: Default::default(),
 285                buffers_state: Default::default(),
 286                loading_buffers: Default::default(),
 287                shared_buffers: Default::default(),
 288                client_state: ProjectClientState::Local {
 289                    is_shared: false,
 290                    remote_id_tx,
 291                    remote_id_rx,
 292                    _maintain_remote_id_task,
 293                },
 294                opened_buffer: broadcast::channel(1).0,
 295                subscriptions: Vec::new(),
 296                active_entry: None,
 297                languages,
 298                client,
 299                user_store,
 300                fs,
 301                language_servers_with_diagnostics_running: 0,
 302                language_servers: Default::default(),
 303                started_language_servers: Default::default(),
 304                nonce: StdRng::from_entropy().gen(),
 305            }
 306        })
 307    }
 308
 309    pub async fn remote(
 310        remote_id: u64,
 311        client: Arc<Client>,
 312        user_store: ModelHandle<UserStore>,
 313        languages: Arc<LanguageRegistry>,
 314        fs: Arc<dyn Fs>,
 315        cx: &mut AsyncAppContext,
 316    ) -> Result<ModelHandle<Self>> {
 317        client.authenticate_and_connect(&cx).await?;
 318
 319        let response = client
 320            .request(proto::JoinProject {
 321                project_id: remote_id,
 322            })
 323            .await?;
 324
 325        let replica_id = response.replica_id as ReplicaId;
 326
 327        let mut worktrees = Vec::new();
 328        for worktree in response.worktrees {
 329            let (worktree, load_task) = cx
 330                .update(|cx| Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx));
 331            worktrees.push(worktree);
 332            load_task.detach();
 333        }
 334
 335        let this = cx.add_model(|cx| {
 336            let mut this = Self {
 337                worktrees: Vec::new(),
 338                loading_buffers: Default::default(),
 339                opened_buffer: broadcast::channel(1).0,
 340                shared_buffers: Default::default(),
 341                active_entry: None,
 342                collaborators: Default::default(),
 343                languages,
 344                user_store: user_store.clone(),
 345                fs,
 346                subscriptions: vec![client.add_model_for_remote_entity(remote_id, cx)],
 347                client,
 348                client_state: ProjectClientState::Remote {
 349                    sharing_has_stopped: false,
 350                    remote_id,
 351                    replica_id,
 352                },
 353                language_servers_with_diagnostics_running: 0,
 354                language_servers: Default::default(),
 355                started_language_servers: Default::default(),
 356                buffers_state: Default::default(),
 357                nonce: StdRng::from_entropy().gen(),
 358            };
 359            for worktree in worktrees {
 360                this.add_worktree(&worktree, cx);
 361            }
 362            this
 363        });
 364
 365        let user_ids = response
 366            .collaborators
 367            .iter()
 368            .map(|peer| peer.user_id)
 369            .collect();
 370        user_store
 371            .update(cx, |user_store, cx| user_store.load_users(user_ids, cx))
 372            .await?;
 373        let mut collaborators = HashMap::default();
 374        for message in response.collaborators {
 375            let collaborator = Collaborator::from_proto(message, &user_store, cx).await?;
 376            collaborators.insert(collaborator.peer_id, collaborator);
 377        }
 378
 379        this.update(cx, |this, _| {
 380            this.collaborators = collaborators;
 381        });
 382
 383        Ok(this)
 384    }
 385
 386    #[cfg(any(test, feature = "test-support"))]
 387    pub fn test(fs: Arc<dyn Fs>, cx: &mut gpui::TestAppContext) -> ModelHandle<Project> {
 388        let languages = Arc::new(LanguageRegistry::new());
 389        let http_client = client::test::FakeHttpClient::with_404_response();
 390        let client = client::Client::new(http_client.clone());
 391        let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
 392        cx.update(|cx| Project::local(client, user_store, languages, fs, cx))
 393    }
 394
 395    #[cfg(any(test, feature = "test-support"))]
 396    pub fn shared_buffer(&self, peer_id: PeerId, remote_id: u64) -> Option<ModelHandle<Buffer>> {
 397        self.shared_buffers
 398            .get(&peer_id)
 399            .and_then(|buffers| buffers.get(&remote_id))
 400            .cloned()
 401    }
 402
 403    #[cfg(any(test, feature = "test-support"))]
 404    pub fn has_buffered_operations(&self) -> bool {
 405        self.buffers_state
 406            .borrow()
 407            .open_buffers
 408            .values()
 409            .any(|buffer| matches!(buffer, OpenBuffer::Loading(_)))
 410    }
 411
 412    #[cfg(any(test, feature = "test-support"))]
 413    pub fn languages(&self) -> &Arc<LanguageRegistry> {
 414        &self.languages
 415    }
 416
 417    pub fn fs(&self) -> &Arc<dyn Fs> {
 418        &self.fs
 419    }
 420
 421    fn set_remote_id(&mut self, remote_id: Option<u64>, cx: &mut ModelContext<Self>) {
 422        if let ProjectClientState::Local { remote_id_tx, .. } = &mut self.client_state {
 423            *remote_id_tx.borrow_mut() = remote_id;
 424        }
 425
 426        self.subscriptions.clear();
 427        if let Some(remote_id) = remote_id {
 428            self.subscriptions
 429                .push(self.client.add_model_for_remote_entity(remote_id, cx));
 430        }
 431    }
 432
 433    pub fn remote_id(&self) -> Option<u64> {
 434        match &self.client_state {
 435            ProjectClientState::Local { remote_id_rx, .. } => *remote_id_rx.borrow(),
 436            ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
 437        }
 438    }
 439
 440    pub fn next_remote_id(&self) -> impl Future<Output = u64> {
 441        let mut id = None;
 442        let mut watch = None;
 443        match &self.client_state {
 444            ProjectClientState::Local { remote_id_rx, .. } => watch = Some(remote_id_rx.clone()),
 445            ProjectClientState::Remote { remote_id, .. } => id = Some(*remote_id),
 446        }
 447
 448        async move {
 449            if let Some(id) = id {
 450                return id;
 451            }
 452            let mut watch = watch.unwrap();
 453            loop {
 454                let id = *watch.borrow();
 455                if let Some(id) = id {
 456                    return id;
 457                }
 458                watch.recv().await;
 459            }
 460        }
 461    }
 462
 463    pub fn replica_id(&self) -> ReplicaId {
 464        match &self.client_state {
 465            ProjectClientState::Local { .. } => 0,
 466            ProjectClientState::Remote { replica_id, .. } => *replica_id,
 467        }
 468    }
 469
 470    pub fn collaborators(&self) -> &HashMap<PeerId, Collaborator> {
 471        &self.collaborators
 472    }
 473
 474    pub fn worktrees<'a>(
 475        &'a self,
 476        cx: &'a AppContext,
 477    ) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
 478        self.worktrees
 479            .iter()
 480            .filter_map(move |worktree| worktree.upgrade(cx))
 481    }
 482
 483    pub fn strong_worktrees<'a>(
 484        &'a self,
 485        cx: &'a AppContext,
 486    ) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
 487        self.worktrees.iter().filter_map(|worktree| {
 488            worktree.upgrade(cx).and_then(|worktree| {
 489                if worktree.read(cx).is_weak() {
 490                    None
 491                } else {
 492                    Some(worktree)
 493                }
 494            })
 495        })
 496    }
 497
 498    pub fn worktree_for_id(
 499        &self,
 500        id: WorktreeId,
 501        cx: &AppContext,
 502    ) -> Option<ModelHandle<Worktree>> {
 503        self.worktrees(cx)
 504            .find(|worktree| worktree.read(cx).id() == id)
 505    }
 506
 507    pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 508        let rpc = self.client.clone();
 509        cx.spawn(|this, mut cx| async move {
 510            let project_id = this.update(&mut cx, |this, _| {
 511                if let ProjectClientState::Local {
 512                    is_shared,
 513                    remote_id_rx,
 514                    ..
 515                } = &mut this.client_state
 516                {
 517                    *is_shared = true;
 518                    remote_id_rx
 519                        .borrow()
 520                        .ok_or_else(|| anyhow!("no project id"))
 521                } else {
 522                    Err(anyhow!("can't share a remote project"))
 523                }
 524            })?;
 525
 526            rpc.request(proto::ShareProject { project_id }).await?;
 527            let mut tasks = Vec::new();
 528            this.update(&mut cx, |this, cx| {
 529                for worktree in this.worktrees(cx).collect::<Vec<_>>() {
 530                    worktree.update(cx, |worktree, cx| {
 531                        let worktree = worktree.as_local_mut().unwrap();
 532                        tasks.push(worktree.share(project_id, cx));
 533                    });
 534                }
 535            });
 536            for task in tasks {
 537                task.await?;
 538            }
 539            this.update(&mut cx, |_, cx| cx.notify());
 540            Ok(())
 541        })
 542    }
 543
 544    pub fn unshare(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 545        let rpc = self.client.clone();
 546        cx.spawn(|this, mut cx| async move {
 547            let project_id = this.update(&mut cx, |this, _| {
 548                if let ProjectClientState::Local {
 549                    is_shared,
 550                    remote_id_rx,
 551                    ..
 552                } = &mut this.client_state
 553                {
 554                    *is_shared = false;
 555                    remote_id_rx
 556                        .borrow()
 557                        .ok_or_else(|| anyhow!("no project id"))
 558                } else {
 559                    Err(anyhow!("can't share a remote project"))
 560                }
 561            })?;
 562
 563            rpc.send(proto::UnshareProject { project_id })?;
 564            this.update(&mut cx, |this, cx| {
 565                this.collaborators.clear();
 566                this.shared_buffers.clear();
 567                for worktree in this.worktrees(cx).collect::<Vec<_>>() {
 568                    worktree.update(cx, |worktree, _| {
 569                        worktree.as_local_mut().unwrap().unshare();
 570                    });
 571                }
 572                cx.notify()
 573            });
 574            Ok(())
 575        })
 576    }
 577
 578    pub fn is_read_only(&self) -> bool {
 579        match &self.client_state {
 580            ProjectClientState::Local { .. } => false,
 581            ProjectClientState::Remote {
 582                sharing_has_stopped,
 583                ..
 584            } => *sharing_has_stopped,
 585        }
 586    }
 587
 588    pub fn is_local(&self) -> bool {
 589        match &self.client_state {
 590            ProjectClientState::Local { .. } => true,
 591            ProjectClientState::Remote { .. } => false,
 592        }
 593    }
 594
 595    pub fn is_remote(&self) -> bool {
 596        !self.is_local()
 597    }
 598
 599    pub fn open_buffer(
 600        &mut self,
 601        path: impl Into<ProjectPath>,
 602        cx: &mut ModelContext<Self>,
 603    ) -> Task<Result<ModelHandle<Buffer>>> {
 604        let project_path = path.into();
 605        let worktree = if let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) {
 606            worktree
 607        } else {
 608            return Task::ready(Err(anyhow!("no such worktree")));
 609        };
 610
 611        // If there is already a buffer for the given path, then return it.
 612        let existing_buffer = self.get_open_buffer(&project_path, cx);
 613        if let Some(existing_buffer) = existing_buffer {
 614            return Task::ready(Ok(existing_buffer));
 615        }
 616
 617        let mut loading_watch = match self.loading_buffers.entry(project_path.clone()) {
 618            // If the given path is already being loaded, then wait for that existing
 619            // task to complete and return the same buffer.
 620            hash_map::Entry::Occupied(e) => e.get().clone(),
 621
 622            // Otherwise, record the fact that this path is now being loaded.
 623            hash_map::Entry::Vacant(entry) => {
 624                let (mut tx, rx) = postage::watch::channel();
 625                entry.insert(rx.clone());
 626
 627                let load_buffer = if worktree.read(cx).is_local() {
 628                    self.open_local_buffer(&project_path.path, &worktree, cx)
 629                } else {
 630                    self.open_remote_buffer(&project_path.path, &worktree, cx)
 631                };
 632
 633                cx.spawn(move |this, mut cx| async move {
 634                    let load_result = load_buffer.await;
 635                    *tx.borrow_mut() = Some(this.update(&mut cx, |this, _| {
 636                        // Record the fact that the buffer is no longer loading.
 637                        this.loading_buffers.remove(&project_path);
 638                        let buffer = load_result.map_err(Arc::new)?;
 639                        Ok(buffer)
 640                    }));
 641                })
 642                .detach();
 643                rx
 644            }
 645        };
 646
 647        cx.foreground().spawn(async move {
 648            loop {
 649                if let Some(result) = loading_watch.borrow().as_ref() {
 650                    match result {
 651                        Ok(buffer) => return Ok(buffer.clone()),
 652                        Err(error) => return Err(anyhow!("{}", error)),
 653                    }
 654                }
 655                loading_watch.recv().await;
 656            }
 657        })
 658    }
 659
 660    fn open_local_buffer(
 661        &mut self,
 662        path: &Arc<Path>,
 663        worktree: &ModelHandle<Worktree>,
 664        cx: &mut ModelContext<Self>,
 665    ) -> Task<Result<ModelHandle<Buffer>>> {
 666        let load_buffer = worktree.update(cx, |worktree, cx| {
 667            let worktree = worktree.as_local_mut().unwrap();
 668            worktree.load_buffer(path, cx)
 669        });
 670        let worktree = worktree.downgrade();
 671        cx.spawn(|this, mut cx| async move {
 672            let buffer = load_buffer.await?;
 673            let worktree = worktree
 674                .upgrade(&cx)
 675                .ok_or_else(|| anyhow!("worktree was removed"))?;
 676            this.update(&mut cx, |this, cx| {
 677                this.register_buffer(&buffer, Some(&worktree), cx)
 678            })?;
 679            Ok(buffer)
 680        })
 681    }
 682
 683    fn open_remote_buffer(
 684        &mut self,
 685        path: &Arc<Path>,
 686        worktree: &ModelHandle<Worktree>,
 687        cx: &mut ModelContext<Self>,
 688    ) -> Task<Result<ModelHandle<Buffer>>> {
 689        let rpc = self.client.clone();
 690        let project_id = self.remote_id().unwrap();
 691        let remote_worktree_id = worktree.read(cx).id();
 692        let path = path.clone();
 693        let path_string = path.to_string_lossy().to_string();
 694        let request_handle = self.start_buffer_request(cx);
 695        cx.spawn(|this, mut cx| async move {
 696            let response = rpc
 697                .request(proto::OpenBuffer {
 698                    project_id,
 699                    worktree_id: remote_worktree_id.to_proto(),
 700                    path: path_string,
 701                })
 702                .await?;
 703            let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
 704
 705            this.update(&mut cx, |this, cx| {
 706                this.deserialize_buffer(buffer, request_handle, cx)
 707            })
 708            .await
 709        })
 710    }
 711
 712    fn open_local_buffer_via_lsp(
 713        &mut self,
 714        abs_path: lsp::Url,
 715        lang_name: String,
 716        lang_server: Arc<LanguageServer>,
 717        cx: &mut ModelContext<Self>,
 718    ) -> Task<Result<ModelHandle<Buffer>>> {
 719        cx.spawn(|this, mut cx| async move {
 720            let abs_path = abs_path
 721                .to_file_path()
 722                .map_err(|_| anyhow!("can't convert URI to path"))?;
 723            let (worktree, relative_path) = if let Some(result) =
 724                this.read_with(&cx, |this, cx| this.find_local_worktree(&abs_path, cx))
 725            {
 726                result
 727            } else {
 728                let worktree = this
 729                    .update(&mut cx, |this, cx| {
 730                        this.create_local_worktree(&abs_path, true, cx)
 731                    })
 732                    .await?;
 733                this.update(&mut cx, |this, cx| {
 734                    this.language_servers
 735                        .insert((worktree.read(cx).id(), lang_name), lang_server);
 736                });
 737                (worktree, PathBuf::new())
 738            };
 739
 740            let project_path = ProjectPath {
 741                worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()),
 742                path: relative_path.into(),
 743            };
 744            this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
 745                .await
 746        })
 747    }
 748
 749    fn start_buffer_request(&self, cx: &AppContext) -> BufferRequestHandle {
 750        BufferRequestHandle::new(self.buffers_state.clone(), cx)
 751    }
 752
 753    pub fn save_buffer_as(
 754        &self,
 755        buffer: ModelHandle<Buffer>,
 756        abs_path: PathBuf,
 757        cx: &mut ModelContext<Project>,
 758    ) -> Task<Result<()>> {
 759        let worktree_task = self.find_or_create_local_worktree(&abs_path, false, cx);
 760        cx.spawn(|this, mut cx| async move {
 761            let (worktree, path) = worktree_task.await?;
 762            worktree
 763                .update(&mut cx, |worktree, cx| {
 764                    worktree
 765                        .as_local_mut()
 766                        .unwrap()
 767                        .save_buffer_as(buffer.clone(), path, cx)
 768                })
 769                .await?;
 770            this.update(&mut cx, |this, cx| {
 771                this.assign_language_to_buffer(&buffer, Some(&worktree), cx);
 772            });
 773            Ok(())
 774        })
 775    }
 776
 777    #[cfg(any(test, feature = "test-support"))]
 778    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
 779        let path = path.into();
 780        if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
 781            self.buffers_state
 782                .borrow()
 783                .open_buffers
 784                .iter()
 785                .any(|(_, buffer)| {
 786                    if let Some(buffer) = buffer.upgrade(cx) {
 787                        if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
 788                            if file.worktree == worktree && file.path() == &path.path {
 789                                return true;
 790                            }
 791                        }
 792                    }
 793                    false
 794                })
 795        } else {
 796            false
 797        }
 798    }
 799
 800    pub fn get_open_buffer(
 801        &mut self,
 802        path: &ProjectPath,
 803        cx: &mut ModelContext<Self>,
 804    ) -> Option<ModelHandle<Buffer>> {
 805        let mut result = None;
 806        let worktree = self.worktree_for_id(path.worktree_id, cx)?;
 807        self.buffers_state
 808            .borrow_mut()
 809            .open_buffers
 810            .retain(|_, buffer| {
 811                if let Some(buffer) = buffer.upgrade(cx) {
 812                    if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
 813                        if file.worktree == worktree && file.path() == &path.path {
 814                            result = Some(buffer);
 815                        }
 816                    }
 817                    true
 818                } else {
 819                    false
 820                }
 821            });
 822        result
 823    }
 824
 825    fn register_buffer(
 826        &mut self,
 827        buffer: &ModelHandle<Buffer>,
 828        worktree: Option<&ModelHandle<Worktree>>,
 829        cx: &mut ModelContext<Self>,
 830    ) -> Result<()> {
 831        let remote_id = buffer.read(cx).remote_id();
 832        match self
 833            .buffers_state
 834            .borrow_mut()
 835            .open_buffers
 836            .insert(remote_id, OpenBuffer::Loaded(buffer.downgrade()))
 837        {
 838            None => {}
 839            Some(OpenBuffer::Loading(operations)) => {
 840                buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?
 841            }
 842            Some(OpenBuffer::Loaded(existing_handle)) => {
 843                if existing_handle.upgrade(cx).is_some() {
 844                    Err(anyhow!(
 845                        "already registered buffer with remote id {}",
 846                        remote_id
 847                    ))?
 848                }
 849            }
 850        }
 851        self.assign_language_to_buffer(&buffer, worktree, cx);
 852        Ok(())
 853    }
 854
 855    fn assign_language_to_buffer(
 856        &mut self,
 857        buffer: &ModelHandle<Buffer>,
 858        worktree: Option<&ModelHandle<Worktree>>,
 859        cx: &mut ModelContext<Self>,
 860    ) -> Option<()> {
 861        let (path, full_path) = {
 862            let file = buffer.read(cx).file()?;
 863            (file.path().clone(), file.full_path(cx))
 864        };
 865
 866        // If the buffer has a language, set it and start/assign the language server
 867        if let Some(language) = self.languages.select_language(&full_path) {
 868            buffer.update(cx, |buffer, cx| {
 869                buffer.set_language(Some(language.clone()), cx);
 870            });
 871
 872            // For local worktrees, start a language server if needed.
 873            // Also assign the language server and any previously stored diagnostics to the buffer.
 874            if let Some(local_worktree) = worktree.and_then(|w| w.read(cx).as_local()) {
 875                let worktree_id = local_worktree.id();
 876                let worktree_abs_path = local_worktree.abs_path().clone();
 877                let buffer = buffer.downgrade();
 878                let language_server =
 879                    self.start_language_server(worktree_id, worktree_abs_path, language, cx);
 880
 881                cx.spawn_weak(|_, mut cx| async move {
 882                    if let Some(language_server) = language_server.await {
 883                        if let Some(buffer) = buffer.upgrade(&cx) {
 884                            buffer.update(&mut cx, |buffer, cx| {
 885                                buffer.set_language_server(Some(language_server), cx);
 886                            });
 887                        }
 888                    }
 889                })
 890                .detach();
 891            }
 892        }
 893
 894        if let Some(local_worktree) = worktree.and_then(|w| w.read(cx).as_local()) {
 895            if let Some(diagnostics) = local_worktree.diagnostics_for_path(&path) {
 896                buffer.update(cx, |buffer, cx| {
 897                    buffer.update_diagnostics(diagnostics, None, cx).log_err();
 898                });
 899            }
 900        }
 901
 902        None
 903    }
 904
 905    fn start_language_server(
 906        &mut self,
 907        worktree_id: WorktreeId,
 908        worktree_path: Arc<Path>,
 909        language: Arc<Language>,
 910        cx: &mut ModelContext<Self>,
 911    ) -> Shared<Task<Option<Arc<LanguageServer>>>> {
 912        enum LspEvent {
 913            DiagnosticsStart,
 914            DiagnosticsUpdate(lsp::PublishDiagnosticsParams),
 915            DiagnosticsFinish,
 916        }
 917
 918        let key = (worktree_id, language.name().to_string());
 919        self.started_language_servers
 920            .entry(key.clone())
 921            .or_insert_with(|| {
 922                let language_server = self.languages.start_language_server(
 923                    &language,
 924                    worktree_path,
 925                    self.client.http_client(),
 926                    cx,
 927                );
 928                let rpc = self.client.clone();
 929                cx.spawn_weak(|this, mut cx| async move {
 930                    let language_server = language_server?.await.log_err()?;
 931                    if let Some(this) = this.upgrade(&cx) {
 932                        this.update(&mut cx, |this, _| {
 933                            this.language_servers.insert(key, language_server.clone());
 934                        });
 935                    }
 936
 937                    let disk_based_sources = language
 938                        .disk_based_diagnostic_sources()
 939                        .cloned()
 940                        .unwrap_or_default();
 941                    let disk_based_diagnostics_progress_token =
 942                        language.disk_based_diagnostics_progress_token().cloned();
 943                    let has_disk_based_diagnostic_progress_token =
 944                        disk_based_diagnostics_progress_token.is_some();
 945                    let (diagnostics_tx, diagnostics_rx) = smol::channel::unbounded();
 946
 947                    // Listen for `PublishDiagnostics` notifications.
 948                    language_server
 949                        .on_notification::<lsp::notification::PublishDiagnostics, _>({
 950                            let diagnostics_tx = diagnostics_tx.clone();
 951                            move |params| {
 952                                if !has_disk_based_diagnostic_progress_token {
 953                                    block_on(diagnostics_tx.send(LspEvent::DiagnosticsStart)).ok();
 954                                }
 955                                block_on(diagnostics_tx.send(LspEvent::DiagnosticsUpdate(params)))
 956                                    .ok();
 957                                if !has_disk_based_diagnostic_progress_token {
 958                                    block_on(diagnostics_tx.send(LspEvent::DiagnosticsFinish)).ok();
 959                                }
 960                            }
 961                        })
 962                        .detach();
 963
 964                    // Listen for `Progress` notifications. Send an event when the language server
 965                    // transitions between running jobs and not running any jobs.
 966                    let mut running_jobs_for_this_server: i32 = 0;
 967                    language_server
 968                        .on_notification::<lsp::notification::Progress, _>(move |params| {
 969                            let token = match params.token {
 970                                lsp::NumberOrString::Number(_) => None,
 971                                lsp::NumberOrString::String(token) => Some(token),
 972                            };
 973
 974                            if token == disk_based_diagnostics_progress_token {
 975                                match params.value {
 976                                    lsp::ProgressParamsValue::WorkDone(progress) => {
 977                                        match progress {
 978                                            lsp::WorkDoneProgress::Begin(_) => {
 979                                                running_jobs_for_this_server += 1;
 980                                                if running_jobs_for_this_server == 1 {
 981                                                    block_on(
 982                                                        diagnostics_tx
 983                                                            .send(LspEvent::DiagnosticsStart),
 984                                                    )
 985                                                    .ok();
 986                                                }
 987                                            }
 988                                            lsp::WorkDoneProgress::End(_) => {
 989                                                running_jobs_for_this_server -= 1;
 990                                                if running_jobs_for_this_server == 0 {
 991                                                    block_on(
 992                                                        diagnostics_tx
 993                                                            .send(LspEvent::DiagnosticsFinish),
 994                                                    )
 995                                                    .ok();
 996                                                }
 997                                            }
 998                                            _ => {}
 999                                        }
1000                                    }
1001                                }
1002                            }
1003                        })
1004                        .detach();
1005
1006                    // Process all the LSP events.
1007                    cx.spawn(|mut cx| async move {
1008                        while let Ok(message) = diagnostics_rx.recv().await {
1009                            let this = this.upgrade(&cx)?;
1010                            match message {
1011                                LspEvent::DiagnosticsStart => {
1012                                    this.update(&mut cx, |this, cx| {
1013                                        this.disk_based_diagnostics_started(cx);
1014                                        if let Some(project_id) = this.remote_id() {
1015                                            rpc.send(proto::DiskBasedDiagnosticsUpdating {
1016                                                project_id,
1017                                            })
1018                                            .log_err();
1019                                        }
1020                                    });
1021                                }
1022                                LspEvent::DiagnosticsUpdate(mut params) => {
1023                                    language.process_diagnostics(&mut params);
1024                                    this.update(&mut cx, |this, cx| {
1025                                        this.update_diagnostics(params, &disk_based_sources, cx)
1026                                            .log_err();
1027                                    });
1028                                }
1029                                LspEvent::DiagnosticsFinish => {
1030                                    this.update(&mut cx, |this, cx| {
1031                                        this.disk_based_diagnostics_finished(cx);
1032                                        if let Some(project_id) = this.remote_id() {
1033                                            rpc.send(proto::DiskBasedDiagnosticsUpdated {
1034                                                project_id,
1035                                            })
1036                                            .log_err();
1037                                        }
1038                                    });
1039                                }
1040                            }
1041                        }
1042                        Some(())
1043                    })
1044                    .detach();
1045
1046                    Some(language_server)
1047                })
1048                .shared()
1049            })
1050            .clone()
1051    }
1052
1053    pub fn update_diagnostics(
1054        &mut self,
1055        params: lsp::PublishDiagnosticsParams,
1056        disk_based_sources: &HashSet<String>,
1057        cx: &mut ModelContext<Self>,
1058    ) -> Result<()> {
1059        let abs_path = params
1060            .uri
1061            .to_file_path()
1062            .map_err(|_| anyhow!("URI is not a file"))?;
1063        let mut next_group_id = 0;
1064        let mut diagnostics = Vec::default();
1065        let mut primary_diagnostic_group_ids = HashMap::default();
1066        let mut sources_by_group_id = HashMap::default();
1067        let mut supporting_diagnostic_severities = HashMap::default();
1068        for diagnostic in &params.diagnostics {
1069            let source = diagnostic.source.as_ref();
1070            let code = diagnostic.code.as_ref().map(|code| match code {
1071                lsp::NumberOrString::Number(code) => code.to_string(),
1072                lsp::NumberOrString::String(code) => code.clone(),
1073            });
1074            let range = range_from_lsp(diagnostic.range);
1075            let is_supporting = diagnostic
1076                .related_information
1077                .as_ref()
1078                .map_or(false, |infos| {
1079                    infos.iter().any(|info| {
1080                        primary_diagnostic_group_ids.contains_key(&(
1081                            source,
1082                            code.clone(),
1083                            range_from_lsp(info.location.range),
1084                        ))
1085                    })
1086                });
1087
1088            if is_supporting {
1089                if let Some(severity) = diagnostic.severity {
1090                    supporting_diagnostic_severities
1091                        .insert((source, code.clone(), range), severity);
1092                }
1093            } else {
1094                let group_id = post_inc(&mut next_group_id);
1095                let is_disk_based =
1096                    source.map_or(false, |source| disk_based_sources.contains(source));
1097
1098                sources_by_group_id.insert(group_id, source);
1099                primary_diagnostic_group_ids
1100                    .insert((source, code.clone(), range.clone()), group_id);
1101
1102                diagnostics.push(DiagnosticEntry {
1103                    range,
1104                    diagnostic: Diagnostic {
1105                        code: code.clone(),
1106                        severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
1107                        message: diagnostic.message.clone(),
1108                        group_id,
1109                        is_primary: true,
1110                        is_valid: true,
1111                        is_disk_based,
1112                    },
1113                });
1114                if let Some(infos) = &diagnostic.related_information {
1115                    for info in infos {
1116                        if info.location.uri == params.uri && !info.message.is_empty() {
1117                            let range = range_from_lsp(info.location.range);
1118                            diagnostics.push(DiagnosticEntry {
1119                                range,
1120                                diagnostic: Diagnostic {
1121                                    code: code.clone(),
1122                                    severity: DiagnosticSeverity::INFORMATION,
1123                                    message: info.message.clone(),
1124                                    group_id,
1125                                    is_primary: false,
1126                                    is_valid: true,
1127                                    is_disk_based,
1128                                },
1129                            });
1130                        }
1131                    }
1132                }
1133            }
1134        }
1135
1136        for entry in &mut diagnostics {
1137            let diagnostic = &mut entry.diagnostic;
1138            if !diagnostic.is_primary {
1139                let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
1140                if let Some(&severity) = supporting_diagnostic_severities.get(&(
1141                    source,
1142                    diagnostic.code.clone(),
1143                    entry.range.clone(),
1144                )) {
1145                    diagnostic.severity = severity;
1146                }
1147            }
1148        }
1149
1150        self.update_diagnostic_entries(abs_path, params.version, diagnostics, cx)?;
1151        Ok(())
1152    }
1153
1154    pub fn update_diagnostic_entries(
1155        &mut self,
1156        abs_path: PathBuf,
1157        version: Option<i32>,
1158        diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
1159        cx: &mut ModelContext<Project>,
1160    ) -> Result<(), anyhow::Error> {
1161        let (worktree, relative_path) = self
1162            .find_local_worktree(&abs_path, cx)
1163            .ok_or_else(|| anyhow!("no worktree found for diagnostics"))?;
1164        let project_path = ProjectPath {
1165            worktree_id: worktree.read(cx).id(),
1166            path: relative_path.into(),
1167        };
1168
1169        for buffer in self.buffers_state.borrow().open_buffers.values() {
1170            if let Some(buffer) = buffer.upgrade(cx) {
1171                if buffer
1172                    .read(cx)
1173                    .file()
1174                    .map_or(false, |file| *file.path() == project_path.path)
1175                {
1176                    buffer.update(cx, |buffer, cx| {
1177                        buffer.update_diagnostics(diagnostics.clone(), version, cx)
1178                    })?;
1179                    break;
1180                }
1181            }
1182        }
1183        worktree.update(cx, |worktree, cx| {
1184            worktree
1185                .as_local_mut()
1186                .ok_or_else(|| anyhow!("not a local worktree"))?
1187                .update_diagnostics(project_path.path.clone(), diagnostics, cx)
1188        })?;
1189        cx.emit(Event::DiagnosticsUpdated(project_path));
1190        Ok(())
1191    }
1192
1193    pub fn format(
1194        &self,
1195        buffers: HashSet<ModelHandle<Buffer>>,
1196        push_to_history: bool,
1197        cx: &mut ModelContext<Project>,
1198    ) -> Task<Result<ProjectTransaction>> {
1199        let mut local_buffers = Vec::new();
1200        let mut remote_buffers = None;
1201        for buffer_handle in buffers {
1202            let buffer = buffer_handle.read(cx);
1203            let worktree;
1204            if let Some(file) = File::from_dyn(buffer.file()) {
1205                worktree = file.worktree.clone();
1206                if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
1207                    let lang_server;
1208                    if let Some(lang) = buffer.language() {
1209                        if let Some(server) = self
1210                            .language_servers
1211                            .get(&(worktree.read(cx).id(), lang.name().to_string()))
1212                        {
1213                            lang_server = server.clone();
1214                        } else {
1215                            return Task::ready(Ok(Default::default()));
1216                        };
1217                    } else {
1218                        return Task::ready(Ok(Default::default()));
1219                    }
1220
1221                    local_buffers.push((buffer_handle, buffer_abs_path, lang_server));
1222                } else {
1223                    remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
1224                }
1225            } else {
1226                return Task::ready(Ok(Default::default()));
1227            }
1228        }
1229
1230        let remote_buffers = self.remote_id().zip(remote_buffers);
1231        let client = self.client.clone();
1232        let request_handle = self.start_buffer_request(cx);
1233
1234        cx.spawn(|this, mut cx| async move {
1235            let mut project_transaction = ProjectTransaction::default();
1236
1237            if let Some((project_id, remote_buffers)) = remote_buffers {
1238                let response = client
1239                    .request(proto::FormatBuffers {
1240                        project_id,
1241                        buffer_ids: remote_buffers
1242                            .iter()
1243                            .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
1244                            .collect(),
1245                    })
1246                    .await?
1247                    .transaction
1248                    .ok_or_else(|| anyhow!("missing transaction"))?;
1249                project_transaction = this
1250                    .update(&mut cx, |this, cx| {
1251                        this.deserialize_project_transaction(
1252                            response,
1253                            push_to_history,
1254                            request_handle,
1255                            cx,
1256                        )
1257                    })
1258                    .await?;
1259            }
1260
1261            for (buffer, buffer_abs_path, lang_server) in local_buffers {
1262                let lsp_edits = lang_server
1263                    .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1264                        text_document: lsp::TextDocumentIdentifier::new(
1265                            lsp::Url::from_file_path(&buffer_abs_path).unwrap(),
1266                        ),
1267                        options: Default::default(),
1268                        work_done_progress_params: Default::default(),
1269                    })
1270                    .await?;
1271
1272                if let Some(lsp_edits) = lsp_edits {
1273                    let edits = buffer
1274                        .update(&mut cx, |buffer, cx| {
1275                            buffer.edits_from_lsp(lsp_edits, None, cx)
1276                        })
1277                        .await?;
1278                    buffer.update(&mut cx, |buffer, cx| {
1279                        buffer.finalize_last_transaction();
1280                        buffer.start_transaction();
1281                        for (range, text) in edits {
1282                            buffer.edit([range], text, cx);
1283                        }
1284                        if buffer.end_transaction(cx).is_some() {
1285                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
1286                            if !push_to_history {
1287                                buffer.forget_transaction(transaction.id);
1288                            }
1289                            project_transaction.0.insert(cx.handle(), transaction);
1290                        }
1291                    });
1292                }
1293            }
1294
1295            Ok(project_transaction)
1296        })
1297    }
1298
1299    pub fn definition<T: ToPointUtf16>(
1300        &self,
1301        buffer: &ModelHandle<Buffer>,
1302        position: T,
1303        cx: &mut ModelContext<Self>,
1304    ) -> Task<Result<Vec<Location>>> {
1305        let position = position.to_point_utf16(buffer.read(cx));
1306        self.request_lsp(buffer.clone(), GetDefinition { position }, cx)
1307    }
1308
1309    pub fn references<T: ToPointUtf16>(
1310        &self,
1311        buffer: &ModelHandle<Buffer>,
1312        position: T,
1313        cx: &mut ModelContext<Self>,
1314    ) -> Task<Result<Vec<Location>>> {
1315        let position = position.to_point_utf16(buffer.read(cx));
1316        self.request_lsp(buffer.clone(), GetReferences { position }, cx)
1317    }
1318
1319    pub fn document_highlights<T: ToPointUtf16>(
1320        &self,
1321        buffer: &ModelHandle<Buffer>,
1322        position: T,
1323        cx: &mut ModelContext<Self>,
1324    ) -> Task<Result<Vec<DocumentHighlight>>> {
1325        let position = position.to_point_utf16(buffer.read(cx));
1326        self.request_lsp(buffer.clone(), GetDocumentHighlights { position }, cx)
1327    }
1328
1329    pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
1330        if self.is_local() {
1331            let mut language_servers = HashMap::default();
1332            for ((worktree_id, language_name), language_server) in self.language_servers.iter() {
1333                if let Some((worktree, language)) = self
1334                    .worktree_for_id(*worktree_id, cx)
1335                    .and_then(|worktree| worktree.read(cx).as_local())
1336                    .zip(self.languages.get_language(language_name))
1337                {
1338                    language_servers
1339                        .entry(Arc::as_ptr(language_server))
1340                        .or_insert((
1341                            language_server.clone(),
1342                            *worktree_id,
1343                            worktree.abs_path().clone(),
1344                            language.clone(),
1345                        ));
1346                }
1347            }
1348
1349            let mut requests = Vec::new();
1350            for (language_server, _, _, _) in language_servers.values() {
1351                requests.push(language_server.request::<lsp::request::WorkspaceSymbol>(
1352                    lsp::WorkspaceSymbolParams {
1353                        query: query.to_string(),
1354                        ..Default::default()
1355                    },
1356                ));
1357            }
1358
1359            cx.spawn_weak(|this, cx| async move {
1360                let responses = futures::future::try_join_all(requests).await?;
1361
1362                let mut symbols = Vec::new();
1363                if let Some(this) = this.upgrade(&cx) {
1364                    this.read_with(&cx, |this, cx| {
1365                        for ((_, source_worktree_id, worktree_abs_path, language), lsp_symbols) in
1366                            language_servers.into_values().zip(responses)
1367                        {
1368                            symbols.extend(lsp_symbols.into_iter().flatten().filter_map(
1369                                |lsp_symbol| {
1370                                    let abs_path = lsp_symbol.location.uri.to_file_path().ok()?;
1371                                    let mut worktree_id = source_worktree_id;
1372                                    let path;
1373                                    if let Some((worktree, rel_path)) =
1374                                        this.find_local_worktree(&abs_path, cx)
1375                                    {
1376                                        worktree_id = worktree.read(cx).id();
1377                                        path = rel_path;
1378                                    } else {
1379                                        path = relativize_path(&worktree_abs_path, &abs_path);
1380                                    }
1381
1382                                    let label = language
1383                                        .label_for_symbol(&lsp_symbol.name, lsp_symbol.kind)
1384                                        .unwrap_or_else(|| {
1385                                            CodeLabel::plain(lsp_symbol.name.clone(), None)
1386                                        });
1387                                    let signature = this.symbol_signature(worktree_id, &path);
1388
1389                                    Some(Symbol {
1390                                        source_worktree_id,
1391                                        worktree_id,
1392                                        language_name: language.name().to_string(),
1393                                        name: lsp_symbol.name,
1394                                        kind: lsp_symbol.kind,
1395                                        label,
1396                                        path,
1397                                        range: range_from_lsp(lsp_symbol.location.range),
1398                                        signature,
1399                                    })
1400                                },
1401                            ));
1402                        }
1403                    })
1404                }
1405
1406                Ok(symbols)
1407            })
1408        } else if let Some(project_id) = self.remote_id() {
1409            let request = self.client.request(proto::GetProjectSymbols {
1410                project_id,
1411                query: query.to_string(),
1412            });
1413            cx.spawn_weak(|this, cx| async move {
1414                let response = request.await?;
1415                let mut symbols = Vec::new();
1416                if let Some(this) = this.upgrade(&cx) {
1417                    this.read_with(&cx, |this, _| {
1418                        symbols.extend(
1419                            response
1420                                .symbols
1421                                .into_iter()
1422                                .filter_map(|symbol| this.deserialize_symbol(symbol).log_err()),
1423                        );
1424                    })
1425                }
1426                Ok(symbols)
1427            })
1428        } else {
1429            Task::ready(Ok(Default::default()))
1430        }
1431    }
1432
1433    pub fn open_buffer_for_symbol(
1434        &mut self,
1435        symbol: &Symbol,
1436        cx: &mut ModelContext<Self>,
1437    ) -> Task<Result<ModelHandle<Buffer>>> {
1438        if self.is_local() {
1439            let language_server = if let Some(server) = self
1440                .language_servers
1441                .get(&(symbol.source_worktree_id, symbol.language_name.clone()))
1442            {
1443                server.clone()
1444            } else {
1445                return Task::ready(Err(anyhow!(
1446                    "language server for worktree and language not found"
1447                )));
1448            };
1449
1450            let worktree_abs_path = if let Some(worktree_abs_path) = self
1451                .worktree_for_id(symbol.worktree_id, cx)
1452                .and_then(|worktree| worktree.read(cx).as_local())
1453                .map(|local_worktree| local_worktree.abs_path())
1454            {
1455                worktree_abs_path
1456            } else {
1457                return Task::ready(Err(anyhow!("worktree not found for symbol")));
1458            };
1459            let symbol_abs_path = worktree_abs_path.join(&symbol.path);
1460            let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
1461                uri
1462            } else {
1463                return Task::ready(Err(anyhow!("invalid symbol path")));
1464            };
1465
1466            self.open_local_buffer_via_lsp(
1467                symbol_uri,
1468                symbol.language_name.clone(),
1469                language_server,
1470                cx,
1471            )
1472        } else if let Some(project_id) = self.remote_id() {
1473            let request_handle = self.start_buffer_request(cx);
1474            let request = self.client.request(proto::OpenBufferForSymbol {
1475                project_id,
1476                symbol: Some(serialize_symbol(symbol)),
1477            });
1478            cx.spawn(|this, mut cx| async move {
1479                let response = request.await?;
1480                let buffer = response.buffer.ok_or_else(|| anyhow!("invalid buffer"))?;
1481                this.update(&mut cx, |this, cx| {
1482                    this.deserialize_buffer(buffer, request_handle, cx)
1483                })
1484                .await
1485            })
1486        } else {
1487            Task::ready(Err(anyhow!("project does not have a remote id")))
1488        }
1489    }
1490
1491    pub fn completions<T: ToPointUtf16>(
1492        &self,
1493        source_buffer_handle: &ModelHandle<Buffer>,
1494        position: T,
1495        cx: &mut ModelContext<Self>,
1496    ) -> Task<Result<Vec<Completion>>> {
1497        let source_buffer_handle = source_buffer_handle.clone();
1498        let source_buffer = source_buffer_handle.read(cx);
1499        let buffer_id = source_buffer.remote_id();
1500        let language = source_buffer.language().cloned();
1501        let worktree;
1502        let buffer_abs_path;
1503        if let Some(file) = File::from_dyn(source_buffer.file()) {
1504            worktree = file.worktree.clone();
1505            buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
1506        } else {
1507            return Task::ready(Ok(Default::default()));
1508        };
1509
1510        let position = position.to_point_utf16(source_buffer);
1511        let anchor = source_buffer.anchor_after(position);
1512
1513        if worktree.read(cx).as_local().is_some() {
1514            let buffer_abs_path = buffer_abs_path.unwrap();
1515            let lang_server = if let Some(server) = source_buffer.language_server().cloned() {
1516                server
1517            } else {
1518                return Task::ready(Ok(Default::default()));
1519            };
1520
1521            cx.spawn(|_, cx| async move {
1522                let completions = lang_server
1523                    .request::<lsp::request::Completion>(lsp::CompletionParams {
1524                        text_document_position: lsp::TextDocumentPositionParams::new(
1525                            lsp::TextDocumentIdentifier::new(
1526                                lsp::Url::from_file_path(buffer_abs_path).unwrap(),
1527                            ),
1528                            position.to_lsp_position(),
1529                        ),
1530                        context: Default::default(),
1531                        work_done_progress_params: Default::default(),
1532                        partial_result_params: Default::default(),
1533                    })
1534                    .await
1535                    .context("lsp completion request failed")?;
1536
1537                let completions = if let Some(completions) = completions {
1538                    match completions {
1539                        lsp::CompletionResponse::Array(completions) => completions,
1540                        lsp::CompletionResponse::List(list) => list.items,
1541                    }
1542                } else {
1543                    Default::default()
1544                };
1545
1546                source_buffer_handle.read_with(&cx, |this, _| {
1547                    Ok(completions
1548                        .into_iter()
1549                        .filter_map(|lsp_completion| {
1550                            let (old_range, new_text) = match lsp_completion.text_edit.as_ref()? {
1551                                lsp::CompletionTextEdit::Edit(edit) => {
1552                                    (range_from_lsp(edit.range), edit.new_text.clone())
1553                                }
1554                                lsp::CompletionTextEdit::InsertAndReplace(_) => {
1555                                    log::info!("unsupported insert/replace completion");
1556                                    return None;
1557                                }
1558                            };
1559
1560                            let clipped_start = this.clip_point_utf16(old_range.start, Bias::Left);
1561                            let clipped_end = this.clip_point_utf16(old_range.end, Bias::Left);
1562                            if clipped_start == old_range.start && clipped_end == old_range.end {
1563                                Some(Completion {
1564                                    old_range: this.anchor_before(old_range.start)
1565                                        ..this.anchor_after(old_range.end),
1566                                    new_text,
1567                                    label: language
1568                                        .as_ref()
1569                                        .and_then(|l| l.label_for_completion(&lsp_completion))
1570                                        .unwrap_or_else(|| {
1571                                            CodeLabel::plain(
1572                                                lsp_completion.label.clone(),
1573                                                lsp_completion.filter_text.as_deref(),
1574                                            )
1575                                        }),
1576                                    lsp_completion,
1577                                })
1578                            } else {
1579                                None
1580                            }
1581                        })
1582                        .collect())
1583                })
1584            })
1585        } else if let Some(project_id) = self.remote_id() {
1586            let rpc = self.client.clone();
1587            let message = proto::GetCompletions {
1588                project_id,
1589                buffer_id,
1590                position: Some(language::proto::serialize_anchor(&anchor)),
1591                version: (&source_buffer.version()).into(),
1592            };
1593            cx.spawn_weak(|_, mut cx| async move {
1594                let response = rpc.request(message).await?;
1595
1596                source_buffer_handle
1597                    .update(&mut cx, |buffer, _| {
1598                        buffer.wait_for_version(response.version.into())
1599                    })
1600                    .await;
1601
1602                response
1603                    .completions
1604                    .into_iter()
1605                    .map(|completion| {
1606                        language::proto::deserialize_completion(completion, language.as_ref())
1607                    })
1608                    .collect()
1609            })
1610        } else {
1611            Task::ready(Ok(Default::default()))
1612        }
1613    }
1614
1615    pub fn apply_additional_edits_for_completion(
1616        &self,
1617        buffer_handle: ModelHandle<Buffer>,
1618        completion: Completion,
1619        push_to_history: bool,
1620        cx: &mut ModelContext<Self>,
1621    ) -> Task<Result<Option<Transaction>>> {
1622        let buffer = buffer_handle.read(cx);
1623        let buffer_id = buffer.remote_id();
1624
1625        if self.is_local() {
1626            let lang_server = if let Some(language_server) = buffer.language_server() {
1627                language_server.clone()
1628            } else {
1629                return Task::ready(Err(anyhow!("buffer does not have a language server")));
1630            };
1631
1632            cx.spawn(|_, mut cx| async move {
1633                let resolved_completion = lang_server
1634                    .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
1635                    .await?;
1636                if let Some(edits) = resolved_completion.additional_text_edits {
1637                    let edits = buffer_handle
1638                        .update(&mut cx, |buffer, cx| buffer.edits_from_lsp(edits, None, cx))
1639                        .await?;
1640                    buffer_handle.update(&mut cx, |buffer, cx| {
1641                        buffer.finalize_last_transaction();
1642                        buffer.start_transaction();
1643                        for (range, text) in edits {
1644                            buffer.edit([range], text, cx);
1645                        }
1646                        let transaction = if buffer.end_transaction(cx).is_some() {
1647                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
1648                            if !push_to_history {
1649                                buffer.forget_transaction(transaction.id);
1650                            }
1651                            Some(transaction)
1652                        } else {
1653                            None
1654                        };
1655                        Ok(transaction)
1656                    })
1657                } else {
1658                    Ok(None)
1659                }
1660            })
1661        } else if let Some(project_id) = self.remote_id() {
1662            let client = self.client.clone();
1663            cx.spawn(|_, mut cx| async move {
1664                let response = client
1665                    .request(proto::ApplyCompletionAdditionalEdits {
1666                        project_id,
1667                        buffer_id,
1668                        completion: Some(language::proto::serialize_completion(&completion)),
1669                    })
1670                    .await?;
1671
1672                if let Some(transaction) = response.transaction {
1673                    let transaction = language::proto::deserialize_transaction(transaction)?;
1674                    buffer_handle
1675                        .update(&mut cx, |buffer, _| {
1676                            buffer.wait_for_edits(transaction.edit_ids.iter().copied())
1677                        })
1678                        .await;
1679                    if push_to_history {
1680                        buffer_handle.update(&mut cx, |buffer, _| {
1681                            buffer.push_transaction(transaction.clone(), Instant::now());
1682                        });
1683                    }
1684                    Ok(Some(transaction))
1685                } else {
1686                    Ok(None)
1687                }
1688            })
1689        } else {
1690            Task::ready(Err(anyhow!("project does not have a remote id")))
1691        }
1692    }
1693
1694    pub fn code_actions<T: ToOffset>(
1695        &self,
1696        buffer_handle: &ModelHandle<Buffer>,
1697        range: Range<T>,
1698        cx: &mut ModelContext<Self>,
1699    ) -> Task<Result<Vec<CodeAction>>> {
1700        let buffer_handle = buffer_handle.clone();
1701        let buffer = buffer_handle.read(cx);
1702        let buffer_id = buffer.remote_id();
1703        let worktree;
1704        let buffer_abs_path;
1705        if let Some(file) = File::from_dyn(buffer.file()) {
1706            worktree = file.worktree.clone();
1707            buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
1708        } else {
1709            return Task::ready(Ok(Default::default()));
1710        };
1711        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
1712
1713        if worktree.read(cx).as_local().is_some() {
1714            let buffer_abs_path = buffer_abs_path.unwrap();
1715            let lang_name;
1716            let lang_server;
1717            if let Some(lang) = buffer.language() {
1718                lang_name = lang.name().to_string();
1719                if let Some(server) = self
1720                    .language_servers
1721                    .get(&(worktree.read(cx).id(), lang_name.clone()))
1722                {
1723                    lang_server = server.clone();
1724                } else {
1725                    return Task::ready(Ok(Default::default()));
1726                };
1727            } else {
1728                return Task::ready(Ok(Default::default()));
1729            }
1730
1731            let lsp_range = lsp::Range::new(
1732                range.start.to_point_utf16(buffer).to_lsp_position(),
1733                range.end.to_point_utf16(buffer).to_lsp_position(),
1734            );
1735            cx.foreground().spawn(async move {
1736                Ok(lang_server
1737                    .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
1738                        text_document: lsp::TextDocumentIdentifier::new(
1739                            lsp::Url::from_file_path(buffer_abs_path).unwrap(),
1740                        ),
1741                        range: lsp_range,
1742                        work_done_progress_params: Default::default(),
1743                        partial_result_params: Default::default(),
1744                        context: lsp::CodeActionContext {
1745                            diagnostics: Default::default(),
1746                            only: Some(vec![
1747                                lsp::CodeActionKind::QUICKFIX,
1748                                lsp::CodeActionKind::REFACTOR,
1749                                lsp::CodeActionKind::REFACTOR_EXTRACT,
1750                            ]),
1751                        },
1752                    })
1753                    .await?
1754                    .unwrap_or_default()
1755                    .into_iter()
1756                    .filter_map(|entry| {
1757                        if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1758                            Some(CodeAction {
1759                                range: range.clone(),
1760                                lsp_action,
1761                            })
1762                        } else {
1763                            None
1764                        }
1765                    })
1766                    .collect())
1767            })
1768        } else if let Some(project_id) = self.remote_id() {
1769            let rpc = self.client.clone();
1770            cx.spawn_weak(|_, mut cx| async move {
1771                let response = rpc
1772                    .request(proto::GetCodeActions {
1773                        project_id,
1774                        buffer_id,
1775                        start: Some(language::proto::serialize_anchor(&range.start)),
1776                        end: Some(language::proto::serialize_anchor(&range.end)),
1777                    })
1778                    .await?;
1779
1780                buffer_handle
1781                    .update(&mut cx, |buffer, _| {
1782                        buffer.wait_for_version(response.version.into())
1783                    })
1784                    .await;
1785
1786                response
1787                    .actions
1788                    .into_iter()
1789                    .map(language::proto::deserialize_code_action)
1790                    .collect()
1791            })
1792        } else {
1793            Task::ready(Ok(Default::default()))
1794        }
1795    }
1796
1797    pub fn apply_code_action(
1798        &self,
1799        buffer_handle: ModelHandle<Buffer>,
1800        mut action: CodeAction,
1801        push_to_history: bool,
1802        cx: &mut ModelContext<Self>,
1803    ) -> Task<Result<ProjectTransaction>> {
1804        if self.is_local() {
1805            let buffer = buffer_handle.read(cx);
1806            let lang_name = if let Some(lang) = buffer.language() {
1807                lang.name().to_string()
1808            } else {
1809                return Task::ready(Ok(Default::default()));
1810            };
1811            let lang_server = if let Some(language_server) = buffer.language_server() {
1812                language_server.clone()
1813            } else {
1814                return Task::ready(Err(anyhow!("buffer does not have a language server")));
1815            };
1816            let range = action.range.to_point_utf16(buffer);
1817
1818            cx.spawn(|this, mut cx| async move {
1819                if let Some(lsp_range) = action
1820                    .lsp_action
1821                    .data
1822                    .as_mut()
1823                    .and_then(|d| d.get_mut("codeActionParams"))
1824                    .and_then(|d| d.get_mut("range"))
1825                {
1826                    *lsp_range = serde_json::to_value(&lsp::Range::new(
1827                        range.start.to_lsp_position(),
1828                        range.end.to_lsp_position(),
1829                    ))
1830                    .unwrap();
1831                    action.lsp_action = lang_server
1832                        .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
1833                        .await?;
1834                } else {
1835                    let actions = this
1836                        .update(&mut cx, |this, cx| {
1837                            this.code_actions(&buffer_handle, action.range, cx)
1838                        })
1839                        .await?;
1840                    action.lsp_action = actions
1841                        .into_iter()
1842                        .find(|a| a.lsp_action.title == action.lsp_action.title)
1843                        .ok_or_else(|| anyhow!("code action is outdated"))?
1844                        .lsp_action;
1845                }
1846
1847                if let Some(edit) = action.lsp_action.edit {
1848                    Self::deserialize_workspace_edit(
1849                        this,
1850                        edit,
1851                        push_to_history,
1852                        lang_name,
1853                        lang_server,
1854                        &mut cx,
1855                    )
1856                    .await
1857                } else {
1858                    Ok(ProjectTransaction::default())
1859                }
1860            })
1861        } else if let Some(project_id) = self.remote_id() {
1862            let client = self.client.clone();
1863            let request_handle = self.start_buffer_request(cx);
1864            let request = proto::ApplyCodeAction {
1865                project_id,
1866                buffer_id: buffer_handle.read(cx).remote_id(),
1867                action: Some(language::proto::serialize_code_action(&action)),
1868            };
1869            cx.spawn(|this, mut cx| async move {
1870                let response = client
1871                    .request(request)
1872                    .await?
1873                    .transaction
1874                    .ok_or_else(|| anyhow!("missing transaction"))?;
1875                this.update(&mut cx, |this, cx| {
1876                    this.deserialize_project_transaction(
1877                        response,
1878                        push_to_history,
1879                        request_handle,
1880                        cx,
1881                    )
1882                })
1883                .await
1884            })
1885        } else {
1886            Task::ready(Err(anyhow!("project does not have a remote id")))
1887        }
1888    }
1889
1890    async fn deserialize_workspace_edit(
1891        this: ModelHandle<Self>,
1892        edit: lsp::WorkspaceEdit,
1893        push_to_history: bool,
1894        language_name: String,
1895        language_server: Arc<LanguageServer>,
1896        cx: &mut AsyncAppContext,
1897    ) -> Result<ProjectTransaction> {
1898        let fs = this.read_with(cx, |this, _| this.fs.clone());
1899        let mut operations = Vec::new();
1900        if let Some(document_changes) = edit.document_changes {
1901            match document_changes {
1902                lsp::DocumentChanges::Edits(edits) => {
1903                    operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
1904                }
1905                lsp::DocumentChanges::Operations(ops) => operations = ops,
1906            }
1907        } else if let Some(changes) = edit.changes {
1908            operations.extend(changes.into_iter().map(|(uri, edits)| {
1909                lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1910                    text_document: lsp::OptionalVersionedTextDocumentIdentifier {
1911                        uri,
1912                        version: None,
1913                    },
1914                    edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
1915                })
1916            }));
1917        }
1918
1919        let mut project_transaction = ProjectTransaction::default();
1920        for operation in operations {
1921            match operation {
1922                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
1923                    let abs_path = op
1924                        .uri
1925                        .to_file_path()
1926                        .map_err(|_| anyhow!("can't convert URI to path"))?;
1927
1928                    if let Some(parent_path) = abs_path.parent() {
1929                        fs.create_dir(parent_path).await?;
1930                    }
1931                    if abs_path.ends_with("/") {
1932                        fs.create_dir(&abs_path).await?;
1933                    } else {
1934                        fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
1935                            .await?;
1936                    }
1937                }
1938                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
1939                    let source_abs_path = op
1940                        .old_uri
1941                        .to_file_path()
1942                        .map_err(|_| anyhow!("can't convert URI to path"))?;
1943                    let target_abs_path = op
1944                        .new_uri
1945                        .to_file_path()
1946                        .map_err(|_| anyhow!("can't convert URI to path"))?;
1947                    fs.rename(
1948                        &source_abs_path,
1949                        &target_abs_path,
1950                        op.options.map(Into::into).unwrap_or_default(),
1951                    )
1952                    .await?;
1953                }
1954                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
1955                    let abs_path = op
1956                        .uri
1957                        .to_file_path()
1958                        .map_err(|_| anyhow!("can't convert URI to path"))?;
1959                    let options = op.options.map(Into::into).unwrap_or_default();
1960                    if abs_path.ends_with("/") {
1961                        fs.remove_dir(&abs_path, options).await?;
1962                    } else {
1963                        fs.remove_file(&abs_path, options).await?;
1964                    }
1965                }
1966                lsp::DocumentChangeOperation::Edit(op) => {
1967                    let buffer_to_edit = this
1968                        .update(cx, |this, cx| {
1969                            this.open_local_buffer_via_lsp(
1970                                op.text_document.uri,
1971                                language_name.clone(),
1972                                language_server.clone(),
1973                                cx,
1974                            )
1975                        })
1976                        .await?;
1977
1978                    let edits = buffer_to_edit
1979                        .update(cx, |buffer, cx| {
1980                            let edits = op.edits.into_iter().map(|edit| match edit {
1981                                lsp::OneOf::Left(edit) => edit,
1982                                lsp::OneOf::Right(edit) => edit.text_edit,
1983                            });
1984                            buffer.edits_from_lsp(edits, op.text_document.version, cx)
1985                        })
1986                        .await?;
1987
1988                    let transaction = buffer_to_edit.update(cx, |buffer, cx| {
1989                        buffer.finalize_last_transaction();
1990                        buffer.start_transaction();
1991                        for (range, text) in edits {
1992                            buffer.edit([range], text, cx);
1993                        }
1994                        let transaction = if buffer.end_transaction(cx).is_some() {
1995                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
1996                            if !push_to_history {
1997                                buffer.forget_transaction(transaction.id);
1998                            }
1999                            Some(transaction)
2000                        } else {
2001                            None
2002                        };
2003
2004                        transaction
2005                    });
2006                    if let Some(transaction) = transaction {
2007                        project_transaction.0.insert(buffer_to_edit, transaction);
2008                    }
2009                }
2010            }
2011        }
2012
2013        Ok(project_transaction)
2014    }
2015
2016    pub fn prepare_rename<T: ToPointUtf16>(
2017        &self,
2018        buffer: ModelHandle<Buffer>,
2019        position: T,
2020        cx: &mut ModelContext<Self>,
2021    ) -> Task<Result<Option<Range<Anchor>>>> {
2022        let position = position.to_point_utf16(buffer.read(cx));
2023        self.request_lsp(buffer, PrepareRename { position }, cx)
2024    }
2025
2026    pub fn perform_rename<T: ToPointUtf16>(
2027        &self,
2028        buffer: ModelHandle<Buffer>,
2029        position: T,
2030        new_name: String,
2031        push_to_history: bool,
2032        cx: &mut ModelContext<Self>,
2033    ) -> Task<Result<ProjectTransaction>> {
2034        let position = position.to_point_utf16(buffer.read(cx));
2035        self.request_lsp(
2036            buffer,
2037            PerformRename {
2038                position,
2039                new_name,
2040                push_to_history,
2041            },
2042            cx,
2043        )
2044    }
2045
2046    pub fn search<T>(
2047        &self,
2048        query: SearchQuery,
2049        cx: &mut ModelContext<Self>,
2050    ) -> Task<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>
2051    where
2052        T: Matcher,
2053    {
2054        if self.is_local() {
2055            let (queue_tx, queue_rx) = smol::channel::bounded(1024);
2056
2057            // Submit all worktree paths to the queue.
2058            let snapshots = self
2059                .strong_worktrees(cx)
2060                .filter_map(|tree| {
2061                    let tree = tree.read(cx).as_local()?;
2062                    Some((tree.abs_path().clone(), tree.snapshot()))
2063                })
2064                .collect::<Vec<_>>();
2065            cx.background()
2066                .spawn({
2067                    let queue_tx = queue_tx.clone();
2068                    async move {
2069                        for (snapshot_abs_path, snapshot) in snapshots {
2070                            for file in snapshot.files(false, 0) {
2071                                if queue_tx
2072                                    .send((snapshot_abs_path.clone(), file.path.clone()))
2073                                    .await
2074                                    .is_err()
2075                                {
2076                                    return;
2077                                }
2078                            }
2079                        }
2080                    }
2081                })
2082                .detach();
2083
2084            let matcher = Arc::new(matcher);
2085            cx.background()
2086                .spawn({
2087                    let background = cx.background().clone();
2088                    let workers = background.num_cpus();
2089                    let searcher = searcher.clone();
2090                    let matcher = matcher.clone();
2091                    async move {
2092                        background
2093                            .scoped(|scope| {
2094                                for _ in 0..workers {
2095                                    let mut paths_rx = queue_rx.clone();
2096                                    scope.spawn(async move {
2097                                        let mut path = PathBuf::new();
2098                                        while let Some((snapshot_abs_path, file_path)) =
2099                                            paths_rx.next().await
2100                                        {
2101                                            path.clear();
2102                                            path.push(snapshot_abs_path);
2103                                            path.push(file_path);
2104                                            let mut matched = false;
2105                                            // searcher.search_path(
2106                                            //     matcher.as_ref(),
2107                                            //     &path,
2108                                            //     grep::searcher::sinks::Bytes(|_, _| {
2109                                            //         matched = true;
2110                                            //         Ok(false)
2111                                            //     }),
2112                                            // );
2113
2114                                            if matched {}
2115                                        }
2116                                    });
2117                                }
2118                            })
2119                            .await;
2120                    }
2121                })
2122                .detach();
2123        } else {
2124        }
2125
2126        todo!()
2127    }
2128
2129    fn request_lsp<R: LspCommand>(
2130        &self,
2131        buffer_handle: ModelHandle<Buffer>,
2132        request: R,
2133        cx: &mut ModelContext<Self>,
2134    ) -> Task<Result<R::Response>>
2135    where
2136        <R::LspRequest as lsp::request::Request>::Result: Send,
2137    {
2138        let buffer = buffer_handle.read(cx);
2139        if self.is_local() {
2140            let file = File::from_dyn(buffer.file()).and_then(File::as_local);
2141            if let Some((file, language_server)) = file.zip(buffer.language_server().cloned()) {
2142                let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
2143                return cx.spawn(|this, cx| async move {
2144                    let response = language_server
2145                        .request::<R::LspRequest>(lsp_params)
2146                        .await
2147                        .context("lsp request failed")?;
2148                    request
2149                        .response_from_lsp(response, this, buffer_handle, cx)
2150                        .await
2151                });
2152            }
2153        } else if let Some(project_id) = self.remote_id() {
2154            let rpc = self.client.clone();
2155            let request_handle = self.start_buffer_request(cx);
2156            let message = request.to_proto(project_id, buffer);
2157            return cx.spawn(|this, cx| async move {
2158                let response = rpc.request(message).await?;
2159                request
2160                    .response_from_proto(response, this, buffer_handle, request_handle, cx)
2161                    .await
2162            });
2163        }
2164        Task::ready(Ok(Default::default()))
2165    }
2166
2167    pub fn find_or_create_local_worktree(
2168        &self,
2169        abs_path: impl AsRef<Path>,
2170        weak: bool,
2171        cx: &mut ModelContext<Self>,
2172    ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
2173        let abs_path = abs_path.as_ref();
2174        if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
2175            Task::ready(Ok((tree.clone(), relative_path.into())))
2176        } else {
2177            let worktree = self.create_local_worktree(abs_path, weak, cx);
2178            cx.foreground()
2179                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
2180        }
2181    }
2182
2183    pub fn find_local_worktree(
2184        &self,
2185        abs_path: &Path,
2186        cx: &AppContext,
2187    ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
2188        for tree in self.worktrees(cx) {
2189            if let Some(relative_path) = tree
2190                .read(cx)
2191                .as_local()
2192                .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
2193            {
2194                return Some((tree.clone(), relative_path.into()));
2195            }
2196        }
2197        None
2198    }
2199
2200    pub fn is_shared(&self) -> bool {
2201        match &self.client_state {
2202            ProjectClientState::Local { is_shared, .. } => *is_shared,
2203            ProjectClientState::Remote { .. } => false,
2204        }
2205    }
2206
2207    fn create_local_worktree(
2208        &self,
2209        abs_path: impl AsRef<Path>,
2210        weak: bool,
2211        cx: &mut ModelContext<Self>,
2212    ) -> Task<Result<ModelHandle<Worktree>>> {
2213        let fs = self.fs.clone();
2214        let client = self.client.clone();
2215        let path = Arc::from(abs_path.as_ref());
2216        cx.spawn(|project, mut cx| async move {
2217            let worktree = Worktree::local(client.clone(), path, weak, fs, &mut cx).await?;
2218
2219            let (remote_project_id, is_shared) = project.update(&mut cx, |project, cx| {
2220                project.add_worktree(&worktree, cx);
2221                (project.remote_id(), project.is_shared())
2222            });
2223
2224            if let Some(project_id) = remote_project_id {
2225                worktree
2226                    .update(&mut cx, |worktree, cx| {
2227                        worktree.as_local_mut().unwrap().register(project_id, cx)
2228                    })
2229                    .await?;
2230                if is_shared {
2231                    worktree
2232                        .update(&mut cx, |worktree, cx| {
2233                            worktree.as_local_mut().unwrap().share(project_id, cx)
2234                        })
2235                        .await?;
2236                }
2237            }
2238
2239            Ok(worktree)
2240        })
2241    }
2242
2243    pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext<Self>) {
2244        self.worktrees.retain(|worktree| {
2245            worktree
2246                .upgrade(cx)
2247                .map_or(false, |w| w.read(cx).id() != id)
2248        });
2249        cx.notify();
2250    }
2251
2252    fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
2253        cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
2254        if worktree.read(cx).is_local() {
2255            cx.subscribe(&worktree, |this, worktree, _, cx| {
2256                this.update_local_worktree_buffers(worktree, cx);
2257            })
2258            .detach();
2259        }
2260
2261        let push_weak_handle = {
2262            let worktree = worktree.read(cx);
2263            worktree.is_local() && worktree.is_weak()
2264        };
2265        if push_weak_handle {
2266            cx.observe_release(&worktree, |this, cx| {
2267                this.worktrees
2268                    .retain(|worktree| worktree.upgrade(cx).is_some());
2269                cx.notify();
2270            })
2271            .detach();
2272            self.worktrees
2273                .push(WorktreeHandle::Weak(worktree.downgrade()));
2274        } else {
2275            self.worktrees
2276                .push(WorktreeHandle::Strong(worktree.clone()));
2277        }
2278        cx.notify();
2279    }
2280
2281    fn update_local_worktree_buffers(
2282        &mut self,
2283        worktree_handle: ModelHandle<Worktree>,
2284        cx: &mut ModelContext<Self>,
2285    ) {
2286        let snapshot = worktree_handle.read(cx).snapshot();
2287        let mut buffers_to_delete = Vec::new();
2288        for (buffer_id, buffer) in &self.buffers_state.borrow().open_buffers {
2289            if let Some(buffer) = buffer.upgrade(cx) {
2290                buffer.update(cx, |buffer, cx| {
2291                    if let Some(old_file) = File::from_dyn(buffer.file()) {
2292                        if old_file.worktree != worktree_handle {
2293                            return;
2294                        }
2295
2296                        let new_file = if let Some(entry) = old_file
2297                            .entry_id
2298                            .and_then(|entry_id| snapshot.entry_for_id(entry_id))
2299                        {
2300                            File {
2301                                is_local: true,
2302                                entry_id: Some(entry.id),
2303                                mtime: entry.mtime,
2304                                path: entry.path.clone(),
2305                                worktree: worktree_handle.clone(),
2306                            }
2307                        } else if let Some(entry) =
2308                            snapshot.entry_for_path(old_file.path().as_ref())
2309                        {
2310                            File {
2311                                is_local: true,
2312                                entry_id: Some(entry.id),
2313                                mtime: entry.mtime,
2314                                path: entry.path.clone(),
2315                                worktree: worktree_handle.clone(),
2316                            }
2317                        } else {
2318                            File {
2319                                is_local: true,
2320                                entry_id: None,
2321                                path: old_file.path().clone(),
2322                                mtime: old_file.mtime(),
2323                                worktree: worktree_handle.clone(),
2324                            }
2325                        };
2326
2327                        if let Some(project_id) = self.remote_id() {
2328                            self.client
2329                                .send(proto::UpdateBufferFile {
2330                                    project_id,
2331                                    buffer_id: *buffer_id as u64,
2332                                    file: Some(new_file.to_proto()),
2333                                })
2334                                .log_err();
2335                        }
2336                        buffer.file_updated(Box::new(new_file), cx).detach();
2337                    }
2338                });
2339            } else {
2340                buffers_to_delete.push(*buffer_id);
2341            }
2342        }
2343
2344        for buffer_id in buffers_to_delete {
2345            self.buffers_state
2346                .borrow_mut()
2347                .open_buffers
2348                .remove(&buffer_id);
2349        }
2350    }
2351
2352    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
2353        let new_active_entry = entry.and_then(|project_path| {
2354            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
2355            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
2356            Some(ProjectEntry {
2357                worktree_id: project_path.worktree_id,
2358                entry_id: entry.id,
2359            })
2360        });
2361        if new_active_entry != self.active_entry {
2362            self.active_entry = new_active_entry;
2363            cx.emit(Event::ActiveEntryChanged(new_active_entry));
2364        }
2365    }
2366
2367    pub fn is_running_disk_based_diagnostics(&self) -> bool {
2368        self.language_servers_with_diagnostics_running > 0
2369    }
2370
2371    pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
2372        let mut summary = DiagnosticSummary::default();
2373        for (_, path_summary) in self.diagnostic_summaries(cx) {
2374            summary.error_count += path_summary.error_count;
2375            summary.warning_count += path_summary.warning_count;
2376            summary.info_count += path_summary.info_count;
2377            summary.hint_count += path_summary.hint_count;
2378        }
2379        summary
2380    }
2381
2382    pub fn diagnostic_summaries<'a>(
2383        &'a self,
2384        cx: &'a AppContext,
2385    ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
2386        self.worktrees(cx).flat_map(move |worktree| {
2387            let worktree = worktree.read(cx);
2388            let worktree_id = worktree.id();
2389            worktree
2390                .diagnostic_summaries()
2391                .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
2392        })
2393    }
2394
2395    pub fn disk_based_diagnostics_started(&mut self, cx: &mut ModelContext<Self>) {
2396        self.language_servers_with_diagnostics_running += 1;
2397        if self.language_servers_with_diagnostics_running == 1 {
2398            cx.emit(Event::DiskBasedDiagnosticsStarted);
2399        }
2400    }
2401
2402    pub fn disk_based_diagnostics_finished(&mut self, cx: &mut ModelContext<Self>) {
2403        cx.emit(Event::DiskBasedDiagnosticsUpdated);
2404        self.language_servers_with_diagnostics_running -= 1;
2405        if self.language_servers_with_diagnostics_running == 0 {
2406            cx.emit(Event::DiskBasedDiagnosticsFinished);
2407        }
2408    }
2409
2410    pub fn active_entry(&self) -> Option<ProjectEntry> {
2411        self.active_entry
2412    }
2413
2414    // RPC message handlers
2415
2416    async fn handle_unshare_project(
2417        this: ModelHandle<Self>,
2418        _: TypedEnvelope<proto::UnshareProject>,
2419        _: Arc<Client>,
2420        mut cx: AsyncAppContext,
2421    ) -> Result<()> {
2422        this.update(&mut cx, |this, cx| {
2423            if let ProjectClientState::Remote {
2424                sharing_has_stopped,
2425                ..
2426            } = &mut this.client_state
2427            {
2428                *sharing_has_stopped = true;
2429                this.collaborators.clear();
2430                cx.notify();
2431            } else {
2432                unreachable!()
2433            }
2434        });
2435
2436        Ok(())
2437    }
2438
2439    async fn handle_add_collaborator(
2440        this: ModelHandle<Self>,
2441        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
2442        _: Arc<Client>,
2443        mut cx: AsyncAppContext,
2444    ) -> Result<()> {
2445        let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
2446        let collaborator = envelope
2447            .payload
2448            .collaborator
2449            .take()
2450            .ok_or_else(|| anyhow!("empty collaborator"))?;
2451
2452        let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
2453        this.update(&mut cx, |this, cx| {
2454            this.collaborators
2455                .insert(collaborator.peer_id, collaborator);
2456            cx.notify();
2457        });
2458
2459        Ok(())
2460    }
2461
2462    async fn handle_remove_collaborator(
2463        this: ModelHandle<Self>,
2464        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
2465        _: Arc<Client>,
2466        mut cx: AsyncAppContext,
2467    ) -> Result<()> {
2468        this.update(&mut cx, |this, cx| {
2469            let peer_id = PeerId(envelope.payload.peer_id);
2470            let replica_id = this
2471                .collaborators
2472                .remove(&peer_id)
2473                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
2474                .replica_id;
2475            this.shared_buffers.remove(&peer_id);
2476            for (_, buffer) in &this.buffers_state.borrow().open_buffers {
2477                if let Some(buffer) = buffer.upgrade(cx) {
2478                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
2479                }
2480            }
2481            cx.notify();
2482            Ok(())
2483        })
2484    }
2485
2486    async fn handle_register_worktree(
2487        this: ModelHandle<Self>,
2488        envelope: TypedEnvelope<proto::RegisterWorktree>,
2489        client: Arc<Client>,
2490        mut cx: AsyncAppContext,
2491    ) -> Result<()> {
2492        this.update(&mut cx, |this, cx| {
2493            let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
2494            let replica_id = this.replica_id();
2495            let worktree = proto::Worktree {
2496                id: envelope.payload.worktree_id,
2497                root_name: envelope.payload.root_name,
2498                entries: Default::default(),
2499                diagnostic_summaries: Default::default(),
2500                weak: envelope.payload.weak,
2501            };
2502            let (worktree, load_task) =
2503                Worktree::remote(remote_id, replica_id, worktree, client, cx);
2504            this.add_worktree(&worktree, cx);
2505            load_task.detach();
2506            Ok(())
2507        })
2508    }
2509
2510    async fn handle_unregister_worktree(
2511        this: ModelHandle<Self>,
2512        envelope: TypedEnvelope<proto::UnregisterWorktree>,
2513        _: Arc<Client>,
2514        mut cx: AsyncAppContext,
2515    ) -> Result<()> {
2516        this.update(&mut cx, |this, cx| {
2517            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
2518            this.remove_worktree(worktree_id, cx);
2519            Ok(())
2520        })
2521    }
2522
2523    async fn handle_update_worktree(
2524        this: ModelHandle<Self>,
2525        envelope: TypedEnvelope<proto::UpdateWorktree>,
2526        _: Arc<Client>,
2527        mut cx: AsyncAppContext,
2528    ) -> Result<()> {
2529        this.update(&mut cx, |this, cx| {
2530            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
2531            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
2532                worktree.update(cx, |worktree, _| {
2533                    let worktree = worktree.as_remote_mut().unwrap();
2534                    worktree.update_from_remote(envelope)
2535                })?;
2536            }
2537            Ok(())
2538        })
2539    }
2540
2541    async fn handle_update_diagnostic_summary(
2542        this: ModelHandle<Self>,
2543        envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
2544        _: Arc<Client>,
2545        mut cx: AsyncAppContext,
2546    ) -> Result<()> {
2547        this.update(&mut cx, |this, cx| {
2548            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
2549            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
2550                if let Some(summary) = envelope.payload.summary {
2551                    let project_path = ProjectPath {
2552                        worktree_id,
2553                        path: Path::new(&summary.path).into(),
2554                    };
2555                    worktree.update(cx, |worktree, _| {
2556                        worktree
2557                            .as_remote_mut()
2558                            .unwrap()
2559                            .update_diagnostic_summary(project_path.path.clone(), &summary);
2560                    });
2561                    cx.emit(Event::DiagnosticsUpdated(project_path));
2562                }
2563            }
2564            Ok(())
2565        })
2566    }
2567
2568    async fn handle_disk_based_diagnostics_updating(
2569        this: ModelHandle<Self>,
2570        _: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>,
2571        _: Arc<Client>,
2572        mut cx: AsyncAppContext,
2573    ) -> Result<()> {
2574        this.update(&mut cx, |this, cx| this.disk_based_diagnostics_started(cx));
2575        Ok(())
2576    }
2577
2578    async fn handle_disk_based_diagnostics_updated(
2579        this: ModelHandle<Self>,
2580        _: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>,
2581        _: Arc<Client>,
2582        mut cx: AsyncAppContext,
2583    ) -> Result<()> {
2584        this.update(&mut cx, |this, cx| this.disk_based_diagnostics_finished(cx));
2585        Ok(())
2586    }
2587
2588    async fn handle_update_buffer(
2589        this: ModelHandle<Self>,
2590        envelope: TypedEnvelope<proto::UpdateBuffer>,
2591        _: Arc<Client>,
2592        mut cx: AsyncAppContext,
2593    ) -> Result<()> {
2594        this.update(&mut cx, |this, cx| {
2595            let payload = envelope.payload.clone();
2596            let buffer_id = payload.buffer_id;
2597            let ops = payload
2598                .operations
2599                .into_iter()
2600                .map(|op| language::proto::deserialize_operation(op))
2601                .collect::<Result<Vec<_>, _>>()?;
2602            let is_remote = this.is_remote();
2603            let mut buffers_state = this.buffers_state.borrow_mut();
2604            let buffer_request_count = buffers_state.buffer_request_count;
2605            match buffers_state.open_buffers.entry(buffer_id) {
2606                hash_map::Entry::Occupied(mut e) => match e.get_mut() {
2607                    OpenBuffer::Loaded(buffer) => {
2608                        if let Some(buffer) = buffer.upgrade(cx) {
2609                            buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
2610                        } else if is_remote && buffer_request_count > 0 {
2611                            e.insert(OpenBuffer::Loading(ops));
2612                        }
2613                    }
2614                    OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
2615                },
2616                hash_map::Entry::Vacant(e) => {
2617                    if is_remote && buffer_request_count > 0 {
2618                        e.insert(OpenBuffer::Loading(ops));
2619                    }
2620                }
2621            }
2622            Ok(())
2623        })
2624    }
2625
2626    async fn handle_update_buffer_file(
2627        this: ModelHandle<Self>,
2628        envelope: TypedEnvelope<proto::UpdateBufferFile>,
2629        _: Arc<Client>,
2630        mut cx: AsyncAppContext,
2631    ) -> Result<()> {
2632        this.update(&mut cx, |this, cx| {
2633            let payload = envelope.payload.clone();
2634            let buffer_id = payload.buffer_id;
2635            let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
2636            let worktree = this
2637                .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
2638                .ok_or_else(|| anyhow!("no such worktree"))?;
2639            let file = File::from_proto(file, worktree.clone(), cx)?;
2640            let buffer = this
2641                .buffers_state
2642                .borrow_mut()
2643                .open_buffers
2644                .get_mut(&buffer_id)
2645                .and_then(|b| b.upgrade(cx))
2646                .ok_or_else(|| anyhow!("no such buffer"))?;
2647            buffer.update(cx, |buffer, cx| {
2648                buffer.file_updated(Box::new(file), cx).detach();
2649            });
2650            Ok(())
2651        })
2652    }
2653
2654    async fn handle_save_buffer(
2655        this: ModelHandle<Self>,
2656        envelope: TypedEnvelope<proto::SaveBuffer>,
2657        _: Arc<Client>,
2658        mut cx: AsyncAppContext,
2659    ) -> Result<proto::BufferSaved> {
2660        let buffer_id = envelope.payload.buffer_id;
2661        let sender_id = envelope.original_sender_id()?;
2662        let requested_version = envelope.payload.version.try_into()?;
2663
2664        let (project_id, buffer) = this.update(&mut cx, |this, _| {
2665            let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
2666            let buffer = this
2667                .shared_buffers
2668                .get(&sender_id)
2669                .and_then(|shared_buffers| shared_buffers.get(&buffer_id).cloned())
2670                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
2671            Ok::<_, anyhow::Error>((project_id, buffer))
2672        })?;
2673
2674        if !buffer
2675            .read_with(&cx, |buffer, _| buffer.version())
2676            .observed_all(&requested_version)
2677        {
2678            Err(anyhow!("save request depends on unreceived edits"))?;
2679        }
2680
2681        let (saved_version, mtime) = buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
2682        Ok(proto::BufferSaved {
2683            project_id,
2684            buffer_id,
2685            version: (&saved_version).into(),
2686            mtime: Some(mtime.into()),
2687        })
2688    }
2689
2690    async fn handle_format_buffers(
2691        this: ModelHandle<Self>,
2692        envelope: TypedEnvelope<proto::FormatBuffers>,
2693        _: Arc<Client>,
2694        mut cx: AsyncAppContext,
2695    ) -> Result<proto::FormatBuffersResponse> {
2696        let sender_id = envelope.original_sender_id()?;
2697        let format = this.update(&mut cx, |this, cx| {
2698            let shared_buffers = this
2699                .shared_buffers
2700                .get(&sender_id)
2701                .ok_or_else(|| anyhow!("peer has no buffers"))?;
2702            let mut buffers = HashSet::default();
2703            for buffer_id in &envelope.payload.buffer_ids {
2704                buffers.insert(
2705                    shared_buffers
2706                        .get(buffer_id)
2707                        .cloned()
2708                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
2709                );
2710            }
2711            Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
2712        })?;
2713
2714        let project_transaction = format.await?;
2715        let project_transaction = this.update(&mut cx, |this, cx| {
2716            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
2717        });
2718        Ok(proto::FormatBuffersResponse {
2719            transaction: Some(project_transaction),
2720        })
2721    }
2722
2723    async fn handle_get_completions(
2724        this: ModelHandle<Self>,
2725        envelope: TypedEnvelope<proto::GetCompletions>,
2726        _: Arc<Client>,
2727        mut cx: AsyncAppContext,
2728    ) -> Result<proto::GetCompletionsResponse> {
2729        let sender_id = envelope.original_sender_id()?;
2730        let position = envelope
2731            .payload
2732            .position
2733            .and_then(language::proto::deserialize_anchor)
2734            .ok_or_else(|| anyhow!("invalid position"))?;
2735        let version = clock::Global::from(envelope.payload.version);
2736        let buffer = this.read_with(&cx, |this, _| {
2737            this.shared_buffers
2738                .get(&sender_id)
2739                .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
2740                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
2741        })?;
2742        if !buffer
2743            .read_with(&cx, |buffer, _| buffer.version())
2744            .observed_all(&version)
2745        {
2746            Err(anyhow!("completion request depends on unreceived edits"))?;
2747        }
2748        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
2749        let completions = this
2750            .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
2751            .await?;
2752
2753        Ok(proto::GetCompletionsResponse {
2754            completions: completions
2755                .iter()
2756                .map(language::proto::serialize_completion)
2757                .collect(),
2758            version: (&version).into(),
2759        })
2760    }
2761
2762    async fn handle_apply_additional_edits_for_completion(
2763        this: ModelHandle<Self>,
2764        envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
2765        _: Arc<Client>,
2766        mut cx: AsyncAppContext,
2767    ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
2768        let sender_id = envelope.original_sender_id()?;
2769        let apply_additional_edits = this.update(&mut cx, |this, cx| {
2770            let buffer = this
2771                .shared_buffers
2772                .get(&sender_id)
2773                .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
2774                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
2775            let language = buffer.read(cx).language();
2776            let completion = language::proto::deserialize_completion(
2777                envelope
2778                    .payload
2779                    .completion
2780                    .ok_or_else(|| anyhow!("invalid completion"))?,
2781                language,
2782            )?;
2783            Ok::<_, anyhow::Error>(
2784                this.apply_additional_edits_for_completion(buffer, completion, false, cx),
2785            )
2786        })?;
2787
2788        Ok(proto::ApplyCompletionAdditionalEditsResponse {
2789            transaction: apply_additional_edits
2790                .await?
2791                .as_ref()
2792                .map(language::proto::serialize_transaction),
2793        })
2794    }
2795
2796    async fn handle_get_code_actions(
2797        this: ModelHandle<Self>,
2798        envelope: TypedEnvelope<proto::GetCodeActions>,
2799        _: Arc<Client>,
2800        mut cx: AsyncAppContext,
2801    ) -> Result<proto::GetCodeActionsResponse> {
2802        let sender_id = envelope.original_sender_id()?;
2803        let start = envelope
2804            .payload
2805            .start
2806            .and_then(language::proto::deserialize_anchor)
2807            .ok_or_else(|| anyhow!("invalid start"))?;
2808        let end = envelope
2809            .payload
2810            .end
2811            .and_then(language::proto::deserialize_anchor)
2812            .ok_or_else(|| anyhow!("invalid end"))?;
2813        let buffer = this.update(&mut cx, |this, _| {
2814            this.shared_buffers
2815                .get(&sender_id)
2816                .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
2817                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
2818        })?;
2819        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
2820        if !version.observed(start.timestamp) || !version.observed(end.timestamp) {
2821            Err(anyhow!("code action request references unreceived edits"))?;
2822        }
2823        let code_actions = this.update(&mut cx, |this, cx| {
2824            Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
2825        })?;
2826
2827        Ok(proto::GetCodeActionsResponse {
2828            actions: code_actions
2829                .await?
2830                .iter()
2831                .map(language::proto::serialize_code_action)
2832                .collect(),
2833            version: (&version).into(),
2834        })
2835    }
2836
2837    async fn handle_apply_code_action(
2838        this: ModelHandle<Self>,
2839        envelope: TypedEnvelope<proto::ApplyCodeAction>,
2840        _: Arc<Client>,
2841        mut cx: AsyncAppContext,
2842    ) -> Result<proto::ApplyCodeActionResponse> {
2843        let sender_id = envelope.original_sender_id()?;
2844        let action = language::proto::deserialize_code_action(
2845            envelope
2846                .payload
2847                .action
2848                .ok_or_else(|| anyhow!("invalid action"))?,
2849        )?;
2850        let apply_code_action = this.update(&mut cx, |this, cx| {
2851            let buffer = this
2852                .shared_buffers
2853                .get(&sender_id)
2854                .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
2855                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
2856            Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
2857        })?;
2858
2859        let project_transaction = apply_code_action.await?;
2860        let project_transaction = this.update(&mut cx, |this, cx| {
2861            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
2862        });
2863        Ok(proto::ApplyCodeActionResponse {
2864            transaction: Some(project_transaction),
2865        })
2866    }
2867
2868    async fn handle_lsp_command<T: LspCommand>(
2869        this: ModelHandle<Self>,
2870        envelope: TypedEnvelope<T::ProtoRequest>,
2871        _: Arc<Client>,
2872        mut cx: AsyncAppContext,
2873    ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
2874    where
2875        <T::LspRequest as lsp::request::Request>::Result: Send,
2876    {
2877        let sender_id = envelope.original_sender_id()?;
2878        let (request, buffer_version) = this.update(&mut cx, |this, cx| {
2879            let buffer_id = T::buffer_id_from_proto(&envelope.payload);
2880            let buffer_handle = this
2881                .shared_buffers
2882                .get(&sender_id)
2883                .and_then(|shared_buffers| shared_buffers.get(&buffer_id).cloned())
2884                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
2885            let buffer = buffer_handle.read(cx);
2886            let buffer_version = buffer.version();
2887            let request = T::from_proto(envelope.payload, this, buffer)?;
2888            Ok::<_, anyhow::Error>((this.request_lsp(buffer_handle, request, cx), buffer_version))
2889        })?;
2890        let response = request.await?;
2891        this.update(&mut cx, |this, cx| {
2892            Ok(T::response_to_proto(
2893                response,
2894                this,
2895                sender_id,
2896                &buffer_version,
2897                cx,
2898            ))
2899        })
2900    }
2901
2902    async fn handle_get_project_symbols(
2903        this: ModelHandle<Self>,
2904        envelope: TypedEnvelope<proto::GetProjectSymbols>,
2905        _: Arc<Client>,
2906        mut cx: AsyncAppContext,
2907    ) -> Result<proto::GetProjectSymbolsResponse> {
2908        let symbols = this
2909            .update(&mut cx, |this, cx| {
2910                this.symbols(&envelope.payload.query, cx)
2911            })
2912            .await?;
2913
2914        Ok(proto::GetProjectSymbolsResponse {
2915            symbols: symbols.iter().map(serialize_symbol).collect(),
2916        })
2917    }
2918
2919    async fn handle_open_buffer_for_symbol(
2920        this: ModelHandle<Self>,
2921        envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
2922        _: Arc<Client>,
2923        mut cx: AsyncAppContext,
2924    ) -> Result<proto::OpenBufferForSymbolResponse> {
2925        let peer_id = envelope.original_sender_id()?;
2926        let symbol = envelope
2927            .payload
2928            .symbol
2929            .ok_or_else(|| anyhow!("invalid symbol"))?;
2930        let symbol = this.read_with(&cx, |this, _| {
2931            let symbol = this.deserialize_symbol(symbol)?;
2932            let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
2933            if signature == symbol.signature {
2934                Ok(symbol)
2935            } else {
2936                Err(anyhow!("invalid symbol signature"))
2937            }
2938        })?;
2939        let buffer = this
2940            .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
2941            .await?;
2942
2943        Ok(proto::OpenBufferForSymbolResponse {
2944            buffer: Some(this.update(&mut cx, |this, cx| {
2945                this.serialize_buffer_for_peer(&buffer, peer_id, cx)
2946            })),
2947        })
2948    }
2949
2950    fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
2951        let mut hasher = Sha256::new();
2952        hasher.update(worktree_id.to_proto().to_be_bytes());
2953        hasher.update(path.to_string_lossy().as_bytes());
2954        hasher.update(self.nonce.to_be_bytes());
2955        hasher.finalize().as_slice().try_into().unwrap()
2956    }
2957
2958    async fn handle_open_buffer(
2959        this: ModelHandle<Self>,
2960        envelope: TypedEnvelope<proto::OpenBuffer>,
2961        _: Arc<Client>,
2962        mut cx: AsyncAppContext,
2963    ) -> Result<proto::OpenBufferResponse> {
2964        let peer_id = envelope.original_sender_id()?;
2965        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
2966        let open_buffer = this.update(&mut cx, |this, cx| {
2967            this.open_buffer(
2968                ProjectPath {
2969                    worktree_id,
2970                    path: PathBuf::from(envelope.payload.path).into(),
2971                },
2972                cx,
2973            )
2974        });
2975
2976        let buffer = open_buffer.await?;
2977        this.update(&mut cx, |this, cx| {
2978            Ok(proto::OpenBufferResponse {
2979                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
2980            })
2981        })
2982    }
2983
2984    fn serialize_project_transaction_for_peer(
2985        &mut self,
2986        project_transaction: ProjectTransaction,
2987        peer_id: PeerId,
2988        cx: &AppContext,
2989    ) -> proto::ProjectTransaction {
2990        let mut serialized_transaction = proto::ProjectTransaction {
2991            buffers: Default::default(),
2992            transactions: Default::default(),
2993        };
2994        for (buffer, transaction) in project_transaction.0 {
2995            serialized_transaction
2996                .buffers
2997                .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
2998            serialized_transaction
2999                .transactions
3000                .push(language::proto::serialize_transaction(&transaction));
3001        }
3002        serialized_transaction
3003    }
3004
3005    fn deserialize_project_transaction(
3006        &mut self,
3007        message: proto::ProjectTransaction,
3008        push_to_history: bool,
3009        request_handle: BufferRequestHandle,
3010        cx: &mut ModelContext<Self>,
3011    ) -> Task<Result<ProjectTransaction>> {
3012        cx.spawn(|this, mut cx| async move {
3013            let mut project_transaction = ProjectTransaction::default();
3014            for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
3015                let buffer = this
3016                    .update(&mut cx, |this, cx| {
3017                        this.deserialize_buffer(buffer, request_handle.clone(), cx)
3018                    })
3019                    .await?;
3020                let transaction = language::proto::deserialize_transaction(transaction)?;
3021                project_transaction.0.insert(buffer, transaction);
3022            }
3023
3024            for (buffer, transaction) in &project_transaction.0 {
3025                buffer
3026                    .update(&mut cx, |buffer, _| {
3027                        buffer.wait_for_edits(transaction.edit_ids.iter().copied())
3028                    })
3029                    .await;
3030
3031                if push_to_history {
3032                    buffer.update(&mut cx, |buffer, _| {
3033                        buffer.push_transaction(transaction.clone(), Instant::now());
3034                    });
3035                }
3036            }
3037
3038            Ok(project_transaction)
3039        })
3040    }
3041
3042    fn serialize_buffer_for_peer(
3043        &mut self,
3044        buffer: &ModelHandle<Buffer>,
3045        peer_id: PeerId,
3046        cx: &AppContext,
3047    ) -> proto::Buffer {
3048        let buffer_id = buffer.read(cx).remote_id();
3049        let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
3050        match shared_buffers.entry(buffer_id) {
3051            hash_map::Entry::Occupied(_) => proto::Buffer {
3052                variant: Some(proto::buffer::Variant::Id(buffer_id)),
3053            },
3054            hash_map::Entry::Vacant(entry) => {
3055                entry.insert(buffer.clone());
3056                proto::Buffer {
3057                    variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
3058                }
3059            }
3060        }
3061    }
3062
3063    fn deserialize_buffer(
3064        &mut self,
3065        buffer: proto::Buffer,
3066        request_handle: BufferRequestHandle,
3067        cx: &mut ModelContext<Self>,
3068    ) -> Task<Result<ModelHandle<Buffer>>> {
3069        let replica_id = self.replica_id();
3070
3071        let mut opened_buffer_tx = self.opened_buffer.clone();
3072        let mut opened_buffer_rx = self.opened_buffer.subscribe();
3073        cx.spawn(|this, mut cx| async move {
3074            match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
3075                proto::buffer::Variant::Id(id) => {
3076                    let buffer = loop {
3077                        let buffer = this.read_with(&cx, |this, cx| {
3078                            this.buffers_state
3079                                .borrow()
3080                                .open_buffers
3081                                .get(&id)
3082                                .and_then(|buffer| buffer.upgrade(cx))
3083                        });
3084                        if let Some(buffer) = buffer {
3085                            break buffer;
3086                        }
3087                        opened_buffer_rx
3088                            .recv()
3089                            .await
3090                            .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
3091                    };
3092                    Ok(buffer)
3093                }
3094                proto::buffer::Variant::State(mut buffer) => {
3095                    let mut buffer_worktree = None;
3096                    let mut buffer_file = None;
3097                    if let Some(file) = buffer.file.take() {
3098                        this.read_with(&cx, |this, cx| {
3099                            let worktree_id = WorktreeId::from_proto(file.worktree_id);
3100                            let worktree =
3101                                this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
3102                                    anyhow!("no worktree found for id {}", file.worktree_id)
3103                                })?;
3104                            buffer_file =
3105                                Some(Box::new(File::from_proto(file, worktree.clone(), cx)?)
3106                                    as Box<dyn language::File>);
3107                            buffer_worktree = Some(worktree);
3108                            Ok::<_, anyhow::Error>(())
3109                        })?;
3110                    }
3111
3112                    let buffer = cx.add_model(|cx| {
3113                        Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
3114                    });
3115
3116                    request_handle.preserve_buffer(buffer.clone());
3117                    this.update(&mut cx, |this, cx| {
3118                        this.register_buffer(&buffer, buffer_worktree.as_ref(), cx)
3119                    })?;
3120
3121                    let _ = opened_buffer_tx.send(()).await;
3122                    Ok(buffer)
3123                }
3124            }
3125        })
3126    }
3127
3128    fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
3129        let language = self
3130            .languages
3131            .get_language(&serialized_symbol.language_name);
3132        let start = serialized_symbol
3133            .start
3134            .ok_or_else(|| anyhow!("invalid start"))?;
3135        let end = serialized_symbol
3136            .end
3137            .ok_or_else(|| anyhow!("invalid end"))?;
3138        let kind = unsafe { mem::transmute(serialized_symbol.kind) };
3139        Ok(Symbol {
3140            source_worktree_id: WorktreeId::from_proto(serialized_symbol.source_worktree_id),
3141            worktree_id: WorktreeId::from_proto(serialized_symbol.worktree_id),
3142            language_name: serialized_symbol.language_name.clone(),
3143            label: language
3144                .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
3145                .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
3146            name: serialized_symbol.name,
3147            path: PathBuf::from(serialized_symbol.path),
3148            range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
3149            kind,
3150            signature: serialized_symbol
3151                .signature
3152                .try_into()
3153                .map_err(|_| anyhow!("invalid signature"))?,
3154        })
3155    }
3156
3157    async fn handle_close_buffer(
3158        this: ModelHandle<Self>,
3159        envelope: TypedEnvelope<proto::CloseBuffer>,
3160        _: Arc<Client>,
3161        mut cx: AsyncAppContext,
3162    ) -> Result<()> {
3163        this.update(&mut cx, |this, cx| {
3164            if let Some(shared_buffers) =
3165                this.shared_buffers.get_mut(&envelope.original_sender_id()?)
3166            {
3167                shared_buffers.remove(&envelope.payload.buffer_id);
3168                cx.notify();
3169            }
3170            Ok(())
3171        })
3172    }
3173
3174    async fn handle_buffer_saved(
3175        this: ModelHandle<Self>,
3176        envelope: TypedEnvelope<proto::BufferSaved>,
3177        _: Arc<Client>,
3178        mut cx: AsyncAppContext,
3179    ) -> Result<()> {
3180        let version = envelope.payload.version.try_into()?;
3181        let mtime = envelope
3182            .payload
3183            .mtime
3184            .ok_or_else(|| anyhow!("missing mtime"))?
3185            .into();
3186
3187        this.update(&mut cx, |this, cx| {
3188            let buffer = this
3189                .buffers_state
3190                .borrow()
3191                .open_buffers
3192                .get(&envelope.payload.buffer_id)
3193                .and_then(|buffer| buffer.upgrade(cx));
3194            if let Some(buffer) = buffer {
3195                buffer.update(cx, |buffer, cx| {
3196                    buffer.did_save(version, mtime, None, cx);
3197                });
3198            }
3199            Ok(())
3200        })
3201    }
3202
3203    async fn handle_buffer_reloaded(
3204        this: ModelHandle<Self>,
3205        envelope: TypedEnvelope<proto::BufferReloaded>,
3206        _: Arc<Client>,
3207        mut cx: AsyncAppContext,
3208    ) -> Result<()> {
3209        let payload = envelope.payload.clone();
3210        let version = payload.version.try_into()?;
3211        let mtime = payload
3212            .mtime
3213            .ok_or_else(|| anyhow!("missing mtime"))?
3214            .into();
3215        this.update(&mut cx, |this, cx| {
3216            let buffer = this
3217                .buffers_state
3218                .borrow()
3219                .open_buffers
3220                .get(&payload.buffer_id)
3221                .and_then(|buffer| buffer.upgrade(cx));
3222            if let Some(buffer) = buffer {
3223                buffer.update(cx, |buffer, cx| {
3224                    buffer.did_reload(version, mtime, cx);
3225                });
3226            }
3227            Ok(())
3228        })
3229    }
3230
3231    pub fn match_paths<'a>(
3232        &self,
3233        query: &'a str,
3234        include_ignored: bool,
3235        smart_case: bool,
3236        max_results: usize,
3237        cancel_flag: &'a AtomicBool,
3238        cx: &AppContext,
3239    ) -> impl 'a + Future<Output = Vec<PathMatch>> {
3240        let worktrees = self
3241            .worktrees(cx)
3242            .filter(|worktree| !worktree.read(cx).is_weak())
3243            .collect::<Vec<_>>();
3244        let include_root_name = worktrees.len() > 1;
3245        let candidate_sets = worktrees
3246            .into_iter()
3247            .map(|worktree| CandidateSet {
3248                snapshot: worktree.read(cx).snapshot(),
3249                include_ignored,
3250                include_root_name,
3251            })
3252            .collect::<Vec<_>>();
3253
3254        let background = cx.background().clone();
3255        async move {
3256            fuzzy::match_paths(
3257                candidate_sets.as_slice(),
3258                query,
3259                smart_case,
3260                max_results,
3261                cancel_flag,
3262                background,
3263            )
3264            .await
3265        }
3266    }
3267}
3268
3269impl BufferRequestHandle {
3270    fn new(state: Rc<RefCell<ProjectBuffers>>, cx: &AppContext) -> Self {
3271        {
3272            let state = &mut *state.borrow_mut();
3273            state.buffer_request_count += 1;
3274            if state.buffer_request_count == 1 {
3275                state.preserved_buffers.extend(
3276                    state
3277                        .open_buffers
3278                        .values()
3279                        .filter_map(|buffer| buffer.upgrade(cx)),
3280                )
3281            }
3282        }
3283        Self(state)
3284    }
3285
3286    fn preserve_buffer(&self, buffer: ModelHandle<Buffer>) {
3287        self.0.borrow_mut().preserved_buffers.push(buffer);
3288    }
3289}
3290
3291impl Clone for BufferRequestHandle {
3292    fn clone(&self) -> Self {
3293        self.0.borrow_mut().buffer_request_count += 1;
3294        Self(self.0.clone())
3295    }
3296}
3297
3298impl Drop for BufferRequestHandle {
3299    fn drop(&mut self) {
3300        let mut state = self.0.borrow_mut();
3301        state.buffer_request_count -= 1;
3302        if state.buffer_request_count == 0 {
3303            state.preserved_buffers.clear();
3304            state
3305                .open_buffers
3306                .retain(|_, buffer| matches!(buffer, OpenBuffer::Loaded(_)))
3307        }
3308    }
3309}
3310
3311impl WorktreeHandle {
3312    pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
3313        match self {
3314            WorktreeHandle::Strong(handle) => Some(handle.clone()),
3315            WorktreeHandle::Weak(handle) => handle.upgrade(cx),
3316        }
3317    }
3318}
3319
3320impl OpenBuffer {
3321    pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
3322        match self {
3323            OpenBuffer::Loaded(handle) => handle.upgrade(cx),
3324            OpenBuffer::Loading(_) => None,
3325        }
3326    }
3327}
3328
3329struct CandidateSet {
3330    snapshot: Snapshot,
3331    include_ignored: bool,
3332    include_root_name: bool,
3333}
3334
3335impl<'a> PathMatchCandidateSet<'a> for CandidateSet {
3336    type Candidates = CandidateSetIter<'a>;
3337
3338    fn id(&self) -> usize {
3339        self.snapshot.id().to_usize()
3340    }
3341
3342    fn len(&self) -> usize {
3343        if self.include_ignored {
3344            self.snapshot.file_count()
3345        } else {
3346            self.snapshot.visible_file_count()
3347        }
3348    }
3349
3350    fn prefix(&self) -> Arc<str> {
3351        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
3352            self.snapshot.root_name().into()
3353        } else if self.include_root_name {
3354            format!("{}/", self.snapshot.root_name()).into()
3355        } else {
3356            "".into()
3357        }
3358    }
3359
3360    fn candidates(&'a self, start: usize) -> Self::Candidates {
3361        CandidateSetIter {
3362            traversal: self.snapshot.files(self.include_ignored, start),
3363        }
3364    }
3365}
3366
3367struct CandidateSetIter<'a> {
3368    traversal: Traversal<'a>,
3369}
3370
3371impl<'a> Iterator for CandidateSetIter<'a> {
3372    type Item = PathMatchCandidate<'a>;
3373
3374    fn next(&mut self) -> Option<Self::Item> {
3375        self.traversal.next().map(|entry| {
3376            if let EntryKind::File(char_bag) = entry.kind {
3377                PathMatchCandidate {
3378                    path: &entry.path,
3379                    char_bag,
3380                }
3381            } else {
3382                unreachable!()
3383            }
3384        })
3385    }
3386}
3387
3388impl Entity for Project {
3389    type Event = Event;
3390
3391    fn release(&mut self, _: &mut gpui::MutableAppContext) {
3392        match &self.client_state {
3393            ProjectClientState::Local { remote_id_rx, .. } => {
3394                if let Some(project_id) = *remote_id_rx.borrow() {
3395                    self.client
3396                        .send(proto::UnregisterProject { project_id })
3397                        .log_err();
3398                }
3399            }
3400            ProjectClientState::Remote { remote_id, .. } => {
3401                self.client
3402                    .send(proto::LeaveProject {
3403                        project_id: *remote_id,
3404                    })
3405                    .log_err();
3406            }
3407        }
3408    }
3409
3410    fn app_will_quit(
3411        &mut self,
3412        _: &mut MutableAppContext,
3413    ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
3414        let shutdown_futures = self
3415            .language_servers
3416            .drain()
3417            .filter_map(|(_, server)| server.shutdown())
3418            .collect::<Vec<_>>();
3419        Some(
3420            async move {
3421                futures::future::join_all(shutdown_futures).await;
3422            }
3423            .boxed(),
3424        )
3425    }
3426}
3427
3428impl Collaborator {
3429    fn from_proto(
3430        message: proto::Collaborator,
3431        user_store: &ModelHandle<UserStore>,
3432        cx: &mut AsyncAppContext,
3433    ) -> impl Future<Output = Result<Self>> {
3434        let user = user_store.update(cx, |user_store, cx| {
3435            user_store.fetch_user(message.user_id, cx)
3436        });
3437
3438        async move {
3439            Ok(Self {
3440                peer_id: PeerId(message.peer_id),
3441                user: user.await?,
3442                replica_id: message.replica_id as ReplicaId,
3443            })
3444        }
3445    }
3446}
3447
3448impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
3449    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
3450        Self {
3451            worktree_id,
3452            path: path.as_ref().into(),
3453        }
3454    }
3455}
3456
3457impl From<lsp::CreateFileOptions> for fs::CreateOptions {
3458    fn from(options: lsp::CreateFileOptions) -> Self {
3459        Self {
3460            overwrite: options.overwrite.unwrap_or(false),
3461            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3462        }
3463    }
3464}
3465
3466impl From<lsp::RenameFileOptions> for fs::RenameOptions {
3467    fn from(options: lsp::RenameFileOptions) -> Self {
3468        Self {
3469            overwrite: options.overwrite.unwrap_or(false),
3470            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3471        }
3472    }
3473}
3474
3475impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
3476    fn from(options: lsp::DeleteFileOptions) -> Self {
3477        Self {
3478            recursive: options.recursive.unwrap_or(false),
3479            ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3480        }
3481    }
3482}
3483
3484fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
3485    proto::Symbol {
3486        source_worktree_id: symbol.source_worktree_id.to_proto(),
3487        worktree_id: symbol.worktree_id.to_proto(),
3488        language_name: symbol.language_name.clone(),
3489        name: symbol.name.clone(),
3490        kind: unsafe { mem::transmute(symbol.kind) },
3491        path: symbol.path.to_string_lossy().to_string(),
3492        start: Some(proto::Point {
3493            row: symbol.range.start.row,
3494            column: symbol.range.start.column,
3495        }),
3496        end: Some(proto::Point {
3497            row: symbol.range.end.row,
3498            column: symbol.range.end.column,
3499        }),
3500        signature: symbol.signature.to_vec(),
3501    }
3502}
3503
3504fn relativize_path(base: &Path, path: &Path) -> PathBuf {
3505    let mut path_components = path.components();
3506    let mut base_components = base.components();
3507    let mut components: Vec<Component> = Vec::new();
3508    loop {
3509        match (path_components.next(), base_components.next()) {
3510            (None, None) => break,
3511            (Some(a), None) => {
3512                components.push(a);
3513                components.extend(path_components.by_ref());
3514                break;
3515            }
3516            (None, _) => components.push(Component::ParentDir),
3517            (Some(a), Some(b)) if components.is_empty() && a == b => (),
3518            (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
3519            (Some(a), Some(_)) => {
3520                components.push(Component::ParentDir);
3521                for _ in base_components {
3522                    components.push(Component::ParentDir);
3523                }
3524                components.push(a);
3525                components.extend(path_components.by_ref());
3526                break;
3527            }
3528        }
3529    }
3530    components.iter().map(|c| c.as_os_str()).collect()
3531}
3532
3533#[cfg(test)]
3534mod tests {
3535    use super::{Event, *};
3536    use fs::RealFs;
3537    use futures::StreamExt;
3538    use gpui::test::subscribe;
3539    use language::{
3540        tree_sitter_rust, AnchorRangeExt, Diagnostic, LanguageConfig, LanguageServerConfig, Point,
3541    };
3542    use lsp::Url;
3543    use serde_json::json;
3544    use std::{cell::RefCell, os::unix, path::PathBuf, rc::Rc};
3545    use unindent::Unindent as _;
3546    use util::test::temp_tree;
3547    use worktree::WorktreeHandle as _;
3548
3549    #[gpui::test]
3550    async fn test_populate_and_search(mut cx: gpui::TestAppContext) {
3551        let dir = temp_tree(json!({
3552            "root": {
3553                "apple": "",
3554                "banana": {
3555                    "carrot": {
3556                        "date": "",
3557                        "endive": "",
3558                    }
3559                },
3560                "fennel": {
3561                    "grape": "",
3562                }
3563            }
3564        }));
3565
3566        let root_link_path = dir.path().join("root_link");
3567        unix::fs::symlink(&dir.path().join("root"), &root_link_path).unwrap();
3568        unix::fs::symlink(
3569            &dir.path().join("root/fennel"),
3570            &dir.path().join("root/finnochio"),
3571        )
3572        .unwrap();
3573
3574        let project = Project::test(Arc::new(RealFs), &mut cx);
3575
3576        let (tree, _) = project
3577            .update(&mut cx, |project, cx| {
3578                project.find_or_create_local_worktree(&root_link_path, false, cx)
3579            })
3580            .await
3581            .unwrap();
3582
3583        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3584            .await;
3585        cx.read(|cx| {
3586            let tree = tree.read(cx);
3587            assert_eq!(tree.file_count(), 5);
3588            assert_eq!(
3589                tree.inode_for_path("fennel/grape"),
3590                tree.inode_for_path("finnochio/grape")
3591            );
3592        });
3593
3594        let cancel_flag = Default::default();
3595        let results = project
3596            .read_with(&cx, |project, cx| {
3597                project.match_paths("bna", false, false, 10, &cancel_flag, cx)
3598            })
3599            .await;
3600        assert_eq!(
3601            results
3602                .into_iter()
3603                .map(|result| result.path)
3604                .collect::<Vec<Arc<Path>>>(),
3605            vec![
3606                PathBuf::from("banana/carrot/date").into(),
3607                PathBuf::from("banana/carrot/endive").into(),
3608            ]
3609        );
3610    }
3611
3612    #[gpui::test]
3613    async fn test_language_server_diagnostics(mut cx: gpui::TestAppContext) {
3614        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
3615        let progress_token = language_server_config
3616            .disk_based_diagnostics_progress_token
3617            .clone()
3618            .unwrap();
3619
3620        let language = Arc::new(Language::new(
3621            LanguageConfig {
3622                name: "Rust".into(),
3623                path_suffixes: vec!["rs".to_string()],
3624                language_server: Some(language_server_config),
3625                ..Default::default()
3626            },
3627            Some(tree_sitter_rust::language()),
3628        ));
3629
3630        let fs = FakeFs::new(cx.background());
3631        fs.insert_tree(
3632            "/dir",
3633            json!({
3634                "a.rs": "fn a() { A }",
3635                "b.rs": "const y: i32 = 1",
3636            }),
3637        )
3638        .await;
3639
3640        let project = Project::test(fs, &mut cx);
3641        project.update(&mut cx, |project, _| {
3642            Arc::get_mut(&mut project.languages).unwrap().add(language);
3643        });
3644
3645        let (tree, _) = project
3646            .update(&mut cx, |project, cx| {
3647                project.find_or_create_local_worktree("/dir", false, cx)
3648            })
3649            .await
3650            .unwrap();
3651        let worktree_id = tree.read_with(&cx, |tree, _| tree.id());
3652
3653        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3654            .await;
3655
3656        // Cause worktree to start the fake language server
3657        let _buffer = project
3658            .update(&mut cx, |project, cx| {
3659                project.open_buffer((worktree_id, Path::new("b.rs")), cx)
3660            })
3661            .await
3662            .unwrap();
3663
3664        let mut events = subscribe(&project, &mut cx);
3665
3666        let mut fake_server = fake_servers.next().await.unwrap();
3667        fake_server.start_progress(&progress_token).await;
3668        assert_eq!(
3669            events.next().await.unwrap(),
3670            Event::DiskBasedDiagnosticsStarted
3671        );
3672
3673        fake_server.start_progress(&progress_token).await;
3674        fake_server.end_progress(&progress_token).await;
3675        fake_server.start_progress(&progress_token).await;
3676
3677        fake_server
3678            .notify::<lsp::notification::PublishDiagnostics>(lsp::PublishDiagnosticsParams {
3679                uri: Url::from_file_path("/dir/a.rs").unwrap(),
3680                version: None,
3681                diagnostics: vec![lsp::Diagnostic {
3682                    range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
3683                    severity: Some(lsp::DiagnosticSeverity::ERROR),
3684                    message: "undefined variable 'A'".to_string(),
3685                    ..Default::default()
3686                }],
3687            })
3688            .await;
3689        assert_eq!(
3690            events.next().await.unwrap(),
3691            Event::DiagnosticsUpdated((worktree_id, Path::new("a.rs")).into())
3692        );
3693
3694        fake_server.end_progress(&progress_token).await;
3695        fake_server.end_progress(&progress_token).await;
3696        assert_eq!(
3697            events.next().await.unwrap(),
3698            Event::DiskBasedDiagnosticsUpdated
3699        );
3700        assert_eq!(
3701            events.next().await.unwrap(),
3702            Event::DiskBasedDiagnosticsFinished
3703        );
3704
3705        let buffer = project
3706            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
3707            .await
3708            .unwrap();
3709
3710        buffer.read_with(&cx, |buffer, _| {
3711            let snapshot = buffer.snapshot();
3712            let diagnostics = snapshot
3713                .diagnostics_in_range::<_, Point>(0..buffer.len())
3714                .collect::<Vec<_>>();
3715            assert_eq!(
3716                diagnostics,
3717                &[DiagnosticEntry {
3718                    range: Point::new(0, 9)..Point::new(0, 10),
3719                    diagnostic: Diagnostic {
3720                        severity: lsp::DiagnosticSeverity::ERROR,
3721                        message: "undefined variable 'A'".to_string(),
3722                        group_id: 0,
3723                        is_primary: true,
3724                        ..Default::default()
3725                    }
3726                }]
3727            )
3728        });
3729    }
3730
3731    #[gpui::test]
3732    async fn test_search_worktree_without_files(mut cx: gpui::TestAppContext) {
3733        let dir = temp_tree(json!({
3734            "root": {
3735                "dir1": {},
3736                "dir2": {
3737                    "dir3": {}
3738                }
3739            }
3740        }));
3741
3742        let project = Project::test(Arc::new(RealFs), &mut cx);
3743        let (tree, _) = project
3744            .update(&mut cx, |project, cx| {
3745                project.find_or_create_local_worktree(&dir.path(), false, cx)
3746            })
3747            .await
3748            .unwrap();
3749
3750        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3751            .await;
3752
3753        let cancel_flag = Default::default();
3754        let results = project
3755            .read_with(&cx, |project, cx| {
3756                project.match_paths("dir", false, false, 10, &cancel_flag, cx)
3757            })
3758            .await;
3759
3760        assert!(results.is_empty());
3761    }
3762
3763    #[gpui::test]
3764    async fn test_definition(mut cx: gpui::TestAppContext) {
3765        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
3766        let language = Arc::new(Language::new(
3767            LanguageConfig {
3768                name: "Rust".into(),
3769                path_suffixes: vec!["rs".to_string()],
3770                language_server: Some(language_server_config),
3771                ..Default::default()
3772            },
3773            Some(tree_sitter_rust::language()),
3774        ));
3775
3776        let fs = FakeFs::new(cx.background());
3777        fs.insert_tree(
3778            "/dir",
3779            json!({
3780                "a.rs": "const fn a() { A }",
3781                "b.rs": "const y: i32 = crate::a()",
3782            }),
3783        )
3784        .await;
3785
3786        let project = Project::test(fs, &mut cx);
3787        project.update(&mut cx, |project, _| {
3788            Arc::get_mut(&mut project.languages).unwrap().add(language);
3789        });
3790
3791        let (tree, _) = project
3792            .update(&mut cx, |project, cx| {
3793                project.find_or_create_local_worktree("/dir/b.rs", false, cx)
3794            })
3795            .await
3796            .unwrap();
3797        let worktree_id = tree.read_with(&cx, |tree, _| tree.id());
3798        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
3799            .await;
3800
3801        let buffer = project
3802            .update(&mut cx, |project, cx| {
3803                project.open_buffer(
3804                    ProjectPath {
3805                        worktree_id,
3806                        path: Path::new("").into(),
3807                    },
3808                    cx,
3809                )
3810            })
3811            .await
3812            .unwrap();
3813
3814        let mut fake_server = fake_servers.next().await.unwrap();
3815        fake_server.handle_request::<lsp::request::GotoDefinition, _>(move |params, _| {
3816            let params = params.text_document_position_params;
3817            assert_eq!(
3818                params.text_document.uri.to_file_path().unwrap(),
3819                Path::new("/dir/b.rs"),
3820            );
3821            assert_eq!(params.position, lsp::Position::new(0, 22));
3822
3823            Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location::new(
3824                lsp::Url::from_file_path("/dir/a.rs").unwrap(),
3825                lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
3826            )))
3827        });
3828
3829        let mut definitions = project
3830            .update(&mut cx, |project, cx| project.definition(&buffer, 22, cx))
3831            .await
3832            .unwrap();
3833
3834        assert_eq!(definitions.len(), 1);
3835        let definition = definitions.pop().unwrap();
3836        cx.update(|cx| {
3837            let target_buffer = definition.buffer.read(cx);
3838            assert_eq!(
3839                target_buffer
3840                    .file()
3841                    .unwrap()
3842                    .as_local()
3843                    .unwrap()
3844                    .abs_path(cx),
3845                Path::new("/dir/a.rs"),
3846            );
3847            assert_eq!(definition.range.to_offset(target_buffer), 9..10);
3848            assert_eq!(
3849                list_worktrees(&project, cx),
3850                [("/dir/b.rs".as_ref(), false), ("/dir/a.rs".as_ref(), true)]
3851            );
3852
3853            drop(definition);
3854        });
3855        cx.read(|cx| {
3856            assert_eq!(
3857                list_worktrees(&project, cx),
3858                [("/dir/b.rs".as_ref(), false)]
3859            );
3860        });
3861
3862        fn list_worktrees<'a>(
3863            project: &'a ModelHandle<Project>,
3864            cx: &'a AppContext,
3865        ) -> Vec<(&'a Path, bool)> {
3866            project
3867                .read(cx)
3868                .worktrees(cx)
3869                .map(|worktree| {
3870                    let worktree = worktree.read(cx);
3871                    (
3872                        worktree.as_local().unwrap().abs_path().as_ref(),
3873                        worktree.is_weak(),
3874                    )
3875                })
3876                .collect::<Vec<_>>()
3877        }
3878    }
3879
3880    #[gpui::test]
3881    async fn test_save_file(mut cx: gpui::TestAppContext) {
3882        let fs = FakeFs::new(cx.background());
3883        fs.insert_tree(
3884            "/dir",
3885            json!({
3886                "file1": "the old contents",
3887            }),
3888        )
3889        .await;
3890
3891        let project = Project::test(fs.clone(), &mut cx);
3892        let worktree_id = project
3893            .update(&mut cx, |p, cx| {
3894                p.find_or_create_local_worktree("/dir", false, cx)
3895            })
3896            .await
3897            .unwrap()
3898            .0
3899            .read_with(&cx, |tree, _| tree.id());
3900
3901        let buffer = project
3902            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
3903            .await
3904            .unwrap();
3905        buffer
3906            .update(&mut cx, |buffer, cx| {
3907                assert_eq!(buffer.text(), "the old contents");
3908                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
3909                buffer.save(cx)
3910            })
3911            .await
3912            .unwrap();
3913
3914        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
3915        assert_eq!(new_text, buffer.read_with(&cx, |buffer, _| buffer.text()));
3916    }
3917
3918    #[gpui::test]
3919    async fn test_save_in_single_file_worktree(mut cx: gpui::TestAppContext) {
3920        let fs = FakeFs::new(cx.background());
3921        fs.insert_tree(
3922            "/dir",
3923            json!({
3924                "file1": "the old contents",
3925            }),
3926        )
3927        .await;
3928
3929        let project = Project::test(fs.clone(), &mut cx);
3930        let worktree_id = project
3931            .update(&mut cx, |p, cx| {
3932                p.find_or_create_local_worktree("/dir/file1", false, cx)
3933            })
3934            .await
3935            .unwrap()
3936            .0
3937            .read_with(&cx, |tree, _| tree.id());
3938
3939        let buffer = project
3940            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, ""), cx))
3941            .await
3942            .unwrap();
3943        buffer
3944            .update(&mut cx, |buffer, cx| {
3945                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
3946                buffer.save(cx)
3947            })
3948            .await
3949            .unwrap();
3950
3951        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
3952        assert_eq!(new_text, buffer.read_with(&cx, |buffer, _| buffer.text()));
3953    }
3954
3955    #[gpui::test(retries = 5)]
3956    async fn test_rescan_and_remote_updates(mut cx: gpui::TestAppContext) {
3957        let dir = temp_tree(json!({
3958            "a": {
3959                "file1": "",
3960                "file2": "",
3961                "file3": "",
3962            },
3963            "b": {
3964                "c": {
3965                    "file4": "",
3966                    "file5": "",
3967                }
3968            }
3969        }));
3970
3971        let project = Project::test(Arc::new(RealFs), &mut cx);
3972        let rpc = project.read_with(&cx, |p, _| p.client.clone());
3973
3974        let (tree, _) = project
3975            .update(&mut cx, |p, cx| {
3976                p.find_or_create_local_worktree(dir.path(), false, cx)
3977            })
3978            .await
3979            .unwrap();
3980        let worktree_id = tree.read_with(&cx, |tree, _| tree.id());
3981
3982        let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
3983            let buffer = project.update(cx, |p, cx| p.open_buffer((worktree_id, path), cx));
3984            async move { buffer.await.unwrap() }
3985        };
3986        let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
3987            tree.read_with(cx, |tree, _| {
3988                tree.entry_for_path(path)
3989                    .expect(&format!("no entry for path {}", path))
3990                    .id
3991            })
3992        };
3993
3994        let buffer2 = buffer_for_path("a/file2", &mut cx).await;
3995        let buffer3 = buffer_for_path("a/file3", &mut cx).await;
3996        let buffer4 = buffer_for_path("b/c/file4", &mut cx).await;
3997        let buffer5 = buffer_for_path("b/c/file5", &mut cx).await;
3998
3999        let file2_id = id_for_path("a/file2", &cx);
4000        let file3_id = id_for_path("a/file3", &cx);
4001        let file4_id = id_for_path("b/c/file4", &cx);
4002
4003        // Wait for the initial scan.
4004        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
4005            .await;
4006
4007        // Create a remote copy of this worktree.
4008        let initial_snapshot = tree.read_with(&cx, |tree, _| tree.as_local().unwrap().snapshot());
4009        let (remote, load_task) = cx.update(|cx| {
4010            Worktree::remote(
4011                1,
4012                1,
4013                initial_snapshot.to_proto(&Default::default(), Default::default()),
4014                rpc.clone(),
4015                cx,
4016            )
4017        });
4018        load_task.await;
4019
4020        cx.read(|cx| {
4021            assert!(!buffer2.read(cx).is_dirty());
4022            assert!(!buffer3.read(cx).is_dirty());
4023            assert!(!buffer4.read(cx).is_dirty());
4024            assert!(!buffer5.read(cx).is_dirty());
4025        });
4026
4027        // Rename and delete files and directories.
4028        tree.flush_fs_events(&cx).await;
4029        std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
4030        std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
4031        std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
4032        std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
4033        tree.flush_fs_events(&cx).await;
4034
4035        let expected_paths = vec![
4036            "a",
4037            "a/file1",
4038            "a/file2.new",
4039            "b",
4040            "d",
4041            "d/file3",
4042            "d/file4",
4043        ];
4044
4045        cx.read(|app| {
4046            assert_eq!(
4047                tree.read(app)
4048                    .paths()
4049                    .map(|p| p.to_str().unwrap())
4050                    .collect::<Vec<_>>(),
4051                expected_paths
4052            );
4053
4054            assert_eq!(id_for_path("a/file2.new", &cx), file2_id);
4055            assert_eq!(id_for_path("d/file3", &cx), file3_id);
4056            assert_eq!(id_for_path("d/file4", &cx), file4_id);
4057
4058            assert_eq!(
4059                buffer2.read(app).file().unwrap().path().as_ref(),
4060                Path::new("a/file2.new")
4061            );
4062            assert_eq!(
4063                buffer3.read(app).file().unwrap().path().as_ref(),
4064                Path::new("d/file3")
4065            );
4066            assert_eq!(
4067                buffer4.read(app).file().unwrap().path().as_ref(),
4068                Path::new("d/file4")
4069            );
4070            assert_eq!(
4071                buffer5.read(app).file().unwrap().path().as_ref(),
4072                Path::new("b/c/file5")
4073            );
4074
4075            assert!(!buffer2.read(app).file().unwrap().is_deleted());
4076            assert!(!buffer3.read(app).file().unwrap().is_deleted());
4077            assert!(!buffer4.read(app).file().unwrap().is_deleted());
4078            assert!(buffer5.read(app).file().unwrap().is_deleted());
4079        });
4080
4081        // Update the remote worktree. Check that it becomes consistent with the
4082        // local worktree.
4083        remote.update(&mut cx, |remote, cx| {
4084            let update_message = tree.read(cx).as_local().unwrap().snapshot().build_update(
4085                &initial_snapshot,
4086                1,
4087                1,
4088                true,
4089            );
4090            remote
4091                .as_remote_mut()
4092                .unwrap()
4093                .snapshot
4094                .apply_remote_update(update_message)
4095                .unwrap();
4096
4097            assert_eq!(
4098                remote
4099                    .paths()
4100                    .map(|p| p.to_str().unwrap())
4101                    .collect::<Vec<_>>(),
4102                expected_paths
4103            );
4104        });
4105    }
4106
4107    #[gpui::test]
4108    async fn test_buffer_deduping(mut cx: gpui::TestAppContext) {
4109        let fs = FakeFs::new(cx.background());
4110        fs.insert_tree(
4111            "/the-dir",
4112            json!({
4113                "a.txt": "a-contents",
4114                "b.txt": "b-contents",
4115            }),
4116        )
4117        .await;
4118
4119        let project = Project::test(fs.clone(), &mut cx);
4120        let worktree_id = project
4121            .update(&mut cx, |p, cx| {
4122                p.find_or_create_local_worktree("/the-dir", false, cx)
4123            })
4124            .await
4125            .unwrap()
4126            .0
4127            .read_with(&cx, |tree, _| tree.id());
4128
4129        // Spawn multiple tasks to open paths, repeating some paths.
4130        let (buffer_a_1, buffer_b, buffer_a_2) = project.update(&mut cx, |p, cx| {
4131            (
4132                p.open_buffer((worktree_id, "a.txt"), cx),
4133                p.open_buffer((worktree_id, "b.txt"), cx),
4134                p.open_buffer((worktree_id, "a.txt"), cx),
4135            )
4136        });
4137
4138        let buffer_a_1 = buffer_a_1.await.unwrap();
4139        let buffer_a_2 = buffer_a_2.await.unwrap();
4140        let buffer_b = buffer_b.await.unwrap();
4141        assert_eq!(buffer_a_1.read_with(&cx, |b, _| b.text()), "a-contents");
4142        assert_eq!(buffer_b.read_with(&cx, |b, _| b.text()), "b-contents");
4143
4144        // There is only one buffer per path.
4145        let buffer_a_id = buffer_a_1.id();
4146        assert_eq!(buffer_a_2.id(), buffer_a_id);
4147
4148        // Open the same path again while it is still open.
4149        drop(buffer_a_1);
4150        let buffer_a_3 = project
4151            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
4152            .await
4153            .unwrap();
4154
4155        // There's still only one buffer per path.
4156        assert_eq!(buffer_a_3.id(), buffer_a_id);
4157    }
4158
4159    #[gpui::test]
4160    async fn test_buffer_is_dirty(mut cx: gpui::TestAppContext) {
4161        use std::fs;
4162
4163        let dir = temp_tree(json!({
4164            "file1": "abc",
4165            "file2": "def",
4166            "file3": "ghi",
4167        }));
4168
4169        let project = Project::test(Arc::new(RealFs), &mut cx);
4170        let (worktree, _) = project
4171            .update(&mut cx, |p, cx| {
4172                p.find_or_create_local_worktree(dir.path(), false, cx)
4173            })
4174            .await
4175            .unwrap();
4176        let worktree_id = worktree.read_with(&cx, |worktree, _| worktree.id());
4177
4178        worktree.flush_fs_events(&cx).await;
4179        worktree
4180            .read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
4181            .await;
4182
4183        let buffer1 = project
4184            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
4185            .await
4186            .unwrap();
4187        let events = Rc::new(RefCell::new(Vec::new()));
4188
4189        // initially, the buffer isn't dirty.
4190        buffer1.update(&mut cx, |buffer, cx| {
4191            cx.subscribe(&buffer1, {
4192                let events = events.clone();
4193                move |_, _, event, _| events.borrow_mut().push(event.clone())
4194            })
4195            .detach();
4196
4197            assert!(!buffer.is_dirty());
4198            assert!(events.borrow().is_empty());
4199
4200            buffer.edit(vec![1..2], "", cx);
4201        });
4202
4203        // after the first edit, the buffer is dirty, and emits a dirtied event.
4204        buffer1.update(&mut cx, |buffer, cx| {
4205            assert!(buffer.text() == "ac");
4206            assert!(buffer.is_dirty());
4207            assert_eq!(
4208                *events.borrow(),
4209                &[language::Event::Edited, language::Event::Dirtied]
4210            );
4211            events.borrow_mut().clear();
4212            buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
4213        });
4214
4215        // after saving, the buffer is not dirty, and emits a saved event.
4216        buffer1.update(&mut cx, |buffer, cx| {
4217            assert!(!buffer.is_dirty());
4218            assert_eq!(*events.borrow(), &[language::Event::Saved]);
4219            events.borrow_mut().clear();
4220
4221            buffer.edit(vec![1..1], "B", cx);
4222            buffer.edit(vec![2..2], "D", cx);
4223        });
4224
4225        // after editing again, the buffer is dirty, and emits another dirty event.
4226        buffer1.update(&mut cx, |buffer, cx| {
4227            assert!(buffer.text() == "aBDc");
4228            assert!(buffer.is_dirty());
4229            assert_eq!(
4230                *events.borrow(),
4231                &[
4232                    language::Event::Edited,
4233                    language::Event::Dirtied,
4234                    language::Event::Edited,
4235                ],
4236            );
4237            events.borrow_mut().clear();
4238
4239            // TODO - currently, after restoring the buffer to its
4240            // previously-saved state, the is still considered dirty.
4241            buffer.edit([1..3], "", cx);
4242            assert!(buffer.text() == "ac");
4243            assert!(buffer.is_dirty());
4244        });
4245
4246        assert_eq!(*events.borrow(), &[language::Event::Edited]);
4247
4248        // When a file is deleted, the buffer is considered dirty.
4249        let events = Rc::new(RefCell::new(Vec::new()));
4250        let buffer2 = project
4251            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "file2"), cx))
4252            .await
4253            .unwrap();
4254        buffer2.update(&mut cx, |_, cx| {
4255            cx.subscribe(&buffer2, {
4256                let events = events.clone();
4257                move |_, _, event, _| events.borrow_mut().push(event.clone())
4258            })
4259            .detach();
4260        });
4261
4262        fs::remove_file(dir.path().join("file2")).unwrap();
4263        buffer2.condition(&cx, |b, _| b.is_dirty()).await;
4264        assert_eq!(
4265            *events.borrow(),
4266            &[language::Event::Dirtied, language::Event::FileHandleChanged]
4267        );
4268
4269        // When a file is already dirty when deleted, we don't emit a Dirtied event.
4270        let events = Rc::new(RefCell::new(Vec::new()));
4271        let buffer3 = project
4272            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "file3"), cx))
4273            .await
4274            .unwrap();
4275        buffer3.update(&mut cx, |_, cx| {
4276            cx.subscribe(&buffer3, {
4277                let events = events.clone();
4278                move |_, _, event, _| events.borrow_mut().push(event.clone())
4279            })
4280            .detach();
4281        });
4282
4283        worktree.flush_fs_events(&cx).await;
4284        buffer3.update(&mut cx, |buffer, cx| {
4285            buffer.edit(Some(0..0), "x", cx);
4286        });
4287        events.borrow_mut().clear();
4288        fs::remove_file(dir.path().join("file3")).unwrap();
4289        buffer3
4290            .condition(&cx, |_, _| !events.borrow().is_empty())
4291            .await;
4292        assert_eq!(*events.borrow(), &[language::Event::FileHandleChanged]);
4293        cx.read(|cx| assert!(buffer3.read(cx).is_dirty()));
4294    }
4295
4296    #[gpui::test]
4297    async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) {
4298        use std::fs;
4299
4300        let initial_contents = "aaa\nbbbbb\nc\n";
4301        let dir = temp_tree(json!({ "the-file": initial_contents }));
4302
4303        let project = Project::test(Arc::new(RealFs), &mut cx);
4304        let (worktree, _) = project
4305            .update(&mut cx, |p, cx| {
4306                p.find_or_create_local_worktree(dir.path(), false, cx)
4307            })
4308            .await
4309            .unwrap();
4310        let worktree_id = worktree.read_with(&cx, |tree, _| tree.id());
4311
4312        worktree
4313            .read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
4314            .await;
4315
4316        let abs_path = dir.path().join("the-file");
4317        let buffer = project
4318            .update(&mut cx, |p, cx| {
4319                p.open_buffer((worktree_id, "the-file"), cx)
4320            })
4321            .await
4322            .unwrap();
4323
4324        // TODO
4325        // Add a cursor on each row.
4326        // let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
4327        //     assert!(!buffer.is_dirty());
4328        //     buffer.add_selection_set(
4329        //         &(0..3)
4330        //             .map(|row| Selection {
4331        //                 id: row as usize,
4332        //                 start: Point::new(row, 1),
4333        //                 end: Point::new(row, 1),
4334        //                 reversed: false,
4335        //                 goal: SelectionGoal::None,
4336        //             })
4337        //             .collect::<Vec<_>>(),
4338        //         cx,
4339        //     )
4340        // });
4341
4342        // Change the file on disk, adding two new lines of text, and removing
4343        // one line.
4344        buffer.read_with(&cx, |buffer, _| {
4345            assert!(!buffer.is_dirty());
4346            assert!(!buffer.has_conflict());
4347        });
4348        let new_contents = "AAAA\naaa\nBB\nbbbbb\n";
4349        fs::write(&abs_path, new_contents).unwrap();
4350
4351        // Because the buffer was not modified, it is reloaded from disk. Its
4352        // contents are edited according to the diff between the old and new
4353        // file contents.
4354        buffer
4355            .condition(&cx, |buffer, _| buffer.text() == new_contents)
4356            .await;
4357
4358        buffer.update(&mut cx, |buffer, _| {
4359            assert_eq!(buffer.text(), new_contents);
4360            assert!(!buffer.is_dirty());
4361            assert!(!buffer.has_conflict());
4362
4363            // TODO
4364            // let cursor_positions = buffer
4365            //     .selection_set(selection_set_id)
4366            //     .unwrap()
4367            //     .selections::<Point>(&*buffer)
4368            //     .map(|selection| {
4369            //         assert_eq!(selection.start, selection.end);
4370            //         selection.start
4371            //     })
4372            //     .collect::<Vec<_>>();
4373            // assert_eq!(
4374            //     cursor_positions,
4375            //     [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
4376            // );
4377        });
4378
4379        // Modify the buffer
4380        buffer.update(&mut cx, |buffer, cx| {
4381            buffer.edit(vec![0..0], " ", cx);
4382            assert!(buffer.is_dirty());
4383            assert!(!buffer.has_conflict());
4384        });
4385
4386        // Change the file on disk again, adding blank lines to the beginning.
4387        fs::write(&abs_path, "\n\n\nAAAA\naaa\nBB\nbbbbb\n").unwrap();
4388
4389        // Because the buffer is modified, it doesn't reload from disk, but is
4390        // marked as having a conflict.
4391        buffer
4392            .condition(&cx, |buffer, _| buffer.has_conflict())
4393            .await;
4394    }
4395
4396    #[gpui::test]
4397    async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) {
4398        let fs = FakeFs::new(cx.background());
4399        fs.insert_tree(
4400            "/the-dir",
4401            json!({
4402                "a.rs": "
4403                    fn foo(mut v: Vec<usize>) {
4404                        for x in &v {
4405                            v.push(1);
4406                        }
4407                    }
4408                "
4409                .unindent(),
4410            }),
4411        )
4412        .await;
4413
4414        let project = Project::test(fs.clone(), &mut cx);
4415        let (worktree, _) = project
4416            .update(&mut cx, |p, cx| {
4417                p.find_or_create_local_worktree("/the-dir", false, cx)
4418            })
4419            .await
4420            .unwrap();
4421        let worktree_id = worktree.read_with(&cx, |tree, _| tree.id());
4422
4423        let buffer = project
4424            .update(&mut cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
4425            .await
4426            .unwrap();
4427
4428        let buffer_uri = Url::from_file_path("/the-dir/a.rs").unwrap();
4429        let message = lsp::PublishDiagnosticsParams {
4430            uri: buffer_uri.clone(),
4431            diagnostics: vec![
4432                lsp::Diagnostic {
4433                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
4434                    severity: Some(DiagnosticSeverity::WARNING),
4435                    message: "error 1".to_string(),
4436                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
4437                        location: lsp::Location {
4438                            uri: buffer_uri.clone(),
4439                            range: lsp::Range::new(
4440                                lsp::Position::new(1, 8),
4441                                lsp::Position::new(1, 9),
4442                            ),
4443                        },
4444                        message: "error 1 hint 1".to_string(),
4445                    }]),
4446                    ..Default::default()
4447                },
4448                lsp::Diagnostic {
4449                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
4450                    severity: Some(DiagnosticSeverity::HINT),
4451                    message: "error 1 hint 1".to_string(),
4452                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
4453                        location: lsp::Location {
4454                            uri: buffer_uri.clone(),
4455                            range: lsp::Range::new(
4456                                lsp::Position::new(1, 8),
4457                                lsp::Position::new(1, 9),
4458                            ),
4459                        },
4460                        message: "original diagnostic".to_string(),
4461                    }]),
4462                    ..Default::default()
4463                },
4464                lsp::Diagnostic {
4465                    range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 17)),
4466                    severity: Some(DiagnosticSeverity::ERROR),
4467                    message: "error 2".to_string(),
4468                    related_information: Some(vec![
4469                        lsp::DiagnosticRelatedInformation {
4470                            location: lsp::Location {
4471                                uri: buffer_uri.clone(),
4472                                range: lsp::Range::new(
4473                                    lsp::Position::new(1, 13),
4474                                    lsp::Position::new(1, 15),
4475                                ),
4476                            },
4477                            message: "error 2 hint 1".to_string(),
4478                        },
4479                        lsp::DiagnosticRelatedInformation {
4480                            location: lsp::Location {
4481                                uri: buffer_uri.clone(),
4482                                range: lsp::Range::new(
4483                                    lsp::Position::new(1, 13),
4484                                    lsp::Position::new(1, 15),
4485                                ),
4486                            },
4487                            message: "error 2 hint 2".to_string(),
4488                        },
4489                    ]),
4490                    ..Default::default()
4491                },
4492                lsp::Diagnostic {
4493                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
4494                    severity: Some(DiagnosticSeverity::HINT),
4495                    message: "error 2 hint 1".to_string(),
4496                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
4497                        location: lsp::Location {
4498                            uri: buffer_uri.clone(),
4499                            range: lsp::Range::new(
4500                                lsp::Position::new(2, 8),
4501                                lsp::Position::new(2, 17),
4502                            ),
4503                        },
4504                        message: "original diagnostic".to_string(),
4505                    }]),
4506                    ..Default::default()
4507                },
4508                lsp::Diagnostic {
4509                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
4510                    severity: Some(DiagnosticSeverity::HINT),
4511                    message: "error 2 hint 2".to_string(),
4512                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
4513                        location: lsp::Location {
4514                            uri: buffer_uri.clone(),
4515                            range: lsp::Range::new(
4516                                lsp::Position::new(2, 8),
4517                                lsp::Position::new(2, 17),
4518                            ),
4519                        },
4520                        message: "original diagnostic".to_string(),
4521                    }]),
4522                    ..Default::default()
4523                },
4524            ],
4525            version: None,
4526        };
4527
4528        project
4529            .update(&mut cx, |p, cx| {
4530                p.update_diagnostics(message, &Default::default(), cx)
4531            })
4532            .unwrap();
4533        let buffer = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4534
4535        assert_eq!(
4536            buffer
4537                .diagnostics_in_range::<_, Point>(0..buffer.len())
4538                .collect::<Vec<_>>(),
4539            &[
4540                DiagnosticEntry {
4541                    range: Point::new(1, 8)..Point::new(1, 9),
4542                    diagnostic: Diagnostic {
4543                        severity: DiagnosticSeverity::WARNING,
4544                        message: "error 1".to_string(),
4545                        group_id: 0,
4546                        is_primary: true,
4547                        ..Default::default()
4548                    }
4549                },
4550                DiagnosticEntry {
4551                    range: Point::new(1, 8)..Point::new(1, 9),
4552                    diagnostic: Diagnostic {
4553                        severity: DiagnosticSeverity::HINT,
4554                        message: "error 1 hint 1".to_string(),
4555                        group_id: 0,
4556                        is_primary: false,
4557                        ..Default::default()
4558                    }
4559                },
4560                DiagnosticEntry {
4561                    range: Point::new(1, 13)..Point::new(1, 15),
4562                    diagnostic: Diagnostic {
4563                        severity: DiagnosticSeverity::HINT,
4564                        message: "error 2 hint 1".to_string(),
4565                        group_id: 1,
4566                        is_primary: false,
4567                        ..Default::default()
4568                    }
4569                },
4570                DiagnosticEntry {
4571                    range: Point::new(1, 13)..Point::new(1, 15),
4572                    diagnostic: Diagnostic {
4573                        severity: DiagnosticSeverity::HINT,
4574                        message: "error 2 hint 2".to_string(),
4575                        group_id: 1,
4576                        is_primary: false,
4577                        ..Default::default()
4578                    }
4579                },
4580                DiagnosticEntry {
4581                    range: Point::new(2, 8)..Point::new(2, 17),
4582                    diagnostic: Diagnostic {
4583                        severity: DiagnosticSeverity::ERROR,
4584                        message: "error 2".to_string(),
4585                        group_id: 1,
4586                        is_primary: true,
4587                        ..Default::default()
4588                    }
4589                }
4590            ]
4591        );
4592
4593        assert_eq!(
4594            buffer.diagnostic_group::<Point>(0).collect::<Vec<_>>(),
4595            &[
4596                DiagnosticEntry {
4597                    range: Point::new(1, 8)..Point::new(1, 9),
4598                    diagnostic: Diagnostic {
4599                        severity: DiagnosticSeverity::WARNING,
4600                        message: "error 1".to_string(),
4601                        group_id: 0,
4602                        is_primary: true,
4603                        ..Default::default()
4604                    }
4605                },
4606                DiagnosticEntry {
4607                    range: Point::new(1, 8)..Point::new(1, 9),
4608                    diagnostic: Diagnostic {
4609                        severity: DiagnosticSeverity::HINT,
4610                        message: "error 1 hint 1".to_string(),
4611                        group_id: 0,
4612                        is_primary: false,
4613                        ..Default::default()
4614                    }
4615                },
4616            ]
4617        );
4618        assert_eq!(
4619            buffer.diagnostic_group::<Point>(1).collect::<Vec<_>>(),
4620            &[
4621                DiagnosticEntry {
4622                    range: Point::new(1, 13)..Point::new(1, 15),
4623                    diagnostic: Diagnostic {
4624                        severity: DiagnosticSeverity::HINT,
4625                        message: "error 2 hint 1".to_string(),
4626                        group_id: 1,
4627                        is_primary: false,
4628                        ..Default::default()
4629                    }
4630                },
4631                DiagnosticEntry {
4632                    range: Point::new(1, 13)..Point::new(1, 15),
4633                    diagnostic: Diagnostic {
4634                        severity: DiagnosticSeverity::HINT,
4635                        message: "error 2 hint 2".to_string(),
4636                        group_id: 1,
4637                        is_primary: false,
4638                        ..Default::default()
4639                    }
4640                },
4641                DiagnosticEntry {
4642                    range: Point::new(2, 8)..Point::new(2, 17),
4643                    diagnostic: Diagnostic {
4644                        severity: DiagnosticSeverity::ERROR,
4645                        message: "error 2".to_string(),
4646                        group_id: 1,
4647                        is_primary: true,
4648                        ..Default::default()
4649                    }
4650                }
4651            ]
4652        );
4653    }
4654
4655    #[gpui::test]
4656    async fn test_rename(mut cx: gpui::TestAppContext) {
4657        let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
4658        let language = Arc::new(Language::new(
4659            LanguageConfig {
4660                name: "Rust".into(),
4661                path_suffixes: vec!["rs".to_string()],
4662                language_server: Some(language_server_config),
4663                ..Default::default()
4664            },
4665            Some(tree_sitter_rust::language()),
4666        ));
4667
4668        let fs = FakeFs::new(cx.background());
4669        fs.insert_tree(
4670            "/dir",
4671            json!({
4672                "one.rs": "const ONE: usize = 1;",
4673                "two.rs": "const TWO: usize = one::ONE + one::ONE;"
4674            }),
4675        )
4676        .await;
4677
4678        let project = Project::test(fs.clone(), &mut cx);
4679        project.update(&mut cx, |project, _| {
4680            Arc::get_mut(&mut project.languages).unwrap().add(language);
4681        });
4682
4683        let (tree, _) = project
4684            .update(&mut cx, |project, cx| {
4685                project.find_or_create_local_worktree("/dir", false, cx)
4686            })
4687            .await
4688            .unwrap();
4689        let worktree_id = tree.read_with(&cx, |tree, _| tree.id());
4690        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
4691            .await;
4692
4693        let buffer = project
4694            .update(&mut cx, |project, cx| {
4695                project.open_buffer((worktree_id, Path::new("one.rs")), cx)
4696            })
4697            .await
4698            .unwrap();
4699
4700        let mut fake_server = fake_servers.next().await.unwrap();
4701
4702        let response = project.update(&mut cx, |project, cx| {
4703            project.prepare_rename(buffer.clone(), 7, cx)
4704        });
4705        fake_server
4706            .handle_request::<lsp::request::PrepareRenameRequest, _>(|params, _| {
4707                assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
4708                assert_eq!(params.position, lsp::Position::new(0, 7));
4709                Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
4710                    lsp::Position::new(0, 6),
4711                    lsp::Position::new(0, 9),
4712                )))
4713            })
4714            .next()
4715            .await
4716            .unwrap();
4717        let range = response.await.unwrap().unwrap();
4718        let range = buffer.read_with(&cx, |buffer, _| range.to_offset(buffer));
4719        assert_eq!(range, 6..9);
4720
4721        let response = project.update(&mut cx, |project, cx| {
4722            project.perform_rename(buffer.clone(), 7, "THREE".to_string(), true, cx)
4723        });
4724        fake_server
4725            .handle_request::<lsp::request::Rename, _>(|params, _| {
4726                assert_eq!(
4727                    params.text_document_position.text_document.uri.as_str(),
4728                    "file:///dir/one.rs"
4729                );
4730                assert_eq!(
4731                    params.text_document_position.position,
4732                    lsp::Position::new(0, 7)
4733                );
4734                assert_eq!(params.new_name, "THREE");
4735                Some(lsp::WorkspaceEdit {
4736                    changes: Some(
4737                        [
4738                            (
4739                                lsp::Url::from_file_path("/dir/one.rs").unwrap(),
4740                                vec![lsp::TextEdit::new(
4741                                    lsp::Range::new(
4742                                        lsp::Position::new(0, 6),
4743                                        lsp::Position::new(0, 9),
4744                                    ),
4745                                    "THREE".to_string(),
4746                                )],
4747                            ),
4748                            (
4749                                lsp::Url::from_file_path("/dir/two.rs").unwrap(),
4750                                vec![
4751                                    lsp::TextEdit::new(
4752                                        lsp::Range::new(
4753                                            lsp::Position::new(0, 24),
4754                                            lsp::Position::new(0, 27),
4755                                        ),
4756                                        "THREE".to_string(),
4757                                    ),
4758                                    lsp::TextEdit::new(
4759                                        lsp::Range::new(
4760                                            lsp::Position::new(0, 35),
4761                                            lsp::Position::new(0, 38),
4762                                        ),
4763                                        "THREE".to_string(),
4764                                    ),
4765                                ],
4766                            ),
4767                        ]
4768                        .into_iter()
4769                        .collect(),
4770                    ),
4771                    ..Default::default()
4772                })
4773            })
4774            .next()
4775            .await
4776            .unwrap();
4777        let mut transaction = response.await.unwrap().0;
4778        assert_eq!(transaction.len(), 2);
4779        assert_eq!(
4780            transaction
4781                .remove_entry(&buffer)
4782                .unwrap()
4783                .0
4784                .read_with(&cx, |buffer, _| buffer.text()),
4785            "const THREE: usize = 1;"
4786        );
4787        assert_eq!(
4788            transaction
4789                .into_keys()
4790                .next()
4791                .unwrap()
4792                .read_with(&cx, |buffer, _| buffer.text()),
4793            "const TWO: usize = one::THREE + one::THREE;"
4794        );
4795    }
4796}