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