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