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