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                    Self::deserialize_workspace_edit(
3822                        this,
3823                        edit,
3824                        push_to_history,
3825                        lsp_adapter.clone(),
3826                        lang_server.clone(),
3827                        &mut cx,
3828                    )
3829                    .await
3830                } else if let Some(command) = action.lsp_action.command {
3831                    this.update(&mut cx, |this, _| {
3832                        this.last_workspace_edits_by_language_server
3833                            .remove(&lang_server.server_id());
3834                    });
3835                    lang_server
3836                        .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
3837                            command: command.command,
3838                            arguments: command.arguments.unwrap_or_default(),
3839                            ..Default::default()
3840                        })
3841                        .await?;
3842                    Ok(this.update(&mut cx, |this, _| {
3843                        this.last_workspace_edits_by_language_server
3844                            .remove(&lang_server.server_id())
3845                            .unwrap_or_default()
3846                    }))
3847                } else {
3848                    Ok(ProjectTransaction::default())
3849                }
3850            })
3851        } else if let Some(project_id) = self.remote_id() {
3852            let client = self.client.clone();
3853            let request = proto::ApplyCodeAction {
3854                project_id,
3855                buffer_id: buffer_handle.read(cx).remote_id(),
3856                action: Some(language::proto::serialize_code_action(&action)),
3857            };
3858            cx.spawn(|this, mut cx| async move {
3859                let response = client
3860                    .request(request)
3861                    .await?
3862                    .transaction
3863                    .ok_or_else(|| anyhow!("missing transaction"))?;
3864                this.update(&mut cx, |this, cx| {
3865                    this.deserialize_project_transaction(response, push_to_history, cx)
3866                })
3867                .await
3868            })
3869        } else {
3870            Task::ready(Err(anyhow!("project does not have a remote id")))
3871        }
3872    }
3873
3874    async fn deserialize_workspace_edit(
3875        this: ModelHandle<Self>,
3876        edit: lsp::WorkspaceEdit,
3877        push_to_history: bool,
3878        lsp_adapter: Arc<dyn LspAdapter>,
3879        language_server: Arc<LanguageServer>,
3880        cx: &mut AsyncAppContext,
3881    ) -> Result<ProjectTransaction> {
3882        let fs = this.read_with(cx, |this, _| this.fs.clone());
3883        let mut operations = Vec::new();
3884        if let Some(document_changes) = edit.document_changes {
3885            match document_changes {
3886                lsp::DocumentChanges::Edits(edits) => {
3887                    operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3888                }
3889                lsp::DocumentChanges::Operations(ops) => operations = ops,
3890            }
3891        } else if let Some(changes) = edit.changes {
3892            operations.extend(changes.into_iter().map(|(uri, edits)| {
3893                lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3894                    text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3895                        uri,
3896                        version: None,
3897                    },
3898                    edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
3899                })
3900            }));
3901        }
3902
3903        let mut project_transaction = ProjectTransaction::default();
3904        for operation in operations {
3905            match operation {
3906                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3907                    let abs_path = op
3908                        .uri
3909                        .to_file_path()
3910                        .map_err(|_| anyhow!("can't convert URI to path"))?;
3911
3912                    if let Some(parent_path) = abs_path.parent() {
3913                        fs.create_dir(parent_path).await?;
3914                    }
3915                    if abs_path.ends_with("/") {
3916                        fs.create_dir(&abs_path).await?;
3917                    } else {
3918                        fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
3919                            .await?;
3920                    }
3921                }
3922                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3923                    let source_abs_path = op
3924                        .old_uri
3925                        .to_file_path()
3926                        .map_err(|_| anyhow!("can't convert URI to path"))?;
3927                    let target_abs_path = op
3928                        .new_uri
3929                        .to_file_path()
3930                        .map_err(|_| anyhow!("can't convert URI to path"))?;
3931                    fs.rename(
3932                        &source_abs_path,
3933                        &target_abs_path,
3934                        op.options.map(Into::into).unwrap_or_default(),
3935                    )
3936                    .await?;
3937                }
3938                lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3939                    let abs_path = op
3940                        .uri
3941                        .to_file_path()
3942                        .map_err(|_| anyhow!("can't convert URI to path"))?;
3943                    let options = op.options.map(Into::into).unwrap_or_default();
3944                    if abs_path.ends_with("/") {
3945                        fs.remove_dir(&abs_path, options).await?;
3946                    } else {
3947                        fs.remove_file(&abs_path, options).await?;
3948                    }
3949                }
3950                lsp::DocumentChangeOperation::Edit(op) => {
3951                    let buffer_to_edit = this
3952                        .update(cx, |this, cx| {
3953                            this.open_local_buffer_via_lsp(
3954                                op.text_document.uri,
3955                                language_server.server_id(),
3956                                lsp_adapter.name(),
3957                                cx,
3958                            )
3959                        })
3960                        .await?;
3961
3962                    let edits = this
3963                        .update(cx, |this, cx| {
3964                            let edits = op.edits.into_iter().map(|edit| match edit {
3965                                lsp::OneOf::Left(edit) => edit,
3966                                lsp::OneOf::Right(edit) => edit.text_edit,
3967                            });
3968                            this.edits_from_lsp(
3969                                &buffer_to_edit,
3970                                edits,
3971                                op.text_document.version,
3972                                cx,
3973                            )
3974                        })
3975                        .await?;
3976
3977                    let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3978                        buffer.finalize_last_transaction();
3979                        buffer.start_transaction();
3980                        for (range, text) in edits {
3981                            buffer.edit([(range, text)], cx);
3982                        }
3983                        let transaction = if buffer.end_transaction(cx).is_some() {
3984                            let transaction = buffer.finalize_last_transaction().unwrap().clone();
3985                            if !push_to_history {
3986                                buffer.forget_transaction(transaction.id);
3987                            }
3988                            Some(transaction)
3989                        } else {
3990                            None
3991                        };
3992
3993                        transaction
3994                    });
3995                    if let Some(transaction) = transaction {
3996                        project_transaction.0.insert(buffer_to_edit, transaction);
3997                    }
3998                }
3999            }
4000        }
4001
4002        Ok(project_transaction)
4003    }
4004
4005    pub fn prepare_rename<T: ToPointUtf16>(
4006        &self,
4007        buffer: ModelHandle<Buffer>,
4008        position: T,
4009        cx: &mut ModelContext<Self>,
4010    ) -> Task<Result<Option<Range<Anchor>>>> {
4011        let position = position.to_point_utf16(buffer.read(cx));
4012        self.request_lsp(buffer, PrepareRename { position }, cx)
4013    }
4014
4015    pub fn perform_rename<T: ToPointUtf16>(
4016        &self,
4017        buffer: ModelHandle<Buffer>,
4018        position: T,
4019        new_name: String,
4020        push_to_history: bool,
4021        cx: &mut ModelContext<Self>,
4022    ) -> Task<Result<ProjectTransaction>> {
4023        let position = position.to_point_utf16(buffer.read(cx));
4024        self.request_lsp(
4025            buffer,
4026            PerformRename {
4027                position,
4028                new_name,
4029                push_to_history,
4030            },
4031            cx,
4032        )
4033    }
4034
4035    pub fn search(
4036        &self,
4037        query: SearchQuery,
4038        cx: &mut ModelContext<Self>,
4039    ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
4040        if self.is_local() {
4041            let snapshots = self
4042                .visible_worktrees(cx)
4043                .filter_map(|tree| {
4044                    let tree = tree.read(cx).as_local()?;
4045                    Some(tree.snapshot())
4046                })
4047                .collect::<Vec<_>>();
4048
4049            let background = cx.background().clone();
4050            let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
4051            if path_count == 0 {
4052                return Task::ready(Ok(Default::default()));
4053            }
4054            let workers = background.num_cpus().min(path_count);
4055            let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
4056            cx.background()
4057                .spawn({
4058                    let fs = self.fs.clone();
4059                    let background = cx.background().clone();
4060                    let query = query.clone();
4061                    async move {
4062                        let fs = &fs;
4063                        let query = &query;
4064                        let matching_paths_tx = &matching_paths_tx;
4065                        let paths_per_worker = (path_count + workers - 1) / workers;
4066                        let snapshots = &snapshots;
4067                        background
4068                            .scoped(|scope| {
4069                                for worker_ix in 0..workers {
4070                                    let worker_start_ix = worker_ix * paths_per_worker;
4071                                    let worker_end_ix = worker_start_ix + paths_per_worker;
4072                                    scope.spawn(async move {
4073                                        let mut snapshot_start_ix = 0;
4074                                        let mut abs_path = PathBuf::new();
4075                                        for snapshot in snapshots {
4076                                            let snapshot_end_ix =
4077                                                snapshot_start_ix + snapshot.visible_file_count();
4078                                            if worker_end_ix <= snapshot_start_ix {
4079                                                break;
4080                                            } else if worker_start_ix > snapshot_end_ix {
4081                                                snapshot_start_ix = snapshot_end_ix;
4082                                                continue;
4083                                            } else {
4084                                                let start_in_snapshot = worker_start_ix
4085                                                    .saturating_sub(snapshot_start_ix);
4086                                                let end_in_snapshot =
4087                                                    cmp::min(worker_end_ix, snapshot_end_ix)
4088                                                        - snapshot_start_ix;
4089
4090                                                for entry in snapshot
4091                                                    .files(false, start_in_snapshot)
4092                                                    .take(end_in_snapshot - start_in_snapshot)
4093                                                {
4094                                                    if matching_paths_tx.is_closed() {
4095                                                        break;
4096                                                    }
4097
4098                                                    abs_path.clear();
4099                                                    abs_path.push(&snapshot.abs_path());
4100                                                    abs_path.push(&entry.path);
4101                                                    let matches = if let Some(file) =
4102                                                        fs.open_sync(&abs_path).await.log_err()
4103                                                    {
4104                                                        query.detect(file).unwrap_or(false)
4105                                                    } else {
4106                                                        false
4107                                                    };
4108
4109                                                    if matches {
4110                                                        let project_path =
4111                                                            (snapshot.id(), entry.path.clone());
4112                                                        if matching_paths_tx
4113                                                            .send(project_path)
4114                                                            .await
4115                                                            .is_err()
4116                                                        {
4117                                                            break;
4118                                                        }
4119                                                    }
4120                                                }
4121
4122                                                snapshot_start_ix = snapshot_end_ix;
4123                                            }
4124                                        }
4125                                    });
4126                                }
4127                            })
4128                            .await;
4129                    }
4130                })
4131                .detach();
4132
4133            let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
4134            let open_buffers = self
4135                .opened_buffers
4136                .values()
4137                .filter_map(|b| b.upgrade(cx))
4138                .collect::<HashSet<_>>();
4139            cx.spawn(|this, cx| async move {
4140                for buffer in &open_buffers {
4141                    let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4142                    buffers_tx.send((buffer.clone(), snapshot)).await?;
4143                }
4144
4145                let open_buffers = Rc::new(RefCell::new(open_buffers));
4146                while let Some(project_path) = matching_paths_rx.next().await {
4147                    if buffers_tx.is_closed() {
4148                        break;
4149                    }
4150
4151                    let this = this.clone();
4152                    let open_buffers = open_buffers.clone();
4153                    let buffers_tx = buffers_tx.clone();
4154                    cx.spawn(|mut cx| async move {
4155                        if let Some(buffer) = this
4156                            .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
4157                            .await
4158                            .log_err()
4159                        {
4160                            if open_buffers.borrow_mut().insert(buffer.clone()) {
4161                                let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4162                                buffers_tx.send((buffer, snapshot)).await?;
4163                            }
4164                        }
4165
4166                        Ok::<_, anyhow::Error>(())
4167                    })
4168                    .detach();
4169                }
4170
4171                Ok::<_, anyhow::Error>(())
4172            })
4173            .detach_and_log_err(cx);
4174
4175            let background = cx.background().clone();
4176            cx.background().spawn(async move {
4177                let query = &query;
4178                let mut matched_buffers = Vec::new();
4179                for _ in 0..workers {
4180                    matched_buffers.push(HashMap::default());
4181                }
4182                background
4183                    .scoped(|scope| {
4184                        for worker_matched_buffers in matched_buffers.iter_mut() {
4185                            let mut buffers_rx = buffers_rx.clone();
4186                            scope.spawn(async move {
4187                                while let Some((buffer, snapshot)) = buffers_rx.next().await {
4188                                    let buffer_matches = query
4189                                        .search(snapshot.as_rope())
4190                                        .await
4191                                        .iter()
4192                                        .map(|range| {
4193                                            snapshot.anchor_before(range.start)
4194                                                ..snapshot.anchor_after(range.end)
4195                                        })
4196                                        .collect::<Vec<_>>();
4197                                    if !buffer_matches.is_empty() {
4198                                        worker_matched_buffers
4199                                            .insert(buffer.clone(), buffer_matches);
4200                                    }
4201                                }
4202                            });
4203                        }
4204                    })
4205                    .await;
4206                Ok(matched_buffers.into_iter().flatten().collect())
4207            })
4208        } else if let Some(project_id) = self.remote_id() {
4209            let request = self.client.request(query.to_proto(project_id));
4210            cx.spawn(|this, mut cx| async move {
4211                let response = request.await?;
4212                let mut result = HashMap::default();
4213                for location in response.locations {
4214                    let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
4215                    let target_buffer = this
4216                        .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4217                        .await?;
4218                    let start = location
4219                        .start
4220                        .and_then(deserialize_anchor)
4221                        .ok_or_else(|| anyhow!("missing target start"))?;
4222                    let end = location
4223                        .end
4224                        .and_then(deserialize_anchor)
4225                        .ok_or_else(|| anyhow!("missing target end"))?;
4226                    result
4227                        .entry(target_buffer)
4228                        .or_insert(Vec::new())
4229                        .push(start..end)
4230                }
4231                Ok(result)
4232            })
4233        } else {
4234            Task::ready(Ok(Default::default()))
4235        }
4236    }
4237
4238    fn request_lsp<R: LspCommand>(
4239        &self,
4240        buffer_handle: ModelHandle<Buffer>,
4241        request: R,
4242        cx: &mut ModelContext<Self>,
4243    ) -> Task<Result<R::Response>>
4244    where
4245        <R::LspRequest as lsp::request::Request>::Result: Send,
4246    {
4247        let buffer = buffer_handle.read(cx);
4248        if self.is_local() {
4249            let file = File::from_dyn(buffer.file()).and_then(File::as_local);
4250            if let Some((file, language_server)) = file.zip(
4251                self.language_server_for_buffer(buffer, cx)
4252                    .map(|(_, server)| server.clone()),
4253            ) {
4254                let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
4255                return cx.spawn(|this, cx| async move {
4256                    if !request.check_capabilities(&language_server.capabilities()) {
4257                        return Ok(Default::default());
4258                    }
4259
4260                    let response = language_server
4261                        .request::<R::LspRequest>(lsp_params)
4262                        .await
4263                        .context("lsp request failed")?;
4264                    request
4265                        .response_from_lsp(response, this, buffer_handle, cx)
4266                        .await
4267                });
4268            }
4269        } else if let Some(project_id) = self.remote_id() {
4270            let rpc = self.client.clone();
4271            let message = request.to_proto(project_id, buffer);
4272            return cx.spawn(|this, cx| async move {
4273                let response = rpc.request(message).await?;
4274                request
4275                    .response_from_proto(response, this, buffer_handle, cx)
4276                    .await
4277            });
4278        }
4279        Task::ready(Ok(Default::default()))
4280    }
4281
4282    pub fn find_or_create_local_worktree(
4283        &mut self,
4284        abs_path: impl AsRef<Path>,
4285        visible: bool,
4286        cx: &mut ModelContext<Self>,
4287    ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
4288        let abs_path = abs_path.as_ref();
4289        if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
4290            Task::ready(Ok((tree.clone(), relative_path.into())))
4291        } else {
4292            let worktree = self.create_local_worktree(abs_path, visible, cx);
4293            cx.foreground()
4294                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
4295        }
4296    }
4297
4298    pub fn find_local_worktree(
4299        &self,
4300        abs_path: &Path,
4301        cx: &AppContext,
4302    ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
4303        for tree in &self.worktrees {
4304            if let Some(tree) = tree.upgrade(cx) {
4305                if let Some(relative_path) = tree
4306                    .read(cx)
4307                    .as_local()
4308                    .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
4309                {
4310                    return Some((tree.clone(), relative_path.into()));
4311                }
4312            }
4313        }
4314        None
4315    }
4316
4317    pub fn is_shared(&self) -> bool {
4318        match &self.client_state {
4319            ProjectClientState::Local { is_shared, .. } => *is_shared,
4320            ProjectClientState::Remote { .. } => false,
4321        }
4322    }
4323
4324    fn create_local_worktree(
4325        &mut self,
4326        abs_path: impl AsRef<Path>,
4327        visible: bool,
4328        cx: &mut ModelContext<Self>,
4329    ) -> Task<Result<ModelHandle<Worktree>>> {
4330        let fs = self.fs.clone();
4331        let client = self.client.clone();
4332        let next_entry_id = self.next_entry_id.clone();
4333        let path: Arc<Path> = abs_path.as_ref().into();
4334        let task = self
4335            .loading_local_worktrees
4336            .entry(path.clone())
4337            .or_insert_with(|| {
4338                cx.spawn(|project, mut cx| {
4339                    async move {
4340                        let worktree = Worktree::local(
4341                            client.clone(),
4342                            path.clone(),
4343                            visible,
4344                            fs,
4345                            next_entry_id,
4346                            &mut cx,
4347                        )
4348                        .await;
4349                        project.update(&mut cx, |project, _| {
4350                            project.loading_local_worktrees.remove(&path);
4351                        });
4352                        let worktree = worktree?;
4353
4354                        let project_id = project.update(&mut cx, |project, cx| {
4355                            project.add_worktree(&worktree, cx);
4356                            project.shared_remote_id()
4357                        });
4358
4359                        if let Some(project_id) = project_id {
4360                            worktree
4361                                .update(&mut cx, |worktree, cx| {
4362                                    worktree.as_local_mut().unwrap().share(project_id, cx)
4363                                })
4364                                .await
4365                                .log_err();
4366                        }
4367
4368                        Ok(worktree)
4369                    }
4370                    .map_err(|err| Arc::new(err))
4371                })
4372                .shared()
4373            })
4374            .clone();
4375        cx.foreground().spawn(async move {
4376            match task.await {
4377                Ok(worktree) => Ok(worktree),
4378                Err(err) => Err(anyhow!("{}", err)),
4379            }
4380        })
4381    }
4382
4383    pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
4384        self.worktrees.retain(|worktree| {
4385            if let Some(worktree) = worktree.upgrade(cx) {
4386                let id = worktree.read(cx).id();
4387                if id == id_to_remove {
4388                    cx.emit(Event::WorktreeRemoved(id));
4389                    false
4390                } else {
4391                    true
4392                }
4393            } else {
4394                false
4395            }
4396        });
4397        self.metadata_changed(true, cx);
4398        cx.notify();
4399    }
4400
4401    fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
4402        cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
4403        if worktree.read(cx).is_local() {
4404            cx.subscribe(&worktree, |this, worktree, _, cx| {
4405                this.update_local_worktree_buffers(worktree, cx);
4406            })
4407            .detach();
4408        }
4409
4410        let push_strong_handle = {
4411            let worktree = worktree.read(cx);
4412            self.is_shared() || worktree.is_visible() || worktree.is_remote()
4413        };
4414        if push_strong_handle {
4415            self.worktrees
4416                .push(WorktreeHandle::Strong(worktree.clone()));
4417        } else {
4418            self.worktrees
4419                .push(WorktreeHandle::Weak(worktree.downgrade()));
4420        }
4421
4422        self.metadata_changed(true, cx);
4423        cx.observe_release(&worktree, |this, worktree, cx| {
4424            this.remove_worktree(worktree.id(), cx);
4425            cx.notify();
4426        })
4427        .detach();
4428
4429        cx.emit(Event::WorktreeAdded);
4430        cx.notify();
4431    }
4432
4433    fn update_local_worktree_buffers(
4434        &mut self,
4435        worktree_handle: ModelHandle<Worktree>,
4436        cx: &mut ModelContext<Self>,
4437    ) {
4438        let snapshot = worktree_handle.read(cx).snapshot();
4439        let mut buffers_to_delete = Vec::new();
4440        let mut renamed_buffers = Vec::new();
4441        for (buffer_id, buffer) in &self.opened_buffers {
4442            if let Some(buffer) = buffer.upgrade(cx) {
4443                buffer.update(cx, |buffer, cx| {
4444                    if let Some(old_file) = File::from_dyn(buffer.file()) {
4445                        if old_file.worktree != worktree_handle {
4446                            return;
4447                        }
4448
4449                        let new_file = if let Some(entry) = old_file
4450                            .entry_id
4451                            .and_then(|entry_id| snapshot.entry_for_id(entry_id))
4452                        {
4453                            File {
4454                                is_local: true,
4455                                entry_id: Some(entry.id),
4456                                mtime: entry.mtime,
4457                                path: entry.path.clone(),
4458                                worktree: worktree_handle.clone(),
4459                            }
4460                        } else if let Some(entry) =
4461                            snapshot.entry_for_path(old_file.path().as_ref())
4462                        {
4463                            File {
4464                                is_local: true,
4465                                entry_id: Some(entry.id),
4466                                mtime: entry.mtime,
4467                                path: entry.path.clone(),
4468                                worktree: worktree_handle.clone(),
4469                            }
4470                        } else {
4471                            File {
4472                                is_local: true,
4473                                entry_id: None,
4474                                path: old_file.path().clone(),
4475                                mtime: old_file.mtime(),
4476                                worktree: worktree_handle.clone(),
4477                            }
4478                        };
4479
4480                        let old_path = old_file.abs_path(cx);
4481                        if new_file.abs_path(cx) != old_path {
4482                            renamed_buffers.push((cx.handle(), old_path));
4483                        }
4484
4485                        if let Some(project_id) = self.shared_remote_id() {
4486                            self.client
4487                                .send(proto::UpdateBufferFile {
4488                                    project_id,
4489                                    buffer_id: *buffer_id as u64,
4490                                    file: Some(new_file.to_proto()),
4491                                })
4492                                .log_err();
4493                        }
4494                        buffer.file_updated(Arc::new(new_file), cx).detach();
4495                    }
4496                });
4497            } else {
4498                buffers_to_delete.push(*buffer_id);
4499            }
4500        }
4501
4502        for buffer_id in buffers_to_delete {
4503            self.opened_buffers.remove(&buffer_id);
4504        }
4505
4506        for (buffer, old_path) in renamed_buffers {
4507            self.unregister_buffer_from_language_server(&buffer, old_path, cx);
4508            self.assign_language_to_buffer(&buffer, cx);
4509            self.register_buffer_with_language_server(&buffer, cx);
4510        }
4511    }
4512
4513    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
4514        let new_active_entry = entry.and_then(|project_path| {
4515            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
4516            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
4517            Some(entry.id)
4518        });
4519        if new_active_entry != self.active_entry {
4520            self.active_entry = new_active_entry;
4521            cx.emit(Event::ActiveEntryChanged(new_active_entry));
4522        }
4523    }
4524
4525    pub fn language_servers_running_disk_based_diagnostics<'a>(
4526        &'a self,
4527    ) -> impl 'a + Iterator<Item = usize> {
4528        self.language_server_statuses
4529            .iter()
4530            .filter_map(|(id, status)| {
4531                if status.has_pending_diagnostic_updates {
4532                    Some(*id)
4533                } else {
4534                    None
4535                }
4536            })
4537    }
4538
4539    pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
4540        let mut summary = DiagnosticSummary::default();
4541        for (_, path_summary) in self.diagnostic_summaries(cx) {
4542            summary.error_count += path_summary.error_count;
4543            summary.warning_count += path_summary.warning_count;
4544        }
4545        summary
4546    }
4547
4548    pub fn diagnostic_summaries<'a>(
4549        &'a self,
4550        cx: &'a AppContext,
4551    ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
4552        self.visible_worktrees(cx).flat_map(move |worktree| {
4553            let worktree = worktree.read(cx);
4554            let worktree_id = worktree.id();
4555            worktree
4556                .diagnostic_summaries()
4557                .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
4558        })
4559    }
4560
4561    pub fn disk_based_diagnostics_started(
4562        &mut self,
4563        language_server_id: usize,
4564        cx: &mut ModelContext<Self>,
4565    ) {
4566        cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
4567    }
4568
4569    pub fn disk_based_diagnostics_finished(
4570        &mut self,
4571        language_server_id: usize,
4572        cx: &mut ModelContext<Self>,
4573    ) {
4574        cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
4575    }
4576
4577    pub fn active_entry(&self) -> Option<ProjectEntryId> {
4578        self.active_entry
4579    }
4580
4581    pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
4582        self.worktree_for_id(path.worktree_id, cx)?
4583            .read(cx)
4584            .entry_for_path(&path.path)
4585            .map(|entry| entry.id)
4586    }
4587
4588    pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
4589        let worktree = self.worktree_for_entry(entry_id, cx)?;
4590        let worktree = worktree.read(cx);
4591        let worktree_id = worktree.id();
4592        let path = worktree.entry_for_id(entry_id)?.path.clone();
4593        Some(ProjectPath { worktree_id, path })
4594    }
4595
4596    // RPC message handlers
4597
4598    async fn handle_request_join_project(
4599        this: ModelHandle<Self>,
4600        message: TypedEnvelope<proto::RequestJoinProject>,
4601        _: Arc<Client>,
4602        mut cx: AsyncAppContext,
4603    ) -> Result<()> {
4604        let user_id = message.payload.requester_id;
4605        if this.read_with(&cx, |project, _| {
4606            project.collaborators.values().any(|c| c.user.id == user_id)
4607        }) {
4608            this.update(&mut cx, |this, cx| {
4609                this.respond_to_join_request(user_id, true, cx)
4610            });
4611        } else {
4612            let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4613            let user = user_store
4614                .update(&mut cx, |store, cx| store.fetch_user(user_id, cx))
4615                .await?;
4616            this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user)));
4617        }
4618        Ok(())
4619    }
4620
4621    async fn handle_unregister_project(
4622        this: ModelHandle<Self>,
4623        _: TypedEnvelope<proto::UnregisterProject>,
4624        _: Arc<Client>,
4625        mut cx: AsyncAppContext,
4626    ) -> Result<()> {
4627        this.update(&mut cx, |this, cx| this.removed_from_project(cx));
4628        Ok(())
4629    }
4630
4631    async fn handle_project_unshared(
4632        this: ModelHandle<Self>,
4633        _: TypedEnvelope<proto::ProjectUnshared>,
4634        _: Arc<Client>,
4635        mut cx: AsyncAppContext,
4636    ) -> Result<()> {
4637        this.update(&mut cx, |this, cx| this.unshared(cx));
4638        Ok(())
4639    }
4640
4641    async fn handle_add_collaborator(
4642        this: ModelHandle<Self>,
4643        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4644        _: Arc<Client>,
4645        mut cx: AsyncAppContext,
4646    ) -> Result<()> {
4647        let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4648        let collaborator = envelope
4649            .payload
4650            .collaborator
4651            .take()
4652            .ok_or_else(|| anyhow!("empty collaborator"))?;
4653
4654        let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
4655        this.update(&mut cx, |this, cx| {
4656            this.collaborators
4657                .insert(collaborator.peer_id, collaborator);
4658            cx.notify();
4659        });
4660
4661        Ok(())
4662    }
4663
4664    async fn handle_remove_collaborator(
4665        this: ModelHandle<Self>,
4666        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4667        _: Arc<Client>,
4668        mut cx: AsyncAppContext,
4669    ) -> Result<()> {
4670        this.update(&mut cx, |this, cx| {
4671            let peer_id = PeerId(envelope.payload.peer_id);
4672            let replica_id = this
4673                .collaborators
4674                .remove(&peer_id)
4675                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4676                .replica_id;
4677            for (_, buffer) in &this.opened_buffers {
4678                if let Some(buffer) = buffer.upgrade(cx) {
4679                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4680                }
4681            }
4682
4683            cx.emit(Event::CollaboratorLeft(peer_id));
4684            cx.notify();
4685            Ok(())
4686        })
4687    }
4688
4689    async fn handle_join_project_request_cancelled(
4690        this: ModelHandle<Self>,
4691        envelope: TypedEnvelope<proto::JoinProjectRequestCancelled>,
4692        _: Arc<Client>,
4693        mut cx: AsyncAppContext,
4694    ) -> Result<()> {
4695        let user = this
4696            .update(&mut cx, |this, cx| {
4697                this.user_store.update(cx, |user_store, cx| {
4698                    user_store.fetch_user(envelope.payload.requester_id, cx)
4699                })
4700            })
4701            .await?;
4702
4703        this.update(&mut cx, |_, cx| {
4704            cx.emit(Event::ContactCancelledJoinRequest(user));
4705        });
4706
4707        Ok(())
4708    }
4709
4710    async fn handle_update_project(
4711        this: ModelHandle<Self>,
4712        envelope: TypedEnvelope<proto::UpdateProject>,
4713        client: Arc<Client>,
4714        mut cx: AsyncAppContext,
4715    ) -> Result<()> {
4716        this.update(&mut cx, |this, cx| {
4717            let replica_id = this.replica_id();
4718            let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
4719
4720            let mut old_worktrees_by_id = this
4721                .worktrees
4722                .drain(..)
4723                .filter_map(|worktree| {
4724                    let worktree = worktree.upgrade(cx)?;
4725                    Some((worktree.read(cx).id(), worktree))
4726                })
4727                .collect::<HashMap<_, _>>();
4728
4729            for worktree in envelope.payload.worktrees {
4730                if let Some(old_worktree) =
4731                    old_worktrees_by_id.remove(&WorktreeId::from_proto(worktree.id))
4732                {
4733                    this.worktrees.push(WorktreeHandle::Strong(old_worktree));
4734                } else {
4735                    let worktree =
4736                        Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx);
4737                    this.add_worktree(&worktree, cx);
4738                }
4739            }
4740
4741            this.metadata_changed(true, cx);
4742            for (id, _) in old_worktrees_by_id {
4743                cx.emit(Event::WorktreeRemoved(id));
4744            }
4745
4746            Ok(())
4747        })
4748    }
4749
4750    async fn handle_update_worktree(
4751        this: ModelHandle<Self>,
4752        envelope: TypedEnvelope<proto::UpdateWorktree>,
4753        _: Arc<Client>,
4754        mut cx: AsyncAppContext,
4755    ) -> Result<()> {
4756        this.update(&mut cx, |this, cx| {
4757            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4758            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4759                worktree.update(cx, |worktree, _| {
4760                    let worktree = worktree.as_remote_mut().unwrap();
4761                    worktree.update_from_remote(envelope.payload);
4762                });
4763            }
4764            Ok(())
4765        })
4766    }
4767
4768    async fn handle_create_project_entry(
4769        this: ModelHandle<Self>,
4770        envelope: TypedEnvelope<proto::CreateProjectEntry>,
4771        _: Arc<Client>,
4772        mut cx: AsyncAppContext,
4773    ) -> Result<proto::ProjectEntryResponse> {
4774        let worktree = this.update(&mut cx, |this, cx| {
4775            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4776            this.worktree_for_id(worktree_id, cx)
4777                .ok_or_else(|| anyhow!("worktree not found"))
4778        })?;
4779        let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4780        let entry = worktree
4781            .update(&mut cx, |worktree, cx| {
4782                let worktree = worktree.as_local_mut().unwrap();
4783                let path = PathBuf::from(OsString::from_vec(envelope.payload.path));
4784                worktree.create_entry(path, envelope.payload.is_directory, cx)
4785            })
4786            .await?;
4787        Ok(proto::ProjectEntryResponse {
4788            entry: Some((&entry).into()),
4789            worktree_scan_id: worktree_scan_id as u64,
4790        })
4791    }
4792
4793    async fn handle_rename_project_entry(
4794        this: ModelHandle<Self>,
4795        envelope: TypedEnvelope<proto::RenameProjectEntry>,
4796        _: Arc<Client>,
4797        mut cx: AsyncAppContext,
4798    ) -> Result<proto::ProjectEntryResponse> {
4799        let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4800        let worktree = this.read_with(&cx, |this, cx| {
4801            this.worktree_for_entry(entry_id, cx)
4802                .ok_or_else(|| anyhow!("worktree not found"))
4803        })?;
4804        let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4805        let entry = worktree
4806            .update(&mut cx, |worktree, cx| {
4807                let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4808                worktree
4809                    .as_local_mut()
4810                    .unwrap()
4811                    .rename_entry(entry_id, new_path, cx)
4812                    .ok_or_else(|| anyhow!("invalid entry"))
4813            })?
4814            .await?;
4815        Ok(proto::ProjectEntryResponse {
4816            entry: Some((&entry).into()),
4817            worktree_scan_id: worktree_scan_id as u64,
4818        })
4819    }
4820
4821    async fn handle_copy_project_entry(
4822        this: ModelHandle<Self>,
4823        envelope: TypedEnvelope<proto::CopyProjectEntry>,
4824        _: Arc<Client>,
4825        mut cx: AsyncAppContext,
4826    ) -> Result<proto::ProjectEntryResponse> {
4827        let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4828        let worktree = this.read_with(&cx, |this, cx| {
4829            this.worktree_for_entry(entry_id, cx)
4830                .ok_or_else(|| anyhow!("worktree not found"))
4831        })?;
4832        let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4833        let entry = worktree
4834            .update(&mut cx, |worktree, cx| {
4835                let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4836                worktree
4837                    .as_local_mut()
4838                    .unwrap()
4839                    .copy_entry(entry_id, new_path, cx)
4840                    .ok_or_else(|| anyhow!("invalid entry"))
4841            })?
4842            .await?;
4843        Ok(proto::ProjectEntryResponse {
4844            entry: Some((&entry).into()),
4845            worktree_scan_id: worktree_scan_id as u64,
4846        })
4847    }
4848
4849    async fn handle_delete_project_entry(
4850        this: ModelHandle<Self>,
4851        envelope: TypedEnvelope<proto::DeleteProjectEntry>,
4852        _: Arc<Client>,
4853        mut cx: AsyncAppContext,
4854    ) -> Result<proto::ProjectEntryResponse> {
4855        let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4856        let worktree = this.read_with(&cx, |this, cx| {
4857            this.worktree_for_entry(entry_id, cx)
4858                .ok_or_else(|| anyhow!("worktree not found"))
4859        })?;
4860        let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4861        worktree
4862            .update(&mut cx, |worktree, cx| {
4863                worktree
4864                    .as_local_mut()
4865                    .unwrap()
4866                    .delete_entry(entry_id, cx)
4867                    .ok_or_else(|| anyhow!("invalid entry"))
4868            })?
4869            .await?;
4870        Ok(proto::ProjectEntryResponse {
4871            entry: None,
4872            worktree_scan_id: worktree_scan_id as u64,
4873        })
4874    }
4875
4876    async fn handle_update_diagnostic_summary(
4877        this: ModelHandle<Self>,
4878        envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
4879        _: Arc<Client>,
4880        mut cx: AsyncAppContext,
4881    ) -> Result<()> {
4882        this.update(&mut cx, |this, cx| {
4883            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4884            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4885                if let Some(summary) = envelope.payload.summary {
4886                    let project_path = ProjectPath {
4887                        worktree_id,
4888                        path: Path::new(&summary.path).into(),
4889                    };
4890                    worktree.update(cx, |worktree, _| {
4891                        worktree
4892                            .as_remote_mut()
4893                            .unwrap()
4894                            .update_diagnostic_summary(project_path.path.clone(), &summary);
4895                    });
4896                    cx.emit(Event::DiagnosticsUpdated {
4897                        language_server_id: summary.language_server_id as usize,
4898                        path: project_path,
4899                    });
4900                }
4901            }
4902            Ok(())
4903        })
4904    }
4905
4906    async fn handle_start_language_server(
4907        this: ModelHandle<Self>,
4908        envelope: TypedEnvelope<proto::StartLanguageServer>,
4909        _: Arc<Client>,
4910        mut cx: AsyncAppContext,
4911    ) -> Result<()> {
4912        let server = envelope
4913            .payload
4914            .server
4915            .ok_or_else(|| anyhow!("invalid server"))?;
4916        this.update(&mut cx, |this, cx| {
4917            this.language_server_statuses.insert(
4918                server.id as usize,
4919                LanguageServerStatus {
4920                    name: server.name,
4921                    pending_work: Default::default(),
4922                    has_pending_diagnostic_updates: false,
4923                    progress_tokens: Default::default(),
4924                },
4925            );
4926            cx.notify();
4927        });
4928        Ok(())
4929    }
4930
4931    async fn handle_update_language_server(
4932        this: ModelHandle<Self>,
4933        envelope: TypedEnvelope<proto::UpdateLanguageServer>,
4934        _: Arc<Client>,
4935        mut cx: AsyncAppContext,
4936    ) -> Result<()> {
4937        let language_server_id = envelope.payload.language_server_id as usize;
4938        match envelope
4939            .payload
4940            .variant
4941            .ok_or_else(|| anyhow!("invalid variant"))?
4942        {
4943            proto::update_language_server::Variant::WorkStart(payload) => {
4944                this.update(&mut cx, |this, cx| {
4945                    this.on_lsp_work_start(
4946                        language_server_id,
4947                        payload.token,
4948                        LanguageServerProgress {
4949                            message: payload.message,
4950                            percentage: payload.percentage.map(|p| p as usize),
4951                            last_update_at: Instant::now(),
4952                        },
4953                        cx,
4954                    );
4955                })
4956            }
4957            proto::update_language_server::Variant::WorkProgress(payload) => {
4958                this.update(&mut cx, |this, cx| {
4959                    this.on_lsp_work_progress(
4960                        language_server_id,
4961                        payload.token,
4962                        LanguageServerProgress {
4963                            message: payload.message,
4964                            percentage: payload.percentage.map(|p| p as usize),
4965                            last_update_at: Instant::now(),
4966                        },
4967                        cx,
4968                    );
4969                })
4970            }
4971            proto::update_language_server::Variant::WorkEnd(payload) => {
4972                this.update(&mut cx, |this, cx| {
4973                    this.on_lsp_work_end(language_server_id, payload.token, cx);
4974                })
4975            }
4976            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
4977                this.update(&mut cx, |this, cx| {
4978                    this.disk_based_diagnostics_started(language_server_id, cx);
4979                })
4980            }
4981            proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
4982                this.update(&mut cx, |this, cx| {
4983                    this.disk_based_diagnostics_finished(language_server_id, cx)
4984                });
4985            }
4986        }
4987
4988        Ok(())
4989    }
4990
4991    async fn handle_update_buffer(
4992        this: ModelHandle<Self>,
4993        envelope: TypedEnvelope<proto::UpdateBuffer>,
4994        _: Arc<Client>,
4995        mut cx: AsyncAppContext,
4996    ) -> Result<()> {
4997        this.update(&mut cx, |this, cx| {
4998            let payload = envelope.payload.clone();
4999            let buffer_id = payload.buffer_id;
5000            let ops = payload
5001                .operations
5002                .into_iter()
5003                .map(|op| language::proto::deserialize_operation(op))
5004                .collect::<Result<Vec<_>, _>>()?;
5005            let is_remote = this.is_remote();
5006            match this.opened_buffers.entry(buffer_id) {
5007                hash_map::Entry::Occupied(mut e) => match e.get_mut() {
5008                    OpenBuffer::Strong(buffer) => {
5009                        buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
5010                    }
5011                    OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
5012                    OpenBuffer::Weak(_) => {}
5013                },
5014                hash_map::Entry::Vacant(e) => {
5015                    assert!(
5016                        is_remote,
5017                        "received buffer update from {:?}",
5018                        envelope.original_sender_id
5019                    );
5020                    e.insert(OpenBuffer::Loading(ops));
5021                }
5022            }
5023            Ok(())
5024        })
5025    }
5026
5027    async fn handle_update_buffer_file(
5028        this: ModelHandle<Self>,
5029        envelope: TypedEnvelope<proto::UpdateBufferFile>,
5030        _: Arc<Client>,
5031        mut cx: AsyncAppContext,
5032    ) -> Result<()> {
5033        this.update(&mut cx, |this, cx| {
5034            let payload = envelope.payload.clone();
5035            let buffer_id = payload.buffer_id;
5036            let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
5037            let worktree = this
5038                .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
5039                .ok_or_else(|| anyhow!("no such worktree"))?;
5040            let file = File::from_proto(file, worktree.clone(), cx)?;
5041            let buffer = this
5042                .opened_buffers
5043                .get_mut(&buffer_id)
5044                .and_then(|b| b.upgrade(cx))
5045                .ok_or_else(|| anyhow!("no such buffer"))?;
5046            buffer.update(cx, |buffer, cx| {
5047                buffer.file_updated(Arc::new(file), cx).detach();
5048            });
5049            Ok(())
5050        })
5051    }
5052
5053    async fn handle_save_buffer(
5054        this: ModelHandle<Self>,
5055        envelope: TypedEnvelope<proto::SaveBuffer>,
5056        _: Arc<Client>,
5057        mut cx: AsyncAppContext,
5058    ) -> Result<proto::BufferSaved> {
5059        let buffer_id = envelope.payload.buffer_id;
5060        let requested_version = deserialize_version(envelope.payload.version);
5061
5062        let (project_id, buffer) = this.update(&mut cx, |this, cx| {
5063            let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
5064            let buffer = this
5065                .opened_buffers
5066                .get(&buffer_id)
5067                .and_then(|buffer| buffer.upgrade(cx))
5068                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
5069            Ok::<_, anyhow::Error>((project_id, buffer))
5070        })?;
5071        buffer
5072            .update(&mut cx, |buffer, _| {
5073                buffer.wait_for_version(requested_version)
5074            })
5075            .await;
5076
5077        let (saved_version, fingerprint, mtime) =
5078            buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
5079        Ok(proto::BufferSaved {
5080            project_id,
5081            buffer_id,
5082            version: serialize_version(&saved_version),
5083            mtime: Some(mtime.into()),
5084            fingerprint,
5085        })
5086    }
5087
5088    async fn handle_reload_buffers(
5089        this: ModelHandle<Self>,
5090        envelope: TypedEnvelope<proto::ReloadBuffers>,
5091        _: Arc<Client>,
5092        mut cx: AsyncAppContext,
5093    ) -> Result<proto::ReloadBuffersResponse> {
5094        let sender_id = envelope.original_sender_id()?;
5095        let reload = this.update(&mut cx, |this, cx| {
5096            let mut buffers = HashSet::default();
5097            for buffer_id in &envelope.payload.buffer_ids {
5098                buffers.insert(
5099                    this.opened_buffers
5100                        .get(buffer_id)
5101                        .and_then(|buffer| buffer.upgrade(cx))
5102                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5103                );
5104            }
5105            Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
5106        })?;
5107
5108        let project_transaction = reload.await?;
5109        let project_transaction = this.update(&mut cx, |this, cx| {
5110            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5111        });
5112        Ok(proto::ReloadBuffersResponse {
5113            transaction: Some(project_transaction),
5114        })
5115    }
5116
5117    async fn handle_format_buffers(
5118        this: ModelHandle<Self>,
5119        envelope: TypedEnvelope<proto::FormatBuffers>,
5120        _: Arc<Client>,
5121        mut cx: AsyncAppContext,
5122    ) -> Result<proto::FormatBuffersResponse> {
5123        let sender_id = envelope.original_sender_id()?;
5124        let format = this.update(&mut cx, |this, cx| {
5125            let mut buffers = HashSet::default();
5126            for buffer_id in &envelope.payload.buffer_ids {
5127                buffers.insert(
5128                    this.opened_buffers
5129                        .get(buffer_id)
5130                        .and_then(|buffer| buffer.upgrade(cx))
5131                        .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5132                );
5133            }
5134            Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
5135        })?;
5136
5137        let project_transaction = format.await?;
5138        let project_transaction = this.update(&mut cx, |this, cx| {
5139            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5140        });
5141        Ok(proto::FormatBuffersResponse {
5142            transaction: Some(project_transaction),
5143        })
5144    }
5145
5146    async fn handle_get_completions(
5147        this: ModelHandle<Self>,
5148        envelope: TypedEnvelope<proto::GetCompletions>,
5149        _: Arc<Client>,
5150        mut cx: AsyncAppContext,
5151    ) -> Result<proto::GetCompletionsResponse> {
5152        let position = envelope
5153            .payload
5154            .position
5155            .and_then(language::proto::deserialize_anchor)
5156            .ok_or_else(|| anyhow!("invalid position"))?;
5157        let version = deserialize_version(envelope.payload.version);
5158        let buffer = this.read_with(&cx, |this, cx| {
5159            this.opened_buffers
5160                .get(&envelope.payload.buffer_id)
5161                .and_then(|buffer| buffer.upgrade(cx))
5162                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5163        })?;
5164        buffer
5165            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
5166            .await;
5167        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5168        let completions = this
5169            .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
5170            .await?;
5171
5172        Ok(proto::GetCompletionsResponse {
5173            completions: completions
5174                .iter()
5175                .map(language::proto::serialize_completion)
5176                .collect(),
5177            version: serialize_version(&version),
5178        })
5179    }
5180
5181    async fn handle_apply_additional_edits_for_completion(
5182        this: ModelHandle<Self>,
5183        envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
5184        _: Arc<Client>,
5185        mut cx: AsyncAppContext,
5186    ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
5187        let apply_additional_edits = this.update(&mut cx, |this, cx| {
5188            let buffer = this
5189                .opened_buffers
5190                .get(&envelope.payload.buffer_id)
5191                .and_then(|buffer| buffer.upgrade(cx))
5192                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5193            let language = buffer.read(cx).language();
5194            let completion = language::proto::deserialize_completion(
5195                envelope
5196                    .payload
5197                    .completion
5198                    .ok_or_else(|| anyhow!("invalid completion"))?,
5199                language,
5200            )?;
5201            Ok::<_, anyhow::Error>(
5202                this.apply_additional_edits_for_completion(buffer, completion, false, cx),
5203            )
5204        })?;
5205
5206        Ok(proto::ApplyCompletionAdditionalEditsResponse {
5207            transaction: apply_additional_edits
5208                .await?
5209                .as_ref()
5210                .map(language::proto::serialize_transaction),
5211        })
5212    }
5213
5214    async fn handle_get_code_actions(
5215        this: ModelHandle<Self>,
5216        envelope: TypedEnvelope<proto::GetCodeActions>,
5217        _: Arc<Client>,
5218        mut cx: AsyncAppContext,
5219    ) -> Result<proto::GetCodeActionsResponse> {
5220        let start = envelope
5221            .payload
5222            .start
5223            .and_then(language::proto::deserialize_anchor)
5224            .ok_or_else(|| anyhow!("invalid start"))?;
5225        let end = envelope
5226            .payload
5227            .end
5228            .and_then(language::proto::deserialize_anchor)
5229            .ok_or_else(|| anyhow!("invalid end"))?;
5230        let buffer = this.update(&mut cx, |this, cx| {
5231            this.opened_buffers
5232                .get(&envelope.payload.buffer_id)
5233                .and_then(|buffer| buffer.upgrade(cx))
5234                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5235        })?;
5236        buffer
5237            .update(&mut cx, |buffer, _| {
5238                buffer.wait_for_version(deserialize_version(envelope.payload.version))
5239            })
5240            .await;
5241
5242        let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5243        let code_actions = this.update(&mut cx, |this, cx| {
5244            Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
5245        })?;
5246
5247        Ok(proto::GetCodeActionsResponse {
5248            actions: code_actions
5249                .await?
5250                .iter()
5251                .map(language::proto::serialize_code_action)
5252                .collect(),
5253            version: serialize_version(&version),
5254        })
5255    }
5256
5257    async fn handle_apply_code_action(
5258        this: ModelHandle<Self>,
5259        envelope: TypedEnvelope<proto::ApplyCodeAction>,
5260        _: Arc<Client>,
5261        mut cx: AsyncAppContext,
5262    ) -> Result<proto::ApplyCodeActionResponse> {
5263        let sender_id = envelope.original_sender_id()?;
5264        let action = language::proto::deserialize_code_action(
5265            envelope
5266                .payload
5267                .action
5268                .ok_or_else(|| anyhow!("invalid action"))?,
5269        )?;
5270        let apply_code_action = this.update(&mut cx, |this, cx| {
5271            let buffer = this
5272                .opened_buffers
5273                .get(&envelope.payload.buffer_id)
5274                .and_then(|buffer| buffer.upgrade(cx))
5275                .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5276            Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
5277        })?;
5278
5279        let project_transaction = apply_code_action.await?;
5280        let project_transaction = this.update(&mut cx, |this, cx| {
5281            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5282        });
5283        Ok(proto::ApplyCodeActionResponse {
5284            transaction: Some(project_transaction),
5285        })
5286    }
5287
5288    async fn handle_lsp_command<T: LspCommand>(
5289        this: ModelHandle<Self>,
5290        envelope: TypedEnvelope<T::ProtoRequest>,
5291        _: Arc<Client>,
5292        mut cx: AsyncAppContext,
5293    ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
5294    where
5295        <T::LspRequest as lsp::request::Request>::Result: Send,
5296    {
5297        let sender_id = envelope.original_sender_id()?;
5298        let buffer_id = T::buffer_id_from_proto(&envelope.payload);
5299        let buffer_handle = this.read_with(&cx, |this, _| {
5300            this.opened_buffers
5301                .get(&buffer_id)
5302                .and_then(|buffer| buffer.upgrade(&cx))
5303                .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
5304        })?;
5305        let request = T::from_proto(
5306            envelope.payload,
5307            this.clone(),
5308            buffer_handle.clone(),
5309            cx.clone(),
5310        )
5311        .await?;
5312        let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
5313        let response = this
5314            .update(&mut cx, |this, cx| {
5315                this.request_lsp(buffer_handle, request, cx)
5316            })
5317            .await?;
5318        this.update(&mut cx, |this, cx| {
5319            Ok(T::response_to_proto(
5320                response,
5321                this,
5322                sender_id,
5323                &buffer_version,
5324                cx,
5325            ))
5326        })
5327    }
5328
5329    async fn handle_get_project_symbols(
5330        this: ModelHandle<Self>,
5331        envelope: TypedEnvelope<proto::GetProjectSymbols>,
5332        _: Arc<Client>,
5333        mut cx: AsyncAppContext,
5334    ) -> Result<proto::GetProjectSymbolsResponse> {
5335        let symbols = this
5336            .update(&mut cx, |this, cx| {
5337                this.symbols(&envelope.payload.query, cx)
5338            })
5339            .await?;
5340
5341        Ok(proto::GetProjectSymbolsResponse {
5342            symbols: symbols.iter().map(serialize_symbol).collect(),
5343        })
5344    }
5345
5346    async fn handle_search_project(
5347        this: ModelHandle<Self>,
5348        envelope: TypedEnvelope<proto::SearchProject>,
5349        _: Arc<Client>,
5350        mut cx: AsyncAppContext,
5351    ) -> Result<proto::SearchProjectResponse> {
5352        let peer_id = envelope.original_sender_id()?;
5353        let query = SearchQuery::from_proto(envelope.payload)?;
5354        let result = this
5355            .update(&mut cx, |this, cx| this.search(query, cx))
5356            .await?;
5357
5358        this.update(&mut cx, |this, cx| {
5359            let mut locations = Vec::new();
5360            for (buffer, ranges) in result {
5361                for range in ranges {
5362                    let start = serialize_anchor(&range.start);
5363                    let end = serialize_anchor(&range.end);
5364                    let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
5365                    locations.push(proto::Location {
5366                        buffer: Some(buffer),
5367                        start: Some(start),
5368                        end: Some(end),
5369                    });
5370                }
5371            }
5372            Ok(proto::SearchProjectResponse { locations })
5373        })
5374    }
5375
5376    async fn handle_open_buffer_for_symbol(
5377        this: ModelHandle<Self>,
5378        envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
5379        _: Arc<Client>,
5380        mut cx: AsyncAppContext,
5381    ) -> Result<proto::OpenBufferForSymbolResponse> {
5382        let peer_id = envelope.original_sender_id()?;
5383        let symbol = envelope
5384            .payload
5385            .symbol
5386            .ok_or_else(|| anyhow!("invalid symbol"))?;
5387        let symbol = this.read_with(&cx, |this, _| {
5388            let symbol = this.deserialize_symbol(symbol)?;
5389            let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
5390            if signature == symbol.signature {
5391                Ok(symbol)
5392            } else {
5393                Err(anyhow!("invalid symbol signature"))
5394            }
5395        })?;
5396        let buffer = this
5397            .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
5398            .await?;
5399
5400        Ok(proto::OpenBufferForSymbolResponse {
5401            buffer: Some(this.update(&mut cx, |this, cx| {
5402                this.serialize_buffer_for_peer(&buffer, peer_id, cx)
5403            })),
5404        })
5405    }
5406
5407    fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
5408        let mut hasher = Sha256::new();
5409        hasher.update(worktree_id.to_proto().to_be_bytes());
5410        hasher.update(path.to_string_lossy().as_bytes());
5411        hasher.update(self.nonce.to_be_bytes());
5412        hasher.finalize().as_slice().try_into().unwrap()
5413    }
5414
5415    async fn handle_open_buffer_by_id(
5416        this: ModelHandle<Self>,
5417        envelope: TypedEnvelope<proto::OpenBufferById>,
5418        _: Arc<Client>,
5419        mut cx: AsyncAppContext,
5420    ) -> Result<proto::OpenBufferResponse> {
5421        let peer_id = envelope.original_sender_id()?;
5422        let buffer = this
5423            .update(&mut cx, |this, cx| {
5424                this.open_buffer_by_id(envelope.payload.id, cx)
5425            })
5426            .await?;
5427        this.update(&mut cx, |this, cx| {
5428            Ok(proto::OpenBufferResponse {
5429                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5430            })
5431        })
5432    }
5433
5434    async fn handle_open_buffer_by_path(
5435        this: ModelHandle<Self>,
5436        envelope: TypedEnvelope<proto::OpenBufferByPath>,
5437        _: Arc<Client>,
5438        mut cx: AsyncAppContext,
5439    ) -> Result<proto::OpenBufferResponse> {
5440        let peer_id = envelope.original_sender_id()?;
5441        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5442        let open_buffer = this.update(&mut cx, |this, cx| {
5443            this.open_buffer(
5444                ProjectPath {
5445                    worktree_id,
5446                    path: PathBuf::from(envelope.payload.path).into(),
5447                },
5448                cx,
5449            )
5450        });
5451
5452        let buffer = open_buffer.await?;
5453        this.update(&mut cx, |this, cx| {
5454            Ok(proto::OpenBufferResponse {
5455                buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5456            })
5457        })
5458    }
5459
5460    fn serialize_project_transaction_for_peer(
5461        &mut self,
5462        project_transaction: ProjectTransaction,
5463        peer_id: PeerId,
5464        cx: &AppContext,
5465    ) -> proto::ProjectTransaction {
5466        let mut serialized_transaction = proto::ProjectTransaction {
5467            buffers: Default::default(),
5468            transactions: Default::default(),
5469        };
5470        for (buffer, transaction) in project_transaction.0 {
5471            serialized_transaction
5472                .buffers
5473                .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
5474            serialized_transaction
5475                .transactions
5476                .push(language::proto::serialize_transaction(&transaction));
5477        }
5478        serialized_transaction
5479    }
5480
5481    fn deserialize_project_transaction(
5482        &mut self,
5483        message: proto::ProjectTransaction,
5484        push_to_history: bool,
5485        cx: &mut ModelContext<Self>,
5486    ) -> Task<Result<ProjectTransaction>> {
5487        cx.spawn(|this, mut cx| async move {
5488            let mut project_transaction = ProjectTransaction::default();
5489            for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
5490                let buffer = this
5491                    .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
5492                    .await?;
5493                let transaction = language::proto::deserialize_transaction(transaction)?;
5494                project_transaction.0.insert(buffer, transaction);
5495            }
5496
5497            for (buffer, transaction) in &project_transaction.0 {
5498                buffer
5499                    .update(&mut cx, |buffer, _| {
5500                        buffer.wait_for_edits(transaction.edit_ids.iter().copied())
5501                    })
5502                    .await;
5503
5504                if push_to_history {
5505                    buffer.update(&mut cx, |buffer, _| {
5506                        buffer.push_transaction(transaction.clone(), Instant::now());
5507                    });
5508                }
5509            }
5510
5511            Ok(project_transaction)
5512        })
5513    }
5514
5515    fn serialize_buffer_for_peer(
5516        &mut self,
5517        buffer: &ModelHandle<Buffer>,
5518        peer_id: PeerId,
5519        cx: &AppContext,
5520    ) -> proto::Buffer {
5521        let buffer_id = buffer.read(cx).remote_id();
5522        let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
5523        if shared_buffers.insert(buffer_id) {
5524            proto::Buffer {
5525                variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
5526            }
5527        } else {
5528            proto::Buffer {
5529                variant: Some(proto::buffer::Variant::Id(buffer_id)),
5530            }
5531        }
5532    }
5533
5534    fn deserialize_buffer(
5535        &mut self,
5536        buffer: proto::Buffer,
5537        cx: &mut ModelContext<Self>,
5538    ) -> Task<Result<ModelHandle<Buffer>>> {
5539        let replica_id = self.replica_id();
5540
5541        let opened_buffer_tx = self.opened_buffer.0.clone();
5542        let mut opened_buffer_rx = self.opened_buffer.1.clone();
5543        cx.spawn(|this, mut cx| async move {
5544            match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
5545                proto::buffer::Variant::Id(id) => {
5546                    let buffer = loop {
5547                        let buffer = this.read_with(&cx, |this, cx| {
5548                            this.opened_buffers
5549                                .get(&id)
5550                                .and_then(|buffer| buffer.upgrade(cx))
5551                        });
5552                        if let Some(buffer) = buffer {
5553                            break buffer;
5554                        }
5555                        opened_buffer_rx
5556                            .next()
5557                            .await
5558                            .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
5559                    };
5560                    Ok(buffer)
5561                }
5562                proto::buffer::Variant::State(mut buffer) => {
5563                    let mut buffer_worktree = None;
5564                    let mut buffer_file = None;
5565                    if let Some(file) = buffer.file.take() {
5566                        this.read_with(&cx, |this, cx| {
5567                            let worktree_id = WorktreeId::from_proto(file.worktree_id);
5568                            let worktree =
5569                                this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
5570                                    anyhow!("no worktree found for id {}", file.worktree_id)
5571                                })?;
5572                            buffer_file =
5573                                Some(Arc::new(File::from_proto(file, worktree.clone(), cx)?)
5574                                    as Arc<dyn language::File>);
5575                            buffer_worktree = Some(worktree);
5576                            Ok::<_, anyhow::Error>(())
5577                        })?;
5578                    }
5579
5580                    let buffer = cx.add_model(|cx| {
5581                        Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
5582                    });
5583
5584                    this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
5585
5586                    *opened_buffer_tx.borrow_mut().borrow_mut() = ();
5587                    Ok(buffer)
5588                }
5589            }
5590        })
5591    }
5592
5593    fn deserialize_symbol(&self, serialized_symbol: proto::Symbol) -> Result<Symbol> {
5594        let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5595        let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5596        let start = serialized_symbol
5597            .start
5598            .ok_or_else(|| anyhow!("invalid start"))?;
5599        let end = serialized_symbol
5600            .end
5601            .ok_or_else(|| anyhow!("invalid end"))?;
5602        let kind = unsafe { mem::transmute(serialized_symbol.kind) };
5603        let path = PathBuf::from(serialized_symbol.path);
5604        let language = self.languages.select_language(&path);
5605        Ok(Symbol {
5606            source_worktree_id,
5607            worktree_id,
5608            language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
5609            label: language
5610                .and_then(|language| language.label_for_symbol(&serialized_symbol.name, kind))
5611                .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None)),
5612            name: serialized_symbol.name,
5613            path,
5614            range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
5615            kind,
5616            signature: serialized_symbol
5617                .signature
5618                .try_into()
5619                .map_err(|_| anyhow!("invalid signature"))?,
5620        })
5621    }
5622
5623    async fn handle_buffer_saved(
5624        this: ModelHandle<Self>,
5625        envelope: TypedEnvelope<proto::BufferSaved>,
5626        _: Arc<Client>,
5627        mut cx: AsyncAppContext,
5628    ) -> Result<()> {
5629        let version = deserialize_version(envelope.payload.version);
5630        let mtime = envelope
5631            .payload
5632            .mtime
5633            .ok_or_else(|| anyhow!("missing mtime"))?
5634            .into();
5635
5636        this.update(&mut cx, |this, cx| {
5637            let buffer = this
5638                .opened_buffers
5639                .get(&envelope.payload.buffer_id)
5640                .and_then(|buffer| buffer.upgrade(cx));
5641            if let Some(buffer) = buffer {
5642                buffer.update(cx, |buffer, cx| {
5643                    buffer.did_save(version, envelope.payload.fingerprint, mtime, None, cx);
5644                });
5645            }
5646            Ok(())
5647        })
5648    }
5649
5650    async fn handle_buffer_reloaded(
5651        this: ModelHandle<Self>,
5652        envelope: TypedEnvelope<proto::BufferReloaded>,
5653        _: Arc<Client>,
5654        mut cx: AsyncAppContext,
5655    ) -> Result<()> {
5656        let payload = envelope.payload;
5657        let version = deserialize_version(payload.version);
5658        let line_ending = deserialize_line_ending(
5659            proto::LineEnding::from_i32(payload.line_ending)
5660                .ok_or_else(|| anyhow!("missing line ending"))?,
5661        );
5662        let mtime = payload
5663            .mtime
5664            .ok_or_else(|| anyhow!("missing mtime"))?
5665            .into();
5666        this.update(&mut cx, |this, cx| {
5667            let buffer = this
5668                .opened_buffers
5669                .get(&payload.buffer_id)
5670                .and_then(|buffer| buffer.upgrade(cx));
5671            if let Some(buffer) = buffer {
5672                buffer.update(cx, |buffer, cx| {
5673                    buffer.did_reload(version, payload.fingerprint, line_ending, mtime, cx);
5674                });
5675            }
5676            Ok(())
5677        })
5678    }
5679
5680    fn edits_from_lsp(
5681        &mut self,
5682        buffer: &ModelHandle<Buffer>,
5683        lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
5684        version: Option<i32>,
5685        cx: &mut ModelContext<Self>,
5686    ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
5687        let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
5688        cx.background().spawn(async move {
5689            let snapshot = snapshot?;
5690            let mut lsp_edits = lsp_edits
5691                .into_iter()
5692                .map(|edit| (range_from_lsp(edit.range), edit.new_text))
5693                .collect::<Vec<_>>();
5694            lsp_edits.sort_by_key(|(range, _)| range.start);
5695
5696            let mut lsp_edits = lsp_edits.into_iter().peekable();
5697            let mut edits = Vec::new();
5698            while let Some((mut range, mut new_text)) = lsp_edits.next() {
5699                // Combine any LSP edits that are adjacent.
5700                //
5701                // Also, combine LSP edits that are separated from each other by only
5702                // a newline. This is important because for some code actions,
5703                // Rust-analyzer rewrites the entire buffer via a series of edits that
5704                // are separated by unchanged newline characters.
5705                //
5706                // In order for the diffing logic below to work properly, any edits that
5707                // cancel each other out must be combined into one.
5708                while let Some((next_range, next_text)) = lsp_edits.peek() {
5709                    if next_range.start > range.end {
5710                        if next_range.start.row > range.end.row + 1
5711                            || next_range.start.column > 0
5712                            || snapshot.clip_point_utf16(
5713                                PointUtf16::new(range.end.row, u32::MAX),
5714                                Bias::Left,
5715                            ) > range.end
5716                        {
5717                            break;
5718                        }
5719                        new_text.push('\n');
5720                    }
5721                    range.end = next_range.end;
5722                    new_text.push_str(&next_text);
5723                    lsp_edits.next();
5724                }
5725
5726                if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
5727                    || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
5728                {
5729                    return Err(anyhow!("invalid edits received from language server"));
5730                }
5731
5732                // For multiline edits, perform a diff of the old and new text so that
5733                // we can identify the changes more precisely, preserving the locations
5734                // of any anchors positioned in the unchanged regions.
5735                if range.end.row > range.start.row {
5736                    let mut offset = range.start.to_offset(&snapshot);
5737                    let old_text = snapshot.text_for_range(range).collect::<String>();
5738
5739                    let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
5740                    let mut moved_since_edit = true;
5741                    for change in diff.iter_all_changes() {
5742                        let tag = change.tag();
5743                        let value = change.value();
5744                        match tag {
5745                            ChangeTag::Equal => {
5746                                offset += value.len();
5747                                moved_since_edit = true;
5748                            }
5749                            ChangeTag::Delete => {
5750                                let start = snapshot.anchor_after(offset);
5751                                let end = snapshot.anchor_before(offset + value.len());
5752                                if moved_since_edit {
5753                                    edits.push((start..end, String::new()));
5754                                } else {
5755                                    edits.last_mut().unwrap().0.end = end;
5756                                }
5757                                offset += value.len();
5758                                moved_since_edit = false;
5759                            }
5760                            ChangeTag::Insert => {
5761                                if moved_since_edit {
5762                                    let anchor = snapshot.anchor_after(offset);
5763                                    edits.push((anchor.clone()..anchor, value.to_string()));
5764                                } else {
5765                                    edits.last_mut().unwrap().1.push_str(value);
5766                                }
5767                                moved_since_edit = false;
5768                            }
5769                        }
5770                    }
5771                } else if range.end == range.start {
5772                    let anchor = snapshot.anchor_after(range.start);
5773                    edits.push((anchor.clone()..anchor, new_text));
5774                } else {
5775                    let edit_start = snapshot.anchor_after(range.start);
5776                    let edit_end = snapshot.anchor_before(range.end);
5777                    edits.push((edit_start..edit_end, new_text));
5778                }
5779            }
5780
5781            Ok(edits)
5782        })
5783    }
5784
5785    fn buffer_snapshot_for_lsp_version(
5786        &mut self,
5787        buffer: &ModelHandle<Buffer>,
5788        version: Option<i32>,
5789        cx: &AppContext,
5790    ) -> Result<TextBufferSnapshot> {
5791        const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5792
5793        if let Some(version) = version {
5794            let buffer_id = buffer.read(cx).remote_id();
5795            let snapshots = self
5796                .buffer_snapshots
5797                .get_mut(&buffer_id)
5798                .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
5799            let mut found_snapshot = None;
5800            snapshots.retain(|(snapshot_version, snapshot)| {
5801                if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
5802                    false
5803                } else {
5804                    if *snapshot_version == version {
5805                        found_snapshot = Some(snapshot.clone());
5806                    }
5807                    true
5808                }
5809            });
5810
5811            found_snapshot.ok_or_else(|| {
5812                anyhow!(
5813                    "snapshot not found for buffer {} at version {}",
5814                    buffer_id,
5815                    version
5816                )
5817            })
5818        } else {
5819            Ok((buffer.read(cx)).text_snapshot())
5820        }
5821    }
5822
5823    fn language_server_for_buffer(
5824        &self,
5825        buffer: &Buffer,
5826        cx: &AppContext,
5827    ) -> Option<(&Arc<dyn LspAdapter>, &Arc<LanguageServer>)> {
5828        if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5829            let worktree_id = file.worktree_id(cx);
5830            let key = (worktree_id, language.lsp_adapter()?.name());
5831
5832            if let Some(server_id) = self.language_server_ids.get(&key) {
5833                if let Some(LanguageServerState::Running { adapter, server }) =
5834                    self.language_servers.get(&server_id)
5835                {
5836                    return Some((adapter, server));
5837                }
5838            }
5839        }
5840
5841        None
5842    }
5843}
5844
5845impl ProjectStore {
5846    pub fn new(db: Arc<Db>) -> Self {
5847        Self {
5848            db,
5849            projects: Default::default(),
5850        }
5851    }
5852
5853    pub fn projects<'a>(
5854        &'a self,
5855        cx: &'a AppContext,
5856    ) -> impl 'a + Iterator<Item = ModelHandle<Project>> {
5857        self.projects
5858            .iter()
5859            .filter_map(|project| project.upgrade(cx))
5860    }
5861
5862    fn add_project(&mut self, project: WeakModelHandle<Project>, cx: &mut ModelContext<Self>) {
5863        if let Err(ix) = self
5864            .projects
5865            .binary_search_by_key(&project.id(), WeakModelHandle::id)
5866        {
5867            self.projects.insert(ix, project);
5868        }
5869        cx.notify();
5870    }
5871
5872    fn prune_projects(&mut self, cx: &mut ModelContext<Self>) {
5873        let mut did_change = false;
5874        self.projects.retain(|project| {
5875            if project.is_upgradable(cx) {
5876                true
5877            } else {
5878                did_change = true;
5879                false
5880            }
5881        });
5882        if did_change {
5883            cx.notify();
5884        }
5885    }
5886}
5887
5888impl WorktreeHandle {
5889    pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
5890        match self {
5891            WorktreeHandle::Strong(handle) => Some(handle.clone()),
5892            WorktreeHandle::Weak(handle) => handle.upgrade(cx),
5893        }
5894    }
5895}
5896
5897impl OpenBuffer {
5898    pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
5899        match self {
5900            OpenBuffer::Strong(handle) => Some(handle.clone()),
5901            OpenBuffer::Weak(handle) => handle.upgrade(cx),
5902            OpenBuffer::Loading(_) => None,
5903        }
5904    }
5905}
5906
5907pub struct PathMatchCandidateSet {
5908    pub snapshot: Snapshot,
5909    pub include_ignored: bool,
5910    pub include_root_name: bool,
5911}
5912
5913impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
5914    type Candidates = PathMatchCandidateSetIter<'a>;
5915
5916    fn id(&self) -> usize {
5917        self.snapshot.id().to_usize()
5918    }
5919
5920    fn len(&self) -> usize {
5921        if self.include_ignored {
5922            self.snapshot.file_count()
5923        } else {
5924            self.snapshot.visible_file_count()
5925        }
5926    }
5927
5928    fn prefix(&self) -> Arc<str> {
5929        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
5930            self.snapshot.root_name().into()
5931        } else if self.include_root_name {
5932            format!("{}/", self.snapshot.root_name()).into()
5933        } else {
5934            "".into()
5935        }
5936    }
5937
5938    fn candidates(&'a self, start: usize) -> Self::Candidates {
5939        PathMatchCandidateSetIter {
5940            traversal: self.snapshot.files(self.include_ignored, start),
5941        }
5942    }
5943}
5944
5945pub struct PathMatchCandidateSetIter<'a> {
5946    traversal: Traversal<'a>,
5947}
5948
5949impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
5950    type Item = fuzzy::PathMatchCandidate<'a>;
5951
5952    fn next(&mut self) -> Option<Self::Item> {
5953        self.traversal.next().map(|entry| {
5954            if let EntryKind::File(char_bag) = entry.kind {
5955                fuzzy::PathMatchCandidate {
5956                    path: &entry.path,
5957                    char_bag,
5958                }
5959            } else {
5960                unreachable!()
5961            }
5962        })
5963    }
5964}
5965
5966impl Entity for ProjectStore {
5967    type Event = ();
5968}
5969
5970impl Entity for Project {
5971    type Event = Event;
5972
5973    fn release(&mut self, cx: &mut gpui::MutableAppContext) {
5974        self.project_store.update(cx, ProjectStore::prune_projects);
5975
5976        match &self.client_state {
5977            ProjectClientState::Local { remote_id_rx, .. } => {
5978                if let Some(project_id) = *remote_id_rx.borrow() {
5979                    self.client
5980                        .send(proto::UnregisterProject { project_id })
5981                        .log_err();
5982                }
5983            }
5984            ProjectClientState::Remote { remote_id, .. } => {
5985                self.client
5986                    .send(proto::LeaveProject {
5987                        project_id: *remote_id,
5988                    })
5989                    .log_err();
5990            }
5991        }
5992    }
5993
5994    fn app_will_quit(
5995        &mut self,
5996        _: &mut MutableAppContext,
5997    ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
5998        let shutdown_futures = self
5999            .language_servers
6000            .drain()
6001            .map(|(_, server_state)| async {
6002                match server_state {
6003                    LanguageServerState::Running { server, .. } => server.shutdown()?.await,
6004                    LanguageServerState::Starting(starting_server) => {
6005                        starting_server.await?.shutdown()?.await
6006                    }
6007                }
6008            })
6009            .collect::<Vec<_>>();
6010
6011        Some(
6012            async move {
6013                futures::future::join_all(shutdown_futures).await;
6014            }
6015            .boxed(),
6016        )
6017    }
6018}
6019
6020impl Collaborator {
6021    fn from_proto(
6022        message: proto::Collaborator,
6023        user_store: &ModelHandle<UserStore>,
6024        cx: &mut AsyncAppContext,
6025    ) -> impl Future<Output = Result<Self>> {
6026        let user = user_store.update(cx, |user_store, cx| {
6027            user_store.fetch_user(message.user_id, cx)
6028        });
6029
6030        async move {
6031            Ok(Self {
6032                peer_id: PeerId(message.peer_id),
6033                user: user.await?,
6034                replica_id: message.replica_id as ReplicaId,
6035            })
6036        }
6037    }
6038}
6039
6040impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
6041    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
6042        Self {
6043            worktree_id,
6044            path: path.as_ref().into(),
6045        }
6046    }
6047}
6048
6049impl From<lsp::CreateFileOptions> for fs::CreateOptions {
6050    fn from(options: lsp::CreateFileOptions) -> Self {
6051        Self {
6052            overwrite: options.overwrite.unwrap_or(false),
6053            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6054        }
6055    }
6056}
6057
6058impl From<lsp::RenameFileOptions> for fs::RenameOptions {
6059    fn from(options: lsp::RenameFileOptions) -> Self {
6060        Self {
6061            overwrite: options.overwrite.unwrap_or(false),
6062            ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6063        }
6064    }
6065}
6066
6067impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
6068    fn from(options: lsp::DeleteFileOptions) -> Self {
6069        Self {
6070            recursive: options.recursive.unwrap_or(false),
6071            ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
6072        }
6073    }
6074}
6075
6076fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
6077    proto::Symbol {
6078        source_worktree_id: symbol.source_worktree_id.to_proto(),
6079        worktree_id: symbol.worktree_id.to_proto(),
6080        language_server_name: symbol.language_server_name.0.to_string(),
6081        name: symbol.name.clone(),
6082        kind: unsafe { mem::transmute(symbol.kind) },
6083        path: symbol.path.to_string_lossy().to_string(),
6084        start: Some(proto::Point {
6085            row: symbol.range.start.row,
6086            column: symbol.range.start.column,
6087        }),
6088        end: Some(proto::Point {
6089            row: symbol.range.end.row,
6090            column: symbol.range.end.column,
6091        }),
6092        signature: symbol.signature.to_vec(),
6093    }
6094}
6095
6096fn relativize_path(base: &Path, path: &Path) -> PathBuf {
6097    let mut path_components = path.components();
6098    let mut base_components = base.components();
6099    let mut components: Vec<Component> = Vec::new();
6100    loop {
6101        match (path_components.next(), base_components.next()) {
6102            (None, None) => break,
6103            (Some(a), None) => {
6104                components.push(a);
6105                components.extend(path_components.by_ref());
6106                break;
6107            }
6108            (None, _) => components.push(Component::ParentDir),
6109            (Some(a), Some(b)) if components.is_empty() && a == b => (),
6110            (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
6111            (Some(a), Some(_)) => {
6112                components.push(Component::ParentDir);
6113                for _ in base_components {
6114                    components.push(Component::ParentDir);
6115                }
6116                components.push(a);
6117                components.extend(path_components.by_ref());
6118                break;
6119            }
6120        }
6121    }
6122    components.iter().map(|c| c.as_os_str()).collect()
6123}
6124
6125impl Item for Buffer {
6126    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
6127        File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
6128    }
6129}