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                    Ok(completions
2492                        .into_iter()
2493                        .filter_map(|lsp_completion| {
2494                            let (old_range, new_text) = match lsp_completion.text_edit.as_ref() {
2495                                Some(lsp::CompletionTextEdit::Edit(edit)) => {
2496                                    (range_from_lsp(edit.range), edit.new_text.clone())
2497                                }
2498                                None => {
2499                                    let clipped_position =
2500                                        this.clip_point_utf16(position, Bias::Left);
2501                                    if position != clipped_position {
2502                                        log::info!("completion out of expected range");
2503                                        return None;
2504                                    }
2505                                    (
2506                                        this.common_prefix_at(
2507                                            clipped_position,
2508                                            &lsp_completion.label,
2509                                        ),
2510                                        lsp_completion.label.clone(),
2511                                    )
2512                                }
2513                                Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
2514                                    log::info!("unsupported insert/replace completion");
2515                                    return None;
2516                                }
2517                            };
2518
2519                            let clipped_start = this.clip_point_utf16(old_range.start, Bias::Left);
2520                            let clipped_end = this.clip_point_utf16(old_range.end, Bias::Left);
2521                            if clipped_start == old_range.start && clipped_end == old_range.end {
2522                                Some(Completion {
2523                                    old_range: this.anchor_before(old_range.start)
2524                                        ..this.anchor_after(old_range.end),
2525                                    new_text,
2526                                    label: language
2527                                        .as_ref()
2528                                        .and_then(|l| l.label_for_completion(&lsp_completion))
2529                                        .unwrap_or_else(|| {
2530                                            CodeLabel::plain(
2531                                                lsp_completion.label.clone(),
2532                                                lsp_completion.filter_text.as_deref(),
2533                                            )
2534                                        }),
2535                                    lsp_completion,
2536                                })
2537                            } else {
2538                                log::info!("completion out of expected range");
2539                                None
2540                            }
2541                        })
2542                        .collect())
2543                })
2544            })
2545        } else if let Some(project_id) = self.remote_id() {
2546            let rpc = self.client.clone();
2547            let message = proto::GetCompletions {
2548                project_id,
2549                buffer_id,
2550                position: Some(language::proto::serialize_anchor(&anchor)),
2551                version: serialize_version(&source_buffer.version()),
2552            };
2553            cx.spawn_weak(|_, mut cx| async move {
2554                let response = rpc.request(message).await?;
2555
2556                source_buffer_handle
2557                    .update(&mut cx, |buffer, _| {
2558                        buffer.wait_for_version(deserialize_version(response.version))
2559                    })
2560                    .await;
2561
2562                response
2563                    .completions
2564                    .into_iter()
2565                    .map(|completion| {
2566                        language::proto::deserialize_completion(completion, language.as_ref())
2567                    })
2568                    .collect()
2569            })
2570        } else {
2571            Task::ready(Ok(Default::default()))
2572        }
2573    }
2574
2575    pub fn apply_additional_edits_for_completion(
2576        &self,
2577        buffer_handle: ModelHandle<Buffer>,
2578        completion: Completion,
2579        push_to_history: bool,
2580        cx: &mut ModelContext<Self>,
2581    ) -> Task<Result<Option<Transaction>>> {
2582        let buffer = buffer_handle.read(cx);
2583        let buffer_id = buffer.remote_id();
2584
2585        if self.is_local() {
2586            let (_, lang_server) = if let Some(server) = self.language_server_for_buffer(buffer, cx)
2587            {
2588                server.clone()
2589            } else {
2590                return Task::ready(Ok(Default::default()));
2591            };
2592
2593            cx.spawn(|this, mut cx| async move {
2594                let resolved_completion = lang_server
2595                    .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
2596                    .await?;
2597                if let Some(edits) = resolved_completion.additional_text_edits {
2598                    let edits = this
2599                        .update(&mut cx, |this, cx| {
2600                            this.edits_from_lsp(&buffer_handle, edits, None, cx)
2601                        })
2602                        .await?;
2603                    buffer_handle.update(&mut cx, |buffer, cx| {
2604                        buffer.finalize_last_transaction();
2605                        buffer.start_transaction();
2606                        for (range, text) in edits {
2607                            buffer.edit([range], text, cx);
2608                        }
2609                        let transaction = if buffer.end_transaction(cx).is_some() {
2610                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
2611                            if !push_to_history {
2612                                buffer.forget_transaction(transaction.id);
2613                            }
2614                            Some(transaction)
2615                        } else {
2616                            None
2617                        };
2618                        Ok(transaction)
2619                    })
2620                } else {
2621                    Ok(None)
2622                }
2623            })
2624        } else if let Some(project_id) = self.remote_id() {
2625            let client = self.client.clone();
2626            cx.spawn(|_, mut cx| async move {
2627                let response = client
2628                    .request(proto::ApplyCompletionAdditionalEdits {
2629                        project_id,
2630                        buffer_id,
2631                        completion: Some(language::proto::serialize_completion(&completion)),
2632                    })
2633                    .await?;
2634
2635                if let Some(transaction) = response.transaction {
2636                    let transaction = language::proto::deserialize_transaction(transaction)?;
2637                    buffer_handle
2638                        .update(&mut cx, |buffer, _| {
2639                            buffer.wait_for_edits(transaction.edit_ids.iter().copied())
2640                        })
2641                        .await;
2642                    if push_to_history {
2643                        buffer_handle.update(&mut cx, |buffer, _| {
2644                            buffer.push_transaction(transaction.clone(), Instant::now());
2645                        });
2646                    }
2647                    Ok(Some(transaction))
2648                } else {
2649                    Ok(None)
2650                }
2651            })
2652        } else {
2653            Task::ready(Err(anyhow!("project does not have a remote id")))
2654        }
2655    }
2656
2657    pub fn code_actions<T: Clone + ToOffset>(
2658        &self,
2659        buffer_handle: &ModelHandle<Buffer>,
2660        range: Range<T>,
2661        cx: &mut ModelContext<Self>,
2662    ) -> Task<Result<Vec<CodeAction>>> {
2663        let buffer_handle = buffer_handle.clone();
2664        let buffer = buffer_handle.read(cx);
2665        let snapshot = buffer.snapshot();
2666        let relevant_diagnostics = snapshot
2667            .diagnostics_in_range::<usize, usize>(range.to_offset(&snapshot), false)
2668            .map(|entry| entry.to_lsp_diagnostic_stub())
2669            .collect();
2670        let buffer_id = buffer.remote_id();
2671        let worktree;
2672        let buffer_abs_path;
2673        if let Some(file) = File::from_dyn(buffer.file()) {
2674            worktree = file.worktree.clone();
2675            buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
2676        } else {
2677            return Task::ready(Ok(Default::default()));
2678        };
2679        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
2680
2681        if worktree.read(cx).as_local().is_some() {
2682            let buffer_abs_path = buffer_abs_path.unwrap();
2683            let (_, lang_server) = if let Some(server) = self.language_server_for_buffer(buffer, cx)
2684            {
2685                server.clone()
2686            } else {
2687                return Task::ready(Ok(Default::default()));
2688            };
2689
2690            let lsp_range = range_to_lsp(range.to_point_utf16(buffer));
2691            cx.foreground().spawn(async move {
2692                if !lang_server.capabilities().code_action_provider.is_some() {
2693                    return Ok(Default::default());
2694                }
2695
2696                Ok(lang_server
2697                    .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
2698                        text_document: lsp::TextDocumentIdentifier::new(
2699                            lsp::Url::from_file_path(buffer_abs_path).unwrap(),
2700                        ),
2701                        range: lsp_range,
2702                        work_done_progress_params: Default::default(),
2703                        partial_result_params: Default::default(),
2704                        context: lsp::CodeActionContext {
2705                            diagnostics: relevant_diagnostics,
2706                            only: Some(vec![
2707                                lsp::CodeActionKind::QUICKFIX,
2708                                lsp::CodeActionKind::REFACTOR,
2709                                lsp::CodeActionKind::REFACTOR_EXTRACT,
2710                                lsp::CodeActionKind::SOURCE,
2711                            ]),
2712                        },
2713                    })
2714                    .await?
2715                    .unwrap_or_default()
2716                    .into_iter()
2717                    .filter_map(|entry| {
2718                        if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
2719                            Some(CodeAction {
2720                                range: range.clone(),
2721                                lsp_action,
2722                            })
2723                        } else {
2724                            None
2725                        }
2726                    })
2727                    .collect())
2728            })
2729        } else if let Some(project_id) = self.remote_id() {
2730            let rpc = self.client.clone();
2731            let version = buffer.version();
2732            cx.spawn_weak(|_, mut cx| async move {
2733                let response = rpc
2734                    .request(proto::GetCodeActions {
2735                        project_id,
2736                        buffer_id,
2737                        start: Some(language::proto::serialize_anchor(&range.start)),
2738                        end: Some(language::proto::serialize_anchor(&range.end)),
2739                        version: serialize_version(&version),
2740                    })
2741                    .await?;
2742
2743                buffer_handle
2744                    .update(&mut cx, |buffer, _| {
2745                        buffer.wait_for_version(deserialize_version(response.version))
2746                    })
2747                    .await;
2748
2749                response
2750                    .actions
2751                    .into_iter()
2752                    .map(language::proto::deserialize_code_action)
2753                    .collect()
2754            })
2755        } else {
2756            Task::ready(Ok(Default::default()))
2757        }
2758    }
2759
2760    pub fn apply_code_action(
2761        &self,
2762        buffer_handle: ModelHandle<Buffer>,
2763        mut action: CodeAction,
2764        push_to_history: bool,
2765        cx: &mut ModelContext<Self>,
2766    ) -> Task<Result<ProjectTransaction>> {
2767        if self.is_local() {
2768            let buffer = buffer_handle.read(cx);
2769            let (lsp_adapter, lang_server) =
2770                if let Some(server) = self.language_server_for_buffer(buffer, cx) {
2771                    server.clone()
2772                } else {
2773                    return Task::ready(Ok(Default::default()));
2774                };
2775            let range = action.range.to_point_utf16(buffer);
2776
2777            cx.spawn(|this, mut cx| async move {
2778                if let Some(lsp_range) = action
2779                    .lsp_action
2780                    .data
2781                    .as_mut()
2782                    .and_then(|d| d.get_mut("codeActionParams"))
2783                    .and_then(|d| d.get_mut("range"))
2784                {
2785                    *lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap();
2786                    action.lsp_action = lang_server
2787                        .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
2788                        .await?;
2789                } else {
2790                    let actions = this
2791                        .update(&mut cx, |this, cx| {
2792                            this.code_actions(&buffer_handle, action.range, cx)
2793                        })
2794                        .await?;
2795                    action.lsp_action = actions
2796                        .into_iter()
2797                        .find(|a| a.lsp_action.title == action.lsp_action.title)
2798                        .ok_or_else(|| anyhow!("code action is outdated"))?
2799                        .lsp_action;
2800                }
2801
2802                if let Some(edit) = action.lsp_action.edit {
2803                    Self::deserialize_workspace_edit(
2804                        this,
2805                        edit,
2806                        push_to_history,
2807                        lsp_adapter,
2808                        lang_server,
2809                        &mut cx,
2810                    )
2811                    .await
2812                } else if let Some(command) = action.lsp_action.command {
2813                    this.update(&mut cx, |this, _| {
2814                        this.last_workspace_edits_by_language_server
2815                            .remove(&lang_server.server_id());
2816                    });
2817                    lang_server
2818                        .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2819                            command: command.command,
2820                            arguments: command.arguments.unwrap_or_default(),
2821                            ..Default::default()
2822                        })
2823                        .await?;
2824                    Ok(this.update(&mut cx, |this, _| {
2825                        this.last_workspace_edits_by_language_server
2826                            .remove(&lang_server.server_id())
2827                            .unwrap_or_default()
2828                    }))
2829                } else {
2830                    Ok(ProjectTransaction::default())
2831                }
2832            })
2833        } else if let Some(project_id) = self.remote_id() {
2834            let client = self.client.clone();
2835            let request = proto::ApplyCodeAction {
2836                project_id,
2837                buffer_id: buffer_handle.read(cx).remote_id(),
2838                action: Some(language::proto::serialize_code_action(&action)),
2839            };
2840            cx.spawn(|this, mut cx| async move {
2841                let response = client
2842                    .request(request)
2843                    .await?
2844                    .transaction
2845                    .ok_or_else(|| anyhow!("missing transaction"))?;
2846                this.update(&mut cx, |this, cx| {
2847                    this.deserialize_project_transaction(response, push_to_history, cx)
2848                })
2849                .await
2850            })
2851        } else {
2852            Task::ready(Err(anyhow!("project does not have a remote id")))
2853        }
2854    }
2855
2856    async fn deserialize_workspace_edit(
2857        this: ModelHandle<Self>,
2858        edit: lsp::WorkspaceEdit,
2859        push_to_history: bool,
2860        lsp_adapter: Arc<dyn LspAdapter>,
2861        language_server: Arc<LanguageServer>,
2862        cx: &mut AsyncAppContext,
2863    ) -> Result<ProjectTransaction> {
2864        let fs = this.read_with(cx, |this, _| this.fs.clone());
2865        let mut operations = Vec::new();
2866        if let Some(document_changes) = edit.document_changes {
2867            match document_changes {
2868                lsp::DocumentChanges::Edits(edits) => {
2869                    operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2870                }
2871                lsp::DocumentChanges::Operations(ops) => operations = ops,
2872            }
2873        } else if let Some(changes) = edit.changes {
2874            operations.extend(changes.into_iter().map(|(uri, edits)| {
2875                lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2876                    text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2877                        uri,
2878                        version: None,
2879                    },
2880                    edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
2881                })
2882            }));
2883        }
2884
2885        let mut project_transaction = ProjectTransaction::default();
2886        for operation in operations {
2887            match operation {
2888                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2889                    let abs_path = op
2890                        .uri
2891                        .to_file_path()
2892                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2893
2894                    if let Some(parent_path) = abs_path.parent() {
2895                        fs.create_dir(parent_path).await?;
2896                    }
2897                    if abs_path.ends_with("/") {
2898                        fs.create_dir(&abs_path).await?;
2899                    } else {
2900                        fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
2901                            .await?;
2902                    }
2903                }
2904                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2905                    let source_abs_path = op
2906                        .old_uri
2907                        .to_file_path()
2908                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2909                    let target_abs_path = op
2910                        .new_uri
2911                        .to_file_path()
2912                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2913                    fs.rename(
2914                        &source_abs_path,
2915                        &target_abs_path,
2916                        op.options.map(Into::into).unwrap_or_default(),
2917                    )
2918                    .await?;
2919                }
2920                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2921                    let abs_path = op
2922                        .uri
2923                        .to_file_path()
2924                        .map_err(|_| anyhow!("can't convert URI to path"))?;
2925                    let options = op.options.map(Into::into).unwrap_or_default();
2926                    if abs_path.ends_with("/") {
2927                        fs.remove_dir(&abs_path, options).await?;
2928                    } else {
2929                        fs.remove_file(&abs_path, options).await?;
2930                    }
2931                }
2932                lsp::DocumentChangeOperation::Edit(op) => {
2933                    let buffer_to_edit = this
2934                        .update(cx, |this, cx| {
2935                            this.open_local_buffer_via_lsp(
2936                                op.text_document.uri,
2937                                lsp_adapter.clone(),
2938                                language_server.clone(),
2939                                cx,
2940                            )
2941                        })
2942                        .await?;
2943
2944                    let edits = this
2945                        .update(cx, |this, cx| {
2946                            let edits = op.edits.into_iter().map(|edit| match edit {
2947                                lsp::OneOf::Left(edit) => edit,
2948                                lsp::OneOf::Right(edit) => edit.text_edit,
2949                            });
2950                            this.edits_from_lsp(
2951                                &buffer_to_edit,
2952                                edits,
2953                                op.text_document.version,
2954                                cx,
2955                            )
2956                        })
2957                        .await?;
2958
2959                    let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2960                        buffer.finalize_last_transaction();
2961                        buffer.start_transaction();
2962                        for (range, text) in edits {
2963                            buffer.edit([range], text, cx);
2964                        }
2965                        let transaction = if buffer.end_transaction(cx).is_some() {
2966                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
2967                            if !push_to_history {
2968                                buffer.forget_transaction(transaction.id);
2969                            }
2970                            Some(transaction)
2971                        } else {
2972                            None
2973                        };
2974
2975                        transaction
2976                    });
2977                    if let Some(transaction) = transaction {
2978                        project_transaction.0.insert(buffer_to_edit, transaction);
2979                    }
2980                }
2981            }
2982        }
2983
2984        Ok(project_transaction)
2985    }
2986
2987    pub fn prepare_rename<T: ToPointUtf16>(
2988        &self,
2989        buffer: ModelHandle<Buffer>,
2990        position: T,
2991        cx: &mut ModelContext<Self>,
2992    ) -> Task<Result<Option<Range<Anchor>>>> {
2993        let position = position.to_point_utf16(buffer.read(cx));
2994        self.request_lsp(buffer, PrepareRename { position }, cx)
2995    }
2996
2997    pub fn perform_rename<T: ToPointUtf16>(
2998        &self,
2999        buffer: ModelHandle<Buffer>,
3000        position: T,
3001        new_name: String,
3002        push_to_history: bool,
3003        cx: &mut ModelContext<Self>,
3004    ) -> Task<Result<ProjectTransaction>> {
3005        let position = position.to_point_utf16(buffer.read(cx));
3006        self.request_lsp(
3007            buffer,
3008            PerformRename {
3009                position,
3010                new_name,
3011                push_to_history,
3012            },
3013            cx,
3014        )
3015    }
3016
3017    pub fn search(
3018        &self,
3019        query: SearchQuery,
3020        cx: &mut ModelContext<Self>,
3021    ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
3022        if self.is_local() {
3023            let snapshots = self
3024                .visible_worktrees(cx)
3025                .filter_map(|tree| {
3026                    let tree = tree.read(cx).as_local()?;
3027                    Some(tree.snapshot())
3028                })
3029                .collect::<Vec<_>>();
3030
3031            let background = cx.background().clone();
3032            let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
3033            if path_count == 0 {
3034                return Task::ready(Ok(Default::default()));
3035            }
3036            let workers = background.num_cpus().min(path_count);
3037            let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
3038            cx.background()
3039                .spawn({
3040                    let fs = self.fs.clone();
3041                    let background = cx.background().clone();
3042                    let query = query.clone();
3043                    async move {
3044                        let fs = &fs;
3045                        let query = &query;
3046                        let matching_paths_tx = &matching_paths_tx;
3047                        let paths_per_worker = (path_count + workers - 1) / workers;
3048                        let snapshots = &snapshots;
3049                        background
3050                            .scoped(|scope| {
3051                                for worker_ix in 0..workers {
3052                                    let worker_start_ix = worker_ix * paths_per_worker;
3053                                    let worker_end_ix = worker_start_ix + paths_per_worker;
3054                                    scope.spawn(async move {
3055                                        let mut snapshot_start_ix = 0;
3056                                        let mut abs_path = PathBuf::new();
3057                                        for snapshot in snapshots {
3058                                            let snapshot_end_ix =
3059                                                snapshot_start_ix + snapshot.visible_file_count();
3060                                            if worker_end_ix <= snapshot_start_ix {
3061                                                break;
3062                                            } else if worker_start_ix > snapshot_end_ix {
3063                                                snapshot_start_ix = snapshot_end_ix;
3064                                                continue;
3065                                            } else {
3066                                                let start_in_snapshot = worker_start_ix
3067                                                    .saturating_sub(snapshot_start_ix);
3068                                                let end_in_snapshot =
3069                                                    cmp::min(worker_end_ix, snapshot_end_ix)
3070                                                        - snapshot_start_ix;
3071
3072                                                for entry in snapshot
3073                                                    .files(false, start_in_snapshot)
3074                                                    .take(end_in_snapshot - start_in_snapshot)
3075                                                {
3076                                                    if matching_paths_tx.is_closed() {
3077                                                        break;
3078                                                    }
3079
3080                                                    abs_path.clear();
3081                                                    abs_path.push(&snapshot.abs_path());
3082                                                    abs_path.push(&entry.path);
3083                                                    let matches = if let Some(file) =
3084                                                        fs.open_sync(&abs_path).await.log_err()
3085                                                    {
3086                                                        query.detect(file).unwrap_or(false)
3087                                                    } else {
3088                                                        false
3089                                                    };
3090
3091                                                    if matches {
3092                                                        let project_path =
3093                                                            (snapshot.id(), entry.path.clone());
3094                                                        if matching_paths_tx
3095                                                            .send(project_path)
3096                                                            .await
3097                                                            .is_err()
3098                                                        {
3099                                                            break;
3100                                                        }
3101                                                    }
3102                                                }
3103
3104                                                snapshot_start_ix = snapshot_end_ix;
3105                                            }
3106                                        }
3107                                    });
3108                                }
3109                            })
3110                            .await;
3111                    }
3112                })
3113                .detach();
3114
3115            let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
3116            let open_buffers = self
3117                .opened_buffers
3118                .values()
3119                .filter_map(|b| b.upgrade(cx))
3120                .collect::<HashSet<_>>();
3121            cx.spawn(|this, cx| async move {
3122                for buffer in &open_buffers {
3123                    let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
3124                    buffers_tx.send((buffer.clone(), snapshot)).await?;
3125                }
3126
3127                let open_buffers = Rc::new(RefCell::new(open_buffers));
3128                while let Some(project_path) = matching_paths_rx.next().await {
3129                    if buffers_tx.is_closed() {
3130                        break;
3131                    }
3132
3133                    let this = this.clone();
3134                    let open_buffers = open_buffers.clone();
3135                    let buffers_tx = buffers_tx.clone();
3136                    cx.spawn(|mut cx| async move {
3137                        if let Some(buffer) = this
3138                            .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
3139                            .await
3140                            .log_err()
3141                        {
3142                            if open_buffers.borrow_mut().insert(buffer.clone()) {
3143                                let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
3144                                buffers_tx.send((buffer, snapshot)).await?;
3145                            }
3146                        }
3147
3148                        Ok::<_, anyhow::Error>(())
3149                    })
3150                    .detach();
3151                }
3152
3153                Ok::<_, anyhow::Error>(())
3154            })
3155            .detach_and_log_err(cx);
3156
3157            let background = cx.background().clone();
3158            cx.background().spawn(async move {
3159                let query = &query;
3160                let mut matched_buffers = Vec::new();
3161                for _ in 0..workers {
3162                    matched_buffers.push(HashMap::default());
3163                }
3164                background
3165                    .scoped(|scope| {
3166                        for worker_matched_buffers in matched_buffers.iter_mut() {
3167                            let mut buffers_rx = buffers_rx.clone();
3168                            scope.spawn(async move {
3169                                while let Some((buffer, snapshot)) = buffers_rx.next().await {
3170                                    let buffer_matches = query
3171                                        .search(snapshot.as_rope())
3172                                        .await
3173                                        .iter()
3174                                        .map(|range| {
3175                                            snapshot.anchor_before(range.start)
3176                                                ..snapshot.anchor_after(range.end)
3177                                        })
3178                                        .collect::<Vec<_>>();
3179                                    if !buffer_matches.is_empty() {
3180                                        worker_matched_buffers
3181                                            .insert(buffer.clone(), buffer_matches);
3182                                    }
3183                                }
3184                            });
3185                        }
3186                    })
3187                    .await;
3188                Ok(matched_buffers.into_iter().flatten().collect())
3189            })
3190        } else if let Some(project_id) = self.remote_id() {
3191            let request = self.client.request(query.to_proto(project_id));
3192            cx.spawn(|this, mut cx| async move {
3193                let response = request.await?;
3194                let mut result = HashMap::default();
3195                for location in response.locations {
3196                    let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
3197                    let target_buffer = this
3198                        .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
3199                        .await?;
3200                    let start = location
3201                        .start
3202                        .and_then(deserialize_anchor)
3203                        .ok_or_else(|| anyhow!("missing target start"))?;
3204                    let end = location
3205                        .end
3206                        .and_then(deserialize_anchor)
3207                        .ok_or_else(|| anyhow!("missing target end"))?;
3208                    result
3209                        .entry(target_buffer)
3210                        .or_insert(Vec::new())
3211                        .push(start..end)
3212                }
3213                Ok(result)
3214            })
3215        } else {
3216            Task::ready(Ok(Default::default()))
3217        }
3218    }
3219
3220    fn request_lsp<R: LspCommand>(
3221        &self,
3222        buffer_handle: ModelHandle<Buffer>,
3223        request: R,
3224        cx: &mut ModelContext<Self>,
3225    ) -> Task<Result<R::Response>>
3226    where
3227        <R::LspRequest as lsp::request::Request>::Result: Send,
3228    {
3229        let buffer = buffer_handle.read(cx);
3230        if self.is_local() {
3231            let file = File::from_dyn(buffer.file()).and_then(File::as_local);
3232            if let Some((file, (_, language_server))) =
3233                file.zip(self.language_server_for_buffer(buffer, cx).cloned())
3234            {
3235                let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
3236                return cx.spawn(|this, cx| async move {
3237                    if !request.check_capabilities(&language_server.capabilities()) {
3238                        return Ok(Default::default());
3239                    }
3240
3241                    let response = language_server
3242                        .request::<R::LspRequest>(lsp_params)
3243                        .await
3244                        .context("lsp request failed")?;
3245                    request
3246                        .response_from_lsp(response, this, buffer_handle, cx)
3247                        .await
3248                });
3249            }
3250        } else if let Some(project_id) = self.remote_id() {
3251            let rpc = self.client.clone();
3252            let message = request.to_proto(project_id, buffer);
3253            return cx.spawn(|this, cx| async move {
3254                let response = rpc.request(message).await?;
3255                request
3256                    .response_from_proto(response, this, buffer_handle, cx)
3257                    .await
3258            });
3259        }
3260        Task::ready(Ok(Default::default()))
3261    }
3262
3263    pub fn find_or_create_local_worktree(
3264        &mut self,
3265        abs_path: impl AsRef<Path>,
3266        visible: bool,
3267        cx: &mut ModelContext<Self>,
3268    ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
3269        let abs_path = abs_path.as_ref();
3270        if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
3271            Task::ready(Ok((tree.clone(), relative_path.into())))
3272        } else {
3273            let worktree = self.create_local_worktree(abs_path, visible, cx);
3274            cx.foreground()
3275                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
3276        }
3277    }
3278
3279    pub fn find_local_worktree(
3280        &self,
3281        abs_path: &Path,
3282        cx: &AppContext,
3283    ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
3284        for tree in self.worktrees(cx) {
3285            if let Some(relative_path) = tree
3286                .read(cx)
3287                .as_local()
3288                .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
3289            {
3290                return Some((tree.clone(), relative_path.into()));
3291            }
3292        }
3293        None
3294    }
3295
3296    pub fn is_shared(&self) -> bool {
3297        match &self.client_state {
3298            ProjectClientState::Local { is_shared, .. } => *is_shared,
3299            ProjectClientState::Remote { .. } => false,
3300        }
3301    }
3302
3303    fn create_local_worktree(
3304        &mut self,
3305        abs_path: impl AsRef<Path>,
3306        visible: bool,
3307        cx: &mut ModelContext<Self>,
3308    ) -> Task<Result<ModelHandle<Worktree>>> {
3309        let fs = self.fs.clone();
3310        let client = self.client.clone();
3311        let next_entry_id = self.next_entry_id.clone();
3312        let path: Arc<Path> = abs_path.as_ref().into();
3313        let task = self
3314            .loading_local_worktrees
3315            .entry(path.clone())
3316            .or_insert_with(|| {
3317                cx.spawn(|project, mut cx| {
3318                    async move {
3319                        let worktree = Worktree::local(
3320                            client.clone(),
3321                            path.clone(),
3322                            visible,
3323                            fs,
3324                            next_entry_id,
3325                            &mut cx,
3326                        )
3327                        .await;
3328                        project.update(&mut cx, |project, _| {
3329                            project.loading_local_worktrees.remove(&path);
3330                        });
3331                        let worktree = worktree?;
3332
3333                        let (remote_project_id, is_shared) =
3334                            project.update(&mut cx, |project, cx| {
3335                                project.add_worktree(&worktree, cx);
3336                                (project.remote_id(), project.is_shared())
3337                            });
3338
3339                        if let Some(project_id) = remote_project_id {
3340                            if is_shared {
3341                                worktree
3342                                    .update(&mut cx, |worktree, cx| {
3343                                        worktree.as_local_mut().unwrap().share(project_id, cx)
3344                                    })
3345                                    .await?;
3346                            } else {
3347                                worktree
3348                                    .update(&mut cx, |worktree, cx| {
3349                                        worktree.as_local_mut().unwrap().register(project_id, cx)
3350                                    })
3351                                    .await?;
3352                            }
3353                        }
3354
3355                        Ok(worktree)
3356                    }
3357                    .map_err(|err| Arc::new(err))
3358                })
3359                .shared()
3360            })
3361            .clone();
3362        cx.foreground().spawn(async move {
3363            match task.await {
3364                Ok(worktree) => Ok(worktree),
3365                Err(err) => Err(anyhow!("{}", err)),
3366            }
3367        })
3368    }
3369
3370    pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext<Self>) {
3371        self.worktrees.retain(|worktree| {
3372            worktree
3373                .upgrade(cx)
3374                .map_or(false, |w| w.read(cx).id() != id)
3375        });
3376        cx.notify();
3377    }
3378
3379    fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
3380        cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
3381        if worktree.read(cx).is_local() {
3382            cx.subscribe(&worktree, |this, worktree, _, cx| {
3383                this.update_local_worktree_buffers(worktree, cx);
3384            })
3385            .detach();
3386        }
3387
3388        let push_strong_handle = {
3389            let worktree = worktree.read(cx);
3390            self.is_shared() || worktree.is_visible() || worktree.is_remote()
3391        };
3392        if push_strong_handle {
3393            self.worktrees
3394                .push(WorktreeHandle::Strong(worktree.clone()));
3395        } else {
3396            cx.observe_release(&worktree, |this, _, cx| {
3397                this.worktrees
3398                    .retain(|worktree| worktree.upgrade(cx).is_some());
3399                cx.notify();
3400            })
3401            .detach();
3402            self.worktrees
3403                .push(WorktreeHandle::Weak(worktree.downgrade()));
3404        }
3405        cx.notify();
3406    }
3407
3408    fn update_local_worktree_buffers(
3409        &mut self,
3410        worktree_handle: ModelHandle<Worktree>,
3411        cx: &mut ModelContext<Self>,
3412    ) {
3413        let snapshot = worktree_handle.read(cx).snapshot();
3414        let mut buffers_to_delete = Vec::new();
3415        let mut renamed_buffers = Vec::new();
3416        for (buffer_id, buffer) in &self.opened_buffers {
3417            if let Some(buffer) = buffer.upgrade(cx) {
3418                buffer.update(cx, |buffer, cx| {
3419                    if let Some(old_file) = File::from_dyn(buffer.file()) {
3420                        if old_file.worktree != worktree_handle {
3421                            return;
3422                        }
3423
3424                        let new_file = if let Some(entry) = old_file
3425                            .entry_id
3426                            .and_then(|entry_id| snapshot.entry_for_id(entry_id))
3427                        {
3428                            File {
3429                                is_local: true,
3430                                entry_id: Some(entry.id),
3431                                mtime: entry.mtime,
3432                                path: entry.path.clone(),
3433                                worktree: worktree_handle.clone(),
3434                            }
3435                        } else if let Some(entry) =
3436                            snapshot.entry_for_path(old_file.path().as_ref())
3437                        {
3438                            File {
3439                                is_local: true,
3440                                entry_id: Some(entry.id),
3441                                mtime: entry.mtime,
3442                                path: entry.path.clone(),
3443                                worktree: worktree_handle.clone(),
3444                            }
3445                        } else {
3446                            File {
3447                                is_local: true,
3448                                entry_id: None,
3449                                path: old_file.path().clone(),
3450                                mtime: old_file.mtime(),
3451                                worktree: worktree_handle.clone(),
3452                            }
3453                        };
3454
3455                        let old_path = old_file.abs_path(cx);
3456                        if new_file.abs_path(cx) != old_path {
3457                            renamed_buffers.push((cx.handle(), old_path));
3458                        }
3459
3460                        if let Some(project_id) = self.remote_id() {
3461                            self.client
3462                                .send(proto::UpdateBufferFile {
3463                                    project_id,
3464                                    buffer_id: *buffer_id as u64,
3465                                    file: Some(new_file.to_proto()),
3466                                })
3467                                .log_err();
3468                        }
3469                        buffer.file_updated(Box::new(new_file), cx).detach();
3470                    }
3471                });
3472            } else {
3473                buffers_to_delete.push(*buffer_id);
3474            }
3475        }
3476
3477        for buffer_id in buffers_to_delete {
3478            self.opened_buffers.remove(&buffer_id);
3479        }
3480
3481        for (buffer, old_path) in renamed_buffers {
3482            self.unregister_buffer_from_language_server(&buffer, old_path, cx);
3483            self.assign_language_to_buffer(&buffer, cx);
3484            self.register_buffer_with_language_server(&buffer, cx);
3485        }
3486    }
3487
3488    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
3489        let new_active_entry = entry.and_then(|project_path| {
3490            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
3491            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
3492            Some(entry.id)
3493        });
3494        if new_active_entry != self.active_entry {
3495            self.active_entry = new_active_entry;
3496            cx.emit(Event::ActiveEntryChanged(new_active_entry));
3497        }
3498    }
3499
3500    pub fn is_running_disk_based_diagnostics(&self) -> bool {
3501        self.language_server_statuses
3502            .values()
3503            .any(|status| status.pending_diagnostic_updates > 0)
3504    }
3505
3506    pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
3507        let mut summary = DiagnosticSummary::default();
3508        for (_, path_summary) in self.diagnostic_summaries(cx) {
3509            summary.error_count += path_summary.error_count;
3510            summary.warning_count += path_summary.warning_count;
3511        }
3512        summary
3513    }
3514
3515    pub fn diagnostic_summaries<'a>(
3516        &'a self,
3517        cx: &'a AppContext,
3518    ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
3519        self.worktrees(cx).flat_map(move |worktree| {
3520            let worktree = worktree.read(cx);
3521            let worktree_id = worktree.id();
3522            worktree
3523                .diagnostic_summaries()
3524                .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
3525        })
3526    }
3527
3528    pub fn disk_based_diagnostics_started(&mut self, cx: &mut ModelContext<Self>) {
3529        if self
3530            .language_server_statuses
3531            .values()
3532            .map(|status| status.pending_diagnostic_updates)
3533            .sum::<isize>()
3534            == 1
3535        {
3536            cx.emit(Event::DiskBasedDiagnosticsStarted);
3537        }
3538    }
3539
3540    pub fn disk_based_diagnostics_finished(&mut self, cx: &mut ModelContext<Self>) {
3541        cx.emit(Event::DiskBasedDiagnosticsUpdated);
3542        if self
3543            .language_server_statuses
3544            .values()
3545            .map(|status| status.pending_diagnostic_updates)
3546            .sum::<isize>()
3547            == 0
3548        {
3549            cx.emit(Event::DiskBasedDiagnosticsFinished);
3550        }
3551    }
3552
3553    pub fn active_entry(&self) -> Option<ProjectEntryId> {
3554        self.active_entry
3555    }
3556
3557    pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
3558        self.worktree_for_id(path.worktree_id, cx)?
3559            .read(cx)
3560            .entry_for_path(&path.path)
3561            .map(|entry| entry.id)
3562    }
3563
3564    pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
3565        let worktree = self.worktree_for_entry(entry_id, cx)?;
3566        let worktree = worktree.read(cx);
3567        let worktree_id = worktree.id();
3568        let path = worktree.entry_for_id(entry_id)?.path.clone();
3569        Some(ProjectPath { worktree_id, path })
3570    }
3571
3572    // RPC message handlers
3573
3574    async fn handle_unshare_project(
3575        this: ModelHandle<Self>,
3576        _: TypedEnvelope<proto::UnshareProject>,
3577        _: Arc<Client>,
3578        mut cx: AsyncAppContext,
3579    ) -> Result<()> {
3580        this.update(&mut cx, |this, cx| this.project_unshared(cx));
3581        Ok(())
3582    }
3583
3584    async fn handle_add_collaborator(
3585        this: ModelHandle<Self>,
3586        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
3587        _: Arc<Client>,
3588        mut cx: AsyncAppContext,
3589    ) -> Result<()> {
3590        let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
3591        let collaborator = envelope
3592            .payload
3593            .collaborator
3594            .take()
3595            .ok_or_else(|| anyhow!("empty collaborator"))?;
3596
3597        let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
3598        this.update(&mut cx, |this, cx| {
3599            this.collaborators
3600                .insert(collaborator.peer_id, collaborator);
3601            cx.notify();
3602        });
3603
3604        Ok(())
3605    }
3606
3607    async fn handle_remove_collaborator(
3608        this: ModelHandle<Self>,
3609        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
3610        _: Arc<Client>,
3611        mut cx: AsyncAppContext,
3612    ) -> Result<()> {
3613        this.update(&mut cx, |this, cx| {
3614            let peer_id = PeerId(envelope.payload.peer_id);
3615            let replica_id = this
3616                .collaborators
3617                .remove(&peer_id)
3618                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
3619                .replica_id;
3620            for (_, buffer) in &this.opened_buffers {
3621                if let Some(buffer) = buffer.upgrade(cx) {
3622                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
3623                }
3624            }
3625            cx.emit(Event::CollaboratorLeft(peer_id));
3626            cx.notify();
3627            Ok(())
3628        })
3629    }
3630
3631    async fn handle_register_worktree(
3632        this: ModelHandle<Self>,
3633        envelope: TypedEnvelope<proto::RegisterWorktree>,
3634        client: Arc<Client>,
3635        mut cx: AsyncAppContext,
3636    ) -> Result<()> {
3637        this.update(&mut cx, |this, cx| {
3638            let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
3639            let replica_id = this.replica_id();
3640            let worktree = proto::Worktree {
3641                id: envelope.payload.worktree_id,
3642                root_name: envelope.payload.root_name,
3643                entries: Default::default(),
3644                diagnostic_summaries: Default::default(),
3645                visible: envelope.payload.visible,
3646            };
3647            let (worktree, load_task) =
3648                Worktree::remote(remote_id, replica_id, worktree, client, cx);
3649            this.add_worktree(&worktree, cx);
3650            load_task.detach();
3651            Ok(())
3652        })
3653    }
3654
3655    async fn handle_unregister_worktree(
3656        this: ModelHandle<Self>,
3657        envelope: TypedEnvelope<proto::UnregisterWorktree>,
3658        _: Arc<Client>,
3659        mut cx: AsyncAppContext,
3660    ) -> Result<()> {
3661        this.update(&mut cx, |this, cx| {
3662            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3663            this.remove_worktree(worktree_id, cx);
3664            Ok(())
3665        })
3666    }
3667
3668    async fn handle_update_worktree(
3669        this: ModelHandle<Self>,
3670        envelope: TypedEnvelope<proto::UpdateWorktree>,
3671        _: Arc<Client>,
3672        mut cx: AsyncAppContext,
3673    ) -> Result<()> {
3674        this.update(&mut cx, |this, cx| {
3675            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3676            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
3677                worktree.update(cx, |worktree, _| {
3678                    let worktree = worktree.as_remote_mut().unwrap();
3679                    worktree.update_from_remote(envelope)
3680                })?;
3681            }
3682            Ok(())
3683        })
3684    }
3685
3686    async fn handle_update_diagnostic_summary(
3687        this: ModelHandle<Self>,
3688        envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
3689        _: Arc<Client>,
3690        mut cx: AsyncAppContext,
3691    ) -> Result<()> {
3692        this.update(&mut cx, |this, cx| {
3693            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3694            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
3695                if let Some(summary) = envelope.payload.summary {
3696                    let project_path = ProjectPath {
3697                        worktree_id,
3698                        path: Path::new(&summary.path).into(),
3699                    };
3700                    worktree.update(cx, |worktree, _| {
3701                        worktree
3702                            .as_remote_mut()
3703                            .unwrap()
3704                            .update_diagnostic_summary(project_path.path.clone(), &summary);
3705                    });
3706                    cx.emit(Event::DiagnosticsUpdated(project_path));
3707                }
3708            }
3709            Ok(())
3710        })
3711    }
3712
3713    async fn handle_start_language_server(
3714        this: ModelHandle<Self>,
3715        envelope: TypedEnvelope<proto::StartLanguageServer>,
3716        _: Arc<Client>,
3717        mut cx: AsyncAppContext,
3718    ) -> Result<()> {
3719        let server = envelope
3720            .payload
3721            .server
3722            .ok_or_else(|| anyhow!("invalid server"))?;
3723        this.update(&mut cx, |this, cx| {
3724            this.language_server_statuses.insert(
3725                server.id as usize,
3726                LanguageServerStatus {
3727                    name: server.name,
3728                    pending_work: Default::default(),
3729                    pending_diagnostic_updates: 0,
3730                },
3731            );
3732            cx.notify();
3733        });
3734        Ok(())
3735    }
3736
3737    async fn handle_update_language_server(
3738        this: ModelHandle<Self>,
3739        envelope: TypedEnvelope<proto::UpdateLanguageServer>,
3740        _: Arc<Client>,
3741        mut cx: AsyncAppContext,
3742    ) -> Result<()> {
3743        let language_server_id = envelope.payload.language_server_id as usize;
3744        match envelope
3745            .payload
3746            .variant
3747            .ok_or_else(|| anyhow!("invalid variant"))?
3748        {
3749            proto::update_language_server::Variant::WorkStart(payload) => {
3750                this.update(&mut cx, |this, cx| {
3751                    this.on_lsp_work_start(language_server_id, payload.token, cx);
3752                })
3753            }
3754            proto::update_language_server::Variant::WorkProgress(payload) => {
3755                this.update(&mut cx, |this, cx| {
3756                    this.on_lsp_work_progress(
3757                        language_server_id,
3758                        payload.token,
3759                        LanguageServerProgress {
3760                            message: payload.message,
3761                            percentage: payload.percentage.map(|p| p as usize),
3762                            last_update_at: Instant::now(),
3763                        },
3764                        cx,
3765                    );
3766                })
3767            }
3768            proto::update_language_server::Variant::WorkEnd(payload) => {
3769                this.update(&mut cx, |this, cx| {
3770                    this.on_lsp_work_end(language_server_id, payload.token, cx);
3771                })
3772            }
3773            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
3774                this.update(&mut cx, |this, cx| {
3775                    this.disk_based_diagnostics_started(cx);
3776                })
3777            }
3778            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
3779                this.update(&mut cx, |this, cx| this.disk_based_diagnostics_finished(cx));
3780            }
3781        }
3782
3783        Ok(())
3784    }
3785
3786    async fn handle_update_buffer(
3787        this: ModelHandle<Self>,
3788        envelope: TypedEnvelope<proto::UpdateBuffer>,
3789        _: Arc<Client>,
3790        mut cx: AsyncAppContext,
3791    ) -> Result<()> {
3792        this.update(&mut cx, |this, cx| {
3793            let payload = envelope.payload.clone();
3794            let buffer_id = payload.buffer_id;
3795            let ops = payload
3796                .operations
3797                .into_iter()
3798                .map(|op| language::proto::deserialize_operation(op))
3799                .collect::<Result<Vec<_>, _>>()?;
3800            match this.opened_buffers.entry(buffer_id) {
3801                hash_map::Entry::Occupied(mut e) => match e.get_mut() {
3802                    OpenBuffer::Strong(buffer) => {
3803                        buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
3804                    }
3805                    OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
3806                    OpenBuffer::Weak(_) => {}
3807                },
3808                hash_map::Entry::Vacant(e) => {
3809                    e.insert(OpenBuffer::Loading(ops));
3810                }
3811            }
3812            Ok(())
3813        })
3814    }
3815
3816    async fn handle_update_buffer_file(
3817        this: ModelHandle<Self>,
3818        envelope: TypedEnvelope<proto::UpdateBufferFile>,
3819        _: Arc<Client>,
3820        mut cx: AsyncAppContext,
3821    ) -> Result<()> {
3822        this.update(&mut cx, |this, cx| {
3823            let payload = envelope.payload.clone();
3824            let buffer_id = payload.buffer_id;
3825            let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
3826            let worktree = this
3827                .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
3828                .ok_or_else(|| anyhow!("no such worktree"))?;
3829            let file = File::from_proto(file, worktree.clone(), cx)?;
3830            let buffer = this
3831                .opened_buffers
3832                .get_mut(&buffer_id)
3833                .and_then(|b| b.upgrade(cx))
3834                .ok_or_else(|| anyhow!("no such buffer"))?;
3835            buffer.update(cx, |buffer, cx| {
3836                buffer.file_updated(Box::new(file), cx).detach();
3837            });
3838            Ok(())
3839        })
3840    }
3841
3842    async fn handle_save_buffer(
3843        this: ModelHandle<Self>,
3844        envelope: TypedEnvelope<proto::SaveBuffer>,
3845        _: Arc<Client>,
3846        mut cx: AsyncAppContext,
3847    ) -> Result<proto::BufferSaved> {
3848        let buffer_id = envelope.payload.buffer_id;
3849        let requested_version = deserialize_version(envelope.payload.version);
3850
3851        let (project_id, buffer) = this.update(&mut cx, |this, cx| {
3852            let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
3853            let buffer = this
3854                .opened_buffers
3855                .get(&buffer_id)
3856                .and_then(|buffer| buffer.upgrade(cx))
3857                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
3858            Ok::<_, anyhow::Error>((project_id, buffer))
3859        })?;
3860        buffer
3861            .update(&mut cx, |buffer, _| {
3862                buffer.wait_for_version(requested_version)
3863            })
3864            .await;
3865
3866        let (saved_version, mtime) = buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
3867        Ok(proto::BufferSaved {
3868            project_id,
3869            buffer_id,
3870            version: serialize_version(&saved_version),
3871            mtime: Some(mtime.into()),
3872        })
3873    }
3874
3875    async fn handle_reload_buffers(
3876        this: ModelHandle<Self>,
3877        envelope: TypedEnvelope<proto::ReloadBuffers>,
3878        _: Arc<Client>,
3879        mut cx: AsyncAppContext,
3880    ) -> Result<proto::ReloadBuffersResponse> {
3881        let sender_id = envelope.original_sender_id()?;
3882        let reload = this.update(&mut cx, |this, cx| {
3883            let mut buffers = HashSet::default();
3884            for buffer_id in &envelope.payload.buffer_ids {
3885                buffers.insert(
3886                    this.opened_buffers
3887                        .get(buffer_id)
3888                        .and_then(|buffer| buffer.upgrade(cx))
3889                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
3890                );
3891            }
3892            Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
3893        })?;
3894
3895        let project_transaction = reload.await?;
3896        let project_transaction = this.update(&mut cx, |this, cx| {
3897            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
3898        });
3899        Ok(proto::ReloadBuffersResponse {
3900            transaction: Some(project_transaction),
3901        })
3902    }
3903
3904    async fn handle_format_buffers(
3905        this: ModelHandle<Self>,
3906        envelope: TypedEnvelope<proto::FormatBuffers>,
3907        _: Arc<Client>,
3908        mut cx: AsyncAppContext,
3909    ) -> Result<proto::FormatBuffersResponse> {
3910        let sender_id = envelope.original_sender_id()?;
3911        let format = this.update(&mut cx, |this, cx| {
3912            let mut buffers = HashSet::default();
3913            for buffer_id in &envelope.payload.buffer_ids {
3914                buffers.insert(
3915                    this.opened_buffers
3916                        .get(buffer_id)
3917                        .and_then(|buffer| buffer.upgrade(cx))
3918                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
3919                );
3920            }
3921            Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
3922        })?;
3923
3924        let project_transaction = format.await?;
3925        let project_transaction = this.update(&mut cx, |this, cx| {
3926            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
3927        });
3928        Ok(proto::FormatBuffersResponse {
3929            transaction: Some(project_transaction),
3930        })
3931    }
3932
3933    async fn handle_get_completions(
3934        this: ModelHandle<Self>,
3935        envelope: TypedEnvelope<proto::GetCompletions>,
3936        _: Arc<Client>,
3937        mut cx: AsyncAppContext,
3938    ) -> Result<proto::GetCompletionsResponse> {
3939        let position = envelope
3940            .payload
3941            .position
3942            .and_then(language::proto::deserialize_anchor)
3943            .ok_or_else(|| anyhow!("invalid position"))?;
3944        let version = deserialize_version(envelope.payload.version);
3945        let buffer = this.read_with(&cx, |this, cx| {
3946            this.opened_buffers
3947                .get(&envelope.payload.buffer_id)
3948                .and_then(|buffer| buffer.upgrade(cx))
3949                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
3950        })?;
3951        buffer
3952            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
3953            .await;
3954        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
3955        let completions = this
3956            .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
3957            .await?;
3958
3959        Ok(proto::GetCompletionsResponse {
3960            completions: completions
3961                .iter()
3962                .map(language::proto::serialize_completion)
3963                .collect(),
3964            version: serialize_version(&version),
3965        })
3966    }
3967
3968    async fn handle_apply_additional_edits_for_completion(
3969        this: ModelHandle<Self>,
3970        envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
3971        _: Arc<Client>,
3972        mut cx: AsyncAppContext,
3973    ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
3974        let apply_additional_edits = this.update(&mut cx, |this, cx| {
3975            let buffer = this
3976                .opened_buffers
3977                .get(&envelope.payload.buffer_id)
3978                .and_then(|buffer| buffer.upgrade(cx))
3979                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
3980            let language = buffer.read(cx).language();
3981            let completion = language::proto::deserialize_completion(
3982                envelope
3983                    .payload
3984                    .completion
3985                    .ok_or_else(|| anyhow!("invalid completion"))?,
3986                language,
3987            )?;
3988            Ok::<_, anyhow::Error>(
3989                this.apply_additional_edits_for_completion(buffer, completion, false, cx),
3990            )
3991        })?;
3992
3993        Ok(proto::ApplyCompletionAdditionalEditsResponse {
3994            transaction: apply_additional_edits
3995                .await?
3996                .as_ref()
3997                .map(language::proto::serialize_transaction),
3998        })
3999    }
4000
4001    async fn handle_get_code_actions(
4002        this: ModelHandle<Self>,
4003        envelope: TypedEnvelope<proto::GetCodeActions>,
4004        _: Arc<Client>,
4005        mut cx: AsyncAppContext,
4006    ) -> Result<proto::GetCodeActionsResponse> {
4007        let start = envelope
4008            .payload
4009            .start
4010            .and_then(language::proto::deserialize_anchor)
4011            .ok_or_else(|| anyhow!("invalid start"))?;
4012        let end = envelope
4013            .payload
4014            .end
4015            .and_then(language::proto::deserialize_anchor)
4016            .ok_or_else(|| anyhow!("invalid end"))?;
4017        let buffer = this.update(&mut cx, |this, cx| {
4018            this.opened_buffers
4019                .get(&envelope.payload.buffer_id)
4020                .and_then(|buffer| buffer.upgrade(cx))
4021                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
4022        })?;
4023        buffer
4024            .update(&mut cx, |buffer, _| {
4025                buffer.wait_for_version(deserialize_version(envelope.payload.version))
4026            })
4027            .await;
4028
4029        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
4030        let code_actions = this.update(&mut cx, |this, cx| {
4031            Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
4032        })?;
4033
4034        Ok(proto::GetCodeActionsResponse {
4035            actions: code_actions
4036                .await?
4037                .iter()
4038                .map(language::proto::serialize_code_action)
4039                .collect(),
4040            version: serialize_version(&version),
4041        })
4042    }
4043
4044    async fn handle_apply_code_action(
4045        this: ModelHandle<Self>,
4046        envelope: TypedEnvelope<proto::ApplyCodeAction>,
4047        _: Arc<Client>,
4048        mut cx: AsyncAppContext,
4049    ) -> Result<proto::ApplyCodeActionResponse> {
4050        let sender_id = envelope.original_sender_id()?;
4051        let action = language::proto::deserialize_code_action(
4052            envelope
4053                .payload
4054                .action
4055                .ok_or_else(|| anyhow!("invalid action"))?,
4056        )?;
4057        let apply_code_action = this.update(&mut cx, |this, cx| {
4058            let buffer = this
4059                .opened_buffers
4060                .get(&envelope.payload.buffer_id)
4061                .and_then(|buffer| buffer.upgrade(cx))
4062                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
4063            Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
4064        })?;
4065
4066        let project_transaction = apply_code_action.await?;
4067        let project_transaction = this.update(&mut cx, |this, cx| {
4068            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
4069        });
4070        Ok(proto::ApplyCodeActionResponse {
4071            transaction: Some(project_transaction),
4072        })
4073    }
4074
4075    async fn handle_lsp_command<T: LspCommand>(
4076        this: ModelHandle<Self>,
4077        envelope: TypedEnvelope<T::ProtoRequest>,
4078        _: Arc<Client>,
4079        mut cx: AsyncAppContext,
4080    ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
4081    where
4082        <T::LspRequest as lsp::request::Request>::Result: Send,
4083    {
4084        let sender_id = envelope.original_sender_id()?;
4085        let buffer_id = T::buffer_id_from_proto(&envelope.payload);
4086        let buffer_handle = this.read_with(&cx, |this, _| {
4087            this.opened_buffers
4088                .get(&buffer_id)
4089                .and_then(|buffer| buffer.upgrade(&cx))
4090                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
4091        })?;
4092        let request = T::from_proto(
4093            envelope.payload,
4094            this.clone(),
4095            buffer_handle.clone(),
4096            cx.clone(),
4097        )
4098        .await?;
4099        let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
4100        let response = this
4101            .update(&mut cx, |this, cx| {
4102                this.request_lsp(buffer_handle, request, cx)
4103            })
4104            .await?;
4105        this.update(&mut cx, |this, cx| {
4106            Ok(T::response_to_proto(
4107                response,
4108                this,
4109                sender_id,
4110                &buffer_version,
4111                cx,
4112            ))
4113        })
4114    }
4115
4116    async fn handle_get_project_symbols(
4117        this: ModelHandle<Self>,
4118        envelope: TypedEnvelope<proto::GetProjectSymbols>,
4119        _: Arc<Client>,
4120        mut cx: AsyncAppContext,
4121    ) -> Result<proto::GetProjectSymbolsResponse> {
4122        let symbols = this
4123            .update(&mut cx, |this, cx| {
4124                this.symbols(&envelope.payload.query, cx)
4125            })
4126            .await?;
4127
4128        Ok(proto::GetProjectSymbolsResponse {
4129            symbols: symbols.iter().map(serialize_symbol).collect(),
4130        })
4131    }
4132
4133    async fn handle_search_project(
4134        this: ModelHandle<Self>,
4135        envelope: TypedEnvelope<proto::SearchProject>,
4136        _: Arc<Client>,
4137        mut cx: AsyncAppContext,
4138    ) -> Result<proto::SearchProjectResponse> {
4139        let peer_id = envelope.original_sender_id()?;
4140        let query = SearchQuery::from_proto(envelope.payload)?;
4141        let result = this
4142            .update(&mut cx, |this, cx| this.search(query, cx))
4143            .await?;
4144
4145        this.update(&mut cx, |this, cx| {
4146            let mut locations = Vec::new();
4147            for (buffer, ranges) in result {
4148                for range in ranges {
4149                    let start = serialize_anchor(&range.start);
4150                    let end = serialize_anchor(&range.end);
4151                    let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
4152                    locations.push(proto::Location {
4153                        buffer: Some(buffer),
4154                        start: Some(start),
4155                        end: Some(end),
4156                    });
4157                }
4158            }
4159            Ok(proto::SearchProjectResponse { locations })
4160        })
4161    }
4162
4163    async fn handle_open_buffer_for_symbol(
4164        this: ModelHandle<Self>,
4165        envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
4166        _: Arc<Client>,
4167        mut cx: AsyncAppContext,
4168    ) -> Result<proto::OpenBufferForSymbolResponse> {
4169        let peer_id = envelope.original_sender_id()?;
4170        let symbol = envelope
4171            .payload
4172            .symbol
4173            .ok_or_else(|| anyhow!("invalid symbol"))?;
4174        let symbol = this.read_with(&cx, |this, _| {
4175            let symbol = this.deserialize_symbol(symbol)?;
4176            let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
4177            if signature == symbol.signature {
4178                Ok(symbol)
4179            } else {
4180                Err(anyhow!("invalid symbol signature"))
4181            }
4182        })?;
4183        let buffer = this
4184            .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
4185            .await?;
4186
4187        Ok(proto::OpenBufferForSymbolResponse {
4188            buffer: Some(this.update(&mut cx, |this, cx| {
4189                this.serialize_buffer_for_peer(&buffer, peer_id, cx)
4190            })),
4191        })
4192    }
4193
4194    fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
4195        let mut hasher = Sha256::new();
4196        hasher.update(worktree_id.to_proto().to_be_bytes());
4197        hasher.update(path.to_string_lossy().as_bytes());
4198        hasher.update(self.nonce.to_be_bytes());
4199        hasher.finalize().as_slice().try_into().unwrap()
4200    }
4201
4202    async fn handle_open_buffer_by_id(
4203        this: ModelHandle<Self>,
4204        envelope: TypedEnvelope<proto::OpenBufferById>,
4205        _: Arc<Client>,
4206        mut cx: AsyncAppContext,
4207    ) -> Result<proto::OpenBufferResponse> {
4208        let peer_id = envelope.original_sender_id()?;
4209        let buffer = this
4210            .update(&mut cx, |this, cx| {
4211                this.open_buffer_by_id(envelope.payload.id, cx)
4212            })
4213            .await?;
4214        this.update(&mut cx, |this, cx| {
4215            Ok(proto::OpenBufferResponse {
4216                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
4217            })
4218        })
4219    }
4220
4221    async fn handle_open_buffer_by_path(
4222        this: ModelHandle<Self>,
4223        envelope: TypedEnvelope<proto::OpenBufferByPath>,
4224        _: Arc<Client>,
4225        mut cx: AsyncAppContext,
4226    ) -> Result<proto::OpenBufferResponse> {
4227        let peer_id = envelope.original_sender_id()?;
4228        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4229        let open_buffer = this.update(&mut cx, |this, cx| {
4230            this.open_buffer(
4231                ProjectPath {
4232                    worktree_id,
4233                    path: PathBuf::from(envelope.payload.path).into(),
4234                },
4235                cx,
4236            )
4237        });
4238
4239        let buffer = open_buffer.await?;
4240        this.update(&mut cx, |this, cx| {
4241            Ok(proto::OpenBufferResponse {
4242                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
4243            })
4244        })
4245    }
4246
4247    fn serialize_project_transaction_for_peer(
4248        &mut self,
4249        project_transaction: ProjectTransaction,
4250        peer_id: PeerId,
4251        cx: &AppContext,
4252    ) -> proto::ProjectTransaction {
4253        let mut serialized_transaction = proto::ProjectTransaction {
4254            buffers: Default::default(),
4255            transactions: Default::default(),
4256        };
4257        for (buffer, transaction) in project_transaction.0 {
4258            serialized_transaction
4259                .buffers
4260                .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
4261            serialized_transaction
4262                .transactions
4263                .push(language::proto::serialize_transaction(&transaction));
4264        }
4265        serialized_transaction
4266    }
4267
4268    fn deserialize_project_transaction(
4269        &mut self,
4270        message: proto::ProjectTransaction,
4271        push_to_history: bool,
4272        cx: &mut ModelContext<Self>,
4273    ) -> Task<Result<ProjectTransaction>> {
4274        cx.spawn(|this, mut cx| async move {
4275            let mut project_transaction = ProjectTransaction::default();
4276            for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
4277                let buffer = this
4278                    .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4279                    .await?;
4280                let transaction = language::proto::deserialize_transaction(transaction)?;
4281                project_transaction.0.insert(buffer, transaction);
4282            }
4283
4284            for (buffer, transaction) in &project_transaction.0 {
4285                buffer
4286                    .update(&mut cx, |buffer, _| {
4287                        buffer.wait_for_edits(transaction.edit_ids.iter().copied())
4288                    })
4289                    .await;
4290
4291                if push_to_history {
4292                    buffer.update(&mut cx, |buffer, _| {
4293                        buffer.push_transaction(transaction.clone(), Instant::now());
4294                    });
4295                }
4296            }
4297
4298            Ok(project_transaction)
4299        })
4300    }
4301
4302    fn serialize_buffer_for_peer(
4303        &mut self,
4304        buffer: &ModelHandle<Buffer>,
4305        peer_id: PeerId,
4306        cx: &AppContext,
4307    ) -> proto::Buffer {
4308        let buffer_id = buffer.read(cx).remote_id();
4309        let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
4310        if shared_buffers.insert(buffer_id) {
4311            proto::Buffer {
4312                variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
4313            }
4314        } else {
4315            proto::Buffer {
4316                variant: Some(proto::buffer::Variant::Id(buffer_id)),
4317            }
4318        }
4319    }
4320
4321    fn deserialize_buffer(
4322        &mut self,
4323        buffer: proto::Buffer,
4324        cx: &mut ModelContext<Self>,
4325    ) -> Task<Result<ModelHandle<Buffer>>> {
4326        let replica_id = self.replica_id();
4327
4328        let opened_buffer_tx = self.opened_buffer.0.clone();
4329        let mut opened_buffer_rx = self.opened_buffer.1.clone();
4330        cx.spawn(|this, mut cx| async move {
4331            match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
4332                proto::buffer::Variant::Id(id) => {
4333                    let buffer = loop {
4334                        let buffer = this.read_with(&cx, |this, cx| {
4335                            this.opened_buffers
4336                                .get(&id)
4337                                .and_then(|buffer| buffer.upgrade(cx))
4338                        });
4339                        if let Some(buffer) = buffer {
4340                            break buffer;
4341                        }
4342                        opened_buffer_rx
4343                            .next()
4344                            .await
4345                            .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
4346                    };
4347                    Ok(buffer)
4348                }
4349                proto::buffer::Variant::State(mut buffer) => {
4350                    let mut buffer_worktree = None;
4351                    let mut buffer_file = None;
4352                    if let Some(file) = buffer.file.take() {
4353                        this.read_with(&cx, |this, cx| {
4354                            let worktree_id = WorktreeId::from_proto(file.worktree_id);
4355                            let worktree =
4356                                this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
4357                                    anyhow!("no worktree found for id {}", file.worktree_id)
4358                                })?;
4359                            buffer_file =
4360                                Some(Box::new(File::from_proto(file, worktree.clone(), cx)?)
4361                                    as Box<dyn language::File>);
4362                            buffer_worktree = Some(worktree);
4363                            Ok::<_, anyhow::Error>(())
4364                        })?;
4365                    }
4366
4367                    let buffer = cx.add_model(|cx| {
4368                        Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
4369                    });
4370
4371                    this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
4372
4373                    *opened_buffer_tx.borrow_mut().borrow_mut() = ();
4374                    Ok(buffer)
4375                }
4376            }
4377        })
4378    }
4379
4380    fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
4381        let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
4382        let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
4383        let start = serialized_symbol
4384            .start
4385            .ok_or_else(|| anyhow!("invalid start"))?;
4386        let end = serialized_symbol
4387            .end
4388            .ok_or_else(|| anyhow!("invalid end"))?;
4389        let kind = unsafe { mem::transmute(serialized_symbol.kind) };
4390        let path = PathBuf::from(serialized_symbol.path);
4391        let language = self.languages.select_language(&path);
4392        Ok(Symbol {
4393            source_worktree_id,
4394            worktree_id,
4395            language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
4396            label: language
4397                .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
4398                .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
4399            name: serialized_symbol.name,
4400            path,
4401            range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
4402            kind,
4403            signature: serialized_symbol
4404                .signature
4405                .try_into()
4406                .map_err(|_| anyhow!("invalid signature"))?,
4407        })
4408    }
4409
4410    async fn handle_buffer_saved(
4411        this: ModelHandle<Self>,
4412        envelope: TypedEnvelope<proto::BufferSaved>,
4413        _: Arc<Client>,
4414        mut cx: AsyncAppContext,
4415    ) -> Result<()> {
4416        let version = deserialize_version(envelope.payload.version);
4417        let mtime = envelope
4418            .payload
4419            .mtime
4420            .ok_or_else(|| anyhow!("missing mtime"))?
4421            .into();
4422
4423        this.update(&mut cx, |this, cx| {
4424            let buffer = this
4425                .opened_buffers
4426                .get(&envelope.payload.buffer_id)
4427                .and_then(|buffer| buffer.upgrade(cx));
4428            if let Some(buffer) = buffer {
4429                buffer.update(cx, |buffer, cx| {
4430                    buffer.did_save(version, mtime, None, cx);
4431                });
4432            }
4433            Ok(())
4434        })
4435    }
4436
4437    async fn handle_buffer_reloaded(
4438        this: ModelHandle<Self>,
4439        envelope: TypedEnvelope<proto::BufferReloaded>,
4440        _: Arc<Client>,
4441        mut cx: AsyncAppContext,
4442    ) -> Result<()> {
4443        let payload = envelope.payload.clone();
4444        let version = deserialize_version(payload.version);
4445        let mtime = payload
4446            .mtime
4447            .ok_or_else(|| anyhow!("missing mtime"))?
4448            .into();
4449        this.update(&mut cx, |this, cx| {
4450            let buffer = this
4451                .opened_buffers
4452                .get(&payload.buffer_id)
4453                .and_then(|buffer| buffer.upgrade(cx));
4454            if let Some(buffer) = buffer {
4455                buffer.update(cx, |buffer, cx| {
4456                    buffer.did_reload(version, mtime, cx);
4457                });
4458            }
4459            Ok(())
4460        })
4461    }
4462
4463    pub fn match_paths<'a>(
4464        &self,
4465        query: &'a str,
4466        include_ignored: bool,
4467        smart_case: bool,
4468        max_results: usize,
4469        cancel_flag: &'a AtomicBool,
4470        cx: &AppContext,
4471    ) -> impl 'a + Future<Output = Vec<PathMatch>> {
4472        let worktrees = self
4473            .worktrees(cx)
4474            .filter(|worktree| worktree.read(cx).is_visible())
4475            .collect::<Vec<_>>();
4476        let include_root_name = worktrees.len() > 1;
4477        let candidate_sets = worktrees
4478            .into_iter()
4479            .map(|worktree| CandidateSet {
4480                snapshot: worktree.read(cx).snapshot(),
4481                include_ignored,
4482                include_root_name,
4483            })
4484            .collect::<Vec<_>>();
4485
4486        let background = cx.background().clone();
4487        async move {
4488            fuzzy::match_paths(
4489                candidate_sets.as_slice(),
4490                query,
4491                smart_case,
4492                max_results,
4493                cancel_flag,
4494                background,
4495            )
4496            .await
4497        }
4498    }
4499
4500    fn edits_from_lsp(
4501        &mut self,
4502        buffer: &ModelHandle<Buffer>,
4503        lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
4504        version: Option<i32>,
4505        cx: &mut ModelContext<Self>,
4506    ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
4507        let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
4508        cx.background().spawn(async move {
4509            let snapshot = snapshot?;
4510            let mut lsp_edits = lsp_edits
4511                .into_iter()
4512                .map(|edit| (range_from_lsp(edit.range), edit.new_text))
4513                .peekable();
4514
4515            let mut edits = Vec::new();
4516            while let Some((mut range, mut new_text)) = lsp_edits.next() {
4517                // Combine any LSP edits that are adjacent.
4518                //
4519                // Also, combine LSP edits that are separated from each other by only
4520                // a newline. This is important because for some code actions,
4521                // Rust-analyzer rewrites the entire buffer via a series of edits that
4522                // are separated by unchanged newline characters.
4523                //
4524                // In order for the diffing logic below to work properly, any edits that
4525                // cancel each other out must be combined into one.
4526                while let Some((next_range, next_text)) = lsp_edits.peek() {
4527                    if next_range.start > range.end {
4528                        if next_range.start.row > range.end.row + 1
4529                            || next_range.start.column > 0
4530                            || snapshot.clip_point_utf16(
4531                                PointUtf16::new(range.end.row, u32::MAX),
4532                                Bias::Left,
4533                            ) > range.end
4534                        {
4535                            break;
4536                        }
4537                        new_text.push('\n');
4538                    }
4539                    range.end = next_range.end;
4540                    new_text.push_str(&next_text);
4541                    lsp_edits.next();
4542                }
4543
4544                if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
4545                    || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
4546                {
4547                    return Err(anyhow!("invalid edits received from language server"));
4548                }
4549
4550                // For multiline edits, perform a diff of the old and new text so that
4551                // we can identify the changes more precisely, preserving the locations
4552                // of any anchors positioned in the unchanged regions.
4553                if range.end.row > range.start.row {
4554                    let mut offset = range.start.to_offset(&snapshot);
4555                    let old_text = snapshot.text_for_range(range).collect::<String>();
4556
4557                    let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
4558                    let mut moved_since_edit = true;
4559                    for change in diff.iter_all_changes() {
4560                        let tag = change.tag();
4561                        let value = change.value();
4562                        match tag {
4563                            ChangeTag::Equal => {
4564                                offset += value.len();
4565                                moved_since_edit = true;
4566                            }
4567                            ChangeTag::Delete => {
4568                                let start = snapshot.anchor_after(offset);
4569                                let end = snapshot.anchor_before(offset + value.len());
4570                                if moved_since_edit {
4571                                    edits.push((start..end, String::new()));
4572                                } else {
4573                                    edits.last_mut().unwrap().0.end = end;
4574                                }
4575                                offset += value.len();
4576                                moved_since_edit = false;
4577                            }
4578                            ChangeTag::Insert => {
4579                                if moved_since_edit {
4580                                    let anchor = snapshot.anchor_after(offset);
4581                                    edits.push((anchor.clone()..anchor, value.to_string()));
4582                                } else {
4583                                    edits.last_mut().unwrap().1.push_str(value);
4584                                }
4585                                moved_since_edit = false;
4586                            }
4587                        }
4588                    }
4589                } else if range.end == range.start {
4590                    let anchor = snapshot.anchor_after(range.start);
4591                    edits.push((anchor.clone()..anchor, new_text));
4592                } else {
4593                    let edit_start = snapshot.anchor_after(range.start);
4594                    let edit_end = snapshot.anchor_before(range.end);
4595                    edits.push((edit_start..edit_end, new_text));
4596                }
4597            }
4598
4599            Ok(edits)
4600        })
4601    }
4602
4603    fn buffer_snapshot_for_lsp_version(
4604        &mut self,
4605        buffer: &ModelHandle<Buffer>,
4606        version: Option<i32>,
4607        cx: &AppContext,
4608    ) -> Result<TextBufferSnapshot> {
4609        const OLD_VERSIONS_TO_RETAIN: i32 = 10;
4610
4611        if let Some(version) = version {
4612            let buffer_id = buffer.read(cx).remote_id();
4613            let snapshots = self
4614                .buffer_snapshots
4615                .get_mut(&buffer_id)
4616                .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
4617            let mut found_snapshot = None;
4618            snapshots.retain(|(snapshot_version, snapshot)| {
4619                if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
4620                    false
4621                } else {
4622                    if *snapshot_version == version {
4623                        found_snapshot = Some(snapshot.clone());
4624                    }
4625                    true
4626                }
4627            });
4628
4629            found_snapshot.ok_or_else(|| {
4630                anyhow!(
4631                    "snapshot not found for buffer {} at version {}",
4632                    buffer_id,
4633                    version
4634                )
4635            })
4636        } else {
4637            Ok((buffer.read(cx)).text_snapshot())
4638        }
4639    }
4640
4641    fn language_server_for_buffer(
4642        &self,
4643        buffer: &Buffer,
4644        cx: &AppContext,
4645    ) -> Option<&(Arc<dyn LspAdapter>, Arc<LanguageServer>)> {
4646        if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
4647            let worktree_id = file.worktree_id(cx);
4648            self.language_servers
4649                .get(&(worktree_id, language.lsp_adapter()?.name()))
4650        } else {
4651            None
4652        }
4653    }
4654}
4655
4656impl WorktreeHandle {
4657    pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
4658        match self {
4659            WorktreeHandle::Strong(handle) => Some(handle.clone()),
4660            WorktreeHandle::Weak(handle) => handle.upgrade(cx),
4661        }
4662    }
4663}
4664
4665impl OpenBuffer {
4666    pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
4667        match self {
4668            OpenBuffer::Strong(handle) => Some(handle.clone()),
4669            OpenBuffer::Weak(handle) => handle.upgrade(cx),
4670            OpenBuffer::Loading(_) => None,
4671        }
4672    }
4673}
4674
4675struct CandidateSet {
4676    snapshot: Snapshot,
4677    include_ignored: bool,
4678    include_root_name: bool,
4679}
4680
4681impl<'a> PathMatchCandidateSet<'a> for CandidateSet {
4682    type Candidates = CandidateSetIter<'a>;
4683
4684    fn id(&self) -> usize {
4685        self.snapshot.id().to_usize()
4686    }
4687
4688    fn len(&self) -> usize {
4689        if self.include_ignored {
4690            self.snapshot.file_count()
4691        } else {
4692            self.snapshot.visible_file_count()
4693        }
4694    }
4695
4696    fn prefix(&self) -> Arc<str> {
4697        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
4698            self.snapshot.root_name().into()
4699        } else if self.include_root_name {
4700            format!("{}/", self.snapshot.root_name()).into()
4701        } else {
4702            "".into()
4703        }
4704    }
4705
4706    fn candidates(&'a self, start: usize) -> Self::Candidates {
4707        CandidateSetIter {
4708            traversal: self.snapshot.files(self.include_ignored, start),
4709        }
4710    }
4711}
4712
4713struct CandidateSetIter<'a> {
4714    traversal: Traversal<'a>,
4715}
4716
4717impl<'a> Iterator for CandidateSetIter<'a> {
4718    type Item = PathMatchCandidate<'a>;
4719
4720    fn next(&mut self) -> Option<Self::Item> {
4721        self.traversal.next().map(|entry| {
4722            if let EntryKind::File(char_bag) = entry.kind {
4723                PathMatchCandidate {
4724                    path: &entry.path,
4725                    char_bag,
4726                }
4727            } else {
4728                unreachable!()
4729            }
4730        })
4731    }
4732}
4733
4734impl Entity for Project {
4735    type Event = Event;
4736
4737    fn release(&mut self, _: &mut gpui::MutableAppContext) {
4738        match &self.client_state {
4739            ProjectClientState::Local { remote_id_rx, .. } => {
4740                if let Some(project_id) = *remote_id_rx.borrow() {
4741                    self.client
4742                        .send(proto::UnregisterProject { project_id })
4743                        .log_err();
4744                }
4745            }
4746            ProjectClientState::Remote { remote_id, .. } => {
4747                self.client
4748                    .send(proto::LeaveProject {
4749                        project_id: *remote_id,
4750                    })
4751                    .log_err();
4752            }
4753        }
4754    }
4755
4756    fn app_will_quit(
4757        &mut self,
4758        _: &mut MutableAppContext,
4759    ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
4760        let shutdown_futures = self
4761            .language_servers
4762            .drain()
4763            .filter_map(|(_, (_, server))| server.shutdown())
4764            .collect::<Vec<_>>();
4765        Some(
4766            async move {
4767                futures::future::join_all(shutdown_futures).await;
4768            }
4769            .boxed(),
4770        )
4771    }
4772}
4773
4774impl Collaborator {
4775    fn from_proto(
4776        message: proto::Collaborator,
4777        user_store: &ModelHandle<UserStore>,
4778        cx: &mut AsyncAppContext,
4779    ) -> impl Future<Output = Result<Self>> {
4780        let user = user_store.update(cx, |user_store, cx| {
4781            user_store.fetch_user(message.user_id, cx)
4782        });
4783
4784        async move {
4785            Ok(Self {
4786                peer_id: PeerId(message.peer_id),
4787                user: user.await?,
4788                replica_id: message.replica_id as ReplicaId,
4789            })
4790        }
4791    }
4792}
4793
4794impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
4795    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
4796        Self {
4797            worktree_id,
4798            path: path.as_ref().into(),
4799        }
4800    }
4801}
4802
4803impl From<lsp::CreateFileOptions> for fs::CreateOptions {
4804    fn from(options: lsp::CreateFileOptions) -> Self {
4805        Self {
4806            overwrite: options.overwrite.unwrap_or(false),
4807            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
4808        }
4809    }
4810}
4811
4812impl From<lsp::RenameFileOptions> for fs::RenameOptions {
4813    fn from(options: lsp::RenameFileOptions) -> Self {
4814        Self {
4815            overwrite: options.overwrite.unwrap_or(false),
4816            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
4817        }
4818    }
4819}
4820
4821impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
4822    fn from(options: lsp::DeleteFileOptions) -> Self {
4823        Self {
4824            recursive: options.recursive.unwrap_or(false),
4825            ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
4826        }
4827    }
4828}
4829
4830fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
4831    proto::Symbol {
4832        source_worktree_id: symbol.source_worktree_id.to_proto(),
4833        worktree_id: symbol.worktree_id.to_proto(),
4834        language_server_name: symbol.language_server_name.0.to_string(),
4835        name: symbol.name.clone(),
4836        kind: unsafe { mem::transmute(symbol.kind) },
4837        path: symbol.path.to_string_lossy().to_string(),
4838        start: Some(proto::Point {
4839            row: symbol.range.start.row,
4840            column: symbol.range.start.column,
4841        }),
4842        end: Some(proto::Point {
4843            row: symbol.range.end.row,
4844            column: symbol.range.end.column,
4845        }),
4846        signature: symbol.signature.to_vec(),
4847    }
4848}
4849
4850fn relativize_path(base: &Path, path: &Path) -> PathBuf {
4851    let mut path_components = path.components();
4852    let mut base_components = base.components();
4853    let mut components: Vec<Component> = Vec::new();
4854    loop {
4855        match (path_components.next(), base_components.next()) {
4856            (None, None) => break,
4857            (Some(a), None) => {
4858                components.push(a);
4859                components.extend(path_components.by_ref());
4860                break;
4861            }
4862            (None, _) => components.push(Component::ParentDir),
4863            (Some(a), Some(b)) if components.is_empty() && a == b => (),
4864            (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
4865            (Some(a), Some(_)) => {
4866                components.push(Component::ParentDir);
4867                for _ in base_components {
4868                    components.push(Component::ParentDir);
4869                }
4870                components.push(a);
4871                components.extend(path_components.by_ref());
4872                break;
4873            }
4874        }
4875    }
4876    components.iter().map(|c| c.as_os_str()).collect()
4877}
4878
4879impl Item for Buffer {
4880    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
4881        File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
4882    }
4883}
4884
4885#[cfg(test)]
4886mod tests {
4887    use super::{Event, *};
4888    use fs::RealFs;
4889    use futures::{future, StreamExt};
4890    use gpui::test::subscribe;
4891    use language::{
4892        tree_sitter_rust, Diagnostic, FakeLspAdapter, LanguageConfig, OffsetRangeExt, Point,
4893        ToPoint,
4894    };
4895    use lsp::Url;
4896    use serde_json::json;
4897    use std::{cell::RefCell, os::unix, path::PathBuf, rc::Rc, task::Poll};
4898    use unindent::Unindent as _;
4899    use util::{assert_set_eq, test::temp_tree};
4900    use worktree::WorktreeHandle as _;
4901
4902    #[gpui::test]
4903    async fn test_populate_and_search(cx: &mut gpui::TestAppContext) {
4904        let dir = temp_tree(json!({
4905            "root": {
4906                "apple": "",
4907                "banana": {
4908                    "carrot": {
4909                        "date": "",
4910                        "endive": "",
4911                    }
4912                },
4913                "fennel": {
4914                    "grape": "",
4915                }
4916            }
4917        }));
4918
4919        let root_link_path = dir.path().join("root_link");
4920        unix::fs::symlink(&dir.path().join("root"), &root_link_path).unwrap();
4921        unix::fs::symlink(
4922            &dir.path().join("root/fennel"),
4923            &dir.path().join("root/finnochio"),
4924        )
4925        .unwrap();
4926
4927        let project = Project::test(Arc::new(RealFs), cx);
4928
4929        let (tree, _) = project
4930            .update(cx, |project, cx| {
4931                project.find_or_create_local_worktree(&root_link_path, true, cx)
4932            })
4933            .await
4934            .unwrap();
4935
4936        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
4937            .await;
4938        cx.read(|cx| {
4939            let tree = tree.read(cx);
4940            assert_eq!(tree.file_count(), 5);
4941            assert_eq!(
4942                tree.inode_for_path("fennel/grape"),
4943                tree.inode_for_path("finnochio/grape")
4944            );
4945        });
4946
4947        let cancel_flag = Default::default();
4948        let results = project
4949            .read_with(cx, |project, cx| {
4950                project.match_paths("bna", false, false, 10, &cancel_flag, cx)
4951            })
4952            .await;
4953        assert_eq!(
4954            results
4955                .into_iter()
4956                .map(|result| result.path)
4957                .collect::<Vec<Arc<Path>>>(),
4958            vec![
4959                PathBuf::from("banana/carrot/date").into(),
4960                PathBuf::from("banana/carrot/endive").into(),
4961            ]
4962        );
4963    }
4964
4965    #[gpui::test]
4966    async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
4967        cx.foreground().forbid_parking();
4968
4969        let mut rust_language = Language::new(
4970            LanguageConfig {
4971                name: "Rust".into(),
4972                path_suffixes: vec!["rs".to_string()],
4973                ..Default::default()
4974            },
4975            Some(tree_sitter_rust::language()),
4976        );
4977        let mut json_language = Language::new(
4978            LanguageConfig {
4979                name: "JSON".into(),
4980                path_suffixes: vec!["json".to_string()],
4981                ..Default::default()
4982            },
4983            None,
4984        );
4985        let mut fake_rust_servers = rust_language.set_fake_lsp_adapter(FakeLspAdapter {
4986            name: "the-rust-language-server",
4987            capabilities: lsp::ServerCapabilities {
4988                completion_provider: Some(lsp::CompletionOptions {
4989                    trigger_characters: Some(vec![".".to_string(), "::".to_string()]),
4990                    ..Default::default()
4991                }),
4992                ..Default::default()
4993            },
4994            ..Default::default()
4995        });
4996        let mut fake_json_servers = json_language.set_fake_lsp_adapter(FakeLspAdapter {
4997            name: "the-json-language-server",
4998            capabilities: lsp::ServerCapabilities {
4999                completion_provider: Some(lsp::CompletionOptions {
5000                    trigger_characters: Some(vec![":".to_string()]),
5001                    ..Default::default()
5002                }),
5003                ..Default::default()
5004            },
5005            ..Default::default()
5006        });
5007
5008        let fs = FakeFs::new(cx.background());
5009        fs.insert_tree(
5010            "/the-root",
5011            json!({
5012                "test.rs": "const A: i32 = 1;",
5013                "test2.rs": "",
5014                "Cargo.toml": "a = 1",
5015                "package.json": "{\"a\": 1}",
5016            }),
5017        )
5018        .await;
5019
5020        let project = Project::test(fs.clone(), cx);
5021        project.update(cx, |project, _| {
5022            project.languages.add(Arc::new(rust_language));
5023            project.languages.add(Arc::new(json_language));
5024        });
5025
5026        let worktree_id = project
5027            .update(cx, |project, cx| {
5028                project.find_or_create_local_worktree("/the-root", true, cx)
5029            })
5030            .await
5031            .unwrap()
5032            .0
5033            .read_with(cx, |tree, _| tree.id());
5034
5035        // Open a buffer without an associated language server.
5036        let toml_buffer = project
5037            .update(cx, |project, cx| {
5038                project.open_buffer((worktree_id, "Cargo.toml"), cx)
5039            })
5040            .await
5041            .unwrap();
5042
5043        // Open a buffer with an associated language server.
5044        let rust_buffer = project
5045            .update(cx, |project, cx| {
5046                project.open_buffer((worktree_id, "test.rs"), cx)
5047            })
5048            .await
5049            .unwrap();
5050
5051        // A server is started up, and it is notified about Rust files.
5052        let mut fake_rust_server = fake_rust_servers.next().await.unwrap();
5053        assert_eq!(
5054            fake_rust_server
5055                .receive_notification::<lsp::notification::DidOpenTextDocument>()
5056                .await
5057                .text_document,
5058            lsp::TextDocumentItem {
5059                uri: lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
5060                version: 0,
5061                text: "const A: i32 = 1;".to_string(),
5062                language_id: Default::default()
5063            }
5064        );
5065
5066        // The buffer is configured based on the language server's capabilities.
5067        rust_buffer.read_with(cx, |buffer, _| {
5068            assert_eq!(
5069                buffer.completion_triggers(),
5070                &[".".to_string(), "::".to_string()]
5071            );
5072        });
5073        toml_buffer.read_with(cx, |buffer, _| {
5074            assert!(buffer.completion_triggers().is_empty());
5075        });
5076
5077        // Edit a buffer. The changes are reported to the language server.
5078        rust_buffer.update(cx, |buffer, cx| buffer.edit([16..16], "2", cx));
5079        assert_eq!(
5080            fake_rust_server
5081                .receive_notification::<lsp::notification::DidChangeTextDocument>()
5082                .await
5083                .text_document,
5084            lsp::VersionedTextDocumentIdentifier::new(
5085                lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
5086                1
5087            )
5088        );
5089
5090        // Open a third buffer with a different associated language server.
5091        let json_buffer = project
5092            .update(cx, |project, cx| {
5093                project.open_buffer((worktree_id, "package.json"), cx)
5094            })
5095            .await
5096            .unwrap();
5097
5098        // A json language server is started up and is only notified about the json buffer.
5099        let mut fake_json_server = fake_json_servers.next().await.unwrap();
5100        assert_eq!(
5101            fake_json_server
5102                .receive_notification::<lsp::notification::DidOpenTextDocument>()
5103                .await
5104                .text_document,
5105            lsp::TextDocumentItem {
5106                uri: lsp::Url::from_file_path("/the-root/package.json").unwrap(),
5107                version: 0,
5108                text: "{\"a\": 1}".to_string(),
5109                language_id: Default::default()
5110            }
5111        );
5112
5113        // This buffer is configured based on the second language server's
5114        // capabilities.
5115        json_buffer.read_with(cx, |buffer, _| {
5116            assert_eq!(buffer.completion_triggers(), &[":".to_string()]);
5117        });
5118
5119        // When opening another buffer whose language server is already running,
5120        // it is also configured based on the existing language server's capabilities.
5121        let rust_buffer2 = project
5122            .update(cx, |project, cx| {
5123                project.open_buffer((worktree_id, "test2.rs"), cx)
5124            })
5125            .await
5126            .unwrap();
5127        rust_buffer2.read_with(cx, |buffer, _| {
5128            assert_eq!(
5129                buffer.completion_triggers(),
5130                &[".".to_string(), "::".to_string()]
5131            );
5132        });
5133
5134        // Changes are reported only to servers matching the buffer's language.
5135        toml_buffer.update(cx, |buffer, cx| buffer.edit([5..5], "23", cx));
5136        rust_buffer2.update(cx, |buffer, cx| buffer.edit([0..0], "let x = 1;", cx));
5137        assert_eq!(
5138            fake_rust_server
5139                .receive_notification::<lsp::notification::DidChangeTextDocument>()
5140                .await
5141                .text_document,
5142            lsp::VersionedTextDocumentIdentifier::new(
5143                lsp::Url::from_file_path("/the-root/test2.rs").unwrap(),
5144                1
5145            )
5146        );
5147
5148        // Save notifications are reported to all servers.
5149        toml_buffer
5150            .update(cx, |buffer, cx| buffer.save(cx))
5151            .await
5152            .unwrap();
5153        assert_eq!(
5154            fake_rust_server
5155                .receive_notification::<lsp::notification::DidSaveTextDocument>()
5156                .await
5157                .text_document,
5158            lsp::TextDocumentIdentifier::new(
5159                lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
5160            )
5161        );
5162        assert_eq!(
5163            fake_json_server
5164                .receive_notification::<lsp::notification::DidSaveTextDocument>()
5165                .await
5166                .text_document,
5167            lsp::TextDocumentIdentifier::new(
5168                lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
5169            )
5170        );
5171
5172        // Renames are reported only to servers matching the buffer's language.
5173        fs.rename(
5174            Path::new("/the-root/test2.rs"),
5175            Path::new("/the-root/test3.rs"),
5176            Default::default(),
5177        )
5178        .await
5179        .unwrap();
5180        assert_eq!(
5181            fake_rust_server
5182                .receive_notification::<lsp::notification::DidCloseTextDocument>()
5183                .await
5184                .text_document,
5185            lsp::TextDocumentIdentifier::new(
5186                lsp::Url::from_file_path("/the-root/test2.rs").unwrap()
5187            ),
5188        );
5189        assert_eq!(
5190            fake_rust_server
5191                .receive_notification::<lsp::notification::DidOpenTextDocument>()
5192                .await
5193                .text_document,
5194            lsp::TextDocumentItem {
5195                uri: lsp::Url::from_file_path("/the-root/test3.rs").unwrap(),
5196                version: 0,
5197                text: rust_buffer2.read_with(cx, |buffer, _| buffer.text()),
5198                language_id: Default::default()
5199            },
5200        );
5201
5202        rust_buffer2.update(cx, |buffer, cx| {
5203            buffer.update_diagnostics(
5204                DiagnosticSet::from_sorted_entries(
5205                    vec![DiagnosticEntry {
5206                        diagnostic: Default::default(),
5207                        range: Anchor::MIN..Anchor::MAX,
5208                    }],
5209                    &buffer.snapshot(),
5210                ),
5211                cx,
5212            );
5213            assert_eq!(
5214                buffer
5215                    .snapshot()
5216                    .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
5217                    .count(),
5218                1
5219            );
5220        });
5221
5222        // When the rename changes the extension of the file, the buffer gets closed on the old
5223        // language server and gets opened on the new one.
5224        fs.rename(
5225            Path::new("/the-root/test3.rs"),
5226            Path::new("/the-root/test3.json"),
5227            Default::default(),
5228        )
5229        .await
5230        .unwrap();
5231        assert_eq!(
5232            fake_rust_server
5233                .receive_notification::<lsp::notification::DidCloseTextDocument>()
5234                .await
5235                .text_document,
5236            lsp::TextDocumentIdentifier::new(
5237                lsp::Url::from_file_path("/the-root/test3.rs").unwrap(),
5238            ),
5239        );
5240        assert_eq!(
5241            fake_json_server
5242                .receive_notification::<lsp::notification::DidOpenTextDocument>()
5243                .await
5244                .text_document,
5245            lsp::TextDocumentItem {
5246                uri: lsp::Url::from_file_path("/the-root/test3.json").unwrap(),
5247                version: 0,
5248                text: rust_buffer2.read_with(cx, |buffer, _| buffer.text()),
5249                language_id: Default::default()
5250            },
5251        );
5252        // We clear the diagnostics, since the language has changed.
5253        rust_buffer2.read_with(cx, |buffer, _| {
5254            assert_eq!(
5255                buffer
5256                    .snapshot()
5257                    .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
5258                    .count(),
5259                0
5260            );
5261        });
5262
5263        // The renamed file's version resets after changing language server.
5264        rust_buffer2.update(cx, |buffer, cx| buffer.edit([0..0], "// ", cx));
5265        assert_eq!(
5266            fake_json_server
5267                .receive_notification::<lsp::notification::DidChangeTextDocument>()
5268                .await
5269                .text_document,
5270            lsp::VersionedTextDocumentIdentifier::new(
5271                lsp::Url::from_file_path("/the-root/test3.json").unwrap(),
5272                1
5273            )
5274        );
5275
5276        // Restart language servers
5277        project.update(cx, |project, cx| {
5278            project.restart_language_servers_for_buffers(
5279                vec![rust_buffer.clone(), json_buffer.clone()],
5280                cx,
5281            );
5282        });
5283
5284        let mut rust_shutdown_requests = fake_rust_server
5285            .handle_request::<lsp::request::Shutdown, _, _>(|_, _| future::ready(Ok(())));
5286        let mut json_shutdown_requests = fake_json_server
5287            .handle_request::<lsp::request::Shutdown, _, _>(|_, _| future::ready(Ok(())));
5288        futures::join!(rust_shutdown_requests.next(), json_shutdown_requests.next());
5289
5290        let mut fake_rust_server = fake_rust_servers.next().await.unwrap();
5291        let mut fake_json_server = fake_json_servers.next().await.unwrap();
5292
5293        // Ensure rust document is reopened in new rust language server
5294        assert_eq!(
5295            fake_rust_server
5296                .receive_notification::<lsp::notification::DidOpenTextDocument>()
5297                .await
5298                .text_document,
5299            lsp::TextDocumentItem {
5300                uri: lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
5301                version: 1,
5302                text: rust_buffer.read_with(cx, |buffer, _| buffer.text()),
5303                language_id: Default::default()
5304            }
5305        );
5306
5307        // Ensure json documents are reopened in new json language server
5308        assert_set_eq!(
5309            [
5310                fake_json_server
5311                    .receive_notification::<lsp::notification::DidOpenTextDocument>()
5312                    .await
5313                    .text_document,
5314                fake_json_server
5315                    .receive_notification::<lsp::notification::DidOpenTextDocument>()
5316                    .await
5317                    .text_document,
5318            ],
5319            [
5320                lsp::TextDocumentItem {
5321                    uri: lsp::Url::from_file_path("/the-root/package.json").unwrap(),
5322                    version: 0,
5323                    text: json_buffer.read_with(cx, |buffer, _| buffer.text()),
5324                    language_id: Default::default()
5325                },
5326                lsp::TextDocumentItem {
5327                    uri: lsp::Url::from_file_path("/the-root/test3.json").unwrap(),
5328                    version: 1,
5329                    text: rust_buffer2.read_with(cx, |buffer, _| buffer.text()),
5330                    language_id: Default::default()
5331                }
5332            ]
5333        );
5334
5335        // Close notifications are reported only to servers matching the buffer's language.
5336        cx.update(|_| drop(json_buffer));
5337        let close_message = lsp::DidCloseTextDocumentParams {
5338            text_document: lsp::TextDocumentIdentifier::new(
5339                lsp::Url::from_file_path("/the-root/package.json").unwrap(),
5340            ),
5341        };
5342        assert_eq!(
5343            fake_json_server
5344                .receive_notification::<lsp::notification::DidCloseTextDocument>()
5345                .await,
5346            close_message,
5347        );
5348    }
5349
5350    #[gpui::test]
5351    async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
5352        cx.foreground().forbid_parking();
5353
5354        let fs = FakeFs::new(cx.background());
5355        fs.insert_tree(
5356            "/dir",
5357            json!({
5358                "a.rs": "let a = 1;",
5359                "b.rs": "let b = 2;"
5360            }),
5361        )
5362        .await;
5363
5364        let project = Project::test(fs, cx);
5365        let worktree_a_id = project
5366            .update(cx, |project, cx| {
5367                project.find_or_create_local_worktree("/dir/a.rs", true, cx)
5368            })
5369            .await
5370            .unwrap()
5371            .0
5372            .read_with(cx, |tree, _| tree.id());
5373        let worktree_b_id = project
5374            .update(cx, |project, cx| {
5375                project.find_or_create_local_worktree("/dir/b.rs", true, cx)
5376            })
5377            .await
5378            .unwrap()
5379            .0
5380            .read_with(cx, |tree, _| tree.id());
5381
5382        let buffer_a = project
5383            .update(cx, |project, cx| {
5384                project.open_buffer((worktree_a_id, ""), cx)
5385            })
5386            .await
5387            .unwrap();
5388        let buffer_b = project
5389            .update(cx, |project, cx| {
5390                project.open_buffer((worktree_b_id, ""), cx)
5391            })
5392            .await
5393            .unwrap();
5394
5395        project.update(cx, |project, cx| {
5396            project
5397                .update_diagnostics(
5398                    lsp::PublishDiagnosticsParams {
5399                        uri: Url::from_file_path("/dir/a.rs").unwrap(),
5400                        version: None,
5401                        diagnostics: vec![lsp::Diagnostic {
5402                            range: lsp::Range::new(
5403                                lsp::Position::new(0, 4),
5404                                lsp::Position::new(0, 5),
5405                            ),
5406                            severity: Some(lsp::DiagnosticSeverity::ERROR),
5407                            message: "error 1".to_string(),
5408                            ..Default::default()
5409                        }],
5410                    },
5411                    &[],
5412                    cx,
5413                )
5414                .unwrap();
5415            project
5416                .update_diagnostics(
5417                    lsp::PublishDiagnosticsParams {
5418                        uri: Url::from_file_path("/dir/b.rs").unwrap(),
5419                        version: None,
5420                        diagnostics: vec![lsp::Diagnostic {
5421                            range: lsp::Range::new(
5422                                lsp::Position::new(0, 4),
5423                                lsp::Position::new(0, 5),
5424                            ),
5425                            severity: Some(lsp::DiagnosticSeverity::WARNING),
5426                            message: "error 2".to_string(),
5427                            ..Default::default()
5428                        }],
5429                    },
5430                    &[],
5431                    cx,
5432                )
5433                .unwrap();
5434        });
5435
5436        buffer_a.read_with(cx, |buffer, _| {
5437            let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len());
5438            assert_eq!(
5439                chunks
5440                    .iter()
5441                    .map(|(s, d)| (s.as_str(), *d))
5442                    .collect::<Vec<_>>(),
5443                &[
5444                    ("let ", None),
5445                    ("a", Some(DiagnosticSeverity::ERROR)),
5446                    (" = 1;", None),
5447                ]
5448            );
5449        });
5450        buffer_b.read_with(cx, |buffer, _| {
5451            let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len());
5452            assert_eq!(
5453                chunks
5454                    .iter()
5455                    .map(|(s, d)| (s.as_str(), *d))
5456                    .collect::<Vec<_>>(),
5457                &[
5458                    ("let ", None),
5459                    ("b", Some(DiagnosticSeverity::WARNING)),
5460                    (" = 2;", None),
5461                ]
5462            );
5463        });
5464    }
5465
5466    #[gpui::test]
5467    async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
5468        cx.foreground().forbid_parking();
5469
5470        let progress_token = "the-progress-token";
5471        let mut language = Language::new(
5472            LanguageConfig {
5473                name: "Rust".into(),
5474                path_suffixes: vec!["rs".to_string()],
5475                ..Default::default()
5476            },
5477            Some(tree_sitter_rust::language()),
5478        );
5479        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
5480            disk_based_diagnostics_progress_token: Some(progress_token),
5481            disk_based_diagnostics_sources: &["disk"],
5482            ..Default::default()
5483        });
5484
5485        let fs = FakeFs::new(cx.background());
5486        fs.insert_tree(
5487            "/dir",
5488            json!({
5489                "a.rs": "fn a() { A }",
5490                "b.rs": "const y: i32 = 1",
5491            }),
5492        )
5493        .await;
5494
5495        let project = Project::test(fs, cx);
5496        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
5497
5498        let (tree, _) = project
5499            .update(cx, |project, cx| {
5500                project.find_or_create_local_worktree("/dir", true, cx)
5501            })
5502            .await
5503            .unwrap();
5504        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
5505
5506        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
5507            .await;
5508
5509        // Cause worktree to start the fake language server
5510        let _buffer = project
5511            .update(cx, |project, cx| {
5512                project.open_buffer((worktree_id, Path::new("b.rs")), cx)
5513            })
5514            .await
5515            .unwrap();
5516
5517        let mut events = subscribe(&project, cx);
5518
5519        let mut fake_server = fake_servers.next().await.unwrap();
5520        fake_server.start_progress(progress_token).await;
5521        assert_eq!(
5522            events.next().await.unwrap(),
5523            Event::DiskBasedDiagnosticsStarted
5524        );
5525
5526        fake_server.start_progress(progress_token).await;
5527        fake_server.end_progress(progress_token).await;
5528        fake_server.start_progress(progress_token).await;
5529
5530        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5531            lsp::PublishDiagnosticsParams {
5532                uri: Url::from_file_path("/dir/a.rs").unwrap(),
5533                version: None,
5534                diagnostics: vec![lsp::Diagnostic {
5535                    range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5536                    severity: Some(lsp::DiagnosticSeverity::ERROR),
5537                    message: "undefined variable 'A'".to_string(),
5538                    ..Default::default()
5539                }],
5540            },
5541        );
5542        assert_eq!(
5543            events.next().await.unwrap(),
5544            Event::DiagnosticsUpdated((worktree_id, Path::new("a.rs")).into())
5545        );
5546
5547        fake_server.end_progress(progress_token).await;
5548        fake_server.end_progress(progress_token).await;
5549        assert_eq!(
5550            events.next().await.unwrap(),
5551            Event::DiskBasedDiagnosticsUpdated
5552        );
5553        assert_eq!(
5554            events.next().await.unwrap(),
5555            Event::DiskBasedDiagnosticsFinished
5556        );
5557
5558        let buffer = project
5559            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
5560            .await
5561            .unwrap();
5562
5563        buffer.read_with(cx, |buffer, _| {
5564            let snapshot = buffer.snapshot();
5565            let diagnostics = snapshot
5566                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
5567                .collect::<Vec<_>>();
5568            assert_eq!(
5569                diagnostics,
5570                &[DiagnosticEntry {
5571                    range: Point::new(0, 9)..Point::new(0, 10),
5572                    diagnostic: Diagnostic {
5573                        severity: lsp::DiagnosticSeverity::ERROR,
5574                        message: "undefined variable 'A'".to_string(),
5575                        group_id: 0,
5576                        is_primary: true,
5577                        ..Default::default()
5578                    }
5579                }]
5580            )
5581        });
5582
5583        // Ensure publishing empty diagnostics twice only results in one update event.
5584        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5585            lsp::PublishDiagnosticsParams {
5586                uri: Url::from_file_path("/dir/a.rs").unwrap(),
5587                version: None,
5588                diagnostics: Default::default(),
5589            },
5590        );
5591        assert_eq!(
5592            events.next().await.unwrap(),
5593            Event::DiagnosticsUpdated((worktree_id, Path::new("a.rs")).into())
5594        );
5595
5596        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5597            lsp::PublishDiagnosticsParams {
5598                uri: Url::from_file_path("/dir/a.rs").unwrap(),
5599                version: None,
5600                diagnostics: Default::default(),
5601            },
5602        );
5603        cx.foreground().run_until_parked();
5604        assert_eq!(futures::poll!(events.next()), Poll::Pending);
5605    }
5606
5607    #[gpui::test]
5608    async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppContext) {
5609        cx.foreground().forbid_parking();
5610
5611        let progress_token = "the-progress-token";
5612        let mut language = Language::new(
5613            LanguageConfig {
5614                path_suffixes: vec!["rs".to_string()],
5615                ..Default::default()
5616            },
5617            None,
5618        );
5619        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
5620            disk_based_diagnostics_sources: &["disk"],
5621            disk_based_diagnostics_progress_token: Some(progress_token),
5622            ..Default::default()
5623        });
5624
5625        let fs = FakeFs::new(cx.background());
5626        fs.insert_tree("/dir", json!({ "a.rs": "" })).await;
5627
5628        let project = Project::test(fs, cx);
5629        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
5630
5631        let worktree_id = project
5632            .update(cx, |project, cx| {
5633                project.find_or_create_local_worktree("/dir", true, cx)
5634            })
5635            .await
5636            .unwrap()
5637            .0
5638            .read_with(cx, |tree, _| tree.id());
5639
5640        let buffer = project
5641            .update(cx, |project, cx| {
5642                project.open_buffer((worktree_id, "a.rs"), cx)
5643            })
5644            .await
5645            .unwrap();
5646
5647        // Simulate diagnostics starting to update.
5648        let mut fake_server = fake_servers.next().await.unwrap();
5649        fake_server.start_progress(progress_token).await;
5650
5651        // Restart the server before the diagnostics finish updating.
5652        project.update(cx, |project, cx| {
5653            project.restart_language_servers_for_buffers([buffer], cx);
5654        });
5655        let mut events = subscribe(&project, cx);
5656
5657        // Simulate the newly started server sending more diagnostics.
5658        let mut fake_server = fake_servers.next().await.unwrap();
5659        fake_server.start_progress(progress_token).await;
5660        assert_eq!(
5661            events.next().await.unwrap(),
5662            Event::DiskBasedDiagnosticsStarted
5663        );
5664
5665        // All diagnostics are considered done, despite the old server's diagnostic
5666        // task never completing.
5667        fake_server.end_progress(progress_token).await;
5668        assert_eq!(
5669            events.next().await.unwrap(),
5670            Event::DiskBasedDiagnosticsUpdated
5671        );
5672        assert_eq!(
5673            events.next().await.unwrap(),
5674            Event::DiskBasedDiagnosticsFinished
5675        );
5676        project.read_with(cx, |project, _| {
5677            assert!(!project.is_running_disk_based_diagnostics());
5678        });
5679    }
5680
5681    #[gpui::test]
5682    async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
5683        cx.foreground().forbid_parking();
5684
5685        let mut language = Language::new(
5686            LanguageConfig {
5687                name: "Rust".into(),
5688                path_suffixes: vec!["rs".to_string()],
5689                ..Default::default()
5690            },
5691            Some(tree_sitter_rust::language()),
5692        );
5693        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
5694            disk_based_diagnostics_sources: &["disk"],
5695            ..Default::default()
5696        });
5697
5698        let text = "
5699            fn a() { A }
5700            fn b() { BB }
5701            fn c() { CCC }
5702        "
5703        .unindent();
5704
5705        let fs = FakeFs::new(cx.background());
5706        fs.insert_tree("/dir", json!({ "a.rs": text })).await;
5707
5708        let project = Project::test(fs, cx);
5709        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
5710
5711        let worktree_id = project
5712            .update(cx, |project, cx| {
5713                project.find_or_create_local_worktree("/dir", true, cx)
5714            })
5715            .await
5716            .unwrap()
5717            .0
5718            .read_with(cx, |tree, _| tree.id());
5719
5720        let buffer = project
5721            .update(cx, |project, cx| {
5722                project.open_buffer((worktree_id, "a.rs"), cx)
5723            })
5724            .await
5725            .unwrap();
5726
5727        let mut fake_server = fake_servers.next().await.unwrap();
5728        let open_notification = fake_server
5729            .receive_notification::<lsp::notification::DidOpenTextDocument>()
5730            .await;
5731
5732        // Edit the buffer, moving the content down
5733        buffer.update(cx, |buffer, cx| buffer.edit([0..0], "\n\n", cx));
5734        let change_notification_1 = fake_server
5735            .receive_notification::<lsp::notification::DidChangeTextDocument>()
5736            .await;
5737        assert!(
5738            change_notification_1.text_document.version > open_notification.text_document.version
5739        );
5740
5741        // Report some diagnostics for the initial version of the buffer
5742        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5743            lsp::PublishDiagnosticsParams {
5744                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5745                version: Some(open_notification.text_document.version),
5746                diagnostics: vec![
5747                    lsp::Diagnostic {
5748                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5749                        severity: Some(DiagnosticSeverity::ERROR),
5750                        message: "undefined variable 'A'".to_string(),
5751                        source: Some("disk".to_string()),
5752                        ..Default::default()
5753                    },
5754                    lsp::Diagnostic {
5755                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
5756                        severity: Some(DiagnosticSeverity::ERROR),
5757                        message: "undefined variable 'BB'".to_string(),
5758                        source: Some("disk".to_string()),
5759                        ..Default::default()
5760                    },
5761                    lsp::Diagnostic {
5762                        range: lsp::Range::new(lsp::Position::new(2, 9), lsp::Position::new(2, 12)),
5763                        severity: Some(DiagnosticSeverity::ERROR),
5764                        source: Some("disk".to_string()),
5765                        message: "undefined variable 'CCC'".to_string(),
5766                        ..Default::default()
5767                    },
5768                ],
5769            },
5770        );
5771
5772        // The diagnostics have moved down since they were created.
5773        buffer.next_notification(cx).await;
5774        buffer.read_with(cx, |buffer, _| {
5775            assert_eq!(
5776                buffer
5777                    .snapshot()
5778                    .diagnostics_in_range::<_, Point>(Point::new(3, 0)..Point::new(5, 0), false)
5779                    .collect::<Vec<_>>(),
5780                &[
5781                    DiagnosticEntry {
5782                        range: Point::new(3, 9)..Point::new(3, 11),
5783                        diagnostic: Diagnostic {
5784                            severity: DiagnosticSeverity::ERROR,
5785                            message: "undefined variable 'BB'".to_string(),
5786                            is_disk_based: true,
5787                            group_id: 1,
5788                            is_primary: true,
5789                            ..Default::default()
5790                        },
5791                    },
5792                    DiagnosticEntry {
5793                        range: Point::new(4, 9)..Point::new(4, 12),
5794                        diagnostic: Diagnostic {
5795                            severity: DiagnosticSeverity::ERROR,
5796                            message: "undefined variable 'CCC'".to_string(),
5797                            is_disk_based: true,
5798                            group_id: 2,
5799                            is_primary: true,
5800                            ..Default::default()
5801                        }
5802                    }
5803                ]
5804            );
5805            assert_eq!(
5806                chunks_with_diagnostics(buffer, 0..buffer.len()),
5807                [
5808                    ("\n\nfn a() { ".to_string(), None),
5809                    ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
5810                    (" }\nfn b() { ".to_string(), None),
5811                    ("BB".to_string(), Some(DiagnosticSeverity::ERROR)),
5812                    (" }\nfn c() { ".to_string(), None),
5813                    ("CCC".to_string(), Some(DiagnosticSeverity::ERROR)),
5814                    (" }\n".to_string(), None),
5815                ]
5816            );
5817            assert_eq!(
5818                chunks_with_diagnostics(buffer, Point::new(3, 10)..Point::new(4, 11)),
5819                [
5820                    ("B".to_string(), Some(DiagnosticSeverity::ERROR)),
5821                    (" }\nfn c() { ".to_string(), None),
5822                    ("CC".to_string(), Some(DiagnosticSeverity::ERROR)),
5823                ]
5824            );
5825        });
5826
5827        // Ensure overlapping diagnostics are highlighted correctly.
5828        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5829            lsp::PublishDiagnosticsParams {
5830                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5831                version: Some(open_notification.text_document.version),
5832                diagnostics: vec![
5833                    lsp::Diagnostic {
5834                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5835                        severity: Some(DiagnosticSeverity::ERROR),
5836                        message: "undefined variable 'A'".to_string(),
5837                        source: Some("disk".to_string()),
5838                        ..Default::default()
5839                    },
5840                    lsp::Diagnostic {
5841                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 12)),
5842                        severity: Some(DiagnosticSeverity::WARNING),
5843                        message: "unreachable statement".to_string(),
5844                        source: Some("disk".to_string()),
5845                        ..Default::default()
5846                    },
5847                ],
5848            },
5849        );
5850
5851        buffer.next_notification(cx).await;
5852        buffer.read_with(cx, |buffer, _| {
5853            assert_eq!(
5854                buffer
5855                    .snapshot()
5856                    .diagnostics_in_range::<_, Point>(Point::new(2, 0)..Point::new(3, 0), false)
5857                    .collect::<Vec<_>>(),
5858                &[
5859                    DiagnosticEntry {
5860                        range: Point::new(2, 9)..Point::new(2, 12),
5861                        diagnostic: Diagnostic {
5862                            severity: DiagnosticSeverity::WARNING,
5863                            message: "unreachable statement".to_string(),
5864                            is_disk_based: true,
5865                            group_id: 1,
5866                            is_primary: true,
5867                            ..Default::default()
5868                        }
5869                    },
5870                    DiagnosticEntry {
5871                        range: Point::new(2, 9)..Point::new(2, 10),
5872                        diagnostic: Diagnostic {
5873                            severity: DiagnosticSeverity::ERROR,
5874                            message: "undefined variable 'A'".to_string(),
5875                            is_disk_based: true,
5876                            group_id: 0,
5877                            is_primary: true,
5878                            ..Default::default()
5879                        },
5880                    }
5881                ]
5882            );
5883            assert_eq!(
5884                chunks_with_diagnostics(buffer, Point::new(2, 0)..Point::new(3, 0)),
5885                [
5886                    ("fn a() { ".to_string(), None),
5887                    ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
5888                    (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
5889                    ("\n".to_string(), None),
5890                ]
5891            );
5892            assert_eq!(
5893                chunks_with_diagnostics(buffer, Point::new(2, 10)..Point::new(3, 0)),
5894                [
5895                    (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
5896                    ("\n".to_string(), None),
5897                ]
5898            );
5899        });
5900
5901        // Keep editing the buffer and ensure disk-based diagnostics get translated according to the
5902        // changes since the last save.
5903        buffer.update(cx, |buffer, cx| {
5904            buffer.edit(Some(Point::new(2, 0)..Point::new(2, 0)), "    ", cx);
5905            buffer.edit(Some(Point::new(2, 8)..Point::new(2, 10)), "(x: usize)", cx);
5906            buffer.edit(Some(Point::new(3, 10)..Point::new(3, 10)), "xxx", cx);
5907        });
5908        let change_notification_2 = fake_server
5909            .receive_notification::<lsp::notification::DidChangeTextDocument>()
5910            .await;
5911        assert!(
5912            change_notification_2.text_document.version
5913                > change_notification_1.text_document.version
5914        );
5915
5916        // Handle out-of-order diagnostics
5917        fake_server.notify::<lsp::notification::PublishDiagnostics>(
5918            lsp::PublishDiagnosticsParams {
5919                uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
5920                version: Some(change_notification_2.text_document.version),
5921                diagnostics: vec![
5922                    lsp::Diagnostic {
5923                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
5924                        severity: Some(DiagnosticSeverity::ERROR),
5925                        message: "undefined variable 'BB'".to_string(),
5926                        source: Some("disk".to_string()),
5927                        ..Default::default()
5928                    },
5929                    lsp::Diagnostic {
5930                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
5931                        severity: Some(DiagnosticSeverity::WARNING),
5932                        message: "undefined variable 'A'".to_string(),
5933                        source: Some("disk".to_string()),
5934                        ..Default::default()
5935                    },
5936                ],
5937            },
5938        );
5939
5940        buffer.next_notification(cx).await;
5941        buffer.read_with(cx, |buffer, _| {
5942            assert_eq!(
5943                buffer
5944                    .snapshot()
5945                    .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
5946                    .collect::<Vec<_>>(),
5947                &[
5948                    DiagnosticEntry {
5949                        range: Point::new(2, 21)..Point::new(2, 22),
5950                        diagnostic: Diagnostic {
5951                            severity: DiagnosticSeverity::WARNING,
5952                            message: "undefined variable 'A'".to_string(),
5953                            is_disk_based: true,
5954                            group_id: 1,
5955                            is_primary: true,
5956                            ..Default::default()
5957                        }
5958                    },
5959                    DiagnosticEntry {
5960                        range: Point::new(3, 9)..Point::new(3, 14),
5961                        diagnostic: Diagnostic {
5962                            severity: DiagnosticSeverity::ERROR,
5963                            message: "undefined variable 'BB'".to_string(),
5964                            is_disk_based: true,
5965                            group_id: 0,
5966                            is_primary: true,
5967                            ..Default::default()
5968                        },
5969                    }
5970                ]
5971            );
5972        });
5973    }
5974
5975    #[gpui::test]
5976    async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
5977        cx.foreground().forbid_parking();
5978
5979        let text = concat!(
5980            "let one = ;\n", //
5981            "let two = \n",
5982            "let three = 3;\n",
5983        );
5984
5985        let fs = FakeFs::new(cx.background());
5986        fs.insert_tree("/dir", json!({ "a.rs": text })).await;
5987
5988        let project = Project::test(fs, cx);
5989        let worktree_id = project
5990            .update(cx, |project, cx| {
5991                project.find_or_create_local_worktree("/dir", true, cx)
5992            })
5993            .await
5994            .unwrap()
5995            .0
5996            .read_with(cx, |tree, _| tree.id());
5997
5998        let buffer = project
5999            .update(cx, |project, cx| {
6000                project.open_buffer((worktree_id, "a.rs"), cx)
6001            })
6002            .await
6003            .unwrap();
6004
6005        project.update(cx, |project, cx| {
6006            project
6007                .update_buffer_diagnostics(
6008                    &buffer,
6009                    vec![
6010                        DiagnosticEntry {
6011                            range: PointUtf16::new(0, 10)..PointUtf16::new(0, 10),
6012                            diagnostic: Diagnostic {
6013                                severity: DiagnosticSeverity::ERROR,
6014                                message: "syntax error 1".to_string(),
6015                                ..Default::default()
6016                            },
6017                        },
6018                        DiagnosticEntry {
6019                            range: PointUtf16::new(1, 10)..PointUtf16::new(1, 10),
6020                            diagnostic: Diagnostic {
6021                                severity: DiagnosticSeverity::ERROR,
6022                                message: "syntax error 2".to_string(),
6023                                ..Default::default()
6024                            },
6025                        },
6026                    ],
6027                    None,
6028                    cx,
6029                )
6030                .unwrap();
6031        });
6032
6033        // An empty range is extended forward to include the following character.
6034        // At the end of a line, an empty range is extended backward to include
6035        // the preceding character.
6036        buffer.read_with(cx, |buffer, _| {
6037            let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len());
6038            assert_eq!(
6039                chunks
6040                    .iter()
6041                    .map(|(s, d)| (s.as_str(), *d))
6042                    .collect::<Vec<_>>(),
6043                &[
6044                    ("let one = ", None),
6045                    (";", Some(DiagnosticSeverity::ERROR)),
6046                    ("\nlet two =", None),
6047                    (" ", Some(DiagnosticSeverity::ERROR)),
6048                    ("\nlet three = 3;\n", None)
6049                ]
6050            );
6051        });
6052    }
6053
6054    #[gpui::test]
6055    async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
6056        cx.foreground().forbid_parking();
6057
6058        let mut language = Language::new(
6059            LanguageConfig {
6060                name: "Rust".into(),
6061                path_suffixes: vec!["rs".to_string()],
6062                ..Default::default()
6063            },
6064            Some(tree_sitter_rust::language()),
6065        );
6066        let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
6067
6068        let text = "
6069            fn a() {
6070                f1();
6071            }
6072            fn b() {
6073                f2();
6074            }
6075            fn c() {
6076                f3();
6077            }
6078        "
6079        .unindent();
6080
6081        let fs = FakeFs::new(cx.background());
6082        fs.insert_tree(
6083            "/dir",
6084            json!({
6085                "a.rs": text.clone(),
6086            }),
6087        )
6088        .await;
6089
6090        let project = Project::test(fs, cx);
6091        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
6092
6093        let worktree_id = project
6094            .update(cx, |project, cx| {
6095                project.find_or_create_local_worktree("/dir", true, cx)
6096            })
6097            .await
6098            .unwrap()
6099            .0
6100            .read_with(cx, |tree, _| tree.id());
6101
6102        let buffer = project
6103            .update(cx, |project, cx| {
6104                project.open_buffer((worktree_id, "a.rs"), cx)
6105            })
6106            .await
6107            .unwrap();
6108
6109        let mut fake_server = fake_servers.next().await.unwrap();
6110        let lsp_document_version = fake_server
6111            .receive_notification::<lsp::notification::DidOpenTextDocument>()
6112            .await
6113            .text_document
6114            .version;
6115
6116        // Simulate editing the buffer after the language server computes some edits.
6117        buffer.update(cx, |buffer, cx| {
6118            buffer.edit(
6119                [Point::new(0, 0)..Point::new(0, 0)],
6120                "// above first function\n",
6121                cx,
6122            );
6123            buffer.edit(
6124                [Point::new(2, 0)..Point::new(2, 0)],
6125                "    // inside first function\n",
6126                cx,
6127            );
6128            buffer.edit(
6129                [Point::new(6, 4)..Point::new(6, 4)],
6130                "// inside second function ",
6131                cx,
6132            );
6133
6134            assert_eq!(
6135                buffer.text(),
6136                "
6137                    // above first function
6138                    fn a() {
6139                        // inside first function
6140                        f1();
6141                    }
6142                    fn b() {
6143                        // inside second function f2();
6144                    }
6145                    fn c() {
6146                        f3();
6147                    }
6148                "
6149                .unindent()
6150            );
6151        });
6152
6153        let edits = project
6154            .update(cx, |project, cx| {
6155                project.edits_from_lsp(
6156                    &buffer,
6157                    vec![
6158                        // replace body of first function
6159                        lsp::TextEdit {
6160                            range: lsp::Range::new(
6161                                lsp::Position::new(0, 0),
6162                                lsp::Position::new(3, 0),
6163                            ),
6164                            new_text: "
6165                                fn a() {
6166                                    f10();
6167                                }
6168                            "
6169                            .unindent(),
6170                        },
6171                        // edit inside second function
6172                        lsp::TextEdit {
6173                            range: lsp::Range::new(
6174                                lsp::Position::new(4, 6),
6175                                lsp::Position::new(4, 6),
6176                            ),
6177                            new_text: "00".into(),
6178                        },
6179                        // edit inside third function via two distinct edits
6180                        lsp::TextEdit {
6181                            range: lsp::Range::new(
6182                                lsp::Position::new(7, 5),
6183                                lsp::Position::new(7, 5),
6184                            ),
6185                            new_text: "4000".into(),
6186                        },
6187                        lsp::TextEdit {
6188                            range: lsp::Range::new(
6189                                lsp::Position::new(7, 5),
6190                                lsp::Position::new(7, 6),
6191                            ),
6192                            new_text: "".into(),
6193                        },
6194                    ],
6195                    Some(lsp_document_version),
6196                    cx,
6197                )
6198            })
6199            .await
6200            .unwrap();
6201
6202        buffer.update(cx, |buffer, cx| {
6203            for (range, new_text) in edits {
6204                buffer.edit([range], new_text, cx);
6205            }
6206            assert_eq!(
6207                buffer.text(),
6208                "
6209                    // above first function
6210                    fn a() {
6211                        // inside first function
6212                        f10();
6213                    }
6214                    fn b() {
6215                        // inside second function f200();
6216                    }
6217                    fn c() {
6218                        f4000();
6219                    }
6220                "
6221                .unindent()
6222            );
6223        });
6224    }
6225
6226    #[gpui::test]
6227    async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestAppContext) {
6228        cx.foreground().forbid_parking();
6229
6230        let text = "
6231            use a::b;
6232            use a::c;
6233
6234            fn f() {
6235                b();
6236                c();
6237            }
6238        "
6239        .unindent();
6240
6241        let fs = FakeFs::new(cx.background());
6242        fs.insert_tree(
6243            "/dir",
6244            json!({
6245                "a.rs": text.clone(),
6246            }),
6247        )
6248        .await;
6249
6250        let project = Project::test(fs, cx);
6251        let worktree_id = project
6252            .update(cx, |project, cx| {
6253                project.find_or_create_local_worktree("/dir", true, cx)
6254            })
6255            .await
6256            .unwrap()
6257            .0
6258            .read_with(cx, |tree, _| tree.id());
6259
6260        let buffer = project
6261            .update(cx, |project, cx| {
6262                project.open_buffer((worktree_id, "a.rs"), cx)
6263            })
6264            .await
6265            .unwrap();
6266
6267        // Simulate the language server sending us a small edit in the form of a very large diff.
6268        // Rust-analyzer does this when performing a merge-imports code action.
6269        let edits = project
6270            .update(cx, |project, cx| {
6271                project.edits_from_lsp(
6272                    &buffer,
6273                    [
6274                        // Replace the first use statement without editing the semicolon.
6275                        lsp::TextEdit {
6276                            range: lsp::Range::new(
6277                                lsp::Position::new(0, 4),
6278                                lsp::Position::new(0, 8),
6279                            ),
6280                            new_text: "a::{b, c}".into(),
6281                        },
6282                        // Reinsert the remainder of the file between the semicolon and the final
6283                        // newline of the file.
6284                        lsp::TextEdit {
6285                            range: lsp::Range::new(
6286                                lsp::Position::new(0, 9),
6287                                lsp::Position::new(0, 9),
6288                            ),
6289                            new_text: "\n\n".into(),
6290                        },
6291                        lsp::TextEdit {
6292                            range: lsp::Range::new(
6293                                lsp::Position::new(0, 9),
6294                                lsp::Position::new(0, 9),
6295                            ),
6296                            new_text: "
6297                                fn f() {
6298                                    b();
6299                                    c();
6300                                }"
6301                            .unindent(),
6302                        },
6303                        // Delete everything after the first newline of the file.
6304                        lsp::TextEdit {
6305                            range: lsp::Range::new(
6306                                lsp::Position::new(1, 0),
6307                                lsp::Position::new(7, 0),
6308                            ),
6309                            new_text: "".into(),
6310                        },
6311                    ],
6312                    None,
6313                    cx,
6314                )
6315            })
6316            .await
6317            .unwrap();
6318
6319        buffer.update(cx, |buffer, cx| {
6320            let edits = edits
6321                .into_iter()
6322                .map(|(range, text)| {
6323                    (
6324                        range.start.to_point(&buffer)..range.end.to_point(&buffer),
6325                        text,
6326                    )
6327                })
6328                .collect::<Vec<_>>();
6329
6330            assert_eq!(
6331                edits,
6332                [
6333                    (Point::new(0, 4)..Point::new(0, 8), "a::{b, c}".into()),
6334                    (Point::new(1, 0)..Point::new(2, 0), "".into())
6335                ]
6336            );
6337
6338            for (range, new_text) in edits {
6339                buffer.edit([range], new_text, cx);
6340            }
6341            assert_eq!(
6342                buffer.text(),
6343                "
6344                    use a::{b, c};
6345
6346                    fn f() {
6347                        b();
6348                        c();
6349                    }
6350                "
6351                .unindent()
6352            );
6353        });
6354    }
6355
6356    fn chunks_with_diagnostics<T: ToOffset + ToPoint>(
6357        buffer: &Buffer,
6358        range: Range<T>,
6359    ) -> Vec<(String, Option<DiagnosticSeverity>)> {
6360        let mut chunks: Vec<(String, Option<DiagnosticSeverity>)> = Vec::new();
6361        for chunk in buffer.snapshot().chunks(range, true) {
6362            if chunks.last().map_or(false, |prev_chunk| {
6363                prev_chunk.1 == chunk.diagnostic_severity
6364            }) {
6365                chunks.last_mut().unwrap().0.push_str(chunk.text);
6366            } else {
6367                chunks.push((chunk.text.to_string(), chunk.diagnostic_severity));
6368            }
6369        }
6370        chunks
6371    }
6372
6373    #[gpui::test]
6374    async fn test_search_worktree_without_files(cx: &mut gpui::TestAppContext) {
6375        let dir = temp_tree(json!({
6376            "root": {
6377                "dir1": {},
6378                "dir2": {
6379                    "dir3": {}
6380                }
6381            }
6382        }));
6383
6384        let project = Project::test(Arc::new(RealFs), cx);
6385        let (tree, _) = project
6386            .update(cx, |project, cx| {
6387                project.find_or_create_local_worktree(&dir.path(), true, cx)
6388            })
6389            .await
6390            .unwrap();
6391
6392        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6393            .await;
6394
6395        let cancel_flag = Default::default();
6396        let results = project
6397            .read_with(cx, |project, cx| {
6398                project.match_paths("dir", false, false, 10, &cancel_flag, cx)
6399            })
6400            .await;
6401
6402        assert!(results.is_empty());
6403    }
6404
6405    #[gpui::test]
6406    async fn test_definition(cx: &mut gpui::TestAppContext) {
6407        let mut language = Language::new(
6408            LanguageConfig {
6409                name: "Rust".into(),
6410                path_suffixes: vec!["rs".to_string()],
6411                ..Default::default()
6412            },
6413            Some(tree_sitter_rust::language()),
6414        );
6415        let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
6416
6417        let fs = FakeFs::new(cx.background());
6418        fs.insert_tree(
6419            "/dir",
6420            json!({
6421                "a.rs": "const fn a() { A }",
6422                "b.rs": "const y: i32 = crate::a()",
6423            }),
6424        )
6425        .await;
6426
6427        let project = Project::test(fs, cx);
6428        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
6429
6430        let (tree, _) = project
6431            .update(cx, |project, cx| {
6432                project.find_or_create_local_worktree("/dir/b.rs", true, cx)
6433            })
6434            .await
6435            .unwrap();
6436        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6437        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6438            .await;
6439
6440        let buffer = project
6441            .update(cx, |project, cx| project.open_buffer((worktree_id, ""), cx))
6442            .await
6443            .unwrap();
6444
6445        let fake_server = fake_servers.next().await.unwrap();
6446        fake_server.handle_request::<lsp::request::GotoDefinition, _, _>(|params, _| async move {
6447            let params = params.text_document_position_params;
6448            assert_eq!(
6449                params.text_document.uri.to_file_path().unwrap(),
6450                Path::new("/dir/b.rs"),
6451            );
6452            assert_eq!(params.position, lsp::Position::new(0, 22));
6453
6454            Ok(Some(lsp::GotoDefinitionResponse::Scalar(
6455                lsp::Location::new(
6456                    lsp::Url::from_file_path("/dir/a.rs").unwrap(),
6457                    lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
6458                ),
6459            )))
6460        });
6461
6462        let mut definitions = project
6463            .update(cx, |project, cx| project.definition(&buffer, 22, cx))
6464            .await
6465            .unwrap();
6466
6467        assert_eq!(definitions.len(), 1);
6468        let definition = definitions.pop().unwrap();
6469        cx.update(|cx| {
6470            let target_buffer = definition.buffer.read(cx);
6471            assert_eq!(
6472                target_buffer
6473                    .file()
6474                    .unwrap()
6475                    .as_local()
6476                    .unwrap()
6477                    .abs_path(cx),
6478                Path::new("/dir/a.rs"),
6479            );
6480            assert_eq!(definition.range.to_offset(target_buffer), 9..10);
6481            assert_eq!(
6482                list_worktrees(&project, cx),
6483                [("/dir/b.rs".as_ref(), true), ("/dir/a.rs".as_ref(), false)]
6484            );
6485
6486            drop(definition);
6487        });
6488        cx.read(|cx| {
6489            assert_eq!(list_worktrees(&project, cx), [("/dir/b.rs".as_ref(), true)]);
6490        });
6491
6492        fn list_worktrees<'a>(
6493            project: &'a ModelHandle<Project>,
6494            cx: &'a AppContext,
6495        ) -> Vec<(&'a Path, bool)> {
6496            project
6497                .read(cx)
6498                .worktrees(cx)
6499                .map(|worktree| {
6500                    let worktree = worktree.read(cx);
6501                    (
6502                        worktree.as_local().unwrap().abs_path().as_ref(),
6503                        worktree.is_visible(),
6504                    )
6505                })
6506                .collect::<Vec<_>>()
6507        }
6508    }
6509
6510    #[gpui::test(iterations = 10)]
6511    async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
6512        let mut language = Language::new(
6513            LanguageConfig {
6514                name: "TypeScript".into(),
6515                path_suffixes: vec!["ts".to_string()],
6516                ..Default::default()
6517            },
6518            None,
6519        );
6520        let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
6521
6522        let fs = FakeFs::new(cx.background());
6523        fs.insert_tree(
6524            "/dir",
6525            json!({
6526                "a.ts": "a",
6527            }),
6528        )
6529        .await;
6530
6531        let project = Project::test(fs, cx);
6532        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
6533
6534        let (tree, _) = project
6535            .update(cx, |project, cx| {
6536                project.find_or_create_local_worktree("/dir", true, cx)
6537            })
6538            .await
6539            .unwrap();
6540        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6541        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6542            .await;
6543
6544        let buffer = project
6545            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.ts"), cx))
6546            .await
6547            .unwrap();
6548
6549        let fake_server = fake_language_servers.next().await.unwrap();
6550
6551        // Language server returns code actions that contain commands, and not edits.
6552        let actions = project.update(cx, |project, cx| project.code_actions(&buffer, 0..0, cx));
6553        fake_server
6554            .handle_request::<lsp::request::CodeActionRequest, _, _>(|_, _| async move {
6555                Ok(Some(vec![
6556                    lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
6557                        title: "The code action".into(),
6558                        command: Some(lsp::Command {
6559                            title: "The command".into(),
6560                            command: "_the/command".into(),
6561                            arguments: Some(vec![json!("the-argument")]),
6562                        }),
6563                        ..Default::default()
6564                    }),
6565                    lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
6566                        title: "two".into(),
6567                        ..Default::default()
6568                    }),
6569                ]))
6570            })
6571            .next()
6572            .await;
6573
6574        let action = actions.await.unwrap()[0].clone();
6575        let apply = project.update(cx, |project, cx| {
6576            project.apply_code_action(buffer.clone(), action, true, cx)
6577        });
6578
6579        // Resolving the code action does not populate its edits. In absence of
6580        // edits, we must execute the given command.
6581        fake_server.handle_request::<lsp::request::CodeActionResolveRequest, _, _>(
6582            |action, _| async move { Ok(action) },
6583        );
6584
6585        // While executing the command, the language server sends the editor
6586        // a `workspaceEdit` request.
6587        fake_server
6588            .handle_request::<lsp::request::ExecuteCommand, _, _>({
6589                let fake = fake_server.clone();
6590                move |params, _| {
6591                    assert_eq!(params.command, "_the/command");
6592                    let fake = fake.clone();
6593                    async move {
6594                        fake.server
6595                            .request::<lsp::request::ApplyWorkspaceEdit>(
6596                                lsp::ApplyWorkspaceEditParams {
6597                                    label: None,
6598                                    edit: lsp::WorkspaceEdit {
6599                                        changes: Some(
6600                                            [(
6601                                                lsp::Url::from_file_path("/dir/a.ts").unwrap(),
6602                                                vec![lsp::TextEdit {
6603                                                    range: lsp::Range::new(
6604                                                        lsp::Position::new(0, 0),
6605                                                        lsp::Position::new(0, 0),
6606                                                    ),
6607                                                    new_text: "X".into(),
6608                                                }],
6609                                            )]
6610                                            .into_iter()
6611                                            .collect(),
6612                                        ),
6613                                        ..Default::default()
6614                                    },
6615                                },
6616                            )
6617                            .await
6618                            .unwrap();
6619                        Ok(Some(json!(null)))
6620                    }
6621                }
6622            })
6623            .next()
6624            .await;
6625
6626        // Applying the code action returns a project transaction containing the edits
6627        // sent by the language server in its `workspaceEdit` request.
6628        let transaction = apply.await.unwrap();
6629        assert!(transaction.0.contains_key(&buffer));
6630        buffer.update(cx, |buffer, cx| {
6631            assert_eq!(buffer.text(), "Xa");
6632            buffer.undo(cx);
6633            assert_eq!(buffer.text(), "a");
6634        });
6635    }
6636
6637    #[gpui::test]
6638    async fn test_save_file(cx: &mut gpui::TestAppContext) {
6639        let fs = FakeFs::new(cx.background());
6640        fs.insert_tree(
6641            "/dir",
6642            json!({
6643                "file1": "the old contents",
6644            }),
6645        )
6646        .await;
6647
6648        let project = Project::test(fs.clone(), cx);
6649        let worktree_id = project
6650            .update(cx, |p, cx| {
6651                p.find_or_create_local_worktree("/dir", true, cx)
6652            })
6653            .await
6654            .unwrap()
6655            .0
6656            .read_with(cx, |tree, _| tree.id());
6657
6658        let buffer = project
6659            .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
6660            .await
6661            .unwrap();
6662        buffer
6663            .update(cx, |buffer, cx| {
6664                assert_eq!(buffer.text(), "the old contents");
6665                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
6666                buffer.save(cx)
6667            })
6668            .await
6669            .unwrap();
6670
6671        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
6672        assert_eq!(new_text, buffer.read_with(cx, |buffer, _| buffer.text()));
6673    }
6674
6675    #[gpui::test]
6676    async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
6677        let fs = FakeFs::new(cx.background());
6678        fs.insert_tree(
6679            "/dir",
6680            json!({
6681                "file1": "the old contents",
6682            }),
6683        )
6684        .await;
6685
6686        let project = Project::test(fs.clone(), cx);
6687        let worktree_id = project
6688            .update(cx, |p, cx| {
6689                p.find_or_create_local_worktree("/dir/file1", true, cx)
6690            })
6691            .await
6692            .unwrap()
6693            .0
6694            .read_with(cx, |tree, _| tree.id());
6695
6696        let buffer = project
6697            .update(cx, |p, cx| p.open_buffer((worktree_id, ""), cx))
6698            .await
6699            .unwrap();
6700        buffer
6701            .update(cx, |buffer, cx| {
6702                buffer.edit(Some(0..0), "a line of text.\n".repeat(10 * 1024), cx);
6703                buffer.save(cx)
6704            })
6705            .await
6706            .unwrap();
6707
6708        let new_text = fs.load(Path::new("/dir/file1")).await.unwrap();
6709        assert_eq!(new_text, buffer.read_with(cx, |buffer, _| buffer.text()));
6710    }
6711
6712    #[gpui::test]
6713    async fn test_save_as(cx: &mut gpui::TestAppContext) {
6714        let fs = FakeFs::new(cx.background());
6715        fs.insert_tree("/dir", json!({})).await;
6716
6717        let project = Project::test(fs.clone(), cx);
6718        let (worktree, _) = project
6719            .update(cx, |project, cx| {
6720                project.find_or_create_local_worktree("/dir", true, cx)
6721            })
6722            .await
6723            .unwrap();
6724        let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
6725
6726        let buffer = project.update(cx, |project, cx| {
6727            project.create_buffer("", None, cx).unwrap()
6728        });
6729        buffer.update(cx, |buffer, cx| {
6730            buffer.edit([0..0], "abc", cx);
6731            assert!(buffer.is_dirty());
6732            assert!(!buffer.has_conflict());
6733        });
6734        project
6735            .update(cx, |project, cx| {
6736                project.save_buffer_as(buffer.clone(), "/dir/file1".into(), cx)
6737            })
6738            .await
6739            .unwrap();
6740        assert_eq!(fs.load(Path::new("/dir/file1")).await.unwrap(), "abc");
6741        buffer.read_with(cx, |buffer, cx| {
6742            assert_eq!(buffer.file().unwrap().full_path(cx), Path::new("dir/file1"));
6743            assert!(!buffer.is_dirty());
6744            assert!(!buffer.has_conflict());
6745        });
6746
6747        let opened_buffer = project
6748            .update(cx, |project, cx| {
6749                project.open_buffer((worktree_id, "file1"), cx)
6750            })
6751            .await
6752            .unwrap();
6753        assert_eq!(opened_buffer, buffer);
6754    }
6755
6756    #[gpui::test(retries = 5)]
6757    async fn test_rescan_and_remote_updates(cx: &mut gpui::TestAppContext) {
6758        let dir = temp_tree(json!({
6759            "a": {
6760                "file1": "",
6761                "file2": "",
6762                "file3": "",
6763            },
6764            "b": {
6765                "c": {
6766                    "file4": "",
6767                    "file5": "",
6768                }
6769            }
6770        }));
6771
6772        let project = Project::test(Arc::new(RealFs), cx);
6773        let rpc = project.read_with(cx, |p, _| p.client.clone());
6774
6775        let (tree, _) = project
6776            .update(cx, |p, cx| {
6777                p.find_or_create_local_worktree(dir.path(), true, cx)
6778            })
6779            .await
6780            .unwrap();
6781        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
6782
6783        let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
6784            let buffer = project.update(cx, |p, cx| p.open_buffer((worktree_id, path), cx));
6785            async move { buffer.await.unwrap() }
6786        };
6787        let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
6788            tree.read_with(cx, |tree, _| {
6789                tree.entry_for_path(path)
6790                    .expect(&format!("no entry for path {}", path))
6791                    .id
6792            })
6793        };
6794
6795        let buffer2 = buffer_for_path("a/file2", cx).await;
6796        let buffer3 = buffer_for_path("a/file3", cx).await;
6797        let buffer4 = buffer_for_path("b/c/file4", cx).await;
6798        let buffer5 = buffer_for_path("b/c/file5", cx).await;
6799
6800        let file2_id = id_for_path("a/file2", &cx);
6801        let file3_id = id_for_path("a/file3", &cx);
6802        let file4_id = id_for_path("b/c/file4", &cx);
6803
6804        // Wait for the initial scan.
6805        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
6806            .await;
6807
6808        // Create a remote copy of this worktree.
6809        let initial_snapshot = tree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot());
6810        let (remote, load_task) = cx.update(|cx| {
6811            Worktree::remote(
6812                1,
6813                1,
6814                initial_snapshot.to_proto(&Default::default(), true),
6815                rpc.clone(),
6816                cx,
6817            )
6818        });
6819        load_task.await;
6820
6821        cx.read(|cx| {
6822            assert!(!buffer2.read(cx).is_dirty());
6823            assert!(!buffer3.read(cx).is_dirty());
6824            assert!(!buffer4.read(cx).is_dirty());
6825            assert!(!buffer5.read(cx).is_dirty());
6826        });
6827
6828        // Rename and delete files and directories.
6829        tree.flush_fs_events(&cx).await;
6830        std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
6831        std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
6832        std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
6833        std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
6834        tree.flush_fs_events(&cx).await;
6835
6836        let expected_paths = vec![
6837            "a",
6838            "a/file1",
6839            "a/file2.new",
6840            "b",
6841            "d",
6842            "d/file3",
6843            "d/file4",
6844        ];
6845
6846        cx.read(|app| {
6847            assert_eq!(
6848                tree.read(app)
6849                    .paths()
6850                    .map(|p| p.to_str().unwrap())
6851                    .collect::<Vec<_>>(),
6852                expected_paths
6853            );
6854
6855            assert_eq!(id_for_path("a/file2.new", &cx), file2_id);
6856            assert_eq!(id_for_path("d/file3", &cx), file3_id);
6857            assert_eq!(id_for_path("d/file4", &cx), file4_id);
6858
6859            assert_eq!(
6860                buffer2.read(app).file().unwrap().path().as_ref(),
6861                Path::new("a/file2.new")
6862            );
6863            assert_eq!(
6864                buffer3.read(app).file().unwrap().path().as_ref(),
6865                Path::new("d/file3")
6866            );
6867            assert_eq!(
6868                buffer4.read(app).file().unwrap().path().as_ref(),
6869                Path::new("d/file4")
6870            );
6871            assert_eq!(
6872                buffer5.read(app).file().unwrap().path().as_ref(),
6873                Path::new("b/c/file5")
6874            );
6875
6876            assert!(!buffer2.read(app).file().unwrap().is_deleted());
6877            assert!(!buffer3.read(app).file().unwrap().is_deleted());
6878            assert!(!buffer4.read(app).file().unwrap().is_deleted());
6879            assert!(buffer5.read(app).file().unwrap().is_deleted());
6880        });
6881
6882        // Update the remote worktree. Check that it becomes consistent with the
6883        // local worktree.
6884        remote.update(cx, |remote, cx| {
6885            let update_message = tree.read(cx).as_local().unwrap().snapshot().build_update(
6886                &initial_snapshot,
6887                1,
6888                1,
6889                true,
6890            );
6891            remote
6892                .as_remote_mut()
6893                .unwrap()
6894                .snapshot
6895                .apply_remote_update(update_message)
6896                .unwrap();
6897
6898            assert_eq!(
6899                remote
6900                    .paths()
6901                    .map(|p| p.to_str().unwrap())
6902                    .collect::<Vec<_>>(),
6903                expected_paths
6904            );
6905        });
6906    }
6907
6908    #[gpui::test]
6909    async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
6910        let fs = FakeFs::new(cx.background());
6911        fs.insert_tree(
6912            "/the-dir",
6913            json!({
6914                "a.txt": "a-contents",
6915                "b.txt": "b-contents",
6916            }),
6917        )
6918        .await;
6919
6920        let project = Project::test(fs.clone(), cx);
6921        let worktree_id = project
6922            .update(cx, |p, cx| {
6923                p.find_or_create_local_worktree("/the-dir", true, cx)
6924            })
6925            .await
6926            .unwrap()
6927            .0
6928            .read_with(cx, |tree, _| tree.id());
6929
6930        // Spawn multiple tasks to open paths, repeating some paths.
6931        let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| {
6932            (
6933                p.open_buffer((worktree_id, "a.txt"), cx),
6934                p.open_buffer((worktree_id, "b.txt"), cx),
6935                p.open_buffer((worktree_id, "a.txt"), cx),
6936            )
6937        });
6938
6939        let buffer_a_1 = buffer_a_1.await.unwrap();
6940        let buffer_a_2 = buffer_a_2.await.unwrap();
6941        let buffer_b = buffer_b.await.unwrap();
6942        assert_eq!(buffer_a_1.read_with(cx, |b, _| b.text()), "a-contents");
6943        assert_eq!(buffer_b.read_with(cx, |b, _| b.text()), "b-contents");
6944
6945        // There is only one buffer per path.
6946        let buffer_a_id = buffer_a_1.id();
6947        assert_eq!(buffer_a_2.id(), buffer_a_id);
6948
6949        // Open the same path again while it is still open.
6950        drop(buffer_a_1);
6951        let buffer_a_3 = project
6952            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
6953            .await
6954            .unwrap();
6955
6956        // There's still only one buffer per path.
6957        assert_eq!(buffer_a_3.id(), buffer_a_id);
6958    }
6959
6960    #[gpui::test]
6961    async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
6962        use std::fs;
6963
6964        let dir = temp_tree(json!({
6965            "file1": "abc",
6966            "file2": "def",
6967            "file3": "ghi",
6968        }));
6969
6970        let project = Project::test(Arc::new(RealFs), cx);
6971        let (worktree, _) = project
6972            .update(cx, |p, cx| {
6973                p.find_or_create_local_worktree(dir.path(), true, cx)
6974            })
6975            .await
6976            .unwrap();
6977        let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
6978
6979        worktree.flush_fs_events(&cx).await;
6980        worktree
6981            .read_with(cx, |t, _| t.as_local().unwrap().scan_complete())
6982            .await;
6983
6984        let buffer1 = project
6985            .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
6986            .await
6987            .unwrap();
6988        let events = Rc::new(RefCell::new(Vec::new()));
6989
6990        // initially, the buffer isn't dirty.
6991        buffer1.update(cx, |buffer, cx| {
6992            cx.subscribe(&buffer1, {
6993                let events = events.clone();
6994                move |_, _, event, _| match event {
6995                    BufferEvent::Operation(_) => {}
6996                    _ => events.borrow_mut().push(event.clone()),
6997                }
6998            })
6999            .detach();
7000
7001            assert!(!buffer.is_dirty());
7002            assert!(events.borrow().is_empty());
7003
7004            buffer.edit(vec![1..2], "", cx);
7005        });
7006
7007        // after the first edit, the buffer is dirty, and emits a dirtied event.
7008        buffer1.update(cx, |buffer, cx| {
7009            assert!(buffer.text() == "ac");
7010            assert!(buffer.is_dirty());
7011            assert_eq!(
7012                *events.borrow(),
7013                &[language::Event::Edited, language::Event::Dirtied]
7014            );
7015            events.borrow_mut().clear();
7016            buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
7017        });
7018
7019        // after saving, the buffer is not dirty, and emits a saved event.
7020        buffer1.update(cx, |buffer, cx| {
7021            assert!(!buffer.is_dirty());
7022            assert_eq!(*events.borrow(), &[language::Event::Saved]);
7023            events.borrow_mut().clear();
7024
7025            buffer.edit(vec![1..1], "B", cx);
7026            buffer.edit(vec![2..2], "D", cx);
7027        });
7028
7029        // after editing again, the buffer is dirty, and emits another dirty event.
7030        buffer1.update(cx, |buffer, cx| {
7031            assert!(buffer.text() == "aBDc");
7032            assert!(buffer.is_dirty());
7033            assert_eq!(
7034                *events.borrow(),
7035                &[
7036                    language::Event::Edited,
7037                    language::Event::Dirtied,
7038                    language::Event::Edited,
7039                ],
7040            );
7041            events.borrow_mut().clear();
7042
7043            // TODO - currently, after restoring the buffer to its
7044            // previously-saved state, the is still considered dirty.
7045            buffer.edit([1..3], "", cx);
7046            assert!(buffer.text() == "ac");
7047            assert!(buffer.is_dirty());
7048        });
7049
7050        assert_eq!(*events.borrow(), &[language::Event::Edited]);
7051
7052        // When a file is deleted, the buffer is considered dirty.
7053        let events = Rc::new(RefCell::new(Vec::new()));
7054        let buffer2 = project
7055            .update(cx, |p, cx| p.open_buffer((worktree_id, "file2"), cx))
7056            .await
7057            .unwrap();
7058        buffer2.update(cx, |_, cx| {
7059            cx.subscribe(&buffer2, {
7060                let events = events.clone();
7061                move |_, _, event, _| events.borrow_mut().push(event.clone())
7062            })
7063            .detach();
7064        });
7065
7066        fs::remove_file(dir.path().join("file2")).unwrap();
7067        buffer2.condition(&cx, |b, _| b.is_dirty()).await;
7068        assert_eq!(
7069            *events.borrow(),
7070            &[language::Event::Dirtied, language::Event::FileHandleChanged]
7071        );
7072
7073        // When a file is already dirty when deleted, we don't emit a Dirtied event.
7074        let events = Rc::new(RefCell::new(Vec::new()));
7075        let buffer3 = project
7076            .update(cx, |p, cx| p.open_buffer((worktree_id, "file3"), cx))
7077            .await
7078            .unwrap();
7079        buffer3.update(cx, |_, cx| {
7080            cx.subscribe(&buffer3, {
7081                let events = events.clone();
7082                move |_, _, event, _| events.borrow_mut().push(event.clone())
7083            })
7084            .detach();
7085        });
7086
7087        worktree.flush_fs_events(&cx).await;
7088        buffer3.update(cx, |buffer, cx| {
7089            buffer.edit(Some(0..0), "x", cx);
7090        });
7091        events.borrow_mut().clear();
7092        fs::remove_file(dir.path().join("file3")).unwrap();
7093        buffer3
7094            .condition(&cx, |_, _| !events.borrow().is_empty())
7095            .await;
7096        assert_eq!(*events.borrow(), &[language::Event::FileHandleChanged]);
7097        cx.read(|cx| assert!(buffer3.read(cx).is_dirty()));
7098    }
7099
7100    #[gpui::test]
7101    async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
7102        use std::fs;
7103
7104        let initial_contents = "aaa\nbbbbb\nc\n";
7105        let dir = temp_tree(json!({ "the-file": initial_contents }));
7106
7107        let project = Project::test(Arc::new(RealFs), cx);
7108        let (worktree, _) = project
7109            .update(cx, |p, cx| {
7110                p.find_or_create_local_worktree(dir.path(), true, cx)
7111            })
7112            .await
7113            .unwrap();
7114        let worktree_id = worktree.read_with(cx, |tree, _| tree.id());
7115
7116        worktree
7117            .read_with(cx, |t, _| t.as_local().unwrap().scan_complete())
7118            .await;
7119
7120        let abs_path = dir.path().join("the-file");
7121        let buffer = project
7122            .update(cx, |p, cx| p.open_buffer((worktree_id, "the-file"), cx))
7123            .await
7124            .unwrap();
7125
7126        // TODO
7127        // Add a cursor on each row.
7128        // let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
7129        //     assert!(!buffer.is_dirty());
7130        //     buffer.add_selection_set(
7131        //         &(0..3)
7132        //             .map(|row| Selection {
7133        //                 id: row as usize,
7134        //                 start: Point::new(row, 1),
7135        //                 end: Point::new(row, 1),
7136        //                 reversed: false,
7137        //                 goal: SelectionGoal::None,
7138        //             })
7139        //             .collect::<Vec<_>>(),
7140        //         cx,
7141        //     )
7142        // });
7143
7144        // Change the file on disk, adding two new lines of text, and removing
7145        // one line.
7146        buffer.read_with(cx, |buffer, _| {
7147            assert!(!buffer.is_dirty());
7148            assert!(!buffer.has_conflict());
7149        });
7150        let new_contents = "AAAA\naaa\nBB\nbbbbb\n";
7151        fs::write(&abs_path, new_contents).unwrap();
7152
7153        // Because the buffer was not modified, it is reloaded from disk. Its
7154        // contents are edited according to the diff between the old and new
7155        // file contents.
7156        buffer
7157            .condition(&cx, |buffer, _| buffer.text() == new_contents)
7158            .await;
7159
7160        buffer.update(cx, |buffer, _| {
7161            assert_eq!(buffer.text(), new_contents);
7162            assert!(!buffer.is_dirty());
7163            assert!(!buffer.has_conflict());
7164
7165            // TODO
7166            // let cursor_positions = buffer
7167            //     .selection_set(selection_set_id)
7168            //     .unwrap()
7169            //     .selections::<Point>(&*buffer)
7170            //     .map(|selection| {
7171            //         assert_eq!(selection.start, selection.end);
7172            //         selection.start
7173            //     })
7174            //     .collect::<Vec<_>>();
7175            // assert_eq!(
7176            //     cursor_positions,
7177            //     [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
7178            // );
7179        });
7180
7181        // Modify the buffer
7182        buffer.update(cx, |buffer, cx| {
7183            buffer.edit(vec![0..0], " ", cx);
7184            assert!(buffer.is_dirty());
7185            assert!(!buffer.has_conflict());
7186        });
7187
7188        // Change the file on disk again, adding blank lines to the beginning.
7189        fs::write(&abs_path, "\n\n\nAAAA\naaa\nBB\nbbbbb\n").unwrap();
7190
7191        // Because the buffer is modified, it doesn't reload from disk, but is
7192        // marked as having a conflict.
7193        buffer
7194            .condition(&cx, |buffer, _| buffer.has_conflict())
7195            .await;
7196    }
7197
7198    #[gpui::test]
7199    async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
7200        cx.foreground().forbid_parking();
7201
7202        let fs = FakeFs::new(cx.background());
7203        fs.insert_tree(
7204            "/the-dir",
7205            json!({
7206                "a.rs": "
7207                    fn foo(mut v: Vec<usize>) {
7208                        for x in &v {
7209                            v.push(1);
7210                        }
7211                    }
7212                "
7213                .unindent(),
7214            }),
7215        )
7216        .await;
7217
7218        let project = Project::test(fs.clone(), cx);
7219        let (worktree, _) = project
7220            .update(cx, |p, cx| {
7221                p.find_or_create_local_worktree("/the-dir", true, cx)
7222            })
7223            .await
7224            .unwrap();
7225        let worktree_id = worktree.read_with(cx, |tree, _| tree.id());
7226
7227        let buffer = project
7228            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
7229            .await
7230            .unwrap();
7231
7232        let buffer_uri = Url::from_file_path("/the-dir/a.rs").unwrap();
7233        let message = lsp::PublishDiagnosticsParams {
7234            uri: buffer_uri.clone(),
7235            diagnostics: vec![
7236                lsp::Diagnostic {
7237                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
7238                    severity: Some(DiagnosticSeverity::WARNING),
7239                    message: "error 1".to_string(),
7240                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
7241                        location: lsp::Location {
7242                            uri: buffer_uri.clone(),
7243                            range: lsp::Range::new(
7244                                lsp::Position::new(1, 8),
7245                                lsp::Position::new(1, 9),
7246                            ),
7247                        },
7248                        message: "error 1 hint 1".to_string(),
7249                    }]),
7250                    ..Default::default()
7251                },
7252                lsp::Diagnostic {
7253                    range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 9)),
7254                    severity: Some(DiagnosticSeverity::HINT),
7255                    message: "error 1 hint 1".to_string(),
7256                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
7257                        location: lsp::Location {
7258                            uri: buffer_uri.clone(),
7259                            range: lsp::Range::new(
7260                                lsp::Position::new(1, 8),
7261                                lsp::Position::new(1, 9),
7262                            ),
7263                        },
7264                        message: "original diagnostic".to_string(),
7265                    }]),
7266                    ..Default::default()
7267                },
7268                lsp::Diagnostic {
7269                    range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 17)),
7270                    severity: Some(DiagnosticSeverity::ERROR),
7271                    message: "error 2".to_string(),
7272                    related_information: Some(vec![
7273                        lsp::DiagnosticRelatedInformation {
7274                            location: lsp::Location {
7275                                uri: buffer_uri.clone(),
7276                                range: lsp::Range::new(
7277                                    lsp::Position::new(1, 13),
7278                                    lsp::Position::new(1, 15),
7279                                ),
7280                            },
7281                            message: "error 2 hint 1".to_string(),
7282                        },
7283                        lsp::DiagnosticRelatedInformation {
7284                            location: lsp::Location {
7285                                uri: buffer_uri.clone(),
7286                                range: lsp::Range::new(
7287                                    lsp::Position::new(1, 13),
7288                                    lsp::Position::new(1, 15),
7289                                ),
7290                            },
7291                            message: "error 2 hint 2".to_string(),
7292                        },
7293                    ]),
7294                    ..Default::default()
7295                },
7296                lsp::Diagnostic {
7297                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
7298                    severity: Some(DiagnosticSeverity::HINT),
7299                    message: "error 2 hint 1".to_string(),
7300                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
7301                        location: lsp::Location {
7302                            uri: buffer_uri.clone(),
7303                            range: lsp::Range::new(
7304                                lsp::Position::new(2, 8),
7305                                lsp::Position::new(2, 17),
7306                            ),
7307                        },
7308                        message: "original diagnostic".to_string(),
7309                    }]),
7310                    ..Default::default()
7311                },
7312                lsp::Diagnostic {
7313                    range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 15)),
7314                    severity: Some(DiagnosticSeverity::HINT),
7315                    message: "error 2 hint 2".to_string(),
7316                    related_information: Some(vec![lsp::DiagnosticRelatedInformation {
7317                        location: lsp::Location {
7318                            uri: buffer_uri.clone(),
7319                            range: lsp::Range::new(
7320                                lsp::Position::new(2, 8),
7321                                lsp::Position::new(2, 17),
7322                            ),
7323                        },
7324                        message: "original diagnostic".to_string(),
7325                    }]),
7326                    ..Default::default()
7327                },
7328            ],
7329            version: None,
7330        };
7331
7332        project
7333            .update(cx, |p, cx| p.update_diagnostics(message, &[], cx))
7334            .unwrap();
7335        let buffer = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7336
7337        assert_eq!(
7338            buffer
7339                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
7340                .collect::<Vec<_>>(),
7341            &[
7342                DiagnosticEntry {
7343                    range: Point::new(1, 8)..Point::new(1, 9),
7344                    diagnostic: Diagnostic {
7345                        severity: DiagnosticSeverity::WARNING,
7346                        message: "error 1".to_string(),
7347                        group_id: 0,
7348                        is_primary: true,
7349                        ..Default::default()
7350                    }
7351                },
7352                DiagnosticEntry {
7353                    range: Point::new(1, 8)..Point::new(1, 9),
7354                    diagnostic: Diagnostic {
7355                        severity: DiagnosticSeverity::HINT,
7356                        message: "error 1 hint 1".to_string(),
7357                        group_id: 0,
7358                        is_primary: false,
7359                        ..Default::default()
7360                    }
7361                },
7362                DiagnosticEntry {
7363                    range: Point::new(1, 13)..Point::new(1, 15),
7364                    diagnostic: Diagnostic {
7365                        severity: DiagnosticSeverity::HINT,
7366                        message: "error 2 hint 1".to_string(),
7367                        group_id: 1,
7368                        is_primary: false,
7369                        ..Default::default()
7370                    }
7371                },
7372                DiagnosticEntry {
7373                    range: Point::new(1, 13)..Point::new(1, 15),
7374                    diagnostic: Diagnostic {
7375                        severity: DiagnosticSeverity::HINT,
7376                        message: "error 2 hint 2".to_string(),
7377                        group_id: 1,
7378                        is_primary: false,
7379                        ..Default::default()
7380                    }
7381                },
7382                DiagnosticEntry {
7383                    range: Point::new(2, 8)..Point::new(2, 17),
7384                    diagnostic: Diagnostic {
7385                        severity: DiagnosticSeverity::ERROR,
7386                        message: "error 2".to_string(),
7387                        group_id: 1,
7388                        is_primary: true,
7389                        ..Default::default()
7390                    }
7391                }
7392            ]
7393        );
7394
7395        assert_eq!(
7396            buffer.diagnostic_group::<Point>(0).collect::<Vec<_>>(),
7397            &[
7398                DiagnosticEntry {
7399                    range: Point::new(1, 8)..Point::new(1, 9),
7400                    diagnostic: Diagnostic {
7401                        severity: DiagnosticSeverity::WARNING,
7402                        message: "error 1".to_string(),
7403                        group_id: 0,
7404                        is_primary: true,
7405                        ..Default::default()
7406                    }
7407                },
7408                DiagnosticEntry {
7409                    range: Point::new(1, 8)..Point::new(1, 9),
7410                    diagnostic: Diagnostic {
7411                        severity: DiagnosticSeverity::HINT,
7412                        message: "error 1 hint 1".to_string(),
7413                        group_id: 0,
7414                        is_primary: false,
7415                        ..Default::default()
7416                    }
7417                },
7418            ]
7419        );
7420        assert_eq!(
7421            buffer.diagnostic_group::<Point>(1).collect::<Vec<_>>(),
7422            &[
7423                DiagnosticEntry {
7424                    range: Point::new(1, 13)..Point::new(1, 15),
7425                    diagnostic: Diagnostic {
7426                        severity: DiagnosticSeverity::HINT,
7427                        message: "error 2 hint 1".to_string(),
7428                        group_id: 1,
7429                        is_primary: false,
7430                        ..Default::default()
7431                    }
7432                },
7433                DiagnosticEntry {
7434                    range: Point::new(1, 13)..Point::new(1, 15),
7435                    diagnostic: Diagnostic {
7436                        severity: DiagnosticSeverity::HINT,
7437                        message: "error 2 hint 2".to_string(),
7438                        group_id: 1,
7439                        is_primary: false,
7440                        ..Default::default()
7441                    }
7442                },
7443                DiagnosticEntry {
7444                    range: Point::new(2, 8)..Point::new(2, 17),
7445                    diagnostic: Diagnostic {
7446                        severity: DiagnosticSeverity::ERROR,
7447                        message: "error 2".to_string(),
7448                        group_id: 1,
7449                        is_primary: true,
7450                        ..Default::default()
7451                    }
7452                }
7453            ]
7454        );
7455    }
7456
7457    #[gpui::test]
7458    async fn test_rename(cx: &mut gpui::TestAppContext) {
7459        cx.foreground().forbid_parking();
7460
7461        let mut language = Language::new(
7462            LanguageConfig {
7463                name: "Rust".into(),
7464                path_suffixes: vec!["rs".to_string()],
7465                ..Default::default()
7466            },
7467            Some(tree_sitter_rust::language()),
7468        );
7469        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
7470            capabilities: lsp::ServerCapabilities {
7471                rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
7472                    prepare_provider: Some(true),
7473                    work_done_progress_options: Default::default(),
7474                })),
7475                ..Default::default()
7476            },
7477            ..Default::default()
7478        });
7479
7480        let fs = FakeFs::new(cx.background());
7481        fs.insert_tree(
7482            "/dir",
7483            json!({
7484                "one.rs": "const ONE: usize = 1;",
7485                "two.rs": "const TWO: usize = one::ONE + one::ONE;"
7486            }),
7487        )
7488        .await;
7489
7490        let project = Project::test(fs.clone(), cx);
7491        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
7492
7493        let (tree, _) = project
7494            .update(cx, |project, cx| {
7495                project.find_or_create_local_worktree("/dir", true, cx)
7496            })
7497            .await
7498            .unwrap();
7499        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
7500        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
7501            .await;
7502
7503        let buffer = project
7504            .update(cx, |project, cx| {
7505                project.open_buffer((worktree_id, Path::new("one.rs")), cx)
7506            })
7507            .await
7508            .unwrap();
7509
7510        let fake_server = fake_servers.next().await.unwrap();
7511
7512        let response = project.update(cx, |project, cx| {
7513            project.prepare_rename(buffer.clone(), 7, cx)
7514        });
7515        fake_server
7516            .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
7517                assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
7518                assert_eq!(params.position, lsp::Position::new(0, 7));
7519                Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
7520                    lsp::Position::new(0, 6),
7521                    lsp::Position::new(0, 9),
7522                ))))
7523            })
7524            .next()
7525            .await
7526            .unwrap();
7527        let range = response.await.unwrap().unwrap();
7528        let range = buffer.read_with(cx, |buffer, _| range.to_offset(buffer));
7529        assert_eq!(range, 6..9);
7530
7531        let response = project.update(cx, |project, cx| {
7532            project.perform_rename(buffer.clone(), 7, "THREE".to_string(), true, cx)
7533        });
7534        fake_server
7535            .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
7536                assert_eq!(
7537                    params.text_document_position.text_document.uri.as_str(),
7538                    "file:///dir/one.rs"
7539                );
7540                assert_eq!(
7541                    params.text_document_position.position,
7542                    lsp::Position::new(0, 7)
7543                );
7544                assert_eq!(params.new_name, "THREE");
7545                Ok(Some(lsp::WorkspaceEdit {
7546                    changes: Some(
7547                        [
7548                            (
7549                                lsp::Url::from_file_path("/dir/one.rs").unwrap(),
7550                                vec![lsp::TextEdit::new(
7551                                    lsp::Range::new(
7552                                        lsp::Position::new(0, 6),
7553                                        lsp::Position::new(0, 9),
7554                                    ),
7555                                    "THREE".to_string(),
7556                                )],
7557                            ),
7558                            (
7559                                lsp::Url::from_file_path("/dir/two.rs").unwrap(),
7560                                vec![
7561                                    lsp::TextEdit::new(
7562                                        lsp::Range::new(
7563                                            lsp::Position::new(0, 24),
7564                                            lsp::Position::new(0, 27),
7565                                        ),
7566                                        "THREE".to_string(),
7567                                    ),
7568                                    lsp::TextEdit::new(
7569                                        lsp::Range::new(
7570                                            lsp::Position::new(0, 35),
7571                                            lsp::Position::new(0, 38),
7572                                        ),
7573                                        "THREE".to_string(),
7574                                    ),
7575                                ],
7576                            ),
7577                        ]
7578                        .into_iter()
7579                        .collect(),
7580                    ),
7581                    ..Default::default()
7582                }))
7583            })
7584            .next()
7585            .await
7586            .unwrap();
7587        let mut transaction = response.await.unwrap().0;
7588        assert_eq!(transaction.len(), 2);
7589        assert_eq!(
7590            transaction
7591                .remove_entry(&buffer)
7592                .unwrap()
7593                .0
7594                .read_with(cx, |buffer, _| buffer.text()),
7595            "const THREE: usize = 1;"
7596        );
7597        assert_eq!(
7598            transaction
7599                .into_keys()
7600                .next()
7601                .unwrap()
7602                .read_with(cx, |buffer, _| buffer.text()),
7603            "const TWO: usize = one::THREE + one::THREE;"
7604        );
7605    }
7606
7607    #[gpui::test]
7608    async fn test_search(cx: &mut gpui::TestAppContext) {
7609        let fs = FakeFs::new(cx.background());
7610        fs.insert_tree(
7611            "/dir",
7612            json!({
7613                "one.rs": "const ONE: usize = 1;",
7614                "two.rs": "const TWO: usize = one::ONE + one::ONE;",
7615                "three.rs": "const THREE: usize = one::ONE + two::TWO;",
7616                "four.rs": "const FOUR: usize = one::ONE + three::THREE;",
7617            }),
7618        )
7619        .await;
7620        let project = Project::test(fs.clone(), cx);
7621        let (tree, _) = project
7622            .update(cx, |project, cx| {
7623                project.find_or_create_local_worktree("/dir", true, cx)
7624            })
7625            .await
7626            .unwrap();
7627        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
7628        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
7629            .await;
7630
7631        assert_eq!(
7632            search(&project, SearchQuery::text("TWO", false, true), cx)
7633                .await
7634                .unwrap(),
7635            HashMap::from_iter([
7636                ("two.rs".to_string(), vec![6..9]),
7637                ("three.rs".to_string(), vec![37..40])
7638            ])
7639        );
7640
7641        let buffer_4 = project
7642            .update(cx, |project, cx| {
7643                project.open_buffer((worktree_id, "four.rs"), cx)
7644            })
7645            .await
7646            .unwrap();
7647        buffer_4.update(cx, |buffer, cx| {
7648            buffer.edit([20..28, 31..43], "two::TWO", cx);
7649        });
7650
7651        assert_eq!(
7652            search(&project, SearchQuery::text("TWO", false, true), cx)
7653                .await
7654                .unwrap(),
7655            HashMap::from_iter([
7656                ("two.rs".to_string(), vec![6..9]),
7657                ("three.rs".to_string(), vec![37..40]),
7658                ("four.rs".to_string(), vec![25..28, 36..39])
7659            ])
7660        );
7661
7662        async fn search(
7663            project: &ModelHandle<Project>,
7664            query: SearchQuery,
7665            cx: &mut gpui::TestAppContext,
7666        ) -> Result<HashMap<String, Vec<Range<usize>>>> {
7667            let results = project
7668                .update(cx, |project, cx| project.search(query, cx))
7669                .await?;
7670
7671            Ok(results
7672                .into_iter()
7673                .map(|(buffer, ranges)| {
7674                    buffer.read_with(cx, |buffer, _| {
7675                        let path = buffer.file().unwrap().path().to_string_lossy().to_string();
7676                        let ranges = ranges
7677                            .into_iter()
7678                            .map(|range| range.to_offset(buffer))
7679                            .collect::<Vec<_>>();
7680                        (path, ranges)
7681                    })
7682                })
7683                .collect())
7684        }
7685    }
7686}