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