project.rs

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