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