project.rs

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