project.rs

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