project.rs

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