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