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