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