project.rs

   1pub mod buffer_store;
   2pub mod connection_manager;
   3pub mod debounced_delay;
   4pub mod lsp_command;
   5pub mod lsp_ext_command;
   6pub mod lsp_store;
   7mod prettier_support;
   8pub mod project_settings;
   9pub mod search;
  10mod task_inventory;
  11pub mod terminals;
  12pub mod worktree_store;
  13
  14#[cfg(test)]
  15mod project_tests;
  16
  17mod environment;
  18pub mod search_history;
  19mod yarn;
  20
  21use anyhow::{anyhow, Context as _, Result};
  22use buffer_store::{BufferStore, BufferStoreEvent};
  23use client::{
  24    proto, Client, Collaborator, DevServerProjectId, PendingEntitySubscription, ProjectId,
  25    TypedEnvelope, UserStore,
  26};
  27use clock::ReplicaId;
  28use collections::{BTreeSet, HashMap, HashSet};
  29use debounced_delay::DebouncedDelay;
  30pub use environment::ProjectEnvironment;
  31use futures::{
  32    channel::mpsc::{self, UnboundedReceiver},
  33    future::try_join_all,
  34    stream::FuturesUnordered,
  35    AsyncWriteExt, FutureExt, StreamExt,
  36};
  37
  38use git::{blame::Blame, repository::GitRepository};
  39use gpui::{
  40    AnyModel, AppContext, AsyncAppContext, BorrowAppContext, Context, EventEmitter, Model,
  41    ModelContext, SharedString, Task, WeakModel, WindowContext,
  42};
  43use itertools::Itertools;
  44use language::{
  45    language_settings::{
  46        language_settings, FormatOnSave, Formatter, InlayHintKind, LanguageSettings,
  47        SelectedFormatter,
  48    },
  49    proto::{
  50        deserialize_anchor, serialize_anchor, serialize_line_ending, serialize_version,
  51        split_operations,
  52    },
  53    Buffer, BufferEvent, CachedLspAdapter, Capability, CodeLabel, ContextProvider, DiagnosticEntry,
  54    Diff, Documentation, File as _, Language, LanguageRegistry, LanguageServerName, PointUtf16,
  55    ToOffset, ToPointUtf16, Transaction, Unclipped,
  56};
  57use lsp::{CompletionContext, DocumentHighlightKind, LanguageServer, LanguageServerId};
  58use lsp_command::*;
  59use node_runtime::NodeRuntime;
  60use parking_lot::{Mutex, RwLock};
  61use paths::{local_tasks_file_relative_path, local_vscode_tasks_file_relative_path};
  62use prettier_support::{DefaultPrettier, PrettierInstance};
  63use project_settings::{LspSettings, ProjectSettings, SettingsObserver};
  64use remote::SshSession;
  65use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};
  66use search::{SearchInputKind, SearchQuery, SearchResult};
  67use search_history::SearchHistory;
  68use settings::{watch_config_file, Settings, SettingsLocation, SettingsStore};
  69use smol::channel::Receiver;
  70use snippet::Snippet;
  71use snippet_provider::SnippetProvider;
  72use std::{
  73    borrow::Cow,
  74    ops::Range,
  75    path::{Component, Path, PathBuf},
  76    str,
  77    sync::Arc,
  78    time::Duration,
  79};
  80use task::{
  81    static_source::{StaticSource, TrackedFile},
  82    HideStrategy, RevealStrategy, Shell, TaskContext, TaskTemplate, TaskVariables, VariableName,
  83};
  84use terminals::Terminals;
  85use text::{Anchor, BufferId};
  86use util::{defer, paths::compare_paths, ResultExt as _};
  87use worktree::{CreatedEntry, Snapshot, Traversal};
  88use worktree_store::{WorktreeStore, WorktreeStoreEvent};
  89
  90pub use fs::*;
  91pub use language::Location;
  92#[cfg(any(test, feature = "test-support"))]
  93pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
  94pub use task_inventory::{
  95    BasicContextProvider, ContextProviderWithTasks, Inventory, TaskSourceKind,
  96};
  97pub use worktree::{
  98    Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,
  99    UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
 100    FS_WATCH_LATENCY,
 101};
 102
 103pub use buffer_store::ProjectTransaction;
 104pub use lsp_store::{
 105    DiagnosticSummary, LanguageServerLogType, LanguageServerProgress, LanguageServerPromptRequest,
 106    LanguageServerStatus, LanguageServerToQuery, LspStore, LspStoreEvent,
 107    SERVER_PROGRESS_THROTTLE_TIMEOUT,
 108};
 109
 110const MAX_PROJECT_SEARCH_HISTORY_SIZE: usize = 500;
 111const MAX_SEARCH_RESULT_FILES: usize = 5_000;
 112const MAX_SEARCH_RESULT_RANGES: usize = 10_000;
 113
 114pub trait Item {
 115    fn try_open(
 116        project: &Model<Project>,
 117        path: &ProjectPath,
 118        cx: &mut AppContext,
 119    ) -> Option<Task<Result<Model<Self>>>>
 120    where
 121        Self: Sized;
 122    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
 123    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
 124}
 125
 126#[derive(Clone)]
 127pub enum OpenedBufferEvent {
 128    Disconnected,
 129    Ok(BufferId),
 130    Err(BufferId, Arc<anyhow::Error>),
 131}
 132
 133/// Semantics-aware entity that is relevant to one or more [`Worktree`] with the files.
 134/// `Project` is responsible for tasks, LSP and collab queries, synchronizing worktree states accordingly.
 135/// Maps [`Worktree`] entries with its own logic using [`ProjectEntryId`] and [`ProjectPath`] structs.
 136///
 137/// Can be either local (for the project opened on the same host) or remote.(for collab projects, browsed by multiple remote users).
 138pub struct Project {
 139    active_entry: Option<ProjectEntryId>,
 140    buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
 141    languages: Arc<LanguageRegistry>,
 142    client: Arc<client::Client>,
 143    current_lsp_settings: HashMap<Arc<str>, LspSettings>,
 144    join_project_response_message_id: u32,
 145    user_store: Model<UserStore>,
 146    fs: Arc<dyn Fs>,
 147    ssh_session: Option<Arc<SshSession>>,
 148    client_state: ProjectClientState,
 149    collaborators: HashMap<proto::PeerId, Collaborator>,
 150    client_subscriptions: Vec<client::Subscription>,
 151    worktree_store: Model<WorktreeStore>,
 152    buffer_store: Model<BufferStore>,
 153    lsp_store: Model<LspStore>,
 154    _subscriptions: Vec<gpui::Subscription>,
 155    buffers_needing_diff: HashSet<WeakModel<Buffer>>,
 156    git_diff_debouncer: DebouncedDelay<Self>,
 157    remotely_created_buffers: Arc<Mutex<RemotelyCreatedBuffers>>,
 158    terminals: Terminals,
 159    node: Option<Arc<dyn NodeRuntime>>,
 160    default_prettier: DefaultPrettier,
 161    prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>,
 162    prettier_instances: HashMap<PathBuf, PrettierInstance>,
 163    tasks: Model<Inventory>,
 164    hosted_project_id: Option<ProjectId>,
 165    dev_server_project_id: Option<client::DevServerProjectId>,
 166    search_history: SearchHistory,
 167    search_included_history: SearchHistory,
 168    search_excluded_history: SearchHistory,
 169    snippets: Model<SnippetProvider>,
 170    last_formatting_failure: Option<String>,
 171    buffers_being_formatted: HashSet<BufferId>,
 172    environment: Model<ProjectEnvironment>,
 173    settings_observer: Model<SettingsObserver>,
 174}
 175
 176#[derive(Default)]
 177struct RemotelyCreatedBuffers {
 178    buffers: Vec<Model<Buffer>>,
 179    retain_count: usize,
 180}
 181
 182struct RemotelyCreatedBufferGuard {
 183    remote_buffers: std::sync::Weak<Mutex<RemotelyCreatedBuffers>>,
 184}
 185
 186impl Drop for RemotelyCreatedBufferGuard {
 187    fn drop(&mut self) {
 188        if let Some(remote_buffers) = self.remote_buffers.upgrade() {
 189            let mut remote_buffers = remote_buffers.lock();
 190            assert!(
 191                remote_buffers.retain_count > 0,
 192                "RemotelyCreatedBufferGuard dropped too many times"
 193            );
 194            remote_buffers.retain_count -= 1;
 195            if remote_buffers.retain_count == 0 {
 196                remote_buffers.buffers.clear();
 197            }
 198        }
 199    }
 200}
 201/// Message ordered with respect to buffer operations
 202#[derive(Debug)]
 203enum BufferOrderedMessage {
 204    Operation {
 205        buffer_id: BufferId,
 206        operation: proto::Operation,
 207    },
 208    LanguageServerUpdate {
 209        language_server_id: LanguageServerId,
 210        message: proto::update_language_server::Variant,
 211    },
 212    Resync,
 213}
 214
 215#[derive(Debug)]
 216enum ProjectClientState {
 217    Local,
 218    Shared {
 219        remote_id: u64,
 220    },
 221    Remote {
 222        sharing_has_stopped: bool,
 223        capability: Capability,
 224        remote_id: u64,
 225        replica_id: ReplicaId,
 226        in_room: bool,
 227    },
 228}
 229
 230#[derive(Clone, Debug, PartialEq)]
 231pub enum Event {
 232    LanguageServerAdded(LanguageServerId),
 233    LanguageServerRemoved(LanguageServerId),
 234    LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
 235    Notification(String),
 236    LanguageServerPrompt(LanguageServerPromptRequest),
 237    LanguageNotFound(Model<Buffer>),
 238    ActiveEntryChanged(Option<ProjectEntryId>),
 239    ActivateProjectPanel,
 240    WorktreeAdded,
 241    WorktreeOrderChanged,
 242    WorktreeRemoved(WorktreeId),
 243    WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet),
 244    WorktreeUpdatedGitRepositories,
 245    DiskBasedDiagnosticsStarted {
 246        language_server_id: LanguageServerId,
 247    },
 248    DiskBasedDiagnosticsFinished {
 249        language_server_id: LanguageServerId,
 250    },
 251    DiagnosticsUpdated {
 252        path: ProjectPath,
 253        language_server_id: LanguageServerId,
 254    },
 255    RemoteIdChanged(Option<u64>),
 256    DisconnectedFromHost,
 257    Closed,
 258    DeletedEntry(ProjectEntryId),
 259    CollaboratorUpdated {
 260        old_peer_id: proto::PeerId,
 261        new_peer_id: proto::PeerId,
 262    },
 263    CollaboratorJoined(proto::PeerId),
 264    CollaboratorLeft(proto::PeerId),
 265    HostReshared,
 266    Reshared,
 267    Rejoined,
 268    RefreshInlayHints,
 269    RevealInProjectPanel(ProjectEntryId),
 270    SnippetEdit(BufferId, Vec<(lsp::Range, Snippet)>),
 271}
 272
 273#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
 274pub struct ProjectPath {
 275    pub worktree_id: WorktreeId,
 276    pub path: Arc<Path>,
 277}
 278
 279impl ProjectPath {
 280    pub fn from_proto(p: proto::ProjectPath) -> Self {
 281        Self {
 282            worktree_id: WorktreeId::from_proto(p.worktree_id),
 283            path: Arc::from(PathBuf::from(p.path)),
 284        }
 285    }
 286
 287    pub fn to_proto(&self) -> proto::ProjectPath {
 288        proto::ProjectPath {
 289            worktree_id: self.worktree_id.to_proto(),
 290            path: self.path.to_string_lossy().to_string(),
 291        }
 292    }
 293}
 294
 295#[derive(Debug, Clone, PartialEq, Eq)]
 296pub struct InlayHint {
 297    pub position: language::Anchor,
 298    pub label: InlayHintLabel,
 299    pub kind: Option<InlayHintKind>,
 300    pub padding_left: bool,
 301    pub padding_right: bool,
 302    pub tooltip: Option<InlayHintTooltip>,
 303    pub resolve_state: ResolveState,
 304}
 305
 306/// The user's intent behind a given completion confirmation
 307#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
 308pub enum CompletionIntent {
 309    /// The user intends to 'commit' this result, if possible
 310    /// completion confirmations should run side effects
 311    Complete,
 312    /// The user intends to continue 'composing' this completion
 313    /// completion confirmations should not run side effects and
 314    /// let the user continue composing their action
 315    Compose,
 316}
 317
 318impl CompletionIntent {
 319    pub fn is_complete(&self) -> bool {
 320        self == &Self::Complete
 321    }
 322
 323    pub fn is_compose(&self) -> bool {
 324        self == &Self::Compose
 325    }
 326}
 327
 328/// A completion provided by a language server
 329#[derive(Clone)]
 330pub struct Completion {
 331    /// The range of the buffer that will be replaced.
 332    pub old_range: Range<Anchor>,
 333    /// The new text that will be inserted.
 334    pub new_text: String,
 335    /// A label for this completion that is shown in the menu.
 336    pub label: CodeLabel,
 337    /// The id of the language server that produced this completion.
 338    pub server_id: LanguageServerId,
 339    /// The documentation for this completion.
 340    pub documentation: Option<Documentation>,
 341    /// The raw completion provided by the language server.
 342    pub lsp_completion: lsp::CompletionItem,
 343    /// An optional callback to invoke when this completion is confirmed.
 344    /// Returns, whether new completions should be retriggered after the current one.
 345    /// If `true` is returned, the editor will show a new completion menu after this completion is confirmed.
 346    /// if no confirmation is provided or `false` is returned, the completion will be committed.
 347    pub confirm: Option<Arc<dyn Send + Sync + Fn(CompletionIntent, &mut WindowContext) -> bool>>,
 348}
 349
 350impl std::fmt::Debug for Completion {
 351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 352        f.debug_struct("Completion")
 353            .field("old_range", &self.old_range)
 354            .field("new_text", &self.new_text)
 355            .field("label", &self.label)
 356            .field("server_id", &self.server_id)
 357            .field("documentation", &self.documentation)
 358            .field("lsp_completion", &self.lsp_completion)
 359            .finish()
 360    }
 361}
 362
 363/// A completion provided by a language server
 364#[derive(Clone, Debug)]
 365pub(crate) struct CoreCompletion {
 366    old_range: Range<Anchor>,
 367    new_text: String,
 368    server_id: LanguageServerId,
 369    lsp_completion: lsp::CompletionItem,
 370}
 371
 372/// A code action provided by a language server.
 373#[derive(Clone, Debug)]
 374pub struct CodeAction {
 375    /// The id of the language server that produced this code action.
 376    pub server_id: LanguageServerId,
 377    /// The range of the buffer where this code action is applicable.
 378    pub range: Range<Anchor>,
 379    /// The raw code action provided by the language server.
 380    pub lsp_action: lsp::CodeAction,
 381}
 382
 383#[derive(Debug, Clone, PartialEq, Eq)]
 384pub enum ResolveState {
 385    Resolved,
 386    CanResolve(LanguageServerId, Option<lsp::LSPAny>),
 387    Resolving,
 388}
 389
 390impl InlayHint {
 391    pub fn text(&self) -> String {
 392        match &self.label {
 393            InlayHintLabel::String(s) => s.to_owned(),
 394            InlayHintLabel::LabelParts(parts) => parts.iter().map(|part| &part.value).join(""),
 395        }
 396    }
 397}
 398
 399#[derive(Debug, Clone, PartialEq, Eq)]
 400pub enum InlayHintLabel {
 401    String(String),
 402    LabelParts(Vec<InlayHintLabelPart>),
 403}
 404
 405#[derive(Debug, Clone, PartialEq, Eq)]
 406pub struct InlayHintLabelPart {
 407    pub value: String,
 408    pub tooltip: Option<InlayHintLabelPartTooltip>,
 409    pub location: Option<(LanguageServerId, lsp::Location)>,
 410}
 411
 412#[derive(Debug, Clone, PartialEq, Eq)]
 413pub enum InlayHintTooltip {
 414    String(String),
 415    MarkupContent(MarkupContent),
 416}
 417
 418#[derive(Debug, Clone, PartialEq, Eq)]
 419pub enum InlayHintLabelPartTooltip {
 420    String(String),
 421    MarkupContent(MarkupContent),
 422}
 423
 424#[derive(Debug, Clone, PartialEq, Eq)]
 425pub struct MarkupContent {
 426    pub kind: HoverBlockKind,
 427    pub value: String,
 428}
 429
 430#[derive(Debug, Clone)]
 431pub struct LocationLink {
 432    pub origin: Option<Location>,
 433    pub target: Location,
 434}
 435
 436#[derive(Debug)]
 437pub struct DocumentHighlight {
 438    pub range: Range<language::Anchor>,
 439    pub kind: DocumentHighlightKind,
 440}
 441
 442#[derive(Clone, Debug)]
 443pub struct Symbol {
 444    pub language_server_name: LanguageServerName,
 445    pub source_worktree_id: WorktreeId,
 446    pub path: ProjectPath,
 447    pub label: CodeLabel,
 448    pub name: String,
 449    pub kind: lsp::SymbolKind,
 450    pub range: Range<Unclipped<PointUtf16>>,
 451    pub signature: [u8; 32],
 452}
 453
 454#[derive(Clone, Debug, PartialEq)]
 455pub struct HoverBlock {
 456    pub text: String,
 457    pub kind: HoverBlockKind,
 458}
 459
 460#[derive(Clone, Debug, PartialEq, Eq)]
 461pub enum HoverBlockKind {
 462    PlainText,
 463    Markdown,
 464    Code { language: String },
 465}
 466
 467#[derive(Debug, Clone)]
 468pub struct Hover {
 469    pub contents: Vec<HoverBlock>,
 470    pub range: Option<Range<language::Anchor>>,
 471    pub language: Option<Arc<Language>>,
 472}
 473
 474impl Hover {
 475    pub fn is_empty(&self) -> bool {
 476        self.contents.iter().all(|block| block.text.is_empty())
 477    }
 478}
 479
 480#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 481pub enum FormatTrigger {
 482    Save,
 483    Manual,
 484}
 485
 486// Currently, formatting operations are represented differently depending on
 487// whether they come from a language server or an external command.
 488#[derive(Debug)]
 489enum FormatOperation {
 490    Lsp(Vec<(Range<Anchor>, String)>),
 491    External(Diff),
 492    Prettier(Diff),
 493}
 494
 495impl FormatTrigger {
 496    fn from_proto(value: i32) -> FormatTrigger {
 497        match value {
 498            0 => FormatTrigger::Save,
 499            1 => FormatTrigger::Manual,
 500            _ => FormatTrigger::Save,
 501        }
 502    }
 503}
 504
 505enum EntitySubscription {
 506    Project(PendingEntitySubscription<Project>),
 507    BufferStore(PendingEntitySubscription<BufferStore>),
 508    WorktreeStore(PendingEntitySubscription<WorktreeStore>),
 509    LspStore(PendingEntitySubscription<LspStore>),
 510    SettingsObserver(PendingEntitySubscription<SettingsObserver>),
 511}
 512
 513#[derive(Clone)]
 514pub enum DirectoryLister {
 515    Project(Model<Project>),
 516    Local(Arc<dyn Fs>),
 517}
 518
 519impl DirectoryLister {
 520    pub fn is_local(&self, cx: &AppContext) -> bool {
 521        match self {
 522            DirectoryLister::Local(_) => true,
 523            DirectoryLister::Project(project) => project.read(cx).is_local_or_ssh(),
 524        }
 525    }
 526
 527    pub fn resolve_tilde<'a>(&self, path: &'a String, cx: &AppContext) -> Cow<'a, str> {
 528        if self.is_local(cx) {
 529            shellexpand::tilde(path)
 530        } else {
 531            Cow::from(path)
 532        }
 533    }
 534
 535    pub fn default_query(&self, cx: &mut AppContext) -> String {
 536        if let DirectoryLister::Project(project) = self {
 537            if let Some(worktree) = project.read(cx).visible_worktrees(cx).next() {
 538                return worktree.read(cx).abs_path().to_string_lossy().to_string();
 539            }
 540        };
 541        "~/".to_string()
 542    }
 543
 544    pub fn list_directory(&self, path: String, cx: &mut AppContext) -> Task<Result<Vec<PathBuf>>> {
 545        match self {
 546            DirectoryLister::Project(project) => {
 547                project.update(cx, |project, cx| project.list_directory(path, cx))
 548            }
 549            DirectoryLister::Local(fs) => {
 550                let fs = fs.clone();
 551                cx.background_executor().spawn(async move {
 552                    let mut results = vec![];
 553                    let expanded = shellexpand::tilde(&path);
 554                    let query = Path::new(expanded.as_ref());
 555                    let mut response = fs.read_dir(query).await?;
 556                    while let Some(path) = response.next().await {
 557                        if let Some(file_name) = path?.file_name() {
 558                            results.push(PathBuf::from(file_name.to_os_string()));
 559                        }
 560                    }
 561                    Ok(results)
 562                })
 563            }
 564        }
 565    }
 566}
 567
 568#[cfg(any(test, feature = "test-support"))]
 569pub const DEFAULT_COMPLETION_CONTEXT: CompletionContext = CompletionContext {
 570    trigger_kind: lsp::CompletionTriggerKind::INVOKED,
 571    trigger_character: None,
 572};
 573
 574impl Project {
 575    pub fn init_settings(cx: &mut AppContext) {
 576        WorktreeSettings::register(cx);
 577        ProjectSettings::register(cx);
 578    }
 579
 580    pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
 581        connection_manager::init(client.clone(), cx);
 582        Self::init_settings(cx);
 583
 584        let client: AnyProtoClient = client.clone().into();
 585        client.add_model_message_handler(Self::handle_add_collaborator);
 586        client.add_model_message_handler(Self::handle_update_project_collaborator);
 587        client.add_model_message_handler(Self::handle_remove_collaborator);
 588        client.add_model_message_handler(Self::handle_update_project);
 589        client.add_model_message_handler(Self::handle_unshare_project);
 590        client.add_model_request_handler(Self::handle_update_buffer);
 591        client.add_model_message_handler(Self::handle_update_worktree);
 592        client.add_model_request_handler(Self::handle_reload_buffers);
 593        client.add_model_request_handler(Self::handle_synchronize_buffers);
 594        client.add_model_request_handler(Self::handle_format_buffers);
 595        client.add_model_request_handler(Self::handle_search_project);
 596        client.add_model_request_handler(Self::handle_search_candidate_buffers);
 597        client.add_model_request_handler(Self::handle_open_buffer_by_id);
 598        client.add_model_request_handler(Self::handle_open_buffer_by_path);
 599        client.add_model_request_handler(Self::handle_open_new_buffer);
 600        client.add_model_request_handler(Self::handle_task_context_for_location);
 601        client.add_model_request_handler(Self::handle_task_templates);
 602        client.add_model_message_handler(Self::handle_create_buffer_for_peer);
 603
 604        WorktreeStore::init(&client);
 605        BufferStore::init(&client);
 606        LspStore::init(&client);
 607        SettingsObserver::init(&client);
 608    }
 609
 610    pub fn local(
 611        client: Arc<Client>,
 612        node: Arc<dyn NodeRuntime>,
 613        user_store: Model<UserStore>,
 614        languages: Arc<LanguageRegistry>,
 615        fs: Arc<dyn Fs>,
 616        env: Option<HashMap<String, String>>,
 617        cx: &mut AppContext,
 618    ) -> Model<Self> {
 619        cx.new_model(|cx: &mut ModelContext<Self>| {
 620            let (tx, rx) = mpsc::unbounded();
 621            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
 622                .detach();
 623            let tasks = Inventory::new(cx);
 624            let global_snippets_dir = paths::config_dir().join("snippets");
 625            let snippets =
 626                SnippetProvider::new(fs.clone(), BTreeSet::from_iter([global_snippets_dir]), cx);
 627
 628            let worktree_store = cx.new_model(|_| WorktreeStore::new(false, fs.clone()));
 629            cx.subscribe(&worktree_store, Self::on_worktree_store_event)
 630                .detach();
 631
 632            let buffer_store =
 633                cx.new_model(|cx| BufferStore::new(worktree_store.clone(), None, cx));
 634            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
 635                .detach();
 636
 637            let settings_observer = cx.new_model(|cx| {
 638                SettingsObserver::new_local(fs.clone(), worktree_store.clone(), cx)
 639            });
 640
 641            let environment = ProjectEnvironment::new(&worktree_store, env, cx);
 642            let lsp_store = cx.new_model(|cx| {
 643                LspStore::new_local(
 644                    buffer_store.clone(),
 645                    worktree_store.clone(),
 646                    environment.clone(),
 647                    languages.clone(),
 648                    Some(client.http_client()),
 649                    fs.clone(),
 650                    cx,
 651                )
 652            });
 653            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
 654
 655            Self {
 656                buffer_ordered_messages_tx: tx,
 657                collaborators: Default::default(),
 658                worktree_store,
 659                buffer_store,
 660                lsp_store,
 661                current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
 662                join_project_response_message_id: 0,
 663                client_state: ProjectClientState::Local,
 664                client_subscriptions: Vec::new(),
 665                _subscriptions: vec![
 666                    cx.observe_global::<SettingsStore>(Self::on_settings_changed),
 667                    cx.on_release(Self::release),
 668                ],
 669                active_entry: None,
 670                snippets,
 671                languages,
 672                client,
 673                user_store,
 674                settings_observer,
 675                fs,
 676                ssh_session: None,
 677                buffers_needing_diff: Default::default(),
 678                git_diff_debouncer: DebouncedDelay::new(),
 679                terminals: Terminals {
 680                    local_handles: Vec::new(),
 681                },
 682                node: Some(node),
 683                default_prettier: DefaultPrettier::default(),
 684                prettiers_per_worktree: HashMap::default(),
 685                prettier_instances: HashMap::default(),
 686                tasks,
 687                hosted_project_id: None,
 688                dev_server_project_id: None,
 689                search_history: Self::new_search_history(),
 690                environment,
 691                remotely_created_buffers: Default::default(),
 692                last_formatting_failure: None,
 693                buffers_being_formatted: Default::default(),
 694                search_included_history: Self::new_search_history(),
 695                search_excluded_history: Self::new_search_history(),
 696            }
 697        })
 698    }
 699
 700    pub fn ssh(
 701        ssh: Arc<SshSession>,
 702        client: Arc<Client>,
 703        node: Arc<dyn NodeRuntime>,
 704        user_store: Model<UserStore>,
 705        languages: Arc<LanguageRegistry>,
 706        fs: Arc<dyn Fs>,
 707        cx: &mut AppContext,
 708    ) -> Model<Self> {
 709        cx.new_model(|cx: &mut ModelContext<Self>| {
 710            let (tx, rx) = mpsc::unbounded();
 711            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
 712                .detach();
 713            let tasks = Inventory::new(cx);
 714            let global_snippets_dir = paths::config_dir().join("snippets");
 715            let snippets =
 716                SnippetProvider::new(fs.clone(), BTreeSet::from_iter([global_snippets_dir]), cx);
 717
 718            let worktree_store = cx.new_model(|_| {
 719                let mut worktree_store = WorktreeStore::new(false, fs.clone());
 720                worktree_store.set_upstream_client(ssh.clone().into());
 721                worktree_store
 722            });
 723            cx.subscribe(&worktree_store, Self::on_worktree_store_event)
 724                .detach();
 725
 726            let buffer_store =
 727                cx.new_model(|cx| BufferStore::new(worktree_store.clone(), None, cx));
 728            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
 729                .detach();
 730
 731            let settings_observer = cx.new_model(|cx| {
 732                SettingsObserver::new_ssh(ssh.clone().into(), worktree_store.clone(), cx)
 733            });
 734
 735            let environment = ProjectEnvironment::new(&worktree_store, None, cx);
 736            let lsp_store = cx.new_model(|cx| {
 737                LspStore::new_ssh(
 738                    buffer_store.clone(),
 739                    worktree_store.clone(),
 740                    languages.clone(),
 741                    ssh.clone().into(),
 742                    0,
 743                    cx,
 744                )
 745            });
 746            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
 747
 748            let this = Self {
 749                buffer_ordered_messages_tx: tx,
 750                collaborators: Default::default(),
 751                worktree_store,
 752                buffer_store,
 753                lsp_store,
 754                current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
 755                join_project_response_message_id: 0,
 756                client_state: ProjectClientState::Local,
 757                client_subscriptions: Vec::new(),
 758                _subscriptions: vec![
 759                    cx.observe_global::<SettingsStore>(Self::on_settings_changed),
 760                    cx.on_release(Self::release),
 761                ],
 762                active_entry: None,
 763                snippets,
 764                languages,
 765                client,
 766                user_store,
 767                settings_observer,
 768                fs,
 769                ssh_session: Some(ssh.clone()),
 770                buffers_needing_diff: Default::default(),
 771                git_diff_debouncer: DebouncedDelay::new(),
 772                terminals: Terminals {
 773                    local_handles: Vec::new(),
 774                },
 775                node: Some(node),
 776                default_prettier: DefaultPrettier::default(),
 777                prettiers_per_worktree: HashMap::default(),
 778                prettier_instances: HashMap::default(),
 779                tasks,
 780                hosted_project_id: None,
 781                dev_server_project_id: None,
 782                search_history: Self::new_search_history(),
 783                environment,
 784                remotely_created_buffers: Default::default(),
 785                last_formatting_failure: None,
 786                buffers_being_formatted: Default::default(),
 787                search_included_history: Self::new_search_history(),
 788                search_excluded_history: Self::new_search_history(),
 789            };
 790
 791            let client: AnyProtoClient = ssh.clone().into();
 792
 793            ssh.subscribe_to_entity(SSH_PROJECT_ID, &cx.handle());
 794            ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.buffer_store);
 795            ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.worktree_store);
 796            ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.lsp_store);
 797            ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.settings_observer);
 798            client.add_model_message_handler(Self::handle_update_worktree);
 799            client.add_model_message_handler(Self::handle_create_buffer_for_peer);
 800            client.add_model_request_handler(BufferStore::handle_update_buffer);
 801            BufferStore::init(&client);
 802            LspStore::init(&client);
 803            SettingsObserver::init(&client);
 804
 805            this
 806        })
 807    }
 808
 809    pub async fn remote(
 810        remote_id: u64,
 811        client: Arc<Client>,
 812        user_store: Model<UserStore>,
 813        languages: Arc<LanguageRegistry>,
 814        fs: Arc<dyn Fs>,
 815        cx: AsyncAppContext,
 816    ) -> Result<Model<Self>> {
 817        let project =
 818            Self::in_room(remote_id, client, user_store, languages, fs, cx.clone()).await?;
 819        cx.update(|cx| {
 820            connection_manager::Manager::global(cx).update(cx, |manager, cx| {
 821                manager.maintain_project_connection(&project, cx)
 822            })
 823        })?;
 824        Ok(project)
 825    }
 826
 827    pub async fn in_room(
 828        remote_id: u64,
 829        client: Arc<Client>,
 830        user_store: Model<UserStore>,
 831        languages: Arc<LanguageRegistry>,
 832        fs: Arc<dyn Fs>,
 833        cx: AsyncAppContext,
 834    ) -> Result<Model<Self>> {
 835        client.authenticate_and_connect(true, &cx).await?;
 836
 837        let subscriptions = [
 838            EntitySubscription::Project(client.subscribe_to_entity::<Self>(remote_id)?),
 839            EntitySubscription::BufferStore(client.subscribe_to_entity::<BufferStore>(remote_id)?),
 840            EntitySubscription::WorktreeStore(
 841                client.subscribe_to_entity::<WorktreeStore>(remote_id)?,
 842            ),
 843            EntitySubscription::LspStore(client.subscribe_to_entity::<LspStore>(remote_id)?),
 844            EntitySubscription::SettingsObserver(
 845                client.subscribe_to_entity::<SettingsObserver>(remote_id)?,
 846            ),
 847        ];
 848        let response = client
 849            .request_envelope(proto::JoinProject {
 850                project_id: remote_id,
 851            })
 852            .await?;
 853        Self::from_join_project_response(
 854            response,
 855            subscriptions,
 856            client,
 857            user_store,
 858            languages,
 859            fs,
 860            cx,
 861        )
 862        .await
 863    }
 864
 865    async fn from_join_project_response(
 866        response: TypedEnvelope<proto::JoinProjectResponse>,
 867        subscriptions: [EntitySubscription; 5],
 868        client: Arc<Client>,
 869        user_store: Model<UserStore>,
 870        languages: Arc<LanguageRegistry>,
 871        fs: Arc<dyn Fs>,
 872        mut cx: AsyncAppContext,
 873    ) -> Result<Model<Self>> {
 874        let remote_id = response.payload.project_id;
 875        let role = response.payload.role();
 876
 877        let worktree_store = cx.new_model(|_| {
 878            let mut store = WorktreeStore::new(true, fs.clone());
 879            store.set_upstream_client(client.clone().into());
 880            if let Some(dev_server_project_id) = response.payload.dev_server_project_id {
 881                store.set_dev_server_project_id(DevServerProjectId(dev_server_project_id));
 882            }
 883            store
 884        })?;
 885        let buffer_store =
 886            cx.new_model(|cx| BufferStore::new(worktree_store.clone(), Some(remote_id), cx))?;
 887
 888        let lsp_store = cx.new_model(|cx| {
 889            let mut lsp_store = LspStore::new_remote(
 890                buffer_store.clone(),
 891                worktree_store.clone(),
 892                languages.clone(),
 893                client.clone().into(),
 894                remote_id,
 895                cx,
 896            );
 897            lsp_store.set_language_server_statuses_from_proto(response.payload.language_servers);
 898            lsp_store
 899        })?;
 900
 901        let settings_observer =
 902            cx.new_model(|cx| SettingsObserver::new_remote(worktree_store.clone(), cx))?;
 903
 904        let this = cx.new_model(|cx| {
 905            let replica_id = response.payload.replica_id as ReplicaId;
 906            let tasks = Inventory::new(cx);
 907            let global_snippets_dir = paths::config_dir().join("snippets");
 908            let snippets =
 909                SnippetProvider::new(fs.clone(), BTreeSet::from_iter([global_snippets_dir]), cx);
 910
 911            let mut worktrees = Vec::new();
 912            for worktree in response.payload.worktrees {
 913                let worktree =
 914                    Worktree::remote(remote_id, replica_id, worktree, client.clone().into(), cx);
 915                worktrees.push(worktree);
 916            }
 917
 918            let (tx, rx) = mpsc::unbounded();
 919            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
 920                .detach();
 921
 922            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
 923                .detach();
 924            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
 925
 926            let mut this = Self {
 927                buffer_ordered_messages_tx: tx,
 928                buffer_store: buffer_store.clone(),
 929                worktree_store: worktree_store.clone(),
 930                lsp_store: lsp_store.clone(),
 931                current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
 932                active_entry: None,
 933                collaborators: Default::default(),
 934                join_project_response_message_id: response.message_id,
 935                languages,
 936                user_store: user_store.clone(),
 937                snippets,
 938                fs,
 939                ssh_session: None,
 940                settings_observer: settings_observer.clone(),
 941                client_subscriptions: Default::default(),
 942                _subscriptions: vec![cx.on_release(Self::release)],
 943                client: client.clone(),
 944                client_state: ProjectClientState::Remote {
 945                    sharing_has_stopped: false,
 946                    capability: Capability::ReadWrite,
 947                    remote_id,
 948                    replica_id,
 949                    in_room: response.payload.dev_server_project_id.is_none(),
 950                },
 951                buffers_needing_diff: Default::default(),
 952                git_diff_debouncer: DebouncedDelay::new(),
 953                terminals: Terminals {
 954                    local_handles: Vec::new(),
 955                },
 956                node: None,
 957                default_prettier: DefaultPrettier::default(),
 958                prettiers_per_worktree: HashMap::default(),
 959                prettier_instances: HashMap::default(),
 960                tasks,
 961                hosted_project_id: None,
 962                dev_server_project_id: response
 963                    .payload
 964                    .dev_server_project_id
 965                    .map(DevServerProjectId),
 966                search_history: Self::new_search_history(),
 967                search_included_history: Self::new_search_history(),
 968                search_excluded_history: Self::new_search_history(),
 969                environment: ProjectEnvironment::new(&worktree_store, None, cx),
 970                remotely_created_buffers: Arc::new(Mutex::new(RemotelyCreatedBuffers::default())),
 971                last_formatting_failure: None,
 972                buffers_being_formatted: Default::default(),
 973            };
 974            this.set_role(role, cx);
 975            for worktree in worktrees {
 976                this.add_worktree(&worktree, cx);
 977            }
 978            this
 979        })?;
 980
 981        let subscriptions = subscriptions
 982            .into_iter()
 983            .map(|s| match s {
 984                EntitySubscription::BufferStore(subscription) => {
 985                    subscription.set_model(&buffer_store, &mut cx)
 986                }
 987                EntitySubscription::WorktreeStore(subscription) => {
 988                    subscription.set_model(&worktree_store, &mut cx)
 989                }
 990                EntitySubscription::SettingsObserver(subscription) => {
 991                    subscription.set_model(&settings_observer, &mut cx)
 992                }
 993                EntitySubscription::Project(subscription) => subscription.set_model(&this, &mut cx),
 994                EntitySubscription::LspStore(subscription) => {
 995                    subscription.set_model(&lsp_store, &mut cx)
 996                }
 997            })
 998            .collect::<Vec<_>>();
 999
1000        let user_ids = response
1001            .payload
1002            .collaborators
1003            .iter()
1004            .map(|peer| peer.user_id)
1005            .collect();
1006        user_store
1007            .update(&mut cx, |user_store, cx| user_store.get_users(user_ids, cx))?
1008            .await?;
1009
1010        this.update(&mut cx, |this, cx| {
1011            this.set_collaborators_from_proto(response.payload.collaborators, cx)?;
1012            this.client_subscriptions.extend(subscriptions);
1013            anyhow::Ok(())
1014        })??;
1015
1016        Ok(this)
1017    }
1018
1019    pub async fn hosted(
1020        remote_id: ProjectId,
1021        user_store: Model<UserStore>,
1022        client: Arc<Client>,
1023        languages: Arc<LanguageRegistry>,
1024        fs: Arc<dyn Fs>,
1025        cx: AsyncAppContext,
1026    ) -> Result<Model<Self>> {
1027        client.authenticate_and_connect(true, &cx).await?;
1028
1029        let subscriptions = [
1030            EntitySubscription::Project(client.subscribe_to_entity::<Self>(remote_id.0)?),
1031            EntitySubscription::BufferStore(
1032                client.subscribe_to_entity::<BufferStore>(remote_id.0)?,
1033            ),
1034            EntitySubscription::WorktreeStore(
1035                client.subscribe_to_entity::<WorktreeStore>(remote_id.0)?,
1036            ),
1037            EntitySubscription::LspStore(client.subscribe_to_entity::<LspStore>(remote_id.0)?),
1038            EntitySubscription::SettingsObserver(
1039                client.subscribe_to_entity::<SettingsObserver>(remote_id.0)?,
1040            ),
1041        ];
1042        let response = client
1043            .request_envelope(proto::JoinHostedProject {
1044                project_id: remote_id.0,
1045            })
1046            .await?;
1047        Self::from_join_project_response(
1048            response,
1049            subscriptions,
1050            client,
1051            user_store,
1052            languages,
1053            fs,
1054            cx,
1055        )
1056        .await
1057    }
1058
1059    fn new_search_history() -> SearchHistory {
1060        SearchHistory::new(
1061            Some(MAX_PROJECT_SEARCH_HISTORY_SIZE),
1062            search_history::QueryInsertionBehavior::AlwaysInsert,
1063        )
1064    }
1065
1066    fn release(&mut self, cx: &mut AppContext) {
1067        match &self.client_state {
1068            ProjectClientState::Local => {}
1069            ProjectClientState::Shared { .. } => {
1070                let _ = self.unshare_internal(cx);
1071            }
1072            ProjectClientState::Remote { remote_id, .. } => {
1073                let _ = self.client.send(proto::LeaveProject {
1074                    project_id: *remote_id,
1075                });
1076                self.disconnected_from_host_internal(cx);
1077            }
1078        }
1079    }
1080
1081    #[cfg(any(test, feature = "test-support"))]
1082    pub async fn example(
1083        root_paths: impl IntoIterator<Item = &Path>,
1084        cx: &mut AsyncAppContext,
1085    ) -> Model<Project> {
1086        use clock::FakeSystemClock;
1087
1088        let fs = Arc::new(RealFs::default());
1089        let languages = LanguageRegistry::test(cx.background_executor().clone());
1090        let clock = Arc::new(FakeSystemClock::default());
1091        let http_client = http_client::FakeHttpClient::with_404_response();
1092        let client = cx
1093            .update(|cx| client::Client::new(clock, http_client.clone(), cx))
1094            .unwrap();
1095        let user_store = cx
1096            .new_model(|cx| UserStore::new(client.clone(), cx))
1097            .unwrap();
1098        let project = cx
1099            .update(|cx| {
1100                Project::local(
1101                    client,
1102                    node_runtime::FakeNodeRuntime::new(),
1103                    user_store,
1104                    Arc::new(languages),
1105                    fs,
1106                    None,
1107                    cx,
1108                )
1109            })
1110            .unwrap();
1111        for path in root_paths {
1112            let (tree, _) = project
1113                .update(cx, |project, cx| {
1114                    project.find_or_create_worktree(path, true, cx)
1115                })
1116                .unwrap()
1117                .await
1118                .unwrap();
1119            tree.update(cx, |tree, _| tree.as_local().unwrap().scan_complete())
1120                .unwrap()
1121                .await;
1122        }
1123        project
1124    }
1125
1126    #[cfg(any(test, feature = "test-support"))]
1127    pub async fn test(
1128        fs: Arc<dyn Fs>,
1129        root_paths: impl IntoIterator<Item = &Path>,
1130        cx: &mut gpui::TestAppContext,
1131    ) -> Model<Project> {
1132        use clock::FakeSystemClock;
1133
1134        let languages = LanguageRegistry::test(cx.executor());
1135        let clock = Arc::new(FakeSystemClock::default());
1136        let http_client = http_client::FakeHttpClient::with_404_response();
1137        let client = cx.update(|cx| client::Client::new(clock, http_client.clone(), cx));
1138        let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx));
1139        let project = cx.update(|cx| {
1140            Project::local(
1141                client,
1142                node_runtime::FakeNodeRuntime::new(),
1143                user_store,
1144                Arc::new(languages),
1145                fs,
1146                None,
1147                cx,
1148            )
1149        });
1150        for path in root_paths {
1151            let (tree, _) = project
1152                .update(cx, |project, cx| {
1153                    project.find_or_create_worktree(path, true, cx)
1154                })
1155                .await
1156                .unwrap();
1157
1158            project.update(cx, |project, cx| {
1159                let tree_id = tree.read(cx).id();
1160                project.environment.update(cx, |environment, _| {
1161                    environment.set_cached(&[(tree_id, HashMap::default())])
1162                });
1163            });
1164
1165            tree.update(cx, |tree, _| tree.as_local().unwrap().scan_complete())
1166                .await;
1167        }
1168        project
1169    }
1170
1171    pub fn lsp_store(&self) -> Model<LspStore> {
1172        self.lsp_store.clone()
1173    }
1174
1175    pub fn worktree_store(&self) -> Model<WorktreeStore> {
1176        self.worktree_store.clone()
1177    }
1178
1179    fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
1180        let mut language_servers_to_start = Vec::new();
1181        let mut language_formatters_to_check = Vec::new();
1182        for buffer in self.buffer_store.read(cx).buffers() {
1183            let buffer = buffer.read(cx);
1184            let buffer_file = File::from_dyn(buffer.file());
1185            let buffer_language = buffer.language();
1186            let settings = language_settings(buffer_language, buffer.file(), cx);
1187            if let Some(language) = buffer_language {
1188                if settings.enable_language_server {
1189                    if let Some(file) = buffer_file {
1190                        language_servers_to_start.push((file.worktree.clone(), language.name()));
1191                    }
1192                }
1193                language_formatters_to_check
1194                    .push((buffer_file.map(|f| f.worktree_id(cx)), settings.clone()));
1195            }
1196        }
1197
1198        let mut language_servers_to_stop = Vec::new();
1199        let mut language_servers_to_restart = Vec::new();
1200        let languages = self.languages.to_vec();
1201
1202        let new_lsp_settings = ProjectSettings::get_global(cx).lsp.clone();
1203        let current_lsp_settings = &self.current_lsp_settings;
1204        for (worktree_id, started_lsp_name) in self.lsp_store.read(cx).started_language_servers() {
1205            let language = languages.iter().find_map(|l| {
1206                let adapter = self
1207                    .languages
1208                    .lsp_adapters(&l.name())
1209                    .iter()
1210                    .find(|adapter| adapter.name == started_lsp_name)?
1211                    .clone();
1212                Some((l, adapter))
1213            });
1214            if let Some((language, adapter)) = language {
1215                let worktree = self.worktree_for_id(worktree_id, cx);
1216                let file = worktree.as_ref().and_then(|tree| {
1217                    tree.update(cx, |tree, cx| tree.root_file(cx).map(|f| f as _))
1218                });
1219                if !language_settings(Some(language), file.as_ref(), cx).enable_language_server {
1220                    language_servers_to_stop.push((worktree_id, started_lsp_name.clone()));
1221                } else if let Some(worktree) = worktree {
1222                    let server_name = &adapter.name.0;
1223                    match (
1224                        current_lsp_settings.get(server_name),
1225                        new_lsp_settings.get(server_name),
1226                    ) {
1227                        (None, None) => {}
1228                        (Some(_), None) | (None, Some(_)) => {
1229                            language_servers_to_restart.push((worktree, language.name()));
1230                        }
1231                        (Some(current_lsp_settings), Some(new_lsp_settings)) => {
1232                            if current_lsp_settings != new_lsp_settings {
1233                                language_servers_to_restart.push((worktree, language.name()));
1234                            }
1235                        }
1236                    }
1237                }
1238            }
1239        }
1240        self.current_lsp_settings = new_lsp_settings;
1241
1242        // Stop all newly-disabled language servers.
1243        self.lsp_store.update(cx, |lsp_store, cx| {
1244            for (worktree_id, adapter_name) in language_servers_to_stop {
1245                lsp_store
1246                    .stop_language_server(worktree_id, adapter_name, cx)
1247                    .detach();
1248            }
1249        });
1250
1251        let mut prettier_plugins_by_worktree = HashMap::default();
1252        for (worktree, language_settings) in language_formatters_to_check {
1253            if let Some(plugins) =
1254                prettier_support::prettier_plugins_for_language(&language_settings)
1255            {
1256                prettier_plugins_by_worktree
1257                    .entry(worktree)
1258                    .or_insert_with(HashSet::default)
1259                    .extend(plugins.iter().cloned());
1260            }
1261        }
1262        for (worktree, prettier_plugins) in prettier_plugins_by_worktree {
1263            self.install_default_prettier(
1264                worktree,
1265                prettier_plugins.into_iter().map(Arc::from),
1266                cx,
1267            );
1268        }
1269
1270        // Start all the newly-enabled language servers.
1271        self.lsp_store.update(cx, |lsp_store, cx| {
1272            for (worktree, language) in language_servers_to_start {
1273                lsp_store.start_language_servers(&worktree, language, cx);
1274            }
1275
1276            // Restart all language servers with changed initialization options.
1277            for (worktree, language) in language_servers_to_restart {
1278                lsp_store.restart_language_servers(worktree, language, cx);
1279            }
1280        });
1281
1282        cx.notify();
1283    }
1284
1285    pub fn buffer_for_id(&self, remote_id: BufferId, cx: &AppContext) -> Option<Model<Buffer>> {
1286        self.buffer_store.read(cx).get(remote_id)
1287    }
1288
1289    pub fn languages(&self) -> &Arc<LanguageRegistry> {
1290        &self.languages
1291    }
1292
1293    pub fn client(&self) -> Arc<Client> {
1294        self.client.clone()
1295    }
1296
1297    pub fn user_store(&self) -> Model<UserStore> {
1298        self.user_store.clone()
1299    }
1300
1301    pub fn node_runtime(&self) -> Option<&Arc<dyn NodeRuntime>> {
1302        self.node.as_ref()
1303    }
1304
1305    pub fn opened_buffers(&self, cx: &AppContext) -> Vec<Model<Buffer>> {
1306        self.buffer_store.read(cx).buffers().collect()
1307    }
1308
1309    pub fn cli_environment(&self, cx: &AppContext) -> Option<HashMap<String, String>> {
1310        self.environment.read(cx).get_cli_environment()
1311    }
1312
1313    #[cfg(any(test, feature = "test-support"))]
1314    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
1315        self.buffer_store
1316            .read(cx)
1317            .get_by_path(&path.into(), cx)
1318            .is_some()
1319    }
1320
1321    pub fn fs(&self) -> &Arc<dyn Fs> {
1322        &self.fs
1323    }
1324
1325    pub fn remote_id(&self) -> Option<u64> {
1326        match self.client_state {
1327            ProjectClientState::Local => None,
1328            ProjectClientState::Shared { remote_id, .. }
1329            | ProjectClientState::Remote { remote_id, .. } => Some(remote_id),
1330        }
1331    }
1332
1333    pub fn hosted_project_id(&self) -> Option<ProjectId> {
1334        self.hosted_project_id
1335    }
1336
1337    pub fn dev_server_project_id(&self) -> Option<DevServerProjectId> {
1338        self.dev_server_project_id
1339    }
1340
1341    pub fn supports_remote_terminal(&self, cx: &AppContext) -> bool {
1342        let Some(id) = self.dev_server_project_id else {
1343            return false;
1344        };
1345        let Some(server) = dev_server_projects::Store::global(cx)
1346            .read(cx)
1347            .dev_server_for_project(id)
1348        else {
1349            return false;
1350        };
1351        server.ssh_connection_string.is_some()
1352    }
1353
1354    pub fn ssh_connection_string(&self, cx: &ModelContext<Self>) -> Option<SharedString> {
1355        if self.is_local_or_ssh() {
1356            return None;
1357        }
1358
1359        let dev_server_id = self.dev_server_project_id()?;
1360        dev_server_projects::Store::global(cx)
1361            .read(cx)
1362            .dev_server_for_project(dev_server_id)?
1363            .ssh_connection_string
1364            .clone()
1365    }
1366
1367    pub fn replica_id(&self) -> ReplicaId {
1368        match self.client_state {
1369            ProjectClientState::Remote { replica_id, .. } => replica_id,
1370            _ => {
1371                if self.ssh_session.is_some() {
1372                    1
1373                } else {
1374                    0
1375                }
1376            }
1377        }
1378    }
1379
1380    fn metadata_changed(&mut self, cx: &mut ModelContext<Self>) {
1381        cx.notify();
1382
1383        let ProjectClientState::Shared { remote_id } = self.client_state else {
1384            return;
1385        };
1386        let project_id = remote_id;
1387
1388        let update_project = self.client.request(proto::UpdateProject {
1389            project_id,
1390            worktrees: self.worktree_metadata_protos(cx),
1391        });
1392        cx.spawn(|this, mut cx| async move {
1393            update_project.await?;
1394            this.update(&mut cx, |this, cx| {
1395                let client = this.client.clone();
1396                let worktrees = this.worktree_store.read(cx).worktrees().collect::<Vec<_>>();
1397
1398                for worktree in worktrees {
1399                    worktree.update(cx, |worktree, cx| {
1400                        let client = client.clone();
1401                        worktree.observe_updates(project_id, cx, {
1402                            move |update| client.request(update).map(|result| result.is_ok())
1403                        });
1404
1405                        this.lsp_store.update(cx, |lsp_store, _| {
1406                            lsp_store.send_diagnostic_summaries(worktree)
1407                        })
1408                    })?;
1409                }
1410
1411                anyhow::Ok(())
1412            })
1413        })
1414        .detach_and_log_err(cx);
1415    }
1416
1417    pub fn task_inventory(&self) -> &Model<Inventory> {
1418        &self.tasks
1419    }
1420
1421    pub fn snippets(&self) -> &Model<SnippetProvider> {
1422        &self.snippets
1423    }
1424
1425    pub fn search_history(&self, kind: SearchInputKind) -> &SearchHistory {
1426        match kind {
1427            SearchInputKind::Query => &self.search_history,
1428            SearchInputKind::Include => &self.search_included_history,
1429            SearchInputKind::Exclude => &self.search_excluded_history,
1430        }
1431    }
1432
1433    pub fn search_history_mut(&mut self, kind: SearchInputKind) -> &mut SearchHistory {
1434        match kind {
1435            SearchInputKind::Query => &mut self.search_history,
1436            SearchInputKind::Include => &mut self.search_included_history,
1437            SearchInputKind::Exclude => &mut self.search_excluded_history,
1438        }
1439    }
1440
1441    pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> {
1442        &self.collaborators
1443    }
1444
1445    pub fn host(&self) -> Option<&Collaborator> {
1446        self.collaborators.values().find(|c| c.replica_id == 0)
1447    }
1448
1449    pub fn set_worktrees_reordered(&mut self, worktrees_reordered: bool, cx: &mut AppContext) {
1450        self.worktree_store.update(cx, |store, _| {
1451            store.set_worktrees_reordered(worktrees_reordered);
1452        });
1453    }
1454
1455    /// Collect all worktrees, including ones that don't appear in the project panel
1456    pub fn worktrees<'a>(
1457        &self,
1458        cx: &'a AppContext,
1459    ) -> impl 'a + DoubleEndedIterator<Item = Model<Worktree>> {
1460        self.worktree_store.read(cx).worktrees()
1461    }
1462
1463    /// Collect all user-visible worktrees, the ones that appear in the project panel.
1464    pub fn visible_worktrees<'a>(
1465        &'a self,
1466        cx: &'a AppContext,
1467    ) -> impl 'a + DoubleEndedIterator<Item = Model<Worktree>> {
1468        self.worktree_store.read(cx).visible_worktrees(cx)
1469    }
1470
1471    pub fn worktree_root_names<'a>(&'a self, cx: &'a AppContext) -> impl Iterator<Item = &'a str> {
1472        self.visible_worktrees(cx)
1473            .map(|tree| tree.read(cx).root_name())
1474    }
1475
1476    pub fn worktree_for_id(&self, id: WorktreeId, cx: &AppContext) -> Option<Model<Worktree>> {
1477        self.worktree_store.read(cx).worktree_for_id(id, cx)
1478    }
1479
1480    pub fn worktree_for_entry(
1481        &self,
1482        entry_id: ProjectEntryId,
1483        cx: &AppContext,
1484    ) -> Option<Model<Worktree>> {
1485        self.worktree_store
1486            .read(cx)
1487            .worktree_for_entry(entry_id, cx)
1488    }
1489
1490    pub fn worktree_id_for_entry(
1491        &self,
1492        entry_id: ProjectEntryId,
1493        cx: &AppContext,
1494    ) -> Option<WorktreeId> {
1495        self.worktree_for_entry(entry_id, cx)
1496            .map(|worktree| worktree.read(cx).id())
1497    }
1498
1499    /// Checks if the entry is the root of a worktree.
1500    pub fn entry_is_worktree_root(&self, entry_id: ProjectEntryId, cx: &AppContext) -> bool {
1501        self.worktree_for_entry(entry_id, cx)
1502            .map(|worktree| {
1503                worktree
1504                    .read(cx)
1505                    .root_entry()
1506                    .is_some_and(|e| e.id == entry_id)
1507            })
1508            .unwrap_or(false)
1509    }
1510
1511    pub fn visibility_for_paths(&self, paths: &[PathBuf], cx: &AppContext) -> Option<bool> {
1512        paths
1513            .iter()
1514            .map(|path| self.visibility_for_path(path, cx))
1515            .max()
1516            .flatten()
1517    }
1518
1519    pub fn visibility_for_path(&self, path: &Path, cx: &AppContext) -> Option<bool> {
1520        self.worktrees(cx)
1521            .filter_map(|worktree| {
1522                let worktree = worktree.read(cx);
1523                worktree
1524                    .as_local()?
1525                    .contains_abs_path(path)
1526                    .then(|| worktree.is_visible())
1527            })
1528            .max()
1529    }
1530
1531    pub fn create_entry(
1532        &mut self,
1533        project_path: impl Into<ProjectPath>,
1534        is_directory: bool,
1535        cx: &mut ModelContext<Self>,
1536    ) -> Task<Result<CreatedEntry>> {
1537        let project_path = project_path.into();
1538        let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) else {
1539            return Task::ready(Err(anyhow!(format!(
1540                "No worktree for path {project_path:?}"
1541            ))));
1542        };
1543        worktree.update(cx, |worktree, cx| {
1544            worktree.create_entry(project_path.path, is_directory, cx)
1545        })
1546    }
1547
1548    pub fn copy_entry(
1549        &mut self,
1550        entry_id: ProjectEntryId,
1551        relative_worktree_source_path: Option<PathBuf>,
1552        new_path: impl Into<Arc<Path>>,
1553        cx: &mut ModelContext<Self>,
1554    ) -> Task<Result<Option<Entry>>> {
1555        let Some(worktree) = self.worktree_for_entry(entry_id, cx) else {
1556            return Task::ready(Ok(None));
1557        };
1558        worktree.update(cx, |worktree, cx| {
1559            worktree.copy_entry(entry_id, relative_worktree_source_path, new_path, cx)
1560        })
1561    }
1562
1563    pub fn rename_entry(
1564        &mut self,
1565        entry_id: ProjectEntryId,
1566        new_path: impl Into<Arc<Path>>,
1567        cx: &mut ModelContext<Self>,
1568    ) -> Task<Result<CreatedEntry>> {
1569        let Some(worktree) = self.worktree_for_entry(entry_id, cx) else {
1570            return Task::ready(Err(anyhow!(format!("No worktree for entry {entry_id:?}"))));
1571        };
1572        worktree.update(cx, |worktree, cx| {
1573            worktree.rename_entry(entry_id, new_path, cx)
1574        })
1575    }
1576
1577    pub fn delete_entry(
1578        &mut self,
1579        entry_id: ProjectEntryId,
1580        trash: bool,
1581        cx: &mut ModelContext<Self>,
1582    ) -> Option<Task<Result<()>>> {
1583        let worktree = self.worktree_for_entry(entry_id, cx)?;
1584        worktree.update(cx, |worktree, cx| {
1585            worktree.delete_entry(entry_id, trash, cx)
1586        })
1587    }
1588
1589    pub fn expand_entry(
1590        &mut self,
1591        worktree_id: WorktreeId,
1592        entry_id: ProjectEntryId,
1593        cx: &mut ModelContext<Self>,
1594    ) -> Option<Task<Result<()>>> {
1595        let worktree = self.worktree_for_id(worktree_id, cx)?;
1596        worktree.update(cx, |worktree, cx| worktree.expand_entry(entry_id, cx))
1597    }
1598
1599    pub fn shared(&mut self, project_id: u64, cx: &mut ModelContext<Self>) -> Result<()> {
1600        if !matches!(self.client_state, ProjectClientState::Local) {
1601            if let ProjectClientState::Remote { in_room, .. } = &mut self.client_state {
1602                if *in_room || self.dev_server_project_id.is_none() {
1603                    return Err(anyhow!("project was already shared"));
1604                } else {
1605                    *in_room = true;
1606                    return Ok(());
1607                }
1608            } else {
1609                return Err(anyhow!("project was already shared"));
1610            }
1611        }
1612        self.client_subscriptions.extend([
1613            self.client
1614                .subscribe_to_entity(project_id)?
1615                .set_model(&cx.handle(), &mut cx.to_async()),
1616            self.client
1617                .subscribe_to_entity(project_id)?
1618                .set_model(&self.worktree_store, &mut cx.to_async()),
1619            self.client
1620                .subscribe_to_entity(project_id)?
1621                .set_model(&self.buffer_store, &mut cx.to_async()),
1622            self.client
1623                .subscribe_to_entity(project_id)?
1624                .set_model(&self.lsp_store, &mut cx.to_async()),
1625            self.client
1626                .subscribe_to_entity(project_id)?
1627                .set_model(&self.settings_observer, &mut cx.to_async()),
1628        ]);
1629
1630        self.buffer_store.update(cx, |buffer_store, cx| {
1631            buffer_store.shared(project_id, self.client.clone().into(), cx)
1632        });
1633        self.worktree_store.update(cx, |worktree_store, cx| {
1634            worktree_store.set_shared(true, cx);
1635        });
1636        self.lsp_store.update(cx, |lsp_store, cx| {
1637            lsp_store.shared(project_id, self.client.clone().into(), cx)
1638        });
1639        self.settings_observer.update(cx, |settings_observer, cx| {
1640            settings_observer.shared(project_id, self.client.clone().into(), cx)
1641        });
1642
1643        self.client_state = ProjectClientState::Shared {
1644            remote_id: project_id,
1645        };
1646
1647        self.metadata_changed(cx);
1648        cx.emit(Event::RemoteIdChanged(Some(project_id)));
1649        cx.notify();
1650        Ok(())
1651    }
1652
1653    pub fn reshared(
1654        &mut self,
1655        message: proto::ResharedProject,
1656        cx: &mut ModelContext<Self>,
1657    ) -> Result<()> {
1658        self.buffer_store
1659            .update(cx, |buffer_store, _| buffer_store.forget_shared_buffers());
1660        self.set_collaborators_from_proto(message.collaborators, cx)?;
1661        self.metadata_changed(cx);
1662        cx.emit(Event::Reshared);
1663        Ok(())
1664    }
1665
1666    pub fn rejoined(
1667        &mut self,
1668        message: proto::RejoinedProject,
1669        message_id: u32,
1670        cx: &mut ModelContext<Self>,
1671    ) -> Result<()> {
1672        cx.update_global::<SettingsStore, _>(|store, cx| {
1673            self.worktree_store.update(cx, |worktree_store, cx| {
1674                for worktree in worktree_store.worktrees() {
1675                    store
1676                        .clear_local_settings(worktree.read(cx).id(), cx)
1677                        .log_err();
1678                }
1679            });
1680        });
1681
1682        self.join_project_response_message_id = message_id;
1683        self.set_worktrees_from_proto(message.worktrees, cx)?;
1684        self.set_collaborators_from_proto(message.collaborators, cx)?;
1685        self.lsp_store.update(cx, |lsp_store, _| {
1686            lsp_store.set_language_server_statuses_from_proto(message.language_servers)
1687        });
1688        self.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
1689            .unwrap();
1690        cx.emit(Event::Rejoined);
1691        cx.notify();
1692        Ok(())
1693    }
1694
1695    pub fn unshare(&mut self, cx: &mut ModelContext<Self>) -> Result<()> {
1696        self.unshare_internal(cx)?;
1697        self.metadata_changed(cx);
1698        cx.notify();
1699        Ok(())
1700    }
1701
1702    fn unshare_internal(&mut self, cx: &mut AppContext) -> Result<()> {
1703        if self.is_via_collab() {
1704            if self.dev_server_project_id().is_some() {
1705                if let ProjectClientState::Remote { in_room, .. } = &mut self.client_state {
1706                    *in_room = false
1707                }
1708                return Ok(());
1709            } else {
1710                return Err(anyhow!("attempted to unshare a remote project"));
1711            }
1712        }
1713
1714        if let ProjectClientState::Shared { remote_id, .. } = self.client_state {
1715            self.client_state = ProjectClientState::Local;
1716            self.collaborators.clear();
1717            self.client_subscriptions.clear();
1718            self.worktree_store.update(cx, |store, cx| {
1719                store.set_shared(false, cx);
1720            });
1721            self.buffer_store.update(cx, |buffer_store, cx| {
1722                buffer_store.forget_shared_buffers();
1723                buffer_store.unshared(cx)
1724            });
1725            self.settings_observer.update(cx, |settings_observer, cx| {
1726                settings_observer.unshared(cx);
1727            });
1728            self.client
1729                .send(proto::UnshareProject {
1730                    project_id: remote_id,
1731                })
1732                .ok();
1733            Ok(())
1734        } else {
1735            Err(anyhow!("attempted to unshare an unshared project"))
1736        }
1737    }
1738
1739    pub fn disconnected_from_host(&mut self, cx: &mut ModelContext<Self>) {
1740        if self.is_disconnected() {
1741            return;
1742        }
1743        self.disconnected_from_host_internal(cx);
1744        cx.emit(Event::DisconnectedFromHost);
1745        cx.notify();
1746    }
1747
1748    pub fn set_role(&mut self, role: proto::ChannelRole, cx: &mut ModelContext<Self>) {
1749        let new_capability =
1750            if role == proto::ChannelRole::Member || role == proto::ChannelRole::Admin {
1751                Capability::ReadWrite
1752            } else {
1753                Capability::ReadOnly
1754            };
1755        if let ProjectClientState::Remote { capability, .. } = &mut self.client_state {
1756            if *capability == new_capability {
1757                return;
1758            }
1759
1760            *capability = new_capability;
1761            for buffer in self.opened_buffers(cx) {
1762                buffer.update(cx, |buffer, cx| buffer.set_capability(new_capability, cx));
1763            }
1764        }
1765    }
1766
1767    fn disconnected_from_host_internal(&mut self, cx: &mut AppContext) {
1768        if let ProjectClientState::Remote {
1769            sharing_has_stopped,
1770            ..
1771        } = &mut self.client_state
1772        {
1773            *sharing_has_stopped = true;
1774            self.collaborators.clear();
1775            self.worktree_store.update(cx, |store, cx| {
1776                store.disconnected_from_host(cx);
1777            });
1778            self.buffer_store.update(cx, |buffer_store, cx| {
1779                buffer_store.disconnected_from_host(cx)
1780            });
1781            self.lsp_store
1782                .update(cx, |lsp_store, _cx| lsp_store.disconnected_from_host());
1783        }
1784    }
1785
1786    pub fn close(&mut self, cx: &mut ModelContext<Self>) {
1787        cx.emit(Event::Closed);
1788    }
1789
1790    pub fn is_disconnected(&self) -> bool {
1791        match &self.client_state {
1792            ProjectClientState::Remote {
1793                sharing_has_stopped,
1794                ..
1795            } => *sharing_has_stopped,
1796            _ => false,
1797        }
1798    }
1799
1800    pub fn capability(&self) -> Capability {
1801        match &self.client_state {
1802            ProjectClientState::Remote { capability, .. } => *capability,
1803            ProjectClientState::Shared { .. } | ProjectClientState::Local => Capability::ReadWrite,
1804        }
1805    }
1806
1807    pub fn is_read_only(&self) -> bool {
1808        self.is_disconnected() || self.capability() == Capability::ReadOnly
1809    }
1810
1811    pub fn is_local(&self) -> bool {
1812        match &self.client_state {
1813            ProjectClientState::Local | ProjectClientState::Shared { .. } => {
1814                self.ssh_session.is_none()
1815            }
1816            ProjectClientState::Remote { .. } => false,
1817        }
1818    }
1819
1820    pub fn is_local_or_ssh(&self) -> bool {
1821        match &self.client_state {
1822            ProjectClientState::Local | ProjectClientState::Shared { .. } => true,
1823            ProjectClientState::Remote { .. } => false,
1824        }
1825    }
1826
1827    pub fn is_via_ssh(&self) -> bool {
1828        match &self.client_state {
1829            ProjectClientState::Local | ProjectClientState::Shared { .. } => {
1830                self.ssh_session.is_some()
1831            }
1832            ProjectClientState::Remote { .. } => false,
1833        }
1834    }
1835
1836    pub fn is_via_collab(&self) -> bool {
1837        match &self.client_state {
1838            ProjectClientState::Local | ProjectClientState::Shared { .. } => false,
1839            ProjectClientState::Remote { .. } => true,
1840        }
1841    }
1842
1843    pub fn create_buffer(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Model<Buffer>>> {
1844        self.buffer_store.update(cx, |buffer_store, cx| {
1845            buffer_store.create_buffer(
1846                if self.is_via_collab() {
1847                    Some((self.client.clone().into(), self.remote_id().unwrap()))
1848                } else {
1849                    None
1850                },
1851                cx,
1852            )
1853        })
1854    }
1855
1856    pub fn create_local_buffer(
1857        &mut self,
1858        text: &str,
1859        language: Option<Arc<Language>>,
1860        cx: &mut ModelContext<Self>,
1861    ) -> Model<Buffer> {
1862        if self.is_via_collab() {
1863            panic!("called create_local_buffer on a remote project")
1864        }
1865        self.buffer_store.update(cx, |buffer_store, cx| {
1866            buffer_store.create_local_buffer(text, language, cx)
1867        })
1868    }
1869
1870    pub fn open_path(
1871        &mut self,
1872        path: ProjectPath,
1873        cx: &mut ModelContext<Self>,
1874    ) -> Task<Result<(Option<ProjectEntryId>, AnyModel)>> {
1875        let task = self.open_buffer(path.clone(), cx);
1876        cx.spawn(move |_, cx| async move {
1877            let buffer = task.await?;
1878            let project_entry_id = buffer.read_with(&cx, |buffer, cx| {
1879                File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
1880            })?;
1881
1882            let buffer: &AnyModel = &buffer;
1883            Ok((project_entry_id, buffer.clone()))
1884        })
1885    }
1886
1887    pub fn open_local_buffer(
1888        &mut self,
1889        abs_path: impl AsRef<Path>,
1890        cx: &mut ModelContext<Self>,
1891    ) -> Task<Result<Model<Buffer>>> {
1892        if let Some((worktree, relative_path)) = self.find_worktree(abs_path.as_ref(), cx) {
1893            self.open_buffer((worktree.read(cx).id(), relative_path), cx)
1894        } else {
1895            Task::ready(Err(anyhow!("no such path")))
1896        }
1897    }
1898
1899    pub fn open_buffer(
1900        &mut self,
1901        path: impl Into<ProjectPath>,
1902        cx: &mut ModelContext<Self>,
1903    ) -> Task<Result<Model<Buffer>>> {
1904        if self.is_via_collab() && self.is_disconnected() {
1905            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
1906        }
1907
1908        self.buffer_store.update(cx, |buffer_store, cx| {
1909            buffer_store.open_buffer(path.into(), cx)
1910        })
1911    }
1912
1913    pub fn open_buffer_by_id(
1914        &mut self,
1915        id: BufferId,
1916        cx: &mut ModelContext<Self>,
1917    ) -> Task<Result<Model<Buffer>>> {
1918        if let Some(buffer) = self.buffer_for_id(id, cx) {
1919            Task::ready(Ok(buffer))
1920        } else if self.is_local_or_ssh() {
1921            Task::ready(Err(anyhow!("buffer {} does not exist", id)))
1922        } else if let Some(project_id) = self.remote_id() {
1923            let request = self.client.request(proto::OpenBufferById {
1924                project_id,
1925                id: id.into(),
1926            });
1927            cx.spawn(move |this, mut cx| async move {
1928                let buffer_id = BufferId::new(request.await?.buffer_id)?;
1929                this.update(&mut cx, |this, cx| {
1930                    this.wait_for_remote_buffer(buffer_id, cx)
1931                })?
1932                .await
1933            })
1934        } else {
1935            Task::ready(Err(anyhow!("cannot open buffer while disconnected")))
1936        }
1937    }
1938
1939    pub fn save_buffers(
1940        &self,
1941        buffers: HashSet<Model<Buffer>>,
1942        cx: &mut ModelContext<Self>,
1943    ) -> Task<Result<()>> {
1944        cx.spawn(move |this, mut cx| async move {
1945            let save_tasks = buffers.into_iter().filter_map(|buffer| {
1946                this.update(&mut cx, |this, cx| this.save_buffer(buffer, cx))
1947                    .ok()
1948            });
1949            try_join_all(save_tasks).await?;
1950            Ok(())
1951        })
1952    }
1953
1954    pub fn save_buffer(
1955        &self,
1956        buffer: Model<Buffer>,
1957        cx: &mut ModelContext<Self>,
1958    ) -> Task<Result<()>> {
1959        self.buffer_store
1960            .update(cx, |buffer_store, cx| buffer_store.save_buffer(buffer, cx))
1961    }
1962
1963    pub fn save_buffer_as(
1964        &mut self,
1965        buffer: Model<Buffer>,
1966        path: ProjectPath,
1967        cx: &mut ModelContext<Self>,
1968    ) -> Task<Result<()>> {
1969        self.buffer_store.update(cx, |buffer_store, cx| {
1970            buffer_store.save_buffer_as(buffer.clone(), path, cx)
1971        })
1972    }
1973
1974    pub fn get_open_buffer(
1975        &mut self,
1976        path: &ProjectPath,
1977        cx: &mut ModelContext<Self>,
1978    ) -> Option<Model<Buffer>> {
1979        self.buffer_store.read(cx).get_by_path(path, cx)
1980    }
1981
1982    fn register_buffer(
1983        &mut self,
1984        buffer: &Model<Buffer>,
1985        cx: &mut ModelContext<Self>,
1986    ) -> Result<()> {
1987        {
1988            let mut remotely_created_buffers = self.remotely_created_buffers.lock();
1989            if remotely_created_buffers.retain_count > 0 {
1990                remotely_created_buffers.buffers.push(buffer.clone())
1991            }
1992        }
1993
1994        self.request_buffer_diff_recalculation(buffer, cx);
1995
1996        cx.subscribe(buffer, |this, buffer, event, cx| {
1997            this.on_buffer_event(buffer, event, cx);
1998        })
1999        .detach();
2000
2001        Ok(())
2002    }
2003
2004    async fn send_buffer_ordered_messages(
2005        this: WeakModel<Self>,
2006        rx: UnboundedReceiver<BufferOrderedMessage>,
2007        mut cx: AsyncAppContext,
2008    ) -> Result<()> {
2009        const MAX_BATCH_SIZE: usize = 128;
2010
2011        let mut operations_by_buffer_id = HashMap::default();
2012        async fn flush_operations(
2013            this: &WeakModel<Project>,
2014            operations_by_buffer_id: &mut HashMap<BufferId, Vec<proto::Operation>>,
2015            needs_resync_with_host: &mut bool,
2016            is_local: bool,
2017            cx: &mut AsyncAppContext,
2018        ) -> Result<()> {
2019            for (buffer_id, operations) in operations_by_buffer_id.drain() {
2020                let request = this.update(cx, |this, _| {
2021                    let project_id = this.remote_id()?;
2022                    Some(this.client.request(proto::UpdateBuffer {
2023                        buffer_id: buffer_id.into(),
2024                        project_id,
2025                        operations,
2026                    }))
2027                })?;
2028                if let Some(request) = request {
2029                    if request.await.is_err() && !is_local {
2030                        *needs_resync_with_host = true;
2031                        break;
2032                    }
2033                }
2034            }
2035            Ok(())
2036        }
2037
2038        let mut needs_resync_with_host = false;
2039        let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
2040
2041        while let Some(changes) = changes.next().await {
2042            let is_local = this.update(&mut cx, |this, _| this.is_local_or_ssh())?;
2043
2044            for change in changes {
2045                match change {
2046                    BufferOrderedMessage::Operation {
2047                        buffer_id,
2048                        operation,
2049                    } => {
2050                        if needs_resync_with_host {
2051                            continue;
2052                        }
2053
2054                        operations_by_buffer_id
2055                            .entry(buffer_id)
2056                            .or_insert(Vec::new())
2057                            .push(operation);
2058                    }
2059
2060                    BufferOrderedMessage::Resync => {
2061                        operations_by_buffer_id.clear();
2062                        if this
2063                            .update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx))?
2064                            .await
2065                            .is_ok()
2066                        {
2067                            needs_resync_with_host = false;
2068                        }
2069                    }
2070
2071                    BufferOrderedMessage::LanguageServerUpdate {
2072                        language_server_id,
2073                        message,
2074                    } => {
2075                        flush_operations(
2076                            &this,
2077                            &mut operations_by_buffer_id,
2078                            &mut needs_resync_with_host,
2079                            is_local,
2080                            &mut cx,
2081                        )
2082                        .await?;
2083
2084                        this.update(&mut cx, |this, _| {
2085                            if let Some(project_id) = this.remote_id() {
2086                                this.client
2087                                    .send(proto::UpdateLanguageServer {
2088                                        project_id,
2089                                        language_server_id: language_server_id.0 as u64,
2090                                        variant: Some(message),
2091                                    })
2092                                    .log_err();
2093                            }
2094                        })?;
2095                    }
2096                }
2097            }
2098
2099            flush_operations(
2100                &this,
2101                &mut operations_by_buffer_id,
2102                &mut needs_resync_with_host,
2103                is_local,
2104                &mut cx,
2105            )
2106            .await?;
2107        }
2108
2109        Ok(())
2110    }
2111
2112    fn on_buffer_store_event(
2113        &mut self,
2114        _: Model<BufferStore>,
2115        event: &BufferStoreEvent,
2116        cx: &mut ModelContext<Self>,
2117    ) {
2118        match event {
2119            BufferStoreEvent::BufferAdded(buffer) => {
2120                self.register_buffer(buffer, cx).log_err();
2121            }
2122            BufferStoreEvent::BufferChangedFilePath { .. } => {}
2123            BufferStoreEvent::BufferDropped(buffer_id) => {
2124                if let Some(ref ssh_session) = self.ssh_session {
2125                    ssh_session
2126                        .send(proto::CloseBuffer {
2127                            project_id: 0,
2128                            buffer_id: buffer_id.to_proto(),
2129                        })
2130                        .log_err();
2131                }
2132            }
2133        }
2134    }
2135
2136    fn on_lsp_store_event(
2137        &mut self,
2138        _: Model<LspStore>,
2139        event: &LspStoreEvent,
2140        cx: &mut ModelContext<Self>,
2141    ) {
2142        match event {
2143            LspStoreEvent::DiagnosticsUpdated {
2144                language_server_id,
2145                path,
2146            } => cx.emit(Event::DiagnosticsUpdated {
2147                path: path.clone(),
2148                language_server_id: *language_server_id,
2149            }),
2150            LspStoreEvent::LanguageServerAdded(language_server_id) => {
2151                cx.emit(Event::LanguageServerAdded(*language_server_id))
2152            }
2153            LspStoreEvent::LanguageServerRemoved(language_server_id) => {
2154                cx.emit(Event::LanguageServerAdded(*language_server_id))
2155            }
2156            LspStoreEvent::LanguageServerLog(server_id, log_type, string) => cx.emit(
2157                Event::LanguageServerLog(*server_id, log_type.clone(), string.clone()),
2158            ),
2159            LspStoreEvent::LanguageDetected {
2160                buffer,
2161                new_language,
2162            } => {
2163                let Some(new_language) = new_language else {
2164                    cx.emit(Event::LanguageNotFound(buffer.clone()));
2165                    return;
2166                };
2167                let buffer_file = buffer.read(cx).file().cloned();
2168                let settings =
2169                    language_settings(Some(new_language), buffer_file.as_ref(), cx).clone();
2170                let buffer_file = File::from_dyn(buffer_file.as_ref());
2171                let worktree = buffer_file.as_ref().map(|f| f.worktree_id(cx));
2172                if let Some(prettier_plugins) =
2173                    prettier_support::prettier_plugins_for_language(&settings)
2174                {
2175                    self.install_default_prettier(
2176                        worktree,
2177                        prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
2178                        cx,
2179                    );
2180                };
2181            }
2182            LspStoreEvent::RefreshInlayHints => cx.emit(Event::RefreshInlayHints),
2183            LspStoreEvent::LanguageServerPrompt(prompt) => {
2184                cx.emit(Event::LanguageServerPrompt(prompt.clone()))
2185            }
2186            LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id } => {
2187                cx.emit(Event::DiskBasedDiagnosticsStarted {
2188                    language_server_id: *language_server_id,
2189                });
2190            }
2191            LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id } => {
2192                cx.emit(Event::DiskBasedDiagnosticsFinished {
2193                    language_server_id: *language_server_id,
2194                });
2195            }
2196            LspStoreEvent::LanguageServerUpdate {
2197                language_server_id,
2198                message,
2199            } => {
2200                if self.is_local_or_ssh() {
2201                    self.enqueue_buffer_ordered_message(
2202                        BufferOrderedMessage::LanguageServerUpdate {
2203                            language_server_id: *language_server_id,
2204                            message: message.clone(),
2205                        },
2206                    )
2207                    .ok();
2208                }
2209            }
2210            LspStoreEvent::Notification(message) => cx.emit(Event::Notification(message.clone())),
2211            LspStoreEvent::SnippetEdit {
2212                buffer_id,
2213                edits,
2214                most_recent_edit,
2215            } => {
2216                if most_recent_edit.replica_id == self.replica_id() {
2217                    cx.emit(Event::SnippetEdit(*buffer_id, edits.clone()))
2218                }
2219            }
2220            LspStoreEvent::StartFormattingLocalBuffer(buffer_id) => {
2221                self.buffers_being_formatted.insert(*buffer_id);
2222            }
2223            LspStoreEvent::FinishFormattingLocalBuffer(buffer_id) => {
2224                self.buffers_being_formatted.remove(buffer_id);
2225            }
2226        }
2227    }
2228
2229    fn on_worktree_store_event(
2230        &mut self,
2231        _: Model<WorktreeStore>,
2232        event: &WorktreeStoreEvent,
2233        cx: &mut ModelContext<Self>,
2234    ) {
2235        match event {
2236            WorktreeStoreEvent::WorktreeAdded(worktree) => {
2237                self.on_worktree_added(worktree, cx);
2238                cx.emit(Event::WorktreeAdded);
2239            }
2240            WorktreeStoreEvent::WorktreeRemoved(_, id) => {
2241                self.on_worktree_removed(*id, cx);
2242                cx.emit(Event::WorktreeRemoved(*id));
2243            }
2244            WorktreeStoreEvent::WorktreeOrderChanged => cx.emit(Event::WorktreeOrderChanged),
2245        }
2246    }
2247
2248    fn on_worktree_added(&mut self, worktree: &Model<Worktree>, cx: &mut ModelContext<Self>) {
2249        cx.observe(worktree, |_, _, cx| cx.notify()).detach();
2250        cx.subscribe(worktree, |this, worktree, event, cx| {
2251            let is_local = worktree.read(cx).is_local();
2252            match event {
2253                worktree::Event::UpdatedEntries(changes) => {
2254                    if is_local {
2255                        this.update_local_worktree_settings(&worktree, changes, cx);
2256                        this.update_prettier_settings(&worktree, changes, cx);
2257                    }
2258
2259                    cx.emit(Event::WorktreeUpdatedEntries(
2260                        worktree.read(cx).id(),
2261                        changes.clone(),
2262                    ));
2263
2264                    let worktree_id = worktree.update(cx, |worktree, _| worktree.id());
2265                    this.client()
2266                        .telemetry()
2267                        .report_discovered_project_events(worktree_id, changes);
2268                }
2269                worktree::Event::UpdatedGitRepositories(_) => {
2270                    cx.emit(Event::WorktreeUpdatedGitRepositories);
2271                }
2272                worktree::Event::DeletedEntry(id) => cx.emit(Event::DeletedEntry(*id)),
2273            }
2274        })
2275        .detach();
2276        self.metadata_changed(cx);
2277    }
2278
2279    fn on_worktree_removed(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
2280        if let Some(dev_server_project_id) = self.dev_server_project_id {
2281            let paths: Vec<String> = self
2282                .visible_worktrees(cx)
2283                .filter_map(|worktree| {
2284                    if worktree.read(cx).id() == id_to_remove {
2285                        None
2286                    } else {
2287                        Some(worktree.read(cx).abs_path().to_string_lossy().to_string())
2288                    }
2289                })
2290                .collect();
2291            if !paths.is_empty() {
2292                let request = self.client.request(proto::UpdateDevServerProject {
2293                    dev_server_project_id: dev_server_project_id.0,
2294                    paths,
2295                });
2296                cx.background_executor()
2297                    .spawn(request)
2298                    .detach_and_log_err(cx);
2299            }
2300            return;
2301        }
2302
2303        let mut prettier_instances_to_clean = FuturesUnordered::new();
2304        if let Some(prettier_paths) = self.prettiers_per_worktree.remove(&id_to_remove) {
2305            for path in prettier_paths.iter().flatten() {
2306                if let Some(prettier_instance) = self.prettier_instances.remove(path) {
2307                    prettier_instances_to_clean.push(async move {
2308                        prettier_instance
2309                            .server()
2310                            .await
2311                            .map(|server| server.server_id())
2312                    });
2313                }
2314            }
2315        }
2316        cx.spawn(|project, mut cx| async move {
2317            while let Some(prettier_server_id) = prettier_instances_to_clean.next().await {
2318                if let Some(prettier_server_id) = prettier_server_id {
2319                    project
2320                        .update(&mut cx, |project, cx| {
2321                            project.lsp_store.update(cx, |lsp_store, cx| {
2322                                lsp_store.unregister_supplementary_language_server(
2323                                    prettier_server_id,
2324                                    cx,
2325                                );
2326                            });
2327                        })
2328                        .ok();
2329                }
2330            }
2331        })
2332        .detach();
2333
2334        self.task_inventory().update(cx, |inventory, _| {
2335            inventory.remove_worktree_sources(id_to_remove);
2336        });
2337
2338        self.metadata_changed(cx);
2339    }
2340
2341    fn on_buffer_event(
2342        &mut self,
2343        buffer: Model<Buffer>,
2344        event: &BufferEvent,
2345        cx: &mut ModelContext<Self>,
2346    ) -> Option<()> {
2347        if matches!(
2348            event,
2349            BufferEvent::Edited { .. } | BufferEvent::Reloaded | BufferEvent::DiffBaseChanged
2350        ) {
2351            self.request_buffer_diff_recalculation(&buffer, cx);
2352        }
2353
2354        let buffer_id = buffer.read(cx).remote_id();
2355        match event {
2356            BufferEvent::Operation(operation) => {
2357                let operation = language::proto::serialize_operation(operation);
2358
2359                if let Some(ssh) = &self.ssh_session {
2360                    ssh.send(proto::UpdateBuffer {
2361                        project_id: 0,
2362                        buffer_id: buffer_id.to_proto(),
2363                        operations: vec![operation.clone()],
2364                    })
2365                    .ok();
2366                }
2367
2368                self.enqueue_buffer_ordered_message(BufferOrderedMessage::Operation {
2369                    buffer_id,
2370                    operation,
2371                })
2372                .ok();
2373            }
2374
2375            BufferEvent::Reloaded => {
2376                if self.is_local_or_ssh() {
2377                    if let Some(project_id) = self.remote_id() {
2378                        let buffer = buffer.read(cx);
2379                        self.client
2380                            .send(proto::BufferReloaded {
2381                                project_id,
2382                                buffer_id: buffer.remote_id().to_proto(),
2383                                version: serialize_version(&buffer.version()),
2384                                mtime: buffer.saved_mtime().map(|t| t.into()),
2385                                line_ending: serialize_line_ending(buffer.line_ending()) as i32,
2386                            })
2387                            .log_err();
2388                    }
2389                }
2390            }
2391
2392            _ => {}
2393        }
2394
2395        None
2396    }
2397
2398    fn request_buffer_diff_recalculation(
2399        &mut self,
2400        buffer: &Model<Buffer>,
2401        cx: &mut ModelContext<Self>,
2402    ) {
2403        self.buffers_needing_diff.insert(buffer.downgrade());
2404        let first_insertion = self.buffers_needing_diff.len() == 1;
2405
2406        let settings = ProjectSettings::get_global(cx);
2407        let delay = if let Some(delay) = settings.git.gutter_debounce {
2408            delay
2409        } else {
2410            if first_insertion {
2411                let this = cx.weak_model();
2412                cx.defer(move |cx| {
2413                    if let Some(this) = this.upgrade() {
2414                        this.update(cx, |this, cx| {
2415                            this.recalculate_buffer_diffs(cx).detach();
2416                        });
2417                    }
2418                });
2419            }
2420            return;
2421        };
2422
2423        const MIN_DELAY: u64 = 50;
2424        let delay = delay.max(MIN_DELAY);
2425        let duration = Duration::from_millis(delay);
2426
2427        self.git_diff_debouncer
2428            .fire_new(duration, cx, move |this, cx| {
2429                this.recalculate_buffer_diffs(cx)
2430            });
2431    }
2432
2433    fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext<Self>) -> Task<()> {
2434        let buffers = self.buffers_needing_diff.drain().collect::<Vec<_>>();
2435        cx.spawn(move |this, mut cx| async move {
2436            let tasks: Vec<_> = buffers
2437                .iter()
2438                .filter_map(|buffer| {
2439                    let buffer = buffer.upgrade()?;
2440                    buffer
2441                        .update(&mut cx, |buffer, cx| buffer.git_diff_recalc(cx))
2442                        .ok()
2443                        .flatten()
2444                })
2445                .collect();
2446
2447            futures::future::join_all(tasks).await;
2448
2449            this.update(&mut cx, |this, cx| {
2450                if this.buffers_needing_diff.is_empty() {
2451                    // TODO: Would a `ModelContext<Project>.notify()` suffice here?
2452                    for buffer in buffers {
2453                        if let Some(buffer) = buffer.upgrade() {
2454                            buffer.update(cx, |_, cx| cx.notify());
2455                        }
2456                    }
2457                } else {
2458                    this.recalculate_buffer_diffs(cx).detach();
2459                }
2460            })
2461            .ok();
2462        })
2463    }
2464
2465    pub fn set_language_for_buffer(
2466        &mut self,
2467        buffer: &Model<Buffer>,
2468        new_language: Arc<Language>,
2469        cx: &mut ModelContext<Self>,
2470    ) {
2471        self.lsp_store.update(cx, |lsp_store, cx| {
2472            lsp_store.set_language_for_buffer(buffer, new_language, cx)
2473        })
2474    }
2475
2476    pub fn restart_language_servers_for_buffers(
2477        &mut self,
2478        buffers: impl IntoIterator<Item = Model<Buffer>>,
2479        cx: &mut ModelContext<Self>,
2480    ) {
2481        self.lsp_store.update(cx, |lsp_store, cx| {
2482            lsp_store.restart_language_servers_for_buffers(buffers, cx)
2483        })
2484    }
2485
2486    pub fn cancel_language_server_work_for_buffers(
2487        &mut self,
2488        buffers: impl IntoIterator<Item = Model<Buffer>>,
2489        cx: &mut ModelContext<Self>,
2490    ) {
2491        self.lsp_store.update(cx, |lsp_store, cx| {
2492            lsp_store.cancel_language_server_work_for_buffers(buffers, cx)
2493        })
2494    }
2495
2496    pub fn cancel_language_server_work(
2497        &mut self,
2498        server_id: LanguageServerId,
2499        token_to_cancel: Option<String>,
2500        cx: &mut ModelContext<Self>,
2501    ) {
2502        self.lsp_store.update(cx, |lsp_store, cx| {
2503            lsp_store.cancel_language_server_work(server_id, token_to_cancel, cx)
2504        })
2505    }
2506
2507    fn enqueue_buffer_ordered_message(&mut self, message: BufferOrderedMessage) -> Result<()> {
2508        self.buffer_ordered_messages_tx
2509            .unbounded_send(message)
2510            .map_err(|e| anyhow!(e))
2511    }
2512
2513    pub fn language_server_statuses<'a>(
2514        &'a self,
2515        cx: &'a AppContext,
2516    ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &'a LanguageServerStatus)> {
2517        self.lsp_store.read(cx).language_server_statuses()
2518    }
2519
2520    pub fn last_formatting_failure(&self) -> Option<&str> {
2521        self.last_formatting_failure.as_deref()
2522    }
2523
2524    pub fn update_diagnostics(
2525        &mut self,
2526        language_server_id: LanguageServerId,
2527        params: lsp::PublishDiagnosticsParams,
2528        disk_based_sources: &[String],
2529        cx: &mut ModelContext<Self>,
2530    ) -> Result<()> {
2531        self.lsp_store.update(cx, |lsp_store, cx| {
2532            lsp_store.update_diagnostics(language_server_id, params, disk_based_sources, cx)
2533        })
2534    }
2535
2536    pub fn update_diagnostic_entries(
2537        &mut self,
2538        server_id: LanguageServerId,
2539        abs_path: PathBuf,
2540        version: Option<i32>,
2541        diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2542        cx: &mut ModelContext<Project>,
2543    ) -> Result<(), anyhow::Error> {
2544        self.lsp_store.update(cx, |lsp_store, cx| {
2545            lsp_store.update_diagnostic_entries(server_id, abs_path, version, diagnostics, cx)
2546        })
2547    }
2548
2549    pub fn reload_buffers(
2550        &self,
2551        buffers: HashSet<Model<Buffer>>,
2552        push_to_history: bool,
2553        cx: &mut ModelContext<Self>,
2554    ) -> Task<Result<ProjectTransaction>> {
2555        let mut local_buffers = Vec::new();
2556        let mut remote_buffers = None;
2557        for buffer_handle in buffers {
2558            let buffer = buffer_handle.read(cx);
2559            if buffer.is_dirty() {
2560                if let Some(file) = File::from_dyn(buffer.file()) {
2561                    if file.is_local() {
2562                        local_buffers.push(buffer_handle);
2563                    } else {
2564                        remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
2565                    }
2566                }
2567            }
2568        }
2569
2570        let remote_buffers = self.remote_id().zip(remote_buffers);
2571        let client = self.client.clone();
2572
2573        cx.spawn(move |this, mut cx| async move {
2574            let mut project_transaction = ProjectTransaction::default();
2575
2576            if let Some((project_id, remote_buffers)) = remote_buffers {
2577                let response = client
2578                    .request(proto::ReloadBuffers {
2579                        project_id,
2580                        buffer_ids: remote_buffers
2581                            .iter()
2582                            .filter_map(|buffer| {
2583                                buffer
2584                                    .update(&mut cx, |buffer, _| buffer.remote_id().into())
2585                                    .ok()
2586                            })
2587                            .collect(),
2588                    })
2589                    .await?
2590                    .transaction
2591                    .ok_or_else(|| anyhow!("missing transaction"))?;
2592                BufferStore::deserialize_project_transaction(
2593                    this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
2594                    response,
2595                    push_to_history,
2596                    cx.clone(),
2597                )
2598                .await?;
2599            }
2600
2601            for buffer in local_buffers {
2602                let transaction = buffer
2603                    .update(&mut cx, |buffer, cx| buffer.reload(cx))?
2604                    .await?;
2605                buffer.update(&mut cx, |buffer, cx| {
2606                    if let Some(transaction) = transaction {
2607                        if !push_to_history {
2608                            buffer.forget_transaction(transaction.id);
2609                        }
2610                        project_transaction.0.insert(cx.handle(), transaction);
2611                    }
2612                })?;
2613            }
2614
2615            Ok(project_transaction)
2616        })
2617    }
2618
2619    pub fn format(
2620        &mut self,
2621        buffers: HashSet<Model<Buffer>>,
2622        push_to_history: bool,
2623        trigger: FormatTrigger,
2624        cx: &mut ModelContext<Project>,
2625    ) -> Task<anyhow::Result<ProjectTransaction>> {
2626        if self.is_local_or_ssh() {
2627            let buffers_with_paths = buffers
2628                .into_iter()
2629                .map(|buffer_handle| {
2630                    let buffer = buffer_handle.read(cx);
2631                    let buffer_abs_path = File::from_dyn(buffer.file())
2632                        .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
2633                    (buffer_handle, buffer_abs_path)
2634                })
2635                .collect::<Vec<_>>();
2636
2637            cx.spawn(move |project, mut cx| async move {
2638                let result = Self::format_locally(
2639                    project.clone(),
2640                    buffers_with_paths,
2641                    push_to_history,
2642                    trigger,
2643                    cx.clone(),
2644                )
2645                .await;
2646
2647                project.update(&mut cx, |project, _| match &result {
2648                    Ok(_) => project.last_formatting_failure = None,
2649                    Err(error) => {
2650                        project.last_formatting_failure.replace(error.to_string());
2651                    }
2652                })?;
2653
2654                result
2655            })
2656        } else {
2657            let remote_id = self.remote_id();
2658            let client = self.client.clone();
2659            cx.spawn(move |this, mut cx| async move {
2660                if let Some(project_id) = remote_id {
2661                    let response = client
2662                        .request(proto::FormatBuffers {
2663                            project_id,
2664                            trigger: trigger as i32,
2665                            buffer_ids: buffers
2666                                .iter()
2667                                .map(|buffer| {
2668                                    buffer.update(&mut cx, |buffer, _| buffer.remote_id().into())
2669                                })
2670                                .collect::<Result<_>>()?,
2671                        })
2672                        .await?
2673                        .transaction
2674                        .ok_or_else(|| anyhow!("missing transaction"))?;
2675                    BufferStore::deserialize_project_transaction(
2676                        this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
2677                        response,
2678                        push_to_history,
2679                        cx,
2680                    )
2681                    .await
2682                } else {
2683                    Ok(ProjectTransaction::default())
2684                }
2685            })
2686        }
2687    }
2688
2689    async fn format_locally(
2690        project: WeakModel<Project>,
2691        mut buffers_with_paths: Vec<(Model<Buffer>, Option<PathBuf>)>,
2692        push_to_history: bool,
2693        trigger: FormatTrigger,
2694        mut cx: AsyncAppContext,
2695    ) -> anyhow::Result<ProjectTransaction> {
2696        // Do not allow multiple concurrent formatting requests for the
2697        // same buffer.
2698        let lsp_store = project.update(&mut cx, |this, cx| {
2699            buffers_with_paths.retain(|(buffer, _)| {
2700                this.buffers_being_formatted
2701                    .insert(buffer.read(cx).remote_id())
2702            });
2703            this.lsp_store.downgrade()
2704        })?;
2705
2706        let _cleanup = defer({
2707            let this = project.clone();
2708            let mut cx = cx.clone();
2709            let buffers = &buffers_with_paths;
2710            move || {
2711                this.update(&mut cx, |this, cx| {
2712                    for (buffer, _) in buffers {
2713                        this.buffers_being_formatted
2714                            .remove(&buffer.read(cx).remote_id());
2715                    }
2716                })
2717                .ok();
2718            }
2719        });
2720
2721        let mut project_transaction = ProjectTransaction::default();
2722        for (buffer, buffer_abs_path) in &buffers_with_paths {
2723            let (primary_adapter_and_server, adapters_and_servers) =
2724                project.update(&mut cx, |project, cx| {
2725                    let buffer = buffer.read(cx);
2726
2727                    let adapters_and_servers = project
2728                        .language_servers_for_buffer(buffer, cx)
2729                        .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
2730                        .collect::<Vec<_>>();
2731
2732                    let primary_adapter = project
2733                        .lsp_store
2734                        .read(cx)
2735                        .primary_language_server_for_buffer(buffer, cx)
2736                        .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()));
2737
2738                    (primary_adapter, adapters_and_servers)
2739                })?;
2740
2741            let settings = buffer.update(&mut cx, |buffer, cx| {
2742                language_settings(buffer.language(), buffer.file(), cx).clone()
2743            })?;
2744
2745            let remove_trailing_whitespace = settings.remove_trailing_whitespace_on_save;
2746            let ensure_final_newline = settings.ensure_final_newline_on_save;
2747
2748            // First, format buffer's whitespace according to the settings.
2749            let trailing_whitespace_diff = if remove_trailing_whitespace {
2750                Some(
2751                    buffer
2752                        .update(&mut cx, |b, cx| b.remove_trailing_whitespace(cx))?
2753                        .await,
2754                )
2755            } else {
2756                None
2757            };
2758            let whitespace_transaction_id = buffer.update(&mut cx, |buffer, cx| {
2759                buffer.finalize_last_transaction();
2760                buffer.start_transaction();
2761                if let Some(diff) = trailing_whitespace_diff {
2762                    buffer.apply_diff(diff, cx);
2763                }
2764                if ensure_final_newline {
2765                    buffer.ensure_final_newline(cx);
2766                }
2767                buffer.end_transaction(cx)
2768            })?;
2769
2770            // Apply the `code_actions_on_format` before we run the formatter.
2771            let code_actions = deserialize_code_actions(&settings.code_actions_on_format);
2772            #[allow(clippy::nonminimal_bool)]
2773            if !code_actions.is_empty()
2774                && !(trigger == FormatTrigger::Save && settings.format_on_save == FormatOnSave::Off)
2775            {
2776                LspStore::execute_code_actions_on_servers(
2777                    &lsp_store,
2778                    &adapters_and_servers,
2779                    code_actions,
2780                    buffer,
2781                    push_to_history,
2782                    &mut project_transaction,
2783                    &mut cx,
2784                )
2785                .await?;
2786            }
2787
2788            // Apply language-specific formatting using either the primary language server
2789            // or external command.
2790            // Except for code actions, which are applied with all connected language servers.
2791            let primary_language_server =
2792                primary_adapter_and_server.map(|(_adapter, server)| server.clone());
2793            let server_and_buffer = primary_language_server
2794                .as_ref()
2795                .zip(buffer_abs_path.as_ref());
2796
2797            let prettier_settings = buffer.read_with(&cx, |buffer, cx| {
2798                language_settings(buffer.language(), buffer.file(), cx)
2799                    .prettier
2800                    .clone()
2801            })?;
2802
2803            let mut format_operations: Vec<FormatOperation> = vec![];
2804            {
2805                match trigger {
2806                    FormatTrigger::Save => {
2807                        match &settings.format_on_save {
2808                            FormatOnSave::Off => {
2809                                // nothing
2810                            }
2811                            FormatOnSave::On => {
2812                                match &settings.formatter {
2813                                    SelectedFormatter::Auto => {
2814                                        // do the auto-format: prefer prettier, fallback to primary language server
2815                                        let diff = {
2816                                            if prettier_settings.allowed {
2817                                                Self::perform_format(
2818                                                    &Formatter::Prettier,
2819                                                    server_and_buffer,
2820                                                    project.clone(),
2821                                                    buffer,
2822                                                    buffer_abs_path,
2823                                                    &settings,
2824                                                    &adapters_and_servers,
2825                                                    push_to_history,
2826                                                    &mut project_transaction,
2827                                                    &mut cx,
2828                                                )
2829                                                .await
2830                                            } else {
2831                                                Self::perform_format(
2832                                                    &Formatter::LanguageServer { name: None },
2833                                                    server_and_buffer,
2834                                                    project.clone(),
2835                                                    buffer,
2836                                                    buffer_abs_path,
2837                                                    &settings,
2838                                                    &adapters_and_servers,
2839                                                    push_to_history,
2840                                                    &mut project_transaction,
2841                                                    &mut cx,
2842                                                )
2843                                                .await
2844                                            }
2845                                        }
2846                                        .log_err()
2847                                        .flatten();
2848                                        if let Some(op) = diff {
2849                                            format_operations.push(op);
2850                                        }
2851                                    }
2852                                    SelectedFormatter::List(formatters) => {
2853                                        for formatter in formatters.as_ref() {
2854                                            let diff = Self::perform_format(
2855                                                formatter,
2856                                                server_and_buffer,
2857                                                project.clone(),
2858                                                buffer,
2859                                                buffer_abs_path,
2860                                                &settings,
2861                                                &adapters_and_servers,
2862                                                push_to_history,
2863                                                &mut project_transaction,
2864                                                &mut cx,
2865                                            )
2866                                            .await
2867                                            .log_err()
2868                                            .flatten();
2869                                            if let Some(op) = diff {
2870                                                format_operations.push(op);
2871                                            }
2872
2873                                            // format with formatter
2874                                        }
2875                                    }
2876                                }
2877                            }
2878                            FormatOnSave::List(formatters) => {
2879                                for formatter in formatters.as_ref() {
2880                                    let diff = Self::perform_format(
2881                                        formatter,
2882                                        server_and_buffer,
2883                                        project.clone(),
2884                                        buffer,
2885                                        buffer_abs_path,
2886                                        &settings,
2887                                        &adapters_and_servers,
2888                                        push_to_history,
2889                                        &mut project_transaction,
2890                                        &mut cx,
2891                                    )
2892                                    .await
2893                                    .log_err()
2894                                    .flatten();
2895                                    if let Some(op) = diff {
2896                                        format_operations.push(op);
2897                                    }
2898                                }
2899                            }
2900                        }
2901                    }
2902                    FormatTrigger::Manual => {
2903                        match &settings.formatter {
2904                            SelectedFormatter::Auto => {
2905                                // do the auto-format: prefer prettier, fallback to primary language server
2906                                let diff = {
2907                                    if prettier_settings.allowed {
2908                                        Self::perform_format(
2909                                            &Formatter::Prettier,
2910                                            server_and_buffer,
2911                                            project.clone(),
2912                                            buffer,
2913                                            buffer_abs_path,
2914                                            &settings,
2915                                            &adapters_and_servers,
2916                                            push_to_history,
2917                                            &mut project_transaction,
2918                                            &mut cx,
2919                                        )
2920                                        .await
2921                                    } else {
2922                                        Self::perform_format(
2923                                            &Formatter::LanguageServer { name: None },
2924                                            server_and_buffer,
2925                                            project.clone(),
2926                                            buffer,
2927                                            buffer_abs_path,
2928                                            &settings,
2929                                            &adapters_and_servers,
2930                                            push_to_history,
2931                                            &mut project_transaction,
2932                                            &mut cx,
2933                                        )
2934                                        .await
2935                                    }
2936                                }
2937                                .log_err()
2938                                .flatten();
2939
2940                                if let Some(op) = diff {
2941                                    format_operations.push(op)
2942                                }
2943                            }
2944                            SelectedFormatter::List(formatters) => {
2945                                for formatter in formatters.as_ref() {
2946                                    // format with formatter
2947                                    let diff = Self::perform_format(
2948                                        formatter,
2949                                        server_and_buffer,
2950                                        project.clone(),
2951                                        buffer,
2952                                        buffer_abs_path,
2953                                        &settings,
2954                                        &adapters_and_servers,
2955                                        push_to_history,
2956                                        &mut project_transaction,
2957                                        &mut cx,
2958                                    )
2959                                    .await
2960                                    .log_err()
2961                                    .flatten();
2962                                    if let Some(op) = diff {
2963                                        format_operations.push(op);
2964                                    }
2965                                }
2966                            }
2967                        }
2968                    }
2969                }
2970            }
2971
2972            buffer.update(&mut cx, |b, cx| {
2973                // If the buffer had its whitespace formatted and was edited while the language-specific
2974                // formatting was being computed, avoid applying the language-specific formatting, because
2975                // it can't be grouped with the whitespace formatting in the undo history.
2976                if let Some(transaction_id) = whitespace_transaction_id {
2977                    if b.peek_undo_stack()
2978                        .map_or(true, |e| e.transaction_id() != transaction_id)
2979                    {
2980                        format_operations.clear();
2981                    }
2982                }
2983
2984                // Apply any language-specific formatting, and group the two formatting operations
2985                // in the buffer's undo history.
2986                for operation in format_operations {
2987                    match operation {
2988                        FormatOperation::Lsp(edits) => {
2989                            b.edit(edits, None, cx);
2990                        }
2991                        FormatOperation::External(diff) => {
2992                            b.apply_diff(diff, cx);
2993                        }
2994                        FormatOperation::Prettier(diff) => {
2995                            b.apply_diff(diff, cx);
2996                        }
2997                    }
2998
2999                    if let Some(transaction_id) = whitespace_transaction_id {
3000                        b.group_until_transaction(transaction_id);
3001                    } else if let Some(transaction) = project_transaction.0.get(buffer) {
3002                        b.group_until_transaction(transaction.id)
3003                    }
3004                }
3005
3006                if let Some(transaction) = b.finalize_last_transaction().cloned() {
3007                    if !push_to_history {
3008                        b.forget_transaction(transaction.id);
3009                    }
3010                    project_transaction.0.insert(buffer.clone(), transaction);
3011                }
3012            })?;
3013        }
3014
3015        Ok(project_transaction)
3016    }
3017
3018    #[allow(clippy::too_many_arguments)]
3019    async fn perform_format(
3020        formatter: &Formatter,
3021        primary_server_and_buffer: Option<(&Arc<LanguageServer>, &PathBuf)>,
3022        project: WeakModel<Project>,
3023        buffer: &Model<Buffer>,
3024        buffer_abs_path: &Option<PathBuf>,
3025        settings: &LanguageSettings,
3026        adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
3027        push_to_history: bool,
3028        transaction: &mut ProjectTransaction,
3029        cx: &mut AsyncAppContext,
3030    ) -> Result<Option<FormatOperation>, anyhow::Error> {
3031        let result = match formatter {
3032            Formatter::LanguageServer { name } => {
3033                if let Some((language_server, buffer_abs_path)) = primary_server_and_buffer {
3034                    let language_server = if let Some(name) = name {
3035                        adapters_and_servers
3036                            .iter()
3037                            .find_map(|(adapter, server)| {
3038                                adapter.name.0.as_ref().eq(name.as_str()).then_some(server)
3039                            })
3040                            .unwrap_or(language_server)
3041                    } else {
3042                        language_server
3043                    };
3044
3045                    let lsp_store = project.update(cx, |p, _| p.lsp_store.downgrade())?;
3046                    Some(FormatOperation::Lsp(
3047                        LspStore::format_via_lsp(
3048                            &lsp_store,
3049                            buffer,
3050                            buffer_abs_path,
3051                            language_server,
3052                            settings,
3053                            cx,
3054                        )
3055                        .await
3056                        .context("failed to format via language server")?,
3057                    ))
3058                } else {
3059                    None
3060                }
3061            }
3062            Formatter::Prettier => prettier_support::format_with_prettier(&project, buffer, cx)
3063                .await
3064                .transpose()
3065                .ok()
3066                .flatten(),
3067            Formatter::External { command, arguments } => {
3068                let buffer_abs_path = buffer_abs_path.as_ref().map(|path| path.as_path());
3069                Self::format_via_external_command(buffer, buffer_abs_path, command, arguments, cx)
3070                    .await
3071                    .context(format!(
3072                        "failed to format via external command {:?}",
3073                        command
3074                    ))?
3075                    .map(FormatOperation::External)
3076            }
3077            Formatter::CodeActions(code_actions) => {
3078                let code_actions = deserialize_code_actions(code_actions);
3079                let lsp_store = project.update(cx, |p, _| p.lsp_store.downgrade())?;
3080                if !code_actions.is_empty() {
3081                    LspStore::execute_code_actions_on_servers(
3082                        &lsp_store,
3083                        adapters_and_servers,
3084                        code_actions,
3085                        buffer,
3086                        push_to_history,
3087                        transaction,
3088                        cx,
3089                    )
3090                    .await?;
3091                }
3092                None
3093            }
3094        };
3095        anyhow::Ok(result)
3096    }
3097
3098    async fn format_via_external_command(
3099        buffer: &Model<Buffer>,
3100        buffer_abs_path: Option<&Path>,
3101        command: &str,
3102        arguments: &[String],
3103        cx: &mut AsyncAppContext,
3104    ) -> Result<Option<Diff>> {
3105        let working_dir_path = buffer.update(cx, |buffer, cx| {
3106            let file = File::from_dyn(buffer.file())?;
3107            let worktree = file.worktree.read(cx);
3108            let mut worktree_path = worktree.abs_path().to_path_buf();
3109            if worktree.root_entry()?.is_file() {
3110                worktree_path.pop();
3111            }
3112            Some(worktree_path)
3113        })?;
3114
3115        let mut child = smol::process::Command::new(command);
3116        #[cfg(target_os = "windows")]
3117        {
3118            use smol::process::windows::CommandExt;
3119            child.creation_flags(windows::Win32::System::Threading::CREATE_NO_WINDOW.0);
3120        }
3121
3122        if let Some(working_dir_path) = working_dir_path {
3123            child.current_dir(working_dir_path);
3124        }
3125
3126        let mut child = child
3127            .args(arguments.iter().map(|arg| {
3128                if let Some(buffer_abs_path) = buffer_abs_path {
3129                    arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
3130                } else {
3131                    arg.replace("{buffer_path}", "Untitled")
3132                }
3133            }))
3134            .stdin(smol::process::Stdio::piped())
3135            .stdout(smol::process::Stdio::piped())
3136            .stderr(smol::process::Stdio::piped())
3137            .spawn()?;
3138
3139        let stdin = child
3140            .stdin
3141            .as_mut()
3142            .ok_or_else(|| anyhow!("failed to acquire stdin"))?;
3143        let text = buffer.update(cx, |buffer, _| buffer.as_rope().clone())?;
3144        for chunk in text.chunks() {
3145            stdin.write_all(chunk.as_bytes()).await?;
3146        }
3147        stdin.flush().await?;
3148
3149        let output = child.output().await?;
3150        if !output.status.success() {
3151            return Err(anyhow!(
3152                "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
3153                output.status.code(),
3154                String::from_utf8_lossy(&output.stdout),
3155                String::from_utf8_lossy(&output.stderr),
3156            ));
3157        }
3158
3159        let stdout = String::from_utf8(output.stdout)?;
3160        Ok(Some(
3161            buffer
3162                .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
3163                .await,
3164        ))
3165    }
3166
3167    #[inline(never)]
3168    fn definition_impl(
3169        &self,
3170        buffer: &Model<Buffer>,
3171        position: PointUtf16,
3172        cx: &mut ModelContext<Self>,
3173    ) -> Task<Result<Vec<LocationLink>>> {
3174        self.request_lsp(
3175            buffer.clone(),
3176            LanguageServerToQuery::Primary,
3177            GetDefinition { position },
3178            cx,
3179        )
3180    }
3181    pub fn definition<T: ToPointUtf16>(
3182        &self,
3183        buffer: &Model<Buffer>,
3184        position: T,
3185        cx: &mut ModelContext<Self>,
3186    ) -> Task<Result<Vec<LocationLink>>> {
3187        let position = position.to_point_utf16(buffer.read(cx));
3188        self.definition_impl(buffer, position, cx)
3189    }
3190
3191    fn declaration_impl(
3192        &self,
3193        buffer: &Model<Buffer>,
3194        position: PointUtf16,
3195        cx: &mut ModelContext<Self>,
3196    ) -> Task<Result<Vec<LocationLink>>> {
3197        self.request_lsp(
3198            buffer.clone(),
3199            LanguageServerToQuery::Primary,
3200            GetDeclaration { position },
3201            cx,
3202        )
3203    }
3204
3205    pub fn declaration<T: ToPointUtf16>(
3206        &self,
3207        buffer: &Model<Buffer>,
3208        position: T,
3209        cx: &mut ModelContext<Self>,
3210    ) -> Task<Result<Vec<LocationLink>>> {
3211        let position = position.to_point_utf16(buffer.read(cx));
3212        self.declaration_impl(buffer, position, cx)
3213    }
3214
3215    fn type_definition_impl(
3216        &self,
3217        buffer: &Model<Buffer>,
3218        position: PointUtf16,
3219        cx: &mut ModelContext<Self>,
3220    ) -> Task<Result<Vec<LocationLink>>> {
3221        self.request_lsp(
3222            buffer.clone(),
3223            LanguageServerToQuery::Primary,
3224            GetTypeDefinition { position },
3225            cx,
3226        )
3227    }
3228
3229    pub fn type_definition<T: ToPointUtf16>(
3230        &self,
3231        buffer: &Model<Buffer>,
3232        position: T,
3233        cx: &mut ModelContext<Self>,
3234    ) -> Task<Result<Vec<LocationLink>>> {
3235        let position = position.to_point_utf16(buffer.read(cx));
3236        self.type_definition_impl(buffer, position, cx)
3237    }
3238
3239    pub fn implementation<T: ToPointUtf16>(
3240        &self,
3241        buffer: &Model<Buffer>,
3242        position: T,
3243        cx: &mut ModelContext<Self>,
3244    ) -> Task<Result<Vec<LocationLink>>> {
3245        let position = position.to_point_utf16(buffer.read(cx));
3246        self.request_lsp(
3247            buffer.clone(),
3248            LanguageServerToQuery::Primary,
3249            GetImplementation { position },
3250            cx,
3251        )
3252    }
3253
3254    pub fn references<T: ToPointUtf16>(
3255        &self,
3256        buffer: &Model<Buffer>,
3257        position: T,
3258        cx: &mut ModelContext<Self>,
3259    ) -> Task<Result<Vec<Location>>> {
3260        let position = position.to_point_utf16(buffer.read(cx));
3261        self.request_lsp(
3262            buffer.clone(),
3263            LanguageServerToQuery::Primary,
3264            GetReferences { position },
3265            cx,
3266        )
3267    }
3268
3269    fn document_highlights_impl(
3270        &self,
3271        buffer: &Model<Buffer>,
3272        position: PointUtf16,
3273        cx: &mut ModelContext<Self>,
3274    ) -> Task<Result<Vec<DocumentHighlight>>> {
3275        self.request_lsp(
3276            buffer.clone(),
3277            LanguageServerToQuery::Primary,
3278            GetDocumentHighlights { position },
3279            cx,
3280        )
3281    }
3282
3283    pub fn document_highlights<T: ToPointUtf16>(
3284        &self,
3285        buffer: &Model<Buffer>,
3286        position: T,
3287        cx: &mut ModelContext<Self>,
3288    ) -> Task<Result<Vec<DocumentHighlight>>> {
3289        let position = position.to_point_utf16(buffer.read(cx));
3290        self.document_highlights_impl(buffer, position, cx)
3291    }
3292
3293    pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
3294        self.lsp_store
3295            .update(cx, |lsp_store, cx| lsp_store.symbols(query, cx))
3296    }
3297
3298    pub fn open_buffer_for_symbol(
3299        &mut self,
3300        symbol: &Symbol,
3301        cx: &mut ModelContext<Self>,
3302    ) -> Task<Result<Model<Buffer>>> {
3303        self.lsp_store.update(cx, |lsp_store, cx| {
3304            lsp_store.open_buffer_for_symbol(symbol, cx)
3305        })
3306    }
3307
3308    pub fn open_local_buffer_via_lsp(
3309        &mut self,
3310        abs_path: lsp::Url,
3311        language_server_id: LanguageServerId,
3312        language_server_name: LanguageServerName,
3313        cx: &mut ModelContext<Self>,
3314    ) -> Task<Result<Model<Buffer>>> {
3315        self.lsp_store.update(cx, |lsp_store, cx| {
3316            lsp_store.open_local_buffer_via_lsp(
3317                abs_path,
3318                language_server_id,
3319                language_server_name,
3320                cx,
3321            )
3322        })
3323    }
3324
3325    pub fn signature_help<T: ToPointUtf16>(
3326        &self,
3327        buffer: &Model<Buffer>,
3328        position: T,
3329        cx: &mut ModelContext<Self>,
3330    ) -> Task<Vec<SignatureHelp>> {
3331        self.lsp_store.update(cx, |lsp_store, cx| {
3332            lsp_store.signature_help(buffer, position, cx)
3333        })
3334    }
3335
3336    pub fn hover<T: ToPointUtf16>(
3337        &self,
3338        buffer: &Model<Buffer>,
3339        position: T,
3340        cx: &mut ModelContext<Self>,
3341    ) -> Task<Vec<Hover>> {
3342        let position = position.to_point_utf16(buffer.read(cx));
3343        self.lsp_store
3344            .update(cx, |lsp_store, cx| lsp_store.hover(buffer, position, cx))
3345    }
3346
3347    pub fn linked_edit(
3348        &self,
3349        buffer: &Model<Buffer>,
3350        position: Anchor,
3351        cx: &mut ModelContext<Self>,
3352    ) -> Task<Result<Vec<Range<Anchor>>>> {
3353        self.lsp_store.update(cx, |lsp_store, cx| {
3354            lsp_store.linked_edit(buffer, position, cx)
3355        })
3356    }
3357
3358    pub fn completions<T: ToOffset + ToPointUtf16>(
3359        &self,
3360        buffer: &Model<Buffer>,
3361        position: T,
3362        context: CompletionContext,
3363        cx: &mut ModelContext<Self>,
3364    ) -> Task<Result<Vec<Completion>>> {
3365        let position = position.to_point_utf16(buffer.read(cx));
3366        self.lsp_store.update(cx, |lsp_store, cx| {
3367            lsp_store.completions(buffer, position, context, cx)
3368        })
3369    }
3370
3371    pub fn resolve_completions(
3372        &self,
3373        buffer: Model<Buffer>,
3374        completion_indices: Vec<usize>,
3375        completions: Arc<RwLock<Box<[Completion]>>>,
3376        cx: &mut ModelContext<Self>,
3377    ) -> Task<Result<bool>> {
3378        self.lsp_store.update(cx, |lsp_store, cx| {
3379            lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
3380        })
3381    }
3382
3383    pub fn apply_additional_edits_for_completion(
3384        &self,
3385        buffer_handle: Model<Buffer>,
3386        completion: Completion,
3387        push_to_history: bool,
3388        cx: &mut ModelContext<Self>,
3389    ) -> Task<Result<Option<Transaction>>> {
3390        self.lsp_store.update(cx, |lsp_store, cx| {
3391            lsp_store.apply_additional_edits_for_completion(
3392                buffer_handle,
3393                completion,
3394                push_to_history,
3395                cx,
3396            )
3397        })
3398    }
3399
3400    pub fn code_actions<T: Clone + ToOffset>(
3401        &mut self,
3402        buffer_handle: &Model<Buffer>,
3403        range: Range<T>,
3404        cx: &mut ModelContext<Self>,
3405    ) -> Task<Vec<CodeAction>> {
3406        let buffer = buffer_handle.read(cx);
3407        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
3408        self.lsp_store.update(cx, |lsp_store, cx| {
3409            lsp_store.code_actions(buffer_handle, range, cx)
3410        })
3411    }
3412
3413    pub fn apply_code_action(
3414        &self,
3415        buffer_handle: Model<Buffer>,
3416        action: CodeAction,
3417        push_to_history: bool,
3418        cx: &mut ModelContext<Self>,
3419    ) -> Task<Result<ProjectTransaction>> {
3420        self.lsp_store.update(cx, |lsp_store, cx| {
3421            lsp_store.apply_code_action(buffer_handle, action, push_to_history, cx)
3422        })
3423    }
3424
3425    fn prepare_rename_impl(
3426        &mut self,
3427        buffer: Model<Buffer>,
3428        position: PointUtf16,
3429        cx: &mut ModelContext<Self>,
3430    ) -> Task<Result<Option<Range<Anchor>>>> {
3431        self.request_lsp(
3432            buffer,
3433            LanguageServerToQuery::Primary,
3434            PrepareRename { position },
3435            cx,
3436        )
3437    }
3438    pub fn prepare_rename<T: ToPointUtf16>(
3439        &mut self,
3440        buffer: Model<Buffer>,
3441        position: T,
3442        cx: &mut ModelContext<Self>,
3443    ) -> Task<Result<Option<Range<Anchor>>>> {
3444        let position = position.to_point_utf16(buffer.read(cx));
3445        self.prepare_rename_impl(buffer, position, cx)
3446    }
3447
3448    fn perform_rename_impl(
3449        &mut self,
3450        buffer: Model<Buffer>,
3451        position: PointUtf16,
3452        new_name: String,
3453        push_to_history: bool,
3454        cx: &mut ModelContext<Self>,
3455    ) -> Task<Result<ProjectTransaction>> {
3456        let position = position.to_point_utf16(buffer.read(cx));
3457        self.request_lsp(
3458            buffer,
3459            LanguageServerToQuery::Primary,
3460            PerformRename {
3461                position,
3462                new_name,
3463                push_to_history,
3464            },
3465            cx,
3466        )
3467    }
3468    pub fn perform_rename<T: ToPointUtf16>(
3469        &mut self,
3470        buffer: Model<Buffer>,
3471        position: T,
3472        new_name: String,
3473        push_to_history: bool,
3474        cx: &mut ModelContext<Self>,
3475    ) -> Task<Result<ProjectTransaction>> {
3476        let position = position.to_point_utf16(buffer.read(cx));
3477        self.perform_rename_impl(buffer, position, new_name, push_to_history, cx)
3478    }
3479
3480    pub fn on_type_format<T: ToPointUtf16>(
3481        &mut self,
3482        buffer: Model<Buffer>,
3483        position: T,
3484        trigger: String,
3485        push_to_history: bool,
3486        cx: &mut ModelContext<Self>,
3487    ) -> Task<Result<Option<Transaction>>> {
3488        self.lsp_store.update(cx, |lsp_store, cx| {
3489            lsp_store.on_type_format(buffer, position, trigger, push_to_history, cx)
3490        })
3491    }
3492
3493    pub fn inlay_hints<T: ToOffset>(
3494        &mut self,
3495        buffer_handle: Model<Buffer>,
3496        range: Range<T>,
3497        cx: &mut ModelContext<Self>,
3498    ) -> Task<anyhow::Result<Vec<InlayHint>>> {
3499        let buffer = buffer_handle.read(cx);
3500        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
3501        self.lsp_store.update(cx, |lsp_store, cx| {
3502            lsp_store.inlay_hints(buffer_handle, range, cx)
3503        })
3504    }
3505
3506    pub fn resolve_inlay_hint(
3507        &self,
3508        hint: InlayHint,
3509        buffer_handle: Model<Buffer>,
3510        server_id: LanguageServerId,
3511        cx: &mut ModelContext<Self>,
3512    ) -> Task<anyhow::Result<InlayHint>> {
3513        self.lsp_store.update(cx, |lsp_store, cx| {
3514            lsp_store.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
3515        })
3516    }
3517
3518    pub fn search(
3519        &mut self,
3520        query: SearchQuery,
3521        cx: &mut ModelContext<Self>,
3522    ) -> Receiver<SearchResult> {
3523        let (result_tx, result_rx) = smol::channel::unbounded();
3524
3525        let matching_buffers_rx = if query.is_opened_only() {
3526            self.sort_candidate_buffers(&query, cx)
3527        } else {
3528            self.search_for_candidate_buffers(&query, MAX_SEARCH_RESULT_FILES + 1, cx)
3529        };
3530
3531        cx.spawn(|_, cx| async move {
3532            let mut range_count = 0;
3533            let mut buffer_count = 0;
3534            let mut limit_reached = false;
3535            let query = Arc::new(query);
3536            let mut chunks = matching_buffers_rx.ready_chunks(64);
3537
3538            // Now that we know what paths match the query, we will load at most
3539            // 64 buffers at a time to avoid overwhelming the main thread. For each
3540            // opened buffer, we will spawn a background task that retrieves all the
3541            // ranges in the buffer matched by the query.
3542            'outer: while let Some(matching_buffer_chunk) = chunks.next().await {
3543                let mut chunk_results = Vec::new();
3544                for buffer in matching_buffer_chunk {
3545                    let buffer = buffer.clone();
3546                    let query = query.clone();
3547                    let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
3548                    chunk_results.push(cx.background_executor().spawn(async move {
3549                        let ranges = query
3550                            .search(&snapshot, None)
3551                            .await
3552                            .iter()
3553                            .map(|range| {
3554                                snapshot.anchor_before(range.start)
3555                                    ..snapshot.anchor_after(range.end)
3556                            })
3557                            .collect::<Vec<_>>();
3558                        anyhow::Ok((buffer, ranges))
3559                    }));
3560                }
3561
3562                let chunk_results = futures::future::join_all(chunk_results).await;
3563                for result in chunk_results {
3564                    if let Some((buffer, ranges)) = result.log_err() {
3565                        range_count += ranges.len();
3566                        buffer_count += 1;
3567                        result_tx
3568                            .send(SearchResult::Buffer { buffer, ranges })
3569                            .await?;
3570                        if buffer_count > MAX_SEARCH_RESULT_FILES
3571                            || range_count > MAX_SEARCH_RESULT_RANGES
3572                        {
3573                            limit_reached = true;
3574                            break 'outer;
3575                        }
3576                    }
3577                }
3578            }
3579
3580            if limit_reached {
3581                result_tx.send(SearchResult::LimitReached).await?;
3582            }
3583
3584            anyhow::Ok(())
3585        })
3586        .detach();
3587
3588        result_rx
3589    }
3590
3591    fn search_for_candidate_buffers(
3592        &mut self,
3593        query: &SearchQuery,
3594        limit: usize,
3595        cx: &mut ModelContext<Project>,
3596    ) -> Receiver<Model<Buffer>> {
3597        if self.is_local() {
3598            let fs = self.fs.clone();
3599            self.buffer_store.update(cx, |buffer_store, cx| {
3600                buffer_store.find_search_candidates(query, limit, fs, cx)
3601            })
3602        } else {
3603            self.search_for_candidate_buffers_remote(query, limit, cx)
3604        }
3605    }
3606
3607    fn sort_candidate_buffers(
3608        &mut self,
3609        search_query: &SearchQuery,
3610        cx: &mut ModelContext<Project>,
3611    ) -> Receiver<Model<Buffer>> {
3612        let worktree_store = self.worktree_store.read(cx);
3613        let mut buffers = search_query
3614            .buffers()
3615            .into_iter()
3616            .flatten()
3617            .filter(|buffer| {
3618                let b = buffer.read(cx);
3619                if let Some(file) = b.file() {
3620                    if !search_query.file_matches(file.path()) {
3621                        return false;
3622                    }
3623                    if let Some(entry) = b
3624                        .entry_id(cx)
3625                        .and_then(|entry_id| worktree_store.entry_for_id(entry_id, cx))
3626                    {
3627                        if entry.is_ignored && !search_query.include_ignored() {
3628                            return false;
3629                        }
3630                    }
3631                }
3632                true
3633            })
3634            .collect::<Vec<_>>();
3635        let (tx, rx) = smol::channel::unbounded();
3636        buffers.sort_by(|a, b| match (a.read(cx).file(), b.read(cx).file()) {
3637            (None, None) => a.read(cx).remote_id().cmp(&b.read(cx).remote_id()),
3638            (None, Some(_)) => std::cmp::Ordering::Less,
3639            (Some(_), None) => std::cmp::Ordering::Greater,
3640            (Some(a), Some(b)) => compare_paths((a.path(), true), (b.path(), true)),
3641        });
3642        for buffer in buffers {
3643            tx.send_blocking(buffer.clone()).unwrap()
3644        }
3645
3646        rx
3647    }
3648
3649    fn search_for_candidate_buffers_remote(
3650        &mut self,
3651        query: &SearchQuery,
3652        limit: usize,
3653        cx: &mut ModelContext<Project>,
3654    ) -> Receiver<Model<Buffer>> {
3655        let (tx, rx) = smol::channel::unbounded();
3656
3657        let (client, remote_id): (AnyProtoClient, _) =
3658            if let Some(ssh_session) = self.ssh_session.clone() {
3659                (ssh_session.into(), 0)
3660            } else if let Some(remote_id) = self.remote_id() {
3661                (self.client.clone().into(), remote_id)
3662            } else {
3663                return rx;
3664            };
3665
3666        let request = client.request(proto::FindSearchCandidates {
3667            project_id: remote_id,
3668            query: Some(query.to_proto()),
3669            limit: limit as _,
3670        });
3671        let guard = self.retain_remotely_created_buffers(cx);
3672
3673        cx.spawn(move |this, mut cx| async move {
3674            let response = request.await?;
3675            for buffer_id in response.buffer_ids {
3676                let buffer_id = BufferId::new(buffer_id)?;
3677                let buffer = this
3678                    .update(&mut cx, |this, cx| {
3679                        this.wait_for_remote_buffer(buffer_id, cx)
3680                    })?
3681                    .await?;
3682                let _ = tx.send(buffer).await;
3683            }
3684
3685            drop(guard);
3686            anyhow::Ok(())
3687        })
3688        .detach_and_log_err(cx);
3689        rx
3690    }
3691
3692    pub fn request_lsp<R: LspCommand>(
3693        &self,
3694        buffer_handle: Model<Buffer>,
3695        server: LanguageServerToQuery,
3696        request: R,
3697        cx: &mut ModelContext<Self>,
3698    ) -> Task<Result<R::Response>>
3699    where
3700        <R::LspRequest as lsp::request::Request>::Result: Send,
3701        <R::LspRequest as lsp::request::Request>::Params: Send,
3702    {
3703        self.lsp_store.update(cx, |lsp_store, cx| {
3704            lsp_store.request_lsp(buffer_handle, server, request, cx)
3705        })
3706    }
3707
3708    /// Move a worktree to a new position in the worktree order.
3709    ///
3710    /// The worktree will moved to the opposite side of the destination worktree.
3711    ///
3712    /// # Example
3713    ///
3714    /// Given the worktree order `[11, 22, 33]` and a call to move worktree `22` to `33`,
3715    /// worktree_order will be updated to produce the indexes `[11, 33, 22]`.
3716    ///
3717    /// Given the worktree order `[11, 22, 33]` and a call to move worktree `22` to `11`,
3718    /// worktree_order will be updated to produce the indexes `[22, 11, 33]`.
3719    ///
3720    /// # Errors
3721    ///
3722    /// An error will be returned if the worktree or destination worktree are not found.
3723    pub fn move_worktree(
3724        &mut self,
3725        source: WorktreeId,
3726        destination: WorktreeId,
3727        cx: &mut ModelContext<'_, Self>,
3728    ) -> Result<()> {
3729        self.worktree_store.update(cx, |worktree_store, cx| {
3730            worktree_store.move_worktree(source, destination, cx)
3731        })
3732    }
3733
3734    pub fn find_or_create_worktree(
3735        &mut self,
3736        abs_path: impl AsRef<Path>,
3737        visible: bool,
3738        cx: &mut ModelContext<Self>,
3739    ) -> Task<Result<(Model<Worktree>, PathBuf)>> {
3740        let abs_path = abs_path.as_ref();
3741        if let Some((tree, relative_path)) = self.find_worktree(abs_path, cx) {
3742            Task::ready(Ok((tree, relative_path)))
3743        } else {
3744            let worktree = self.create_worktree(abs_path, visible, cx);
3745            cx.background_executor()
3746                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
3747        }
3748    }
3749
3750    pub fn find_worktree(
3751        &self,
3752        abs_path: &Path,
3753        cx: &AppContext,
3754    ) -> Option<(Model<Worktree>, PathBuf)> {
3755        self.worktree_store.read_with(cx, |worktree_store, cx| {
3756            worktree_store.find_worktree(abs_path, cx)
3757        })
3758    }
3759
3760    pub fn is_shared(&self) -> bool {
3761        match &self.client_state {
3762            ProjectClientState::Shared { .. } => true,
3763            ProjectClientState::Local => false,
3764            ProjectClientState::Remote { in_room, .. } => *in_room,
3765        }
3766    }
3767
3768    // Returns the resolved version of `path`, that was found in `buffer`, if it exists.
3769    pub fn resolve_existing_file_path(
3770        &self,
3771        path: &str,
3772        buffer: &Model<Buffer>,
3773        cx: &mut ModelContext<Self>,
3774    ) -> Task<Option<ResolvedPath>> {
3775        // TODO: ssh based remoting.
3776        if self.ssh_session.is_some() {
3777            return Task::ready(None);
3778        }
3779
3780        if self.is_local_or_ssh() {
3781            let expanded = PathBuf::from(shellexpand::tilde(&path).into_owned());
3782
3783            if expanded.is_absolute() {
3784                let fs = self.fs.clone();
3785                cx.background_executor().spawn(async move {
3786                    let path = expanded.as_path();
3787                    let exists = fs.is_file(path).await;
3788
3789                    exists.then(|| ResolvedPath::AbsPath(expanded))
3790                })
3791            } else {
3792                self.resolve_path_in_worktrees(expanded, buffer, cx)
3793            }
3794        } else {
3795            let path = PathBuf::from(path);
3796            if path.is_absolute() || path.starts_with("~") {
3797                return Task::ready(None);
3798            }
3799
3800            self.resolve_path_in_worktrees(path, buffer, cx)
3801        }
3802    }
3803
3804    fn resolve_path_in_worktrees(
3805        &self,
3806        path: PathBuf,
3807        buffer: &Model<Buffer>,
3808        cx: &mut ModelContext<Self>,
3809    ) -> Task<Option<ResolvedPath>> {
3810        let mut candidates = vec![path.clone()];
3811
3812        if let Some(file) = buffer.read(cx).file() {
3813            if let Some(dir) = file.path().parent() {
3814                let joined = dir.to_path_buf().join(path);
3815                candidates.push(joined);
3816            }
3817        }
3818
3819        let worktrees = self.worktrees(cx).collect::<Vec<_>>();
3820        cx.spawn(|_, mut cx| async move {
3821            for worktree in worktrees {
3822                for candidate in candidates.iter() {
3823                    let path = worktree
3824                        .update(&mut cx, |worktree, _| {
3825                            let root_entry_path = &worktree.root_entry()?.path;
3826
3827                            let resolved = resolve_path(root_entry_path, candidate);
3828
3829                            let stripped =
3830                                resolved.strip_prefix(root_entry_path).unwrap_or(&resolved);
3831
3832                            worktree.entry_for_path(stripped).map(|entry| {
3833                                ResolvedPath::ProjectPath(ProjectPath {
3834                                    worktree_id: worktree.id(),
3835                                    path: entry.path.clone(),
3836                                })
3837                            })
3838                        })
3839                        .ok()?;
3840
3841                    if path.is_some() {
3842                        return path;
3843                    }
3844                }
3845            }
3846            None
3847        })
3848    }
3849
3850    pub fn list_directory(
3851        &self,
3852        query: String,
3853        cx: &mut ModelContext<Self>,
3854    ) -> Task<Result<Vec<PathBuf>>> {
3855        if self.is_local_or_ssh() {
3856            DirectoryLister::Local(self.fs.clone()).list_directory(query, cx)
3857        } else if let Some(dev_server) = self.dev_server_project_id().and_then(|id| {
3858            dev_server_projects::Store::global(cx)
3859                .read(cx)
3860                .dev_server_for_project(id)
3861        }) {
3862            let request = proto::ListRemoteDirectory {
3863                dev_server_id: dev_server.id.0,
3864                path: query,
3865            };
3866            let response = self.client.request(request);
3867            cx.background_executor().spawn(async move {
3868                let response = response.await?;
3869                Ok(response.entries.into_iter().map(PathBuf::from).collect())
3870            })
3871        } else {
3872            Task::ready(Err(anyhow!("cannot list directory in remote project")))
3873        }
3874    }
3875
3876    fn create_worktree(
3877        &mut self,
3878        abs_path: impl AsRef<Path>,
3879        visible: bool,
3880        cx: &mut ModelContext<Self>,
3881    ) -> Task<Result<Model<Worktree>>> {
3882        self.worktree_store.update(cx, |worktree_store, cx| {
3883            worktree_store.create_worktree(abs_path, visible, cx)
3884        })
3885    }
3886
3887    pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
3888        self.worktree_store.update(cx, |worktree_store, cx| {
3889            worktree_store.remove_worktree(id_to_remove, cx);
3890        });
3891    }
3892
3893    fn add_worktree(&mut self, worktree: &Model<Worktree>, cx: &mut ModelContext<Self>) {
3894        self.worktree_store.update(cx, |worktree_store, cx| {
3895            worktree_store.add(worktree, cx);
3896        });
3897    }
3898
3899    fn update_local_worktree_settings(
3900        &mut self,
3901        worktree: &Model<Worktree>,
3902        changes: &UpdatedEntriesSet,
3903        cx: &mut ModelContext<Self>,
3904    ) {
3905        if worktree.read(cx).is_remote() {
3906            return;
3907        }
3908        let remote_worktree_id = worktree.read(cx).id();
3909
3910        for (path, _, change) in changes.iter() {
3911            let removed = change == &PathChange::Removed;
3912            let abs_path = match worktree.read(cx).absolutize(path) {
3913                Ok(abs_path) => abs_path,
3914                Err(e) => {
3915                    log::warn!("Cannot absolutize {path:?} received as {change:?} FS change: {e}");
3916                    continue;
3917                }
3918            };
3919
3920            if path.ends_with(local_tasks_file_relative_path()) {
3921                self.task_inventory().update(cx, |task_inventory, cx| {
3922                    if removed {
3923                        task_inventory.remove_local_static_source(&abs_path);
3924                    } else {
3925                        let fs = self.fs.clone();
3926                        let task_abs_path = abs_path.clone();
3927                        let tasks_file_rx =
3928                            watch_config_file(cx.background_executor(), fs, task_abs_path);
3929                        task_inventory.add_source(
3930                            TaskSourceKind::Worktree {
3931                                id: remote_worktree_id,
3932                                abs_path,
3933                                id_base: "local_tasks_for_worktree".into(),
3934                            },
3935                            |tx, cx| StaticSource::new(TrackedFile::new(tasks_file_rx, tx, cx)),
3936                            cx,
3937                        );
3938                    }
3939                })
3940            } else if path.ends_with(local_vscode_tasks_file_relative_path()) {
3941                self.task_inventory().update(cx, |task_inventory, cx| {
3942                    if removed {
3943                        task_inventory.remove_local_static_source(&abs_path);
3944                    } else {
3945                        let fs = self.fs.clone();
3946                        let task_abs_path = abs_path.clone();
3947                        let tasks_file_rx =
3948                            watch_config_file(cx.background_executor(), fs, task_abs_path);
3949                        task_inventory.add_source(
3950                            TaskSourceKind::Worktree {
3951                                id: remote_worktree_id,
3952                                abs_path,
3953                                id_base: "local_vscode_tasks_for_worktree".into(),
3954                            },
3955                            |tx, cx| {
3956                                StaticSource::new(TrackedFile::new_convertible::<
3957                                    task::VsCodeTaskFile,
3958                                >(
3959                                    tasks_file_rx, tx, cx
3960                                ))
3961                            },
3962                            cx,
3963                        );
3964                    }
3965                })
3966            }
3967        }
3968    }
3969
3970    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
3971        let new_active_entry = entry.and_then(|project_path| {
3972            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
3973            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
3974            Some(entry.id)
3975        });
3976        if new_active_entry != self.active_entry {
3977            self.active_entry = new_active_entry;
3978            self.lsp_store.update(cx, |lsp_store, _| {
3979                lsp_store.set_active_entry(new_active_entry);
3980            });
3981            cx.emit(Event::ActiveEntryChanged(new_active_entry));
3982        }
3983    }
3984
3985    pub fn language_servers_running_disk_based_diagnostics<'a>(
3986        &'a self,
3987        cx: &'a AppContext,
3988    ) -> impl Iterator<Item = LanguageServerId> + 'a {
3989        self.lsp_store
3990            .read(cx)
3991            .language_servers_running_disk_based_diagnostics()
3992    }
3993
3994    pub fn diagnostic_summary(&self, include_ignored: bool, cx: &AppContext) -> DiagnosticSummary {
3995        let mut summary = DiagnosticSummary::default();
3996        for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
3997            summary.error_count += path_summary.error_count;
3998            summary.warning_count += path_summary.warning_count;
3999        }
4000        summary
4001    }
4002
4003    pub fn diagnostic_summaries<'a>(
4004        &'a self,
4005        include_ignored: bool,
4006        cx: &'a AppContext,
4007    ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
4008        self.lsp_store
4009            .read(cx)
4010            .diagnostic_summaries(include_ignored, cx)
4011    }
4012
4013    pub fn active_entry(&self) -> Option<ProjectEntryId> {
4014        self.active_entry
4015    }
4016
4017    pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<Entry> {
4018        self.worktree_store.read(cx).entry_for_path(path, cx)
4019    }
4020
4021    pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
4022        let worktree = self.worktree_for_entry(entry_id, cx)?;
4023        let worktree = worktree.read(cx);
4024        let worktree_id = worktree.id();
4025        let path = worktree.entry_for_id(entry_id)?.path.clone();
4026        Some(ProjectPath { worktree_id, path })
4027    }
4028
4029    pub fn absolute_path(&self, project_path: &ProjectPath, cx: &AppContext) -> Option<PathBuf> {
4030        let workspace_root = self
4031            .worktree_for_id(project_path.worktree_id, cx)?
4032            .read(cx)
4033            .abs_path();
4034        let project_path = project_path.path.as_ref();
4035
4036        Some(if project_path == Path::new("") {
4037            workspace_root.to_path_buf()
4038        } else {
4039            workspace_root.join(project_path)
4040        })
4041    }
4042
4043    /// Attempts to find a `ProjectPath` corresponding to the given path. If the path
4044    /// is a *full path*, meaning it starts with the root name of a worktree, we'll locate
4045    /// it in that worktree. Otherwise, we'll attempt to find it as a relative path in
4046    /// the first visible worktree that has an entry for that relative path.
4047    ///
4048    /// We use this to resolve edit steps, when there's a chance an LLM may omit the workree
4049    /// root name from paths.
4050    ///
4051    /// # Arguments
4052    ///
4053    /// * `path` - A full path that starts with a worktree root name, or alternatively a
4054    ///            relative path within a visible worktree.
4055    /// * `cx` - A reference to the `AppContext`.
4056    ///
4057    /// # Returns
4058    ///
4059    /// Returns `Some(ProjectPath)` if a matching worktree is found, otherwise `None`.
4060    pub fn find_project_path(&self, path: &Path, cx: &AppContext) -> Option<ProjectPath> {
4061        let worktree_store = self.worktree_store.read(cx);
4062
4063        for worktree in worktree_store.visible_worktrees(cx) {
4064            let worktree_root_name = worktree.read(cx).root_name();
4065            if let Ok(relative_path) = path.strip_prefix(worktree_root_name) {
4066                return Some(ProjectPath {
4067                    worktree_id: worktree.read(cx).id(),
4068                    path: relative_path.into(),
4069                });
4070            }
4071        }
4072
4073        for worktree in worktree_store.visible_worktrees(cx) {
4074            let worktree = worktree.read(cx);
4075            if let Some(entry) = worktree.entry_for_path(path) {
4076                return Some(ProjectPath {
4077                    worktree_id: worktree.id(),
4078                    path: entry.path.clone(),
4079                });
4080            }
4081        }
4082
4083        None
4084    }
4085
4086    pub fn get_workspace_root(
4087        &self,
4088        project_path: &ProjectPath,
4089        cx: &AppContext,
4090    ) -> Option<PathBuf> {
4091        Some(
4092            self.worktree_for_id(project_path.worktree_id, cx)?
4093                .read(cx)
4094                .abs_path()
4095                .to_path_buf(),
4096        )
4097    }
4098
4099    pub fn get_repo(
4100        &self,
4101        project_path: &ProjectPath,
4102        cx: &AppContext,
4103    ) -> Option<Arc<dyn GitRepository>> {
4104        self.worktree_for_id(project_path.worktree_id, cx)?
4105            .read(cx)
4106            .as_local()?
4107            .local_git_repo(&project_path.path)
4108    }
4109
4110    pub fn get_first_worktree_root_repo(&self, cx: &AppContext) -> Option<Arc<dyn GitRepository>> {
4111        let worktree = self.visible_worktrees(cx).next()?.read(cx).as_local()?;
4112        let root_entry = worktree.root_git_entry()?;
4113        worktree.get_local_repo(&root_entry)?.repo().clone().into()
4114    }
4115
4116    pub fn blame_buffer(
4117        &self,
4118        buffer: &Model<Buffer>,
4119        version: Option<clock::Global>,
4120        cx: &AppContext,
4121    ) -> Task<Result<Blame>> {
4122        self.buffer_store.read(cx).blame_buffer(buffer, version, cx)
4123    }
4124
4125    // RPC message handlers
4126
4127    async fn handle_unshare_project(
4128        this: Model<Self>,
4129        _: TypedEnvelope<proto::UnshareProject>,
4130        mut cx: AsyncAppContext,
4131    ) -> Result<()> {
4132        this.update(&mut cx, |this, cx| {
4133            if this.is_local_or_ssh() {
4134                this.unshare(cx)?;
4135            } else {
4136                this.disconnected_from_host(cx);
4137            }
4138            Ok(())
4139        })?
4140    }
4141
4142    async fn handle_add_collaborator(
4143        this: Model<Self>,
4144        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4145        mut cx: AsyncAppContext,
4146    ) -> Result<()> {
4147        let collaborator = envelope
4148            .payload
4149            .collaborator
4150            .take()
4151            .ok_or_else(|| anyhow!("empty collaborator"))?;
4152
4153        let collaborator = Collaborator::from_proto(collaborator)?;
4154        this.update(&mut cx, |this, cx| {
4155            this.buffer_store.update(cx, |buffer_store, _| {
4156                buffer_store.forget_shared_buffers_for(&collaborator.peer_id);
4157            });
4158            cx.emit(Event::CollaboratorJoined(collaborator.peer_id));
4159            this.collaborators
4160                .insert(collaborator.peer_id, collaborator);
4161            cx.notify();
4162        })?;
4163
4164        Ok(())
4165    }
4166
4167    async fn handle_update_project_collaborator(
4168        this: Model<Self>,
4169        envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
4170        mut cx: AsyncAppContext,
4171    ) -> Result<()> {
4172        let old_peer_id = envelope
4173            .payload
4174            .old_peer_id
4175            .ok_or_else(|| anyhow!("missing old peer id"))?;
4176        let new_peer_id = envelope
4177            .payload
4178            .new_peer_id
4179            .ok_or_else(|| anyhow!("missing new peer id"))?;
4180        this.update(&mut cx, |this, cx| {
4181            let collaborator = this
4182                .collaborators
4183                .remove(&old_peer_id)
4184                .ok_or_else(|| anyhow!("received UpdateProjectCollaborator for unknown peer"))?;
4185            let is_host = collaborator.replica_id == 0;
4186            this.collaborators.insert(new_peer_id, collaborator);
4187
4188            log::info!("peer {} became {}", old_peer_id, new_peer_id,);
4189            this.buffer_store.update(cx, |buffer_store, _| {
4190                buffer_store.update_peer_id(&old_peer_id, new_peer_id)
4191            });
4192
4193            if is_host {
4194                this.buffer_store
4195                    .update(cx, |buffer_store, _| buffer_store.discard_incomplete());
4196                this.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
4197                    .unwrap();
4198                cx.emit(Event::HostReshared);
4199            }
4200
4201            cx.emit(Event::CollaboratorUpdated {
4202                old_peer_id,
4203                new_peer_id,
4204            });
4205            cx.notify();
4206            Ok(())
4207        })?
4208    }
4209
4210    async fn handle_remove_collaborator(
4211        this: Model<Self>,
4212        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4213        mut cx: AsyncAppContext,
4214    ) -> Result<()> {
4215        this.update(&mut cx, |this, cx| {
4216            let peer_id = envelope
4217                .payload
4218                .peer_id
4219                .ok_or_else(|| anyhow!("invalid peer id"))?;
4220            let replica_id = this
4221                .collaborators
4222                .remove(&peer_id)
4223                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4224                .replica_id;
4225            this.buffer_store.update(cx, |buffer_store, cx| {
4226                buffer_store.forget_shared_buffers_for(&peer_id);
4227                for buffer in buffer_store.buffers() {
4228                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4229                }
4230            });
4231
4232            cx.emit(Event::CollaboratorLeft(peer_id));
4233            cx.notify();
4234            Ok(())
4235        })?
4236    }
4237
4238    async fn handle_update_project(
4239        this: Model<Self>,
4240        envelope: TypedEnvelope<proto::UpdateProject>,
4241        mut cx: AsyncAppContext,
4242    ) -> Result<()> {
4243        this.update(&mut cx, |this, cx| {
4244            // Don't handle messages that were sent before the response to us joining the project
4245            if envelope.message_id > this.join_project_response_message_id {
4246                this.set_worktrees_from_proto(envelope.payload.worktrees, cx)?;
4247            }
4248            Ok(())
4249        })?
4250    }
4251
4252    async fn handle_update_worktree(
4253        this: Model<Self>,
4254        envelope: TypedEnvelope<proto::UpdateWorktree>,
4255        mut cx: AsyncAppContext,
4256    ) -> Result<()> {
4257        this.update(&mut cx, |this, cx| {
4258            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4259            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4260                worktree.update(cx, |worktree, _| {
4261                    let worktree = worktree.as_remote_mut().unwrap();
4262                    worktree.update_from_remote(envelope.payload);
4263                });
4264            }
4265            Ok(())
4266        })?
4267    }
4268
4269    async fn handle_update_buffer(
4270        this: Model<Self>,
4271        envelope: TypedEnvelope<proto::UpdateBuffer>,
4272        cx: AsyncAppContext,
4273    ) -> Result<proto::Ack> {
4274        let buffer_store = this.read_with(&cx, |this, cx| {
4275            if let Some(ssh) = &this.ssh_session {
4276                let mut payload = envelope.payload.clone();
4277                payload.project_id = 0;
4278                cx.background_executor()
4279                    .spawn(ssh.request(payload))
4280                    .detach_and_log_err(cx);
4281            }
4282            this.buffer_store.clone()
4283        })?;
4284        BufferStore::handle_update_buffer(buffer_store, envelope, cx).await
4285    }
4286
4287    fn retain_remotely_created_buffers(
4288        &mut self,
4289        cx: &mut ModelContext<Self>,
4290    ) -> RemotelyCreatedBufferGuard {
4291        {
4292            let mut remotely_created_buffers = self.remotely_created_buffers.lock();
4293            if remotely_created_buffers.retain_count == 0 {
4294                remotely_created_buffers.buffers = self.buffer_store.read(cx).buffers().collect();
4295            }
4296            remotely_created_buffers.retain_count += 1;
4297        }
4298        RemotelyCreatedBufferGuard {
4299            remote_buffers: Arc::downgrade(&self.remotely_created_buffers),
4300        }
4301    }
4302
4303    async fn handle_create_buffer_for_peer(
4304        this: Model<Self>,
4305        envelope: TypedEnvelope<proto::CreateBufferForPeer>,
4306        mut cx: AsyncAppContext,
4307    ) -> Result<()> {
4308        this.update(&mut cx, |this, cx| {
4309            this.buffer_store.update(cx, |buffer_store, cx| {
4310                buffer_store.handle_create_buffer_for_peer(
4311                    envelope,
4312                    this.replica_id(),
4313                    this.capability(),
4314                    cx,
4315                )
4316            })
4317        })?
4318    }
4319
4320    async fn handle_reload_buffers(
4321        this: Model<Self>,
4322        envelope: TypedEnvelope<proto::ReloadBuffers>,
4323        mut cx: AsyncAppContext,
4324    ) -> Result<proto::ReloadBuffersResponse> {
4325        let sender_id = envelope.original_sender_id()?;
4326        let reload = this.update(&mut cx, |this, cx| {
4327            let mut buffers = HashSet::default();
4328            for buffer_id in &envelope.payload.buffer_ids {
4329                let buffer_id = BufferId::new(*buffer_id)?;
4330                buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
4331            }
4332            Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
4333        })??;
4334
4335        let project_transaction = reload.await?;
4336        let project_transaction = this.update(&mut cx, |this, cx| {
4337            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
4338        })?;
4339        Ok(proto::ReloadBuffersResponse {
4340            transaction: Some(project_transaction),
4341        })
4342    }
4343
4344    async fn handle_synchronize_buffers(
4345        this: Model<Self>,
4346        envelope: TypedEnvelope<proto::SynchronizeBuffers>,
4347        mut cx: AsyncAppContext,
4348    ) -> Result<proto::SynchronizeBuffersResponse> {
4349        let response = this.update(&mut cx, |this, cx| {
4350            let client = this.client.clone();
4351            this.buffer_store.update(cx, |this, cx| {
4352                this.handle_synchronize_buffers(envelope, cx, client)
4353            })
4354        })??;
4355
4356        Ok(response)
4357    }
4358
4359    async fn handle_format_buffers(
4360        this: Model<Self>,
4361        envelope: TypedEnvelope<proto::FormatBuffers>,
4362        mut cx: AsyncAppContext,
4363    ) -> Result<proto::FormatBuffersResponse> {
4364        let sender_id = envelope.original_sender_id()?;
4365        let format = this.update(&mut cx, |this, cx| {
4366            let mut buffers = HashSet::default();
4367            for buffer_id in &envelope.payload.buffer_ids {
4368                let buffer_id = BufferId::new(*buffer_id)?;
4369                buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
4370            }
4371            let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
4372            Ok::<_, anyhow::Error>(this.format(buffers, false, trigger, cx))
4373        })??;
4374
4375        let project_transaction = format.await?;
4376        let project_transaction = this.update(&mut cx, |this, cx| {
4377            this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
4378        })?;
4379        Ok(proto::FormatBuffersResponse {
4380            transaction: Some(project_transaction),
4381        })
4382    }
4383
4384    async fn handle_task_context_for_location(
4385        project: Model<Self>,
4386        envelope: TypedEnvelope<proto::TaskContextForLocation>,
4387        mut cx: AsyncAppContext,
4388    ) -> Result<proto::TaskContext> {
4389        let location = envelope
4390            .payload
4391            .location
4392            .context("no location given for task context handling")?;
4393        let location = cx
4394            .update(|cx| deserialize_location(&project, location, cx))?
4395            .await?;
4396        let context_task = project.update(&mut cx, |project, cx| {
4397            let captured_variables = {
4398                let mut variables = TaskVariables::default();
4399                for range in location
4400                    .buffer
4401                    .read(cx)
4402                    .snapshot()
4403                    .runnable_ranges(location.range.clone())
4404                {
4405                    for (capture_name, value) in range.extra_captures {
4406                        variables.insert(VariableName::Custom(capture_name.into()), value);
4407                    }
4408                }
4409                variables
4410            };
4411            project.task_context_for_location(captured_variables, location, cx)
4412        })?;
4413        let task_context = context_task.await.unwrap_or_default();
4414        Ok(proto::TaskContext {
4415            project_env: task_context.project_env.into_iter().collect(),
4416            cwd: task_context
4417                .cwd
4418                .map(|cwd| cwd.to_string_lossy().to_string()),
4419            task_variables: task_context
4420                .task_variables
4421                .into_iter()
4422                .map(|(variable_name, variable_value)| (variable_name.to_string(), variable_value))
4423                .collect(),
4424        })
4425    }
4426
4427    async fn handle_task_templates(
4428        project: Model<Self>,
4429        envelope: TypedEnvelope<proto::TaskTemplates>,
4430        mut cx: AsyncAppContext,
4431    ) -> Result<proto::TaskTemplatesResponse> {
4432        let worktree = envelope.payload.worktree_id.map(WorktreeId::from_proto);
4433        let location = match envelope.payload.location {
4434            Some(location) => Some(
4435                cx.update(|cx| deserialize_location(&project, location, cx))?
4436                    .await
4437                    .context("task templates request location deserializing")?,
4438            ),
4439            None => None,
4440        };
4441
4442        let templates = project
4443            .update(&mut cx, |project, cx| {
4444                project.task_templates(worktree, location, cx)
4445            })?
4446            .await
4447            .context("receiving task templates")?
4448            .into_iter()
4449            .map(|(kind, template)| {
4450                let kind = Some(match kind {
4451                    TaskSourceKind::UserInput => proto::task_source_kind::Kind::UserInput(
4452                        proto::task_source_kind::UserInput {},
4453                    ),
4454                    TaskSourceKind::Worktree {
4455                        id,
4456                        abs_path,
4457                        id_base,
4458                    } => {
4459                        proto::task_source_kind::Kind::Worktree(proto::task_source_kind::Worktree {
4460                            id: id.to_proto(),
4461                            abs_path: abs_path.to_string_lossy().to_string(),
4462                            id_base: id_base.to_string(),
4463                        })
4464                    }
4465                    TaskSourceKind::AbsPath { id_base, abs_path } => {
4466                        proto::task_source_kind::Kind::AbsPath(proto::task_source_kind::AbsPath {
4467                            abs_path: abs_path.to_string_lossy().to_string(),
4468                            id_base: id_base.to_string(),
4469                        })
4470                    }
4471                    TaskSourceKind::Language { name } => {
4472                        proto::task_source_kind::Kind::Language(proto::task_source_kind::Language {
4473                            name: name.to_string(),
4474                        })
4475                    }
4476                });
4477                let kind = Some(proto::TaskSourceKind { kind });
4478                let template = Some(proto::TaskTemplate {
4479                    label: template.label,
4480                    command: template.command,
4481                    args: template.args,
4482                    env: template.env.into_iter().collect(),
4483                    cwd: template.cwd,
4484                    use_new_terminal: template.use_new_terminal,
4485                    allow_concurrent_runs: template.allow_concurrent_runs,
4486                    reveal: match template.reveal {
4487                        RevealStrategy::Always => proto::RevealStrategy::RevealAlways as i32,
4488                        RevealStrategy::Never => proto::RevealStrategy::RevealNever as i32,
4489                    },
4490                    hide: match template.hide {
4491                        HideStrategy::Always => proto::HideStrategy::HideAlways as i32,
4492                        HideStrategy::Never => proto::HideStrategy::HideNever as i32,
4493                        HideStrategy::OnSuccess => proto::HideStrategy::HideOnSuccess as i32,
4494                    },
4495                    shell: Some(proto::Shell {
4496                        shell_type: Some(match template.shell {
4497                            Shell::System => proto::shell::ShellType::System(proto::System {}),
4498                            Shell::Program(program) => proto::shell::ShellType::Program(program),
4499                            Shell::WithArguments { program, args } => {
4500                                proto::shell::ShellType::WithArguments(
4501                                    proto::shell::WithArguments { program, args },
4502                                )
4503                            }
4504                        }),
4505                    }),
4506                    tags: template.tags,
4507                });
4508                proto::TemplatePair { kind, template }
4509            })
4510            .collect();
4511
4512        Ok(proto::TaskTemplatesResponse { templates })
4513    }
4514
4515    async fn handle_search_project(
4516        this: Model<Self>,
4517        envelope: TypedEnvelope<proto::SearchProject>,
4518        mut cx: AsyncAppContext,
4519    ) -> Result<proto::SearchProjectResponse> {
4520        let peer_id = envelope.original_sender_id()?;
4521        let query = SearchQuery::from_proto_v1(envelope.payload)?;
4522        let mut result = this.update(&mut cx, |this, cx| this.search(query, cx))?;
4523
4524        cx.spawn(move |mut cx| async move {
4525            let mut locations = Vec::new();
4526            let mut limit_reached = false;
4527            while let Some(result) = result.next().await {
4528                match result {
4529                    SearchResult::Buffer { buffer, ranges } => {
4530                        for range in ranges {
4531                            let start = serialize_anchor(&range.start);
4532                            let end = serialize_anchor(&range.end);
4533                            let buffer_id = this.update(&mut cx, |this, cx| {
4534                                this.create_buffer_for_peer(&buffer, peer_id, cx).into()
4535                            })?;
4536                            locations.push(proto::Location {
4537                                buffer_id,
4538                                start: Some(start),
4539                                end: Some(end),
4540                            });
4541                        }
4542                    }
4543                    SearchResult::LimitReached => limit_reached = true,
4544                }
4545            }
4546            Ok(proto::SearchProjectResponse {
4547                locations,
4548                limit_reached,
4549                // will restart
4550            })
4551        })
4552        .await
4553    }
4554
4555    async fn handle_search_candidate_buffers(
4556        this: Model<Self>,
4557        envelope: TypedEnvelope<proto::FindSearchCandidates>,
4558        mut cx: AsyncAppContext,
4559    ) -> Result<proto::FindSearchCandidatesResponse> {
4560        let peer_id = envelope.original_sender_id()?;
4561        let message = envelope.payload;
4562        let query = SearchQuery::from_proto(
4563            message
4564                .query
4565                .ok_or_else(|| anyhow!("missing query field"))?,
4566        )?;
4567        let mut results = this.update(&mut cx, |this, cx| {
4568            this.search_for_candidate_buffers(&query, message.limit as _, cx)
4569        })?;
4570
4571        let mut response = proto::FindSearchCandidatesResponse {
4572            buffer_ids: Vec::new(),
4573        };
4574
4575        while let Some(buffer) = results.next().await {
4576            this.update(&mut cx, |this, cx| {
4577                let buffer_id = this.create_buffer_for_peer(&buffer, peer_id, cx);
4578                response.buffer_ids.push(buffer_id.to_proto());
4579            })?;
4580        }
4581
4582        Ok(response)
4583    }
4584
4585    async fn handle_open_buffer_by_id(
4586        this: Model<Self>,
4587        envelope: TypedEnvelope<proto::OpenBufferById>,
4588        mut cx: AsyncAppContext,
4589    ) -> Result<proto::OpenBufferResponse> {
4590        let peer_id = envelope.original_sender_id()?;
4591        let buffer_id = BufferId::new(envelope.payload.id)?;
4592        let buffer = this
4593            .update(&mut cx, |this, cx| this.open_buffer_by_id(buffer_id, cx))?
4594            .await?;
4595        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4596    }
4597
4598    async fn handle_open_buffer_by_path(
4599        this: Model<Self>,
4600        envelope: TypedEnvelope<proto::OpenBufferByPath>,
4601        mut cx: AsyncAppContext,
4602    ) -> Result<proto::OpenBufferResponse> {
4603        let peer_id = envelope.original_sender_id()?;
4604        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4605        let open_buffer = this.update(&mut cx, |this, cx| {
4606            this.open_buffer(
4607                ProjectPath {
4608                    worktree_id,
4609                    path: PathBuf::from(envelope.payload.path).into(),
4610                },
4611                cx,
4612            )
4613        })?;
4614
4615        let buffer = open_buffer.await?;
4616        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4617    }
4618
4619    async fn handle_open_new_buffer(
4620        this: Model<Self>,
4621        envelope: TypedEnvelope<proto::OpenNewBuffer>,
4622        mut cx: AsyncAppContext,
4623    ) -> Result<proto::OpenBufferResponse> {
4624        let buffer = this.update(&mut cx, |this, cx| this.create_local_buffer("", None, cx))?;
4625        let peer_id = envelope.original_sender_id()?;
4626
4627        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4628    }
4629
4630    fn respond_to_open_buffer_request(
4631        this: Model<Self>,
4632        buffer: Model<Buffer>,
4633        peer_id: proto::PeerId,
4634        cx: &mut AsyncAppContext,
4635    ) -> Result<proto::OpenBufferResponse> {
4636        this.update(cx, |this, cx| {
4637            let is_private = buffer
4638                .read(cx)
4639                .file()
4640                .map(|f| f.is_private())
4641                .unwrap_or_default();
4642            if is_private {
4643                Err(anyhow!(ErrorCode::UnsharedItem))
4644            } else {
4645                Ok(proto::OpenBufferResponse {
4646                    buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx).into(),
4647                })
4648            }
4649        })?
4650    }
4651
4652    fn serialize_project_transaction_for_peer(
4653        &mut self,
4654        project_transaction: ProjectTransaction,
4655        peer_id: proto::PeerId,
4656        cx: &mut AppContext,
4657    ) -> proto::ProjectTransaction {
4658        self.buffer_store.update(cx, |buffer_store, cx| {
4659            buffer_store.serialize_project_transaction_for_peer(project_transaction, peer_id, cx)
4660        })
4661    }
4662
4663    fn create_buffer_for_peer(
4664        &mut self,
4665        buffer: &Model<Buffer>,
4666        peer_id: proto::PeerId,
4667        cx: &mut AppContext,
4668    ) -> BufferId {
4669        self.buffer_store
4670            .update(cx, |buffer_store, cx| {
4671                buffer_store.create_buffer_for_peer(buffer, peer_id, cx)
4672            })
4673            .detach_and_log_err(cx);
4674        buffer.read(cx).remote_id()
4675    }
4676
4677    fn wait_for_remote_buffer(
4678        &mut self,
4679        id: BufferId,
4680        cx: &mut ModelContext<Self>,
4681    ) -> Task<Result<Model<Buffer>>> {
4682        self.buffer_store.update(cx, |buffer_store, cx| {
4683            buffer_store.wait_for_remote_buffer(id, cx)
4684        })
4685    }
4686
4687    fn synchronize_remote_buffers(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
4688        let project_id = match self.client_state {
4689            ProjectClientState::Remote {
4690                sharing_has_stopped,
4691                remote_id,
4692                ..
4693            } => {
4694                if sharing_has_stopped {
4695                    return Task::ready(Err(anyhow!(
4696                        "can't synchronize remote buffers on a readonly project"
4697                    )));
4698                } else {
4699                    remote_id
4700                }
4701            }
4702            ProjectClientState::Shared { .. } | ProjectClientState::Local => {
4703                return Task::ready(Err(anyhow!(
4704                    "can't synchronize remote buffers on a local project"
4705                )))
4706            }
4707        };
4708
4709        let client = self.client.clone();
4710        cx.spawn(move |this, mut cx| async move {
4711            let (buffers, incomplete_buffer_ids) = this.update(&mut cx, |this, cx| {
4712                this.buffer_store.read(cx).buffer_version_info(cx)
4713            })?;
4714            let response = client
4715                .request(proto::SynchronizeBuffers {
4716                    project_id,
4717                    buffers,
4718                })
4719                .await?;
4720
4721            let send_updates_for_buffers = this.update(&mut cx, |this, cx| {
4722                response
4723                    .buffers
4724                    .into_iter()
4725                    .map(|buffer| {
4726                        let client = client.clone();
4727                        let buffer_id = match BufferId::new(buffer.id) {
4728                            Ok(id) => id,
4729                            Err(e) => {
4730                                return Task::ready(Err(e));
4731                            }
4732                        };
4733                        let remote_version = language::proto::deserialize_version(&buffer.version);
4734                        if let Some(buffer) = this.buffer_for_id(buffer_id, cx) {
4735                            let operations =
4736                                buffer.read(cx).serialize_ops(Some(remote_version), cx);
4737                            cx.background_executor().spawn(async move {
4738                                let operations = operations.await;
4739                                for chunk in split_operations(operations) {
4740                                    client
4741                                        .request(proto::UpdateBuffer {
4742                                            project_id,
4743                                            buffer_id: buffer_id.into(),
4744                                            operations: chunk,
4745                                        })
4746                                        .await?;
4747                                }
4748                                anyhow::Ok(())
4749                            })
4750                        } else {
4751                            Task::ready(Ok(()))
4752                        }
4753                    })
4754                    .collect::<Vec<_>>()
4755            })?;
4756
4757            // Any incomplete buffers have open requests waiting. Request that the host sends
4758            // creates these buffers for us again to unblock any waiting futures.
4759            for id in incomplete_buffer_ids {
4760                cx.background_executor()
4761                    .spawn(client.request(proto::OpenBufferById {
4762                        project_id,
4763                        id: id.into(),
4764                    }))
4765                    .detach();
4766            }
4767
4768            futures::future::join_all(send_updates_for_buffers)
4769                .await
4770                .into_iter()
4771                .collect()
4772        })
4773    }
4774
4775    pub fn worktree_metadata_protos(&self, cx: &AppContext) -> Vec<proto::WorktreeMetadata> {
4776        self.worktrees(cx)
4777            .map(|worktree| {
4778                let worktree = worktree.read(cx);
4779                proto::WorktreeMetadata {
4780                    id: worktree.id().to_proto(),
4781                    root_name: worktree.root_name().into(),
4782                    visible: worktree.is_visible(),
4783                    abs_path: worktree.abs_path().to_string_lossy().into(),
4784                }
4785            })
4786            .collect()
4787    }
4788
4789    fn set_worktrees_from_proto(
4790        &mut self,
4791        worktrees: Vec<proto::WorktreeMetadata>,
4792        cx: &mut ModelContext<Project>,
4793    ) -> Result<()> {
4794        self.metadata_changed(cx);
4795        self.worktree_store.update(cx, |worktree_store, cx| {
4796            worktree_store.set_worktrees_from_proto(
4797                worktrees,
4798                self.replica_id(),
4799                self.remote_id().ok_or_else(|| anyhow!("invalid project"))?,
4800                self.client.clone().into(),
4801                cx,
4802            )
4803        })
4804    }
4805
4806    fn set_collaborators_from_proto(
4807        &mut self,
4808        messages: Vec<proto::Collaborator>,
4809        cx: &mut ModelContext<Self>,
4810    ) -> Result<()> {
4811        let mut collaborators = HashMap::default();
4812        for message in messages {
4813            let collaborator = Collaborator::from_proto(message)?;
4814            collaborators.insert(collaborator.peer_id, collaborator);
4815        }
4816        for old_peer_id in self.collaborators.keys() {
4817            if !collaborators.contains_key(old_peer_id) {
4818                cx.emit(Event::CollaboratorLeft(*old_peer_id));
4819            }
4820        }
4821        self.collaborators = collaborators;
4822        Ok(())
4823    }
4824
4825    pub fn language_servers<'a>(
4826        &'a self,
4827        cx: &'a AppContext,
4828    ) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
4829        self.lsp_store.read(cx).language_servers()
4830    }
4831
4832    pub fn supplementary_language_servers<'a>(
4833        &'a self,
4834        cx: &'a AppContext,
4835    ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
4836        self.lsp_store.read(cx).supplementary_language_servers()
4837    }
4838
4839    pub fn language_server_adapter_for_id(
4840        &self,
4841        id: LanguageServerId,
4842        cx: &AppContext,
4843    ) -> Option<Arc<CachedLspAdapter>> {
4844        self.lsp_store.read(cx).language_server_adapter_for_id(id)
4845    }
4846
4847    pub fn language_server_for_id(
4848        &self,
4849        id: LanguageServerId,
4850        cx: &AppContext,
4851    ) -> Option<Arc<LanguageServer>> {
4852        self.lsp_store.read(cx).language_server_for_id(id)
4853    }
4854
4855    pub fn language_servers_for_buffer<'a>(
4856        &'a self,
4857        buffer: &'a Buffer,
4858        cx: &'a AppContext,
4859    ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
4860        self.lsp_store
4861            .read(cx)
4862            .language_servers_for_buffer(buffer, cx)
4863    }
4864
4865    pub fn language_server_for_buffer<'a>(
4866        &'a self,
4867        buffer: &'a Buffer,
4868        server_id: LanguageServerId,
4869        cx: &'a AppContext,
4870    ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
4871        self.lsp_store
4872            .read(cx)
4873            .language_server_for_buffer(buffer, server_id, cx)
4874    }
4875
4876    pub fn task_context_for_location(
4877        &self,
4878        captured_variables: TaskVariables,
4879        location: Location,
4880        cx: &mut ModelContext<'_, Project>,
4881    ) -> Task<Option<TaskContext>> {
4882        if self.is_local_or_ssh() {
4883            let (worktree_id, worktree_abs_path) = if let Some(worktree) = self.task_worktree(cx) {
4884                (
4885                    Some(worktree.read(cx).id()),
4886                    Some(worktree.read(cx).abs_path()),
4887                )
4888            } else {
4889                (None, None)
4890            };
4891
4892            cx.spawn(|project, mut cx| async move {
4893                let mut task_variables = cx
4894                    .update(|cx| {
4895                        combine_task_variables(
4896                            captured_variables,
4897                            location,
4898                            BasicContextProvider::new(project.upgrade()?),
4899                            cx,
4900                        )
4901                        .log_err()
4902                    })
4903                    .ok()
4904                    .flatten()?;
4905                // Remove all custom entries starting with _, as they're not intended for use by the end user.
4906                task_variables.sweep();
4907
4908                let project_env = project
4909                    .update(&mut cx, |project, cx| {
4910                        let worktree_abs_path = worktree_abs_path.clone();
4911                        project.environment.update(cx, |environment, cx| {
4912                            environment.get_environment(worktree_id, worktree_abs_path, cx)
4913                        })
4914                    })
4915                    .ok()?
4916                    .await;
4917
4918                Some(TaskContext {
4919                    project_env: project_env.unwrap_or_default(),
4920                    cwd: worktree_abs_path.map(|p| p.to_path_buf()),
4921                    task_variables,
4922                })
4923            })
4924        } else if let Some(project_id) = self
4925            .remote_id()
4926            .filter(|_| self.ssh_connection_string(cx).is_some())
4927        {
4928            let task_context = self.client().request(proto::TaskContextForLocation {
4929                project_id,
4930                location: Some(proto::Location {
4931                    buffer_id: location.buffer.read(cx).remote_id().into(),
4932                    start: Some(serialize_anchor(&location.range.start)),
4933                    end: Some(serialize_anchor(&location.range.end)),
4934                }),
4935            });
4936            cx.background_executor().spawn(async move {
4937                let task_context = task_context.await.log_err()?;
4938                Some(TaskContext {
4939                    project_env: task_context.project_env.into_iter().collect(),
4940                    cwd: task_context.cwd.map(PathBuf::from),
4941                    task_variables: task_context
4942                        .task_variables
4943                        .into_iter()
4944                        .filter_map(
4945                            |(variable_name, variable_value)| match variable_name.parse() {
4946                                Ok(variable_name) => Some((variable_name, variable_value)),
4947                                Err(()) => {
4948                                    log::error!("Unknown variable name: {variable_name}");
4949                                    None
4950                                }
4951                            },
4952                        )
4953                        .collect(),
4954                })
4955            })
4956        } else {
4957            Task::ready(None)
4958        }
4959    }
4960
4961    pub fn task_templates(
4962        &self,
4963        worktree: Option<WorktreeId>,
4964        location: Option<Location>,
4965        cx: &mut ModelContext<Self>,
4966    ) -> Task<Result<Vec<(TaskSourceKind, TaskTemplate)>>> {
4967        if self.is_local_or_ssh() {
4968            let (file, language) = location
4969                .map(|location| {
4970                    let buffer = location.buffer.read(cx);
4971                    (
4972                        buffer.file().cloned(),
4973                        buffer.language_at(location.range.start),
4974                    )
4975                })
4976                .unwrap_or_default();
4977            Task::ready(Ok(self
4978                .task_inventory()
4979                .read(cx)
4980                .list_tasks(file, language, worktree, cx)))
4981        } else if let Some(project_id) = self
4982            .remote_id()
4983            .filter(|_| self.ssh_connection_string(cx).is_some())
4984        {
4985            let remote_templates =
4986                self.query_remote_task_templates(project_id, worktree, location.as_ref(), cx);
4987            cx.background_executor().spawn(remote_templates)
4988        } else {
4989            Task::ready(Ok(Vec::new()))
4990        }
4991    }
4992
4993    pub fn query_remote_task_templates(
4994        &self,
4995        project_id: u64,
4996        worktree: Option<WorktreeId>,
4997        location: Option<&Location>,
4998        cx: &AppContext,
4999    ) -> Task<Result<Vec<(TaskSourceKind, TaskTemplate)>>> {
5000        let client = self.client();
5001        let location = location.map(|location| serialize_location(location, cx));
5002        cx.spawn(|_| async move {
5003            let response = client
5004                .request(proto::TaskTemplates {
5005                    project_id,
5006                    worktree_id: worktree.map(|id| id.to_proto()),
5007                    location,
5008                })
5009                .await?;
5010
5011            Ok(response
5012                .templates
5013                .into_iter()
5014                .filter_map(|template_pair| {
5015                    let task_source_kind = match template_pair.kind?.kind? {
5016                        proto::task_source_kind::Kind::UserInput(_) => TaskSourceKind::UserInput,
5017                        proto::task_source_kind::Kind::Worktree(worktree) => {
5018                            TaskSourceKind::Worktree {
5019                                id: WorktreeId::from_proto(worktree.id),
5020                                abs_path: PathBuf::from(worktree.abs_path),
5021                                id_base: Cow::Owned(worktree.id_base),
5022                            }
5023                        }
5024                        proto::task_source_kind::Kind::AbsPath(abs_path) => {
5025                            TaskSourceKind::AbsPath {
5026                                id_base: Cow::Owned(abs_path.id_base),
5027                                abs_path: PathBuf::from(abs_path.abs_path),
5028                            }
5029                        }
5030                        proto::task_source_kind::Kind::Language(language) => {
5031                            TaskSourceKind::Language {
5032                                name: language.name.into(),
5033                            }
5034                        }
5035                    };
5036
5037                    let proto_template = template_pair.template?;
5038                    let reveal = match proto::RevealStrategy::from_i32(proto_template.reveal)
5039                        .unwrap_or(proto::RevealStrategy::RevealAlways)
5040                    {
5041                        proto::RevealStrategy::RevealAlways => RevealStrategy::Always,
5042                        proto::RevealStrategy::RevealNever => RevealStrategy::Never,
5043                    };
5044                    let hide = match proto::HideStrategy::from_i32(proto_template.hide)
5045                        .unwrap_or(proto::HideStrategy::HideNever)
5046                    {
5047                        proto::HideStrategy::HideAlways => HideStrategy::Always,
5048                        proto::HideStrategy::HideNever => HideStrategy::Never,
5049                        proto::HideStrategy::HideOnSuccess => HideStrategy::OnSuccess,
5050                    };
5051                    let shell = match proto_template
5052                        .shell
5053                        .and_then(|shell| shell.shell_type)
5054                        .unwrap_or(proto::shell::ShellType::System(proto::System {}))
5055                    {
5056                        proto::shell::ShellType::System(_) => Shell::System,
5057                        proto::shell::ShellType::Program(program) => Shell::Program(program),
5058                        proto::shell::ShellType::WithArguments(with_arguments) => {
5059                            Shell::WithArguments {
5060                                program: with_arguments.program,
5061                                args: with_arguments.args,
5062                            }
5063                        }
5064                    };
5065                    let task_template = TaskTemplate {
5066                        label: proto_template.label,
5067                        command: proto_template.command,
5068                        args: proto_template.args,
5069                        env: proto_template.env.into_iter().collect(),
5070                        cwd: proto_template.cwd,
5071                        use_new_terminal: proto_template.use_new_terminal,
5072                        allow_concurrent_runs: proto_template.allow_concurrent_runs,
5073                        reveal,
5074                        hide,
5075                        shell,
5076                        tags: proto_template.tags,
5077                    };
5078                    Some((task_source_kind, task_template))
5079                })
5080                .collect())
5081        })
5082    }
5083
5084    fn task_worktree(&self, cx: &AppContext) -> Option<Model<Worktree>> {
5085        let available_worktrees = self
5086            .worktrees(cx)
5087            .filter(|worktree| {
5088                let worktree = worktree.read(cx);
5089                worktree.is_visible()
5090                    && worktree.is_local()
5091                    && worktree.root_entry().map_or(false, |e| e.is_dir())
5092            })
5093            .collect::<Vec<_>>();
5094
5095        match available_worktrees.len() {
5096            0 => None,
5097            1 => Some(available_worktrees[0].clone()),
5098            _ => self.active_entry().and_then(|entry_id| {
5099                available_worktrees.into_iter().find_map(|worktree| {
5100                    if worktree.read(cx).contains_entry(entry_id) {
5101                        Some(worktree)
5102                    } else {
5103                        None
5104                    }
5105                })
5106            }),
5107        }
5108    }
5109}
5110
5111fn combine_task_variables(
5112    mut captured_variables: TaskVariables,
5113    location: Location,
5114    baseline: BasicContextProvider,
5115    cx: &mut AppContext,
5116) -> anyhow::Result<TaskVariables> {
5117    let language_context_provider = location
5118        .buffer
5119        .read(cx)
5120        .language()
5121        .and_then(|language| language.context_provider());
5122    let baseline = baseline
5123        .build_context(&captured_variables, &location, cx)
5124        .context("building basic default context")?;
5125    captured_variables.extend(baseline);
5126    if let Some(provider) = language_context_provider {
5127        captured_variables.extend(
5128            provider
5129                .build_context(&captured_variables, &location, cx)
5130                .context("building provider context")?,
5131        );
5132    }
5133    Ok(captured_variables)
5134}
5135
5136fn deserialize_code_actions(code_actions: &HashMap<String, bool>) -> Vec<lsp::CodeActionKind> {
5137    code_actions
5138        .iter()
5139        .flat_map(|(kind, enabled)| {
5140            if *enabled {
5141                Some(kind.clone().into())
5142            } else {
5143                None
5144            }
5145        })
5146        .collect()
5147}
5148
5149pub struct PathMatchCandidateSet {
5150    pub snapshot: Snapshot,
5151    pub include_ignored: bool,
5152    pub include_root_name: bool,
5153    pub candidates: Candidates,
5154}
5155
5156pub enum Candidates {
5157    /// Only consider directories.
5158    Directories,
5159    /// Only consider files.
5160    Files,
5161    /// Consider directories and files.
5162    Entries,
5163}
5164
5165impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
5166    type Candidates = PathMatchCandidateSetIter<'a>;
5167
5168    fn id(&self) -> usize {
5169        self.snapshot.id().to_usize()
5170    }
5171
5172    fn len(&self) -> usize {
5173        match self.candidates {
5174            Candidates::Files => {
5175                if self.include_ignored {
5176                    self.snapshot.file_count()
5177                } else {
5178                    self.snapshot.visible_file_count()
5179                }
5180            }
5181
5182            Candidates::Directories => {
5183                if self.include_ignored {
5184                    self.snapshot.dir_count()
5185                } else {
5186                    self.snapshot.visible_dir_count()
5187                }
5188            }
5189
5190            Candidates::Entries => {
5191                if self.include_ignored {
5192                    self.snapshot.entry_count()
5193                } else {
5194                    self.snapshot.visible_entry_count()
5195                }
5196            }
5197        }
5198    }
5199
5200    fn prefix(&self) -> Arc<str> {
5201        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
5202            self.snapshot.root_name().into()
5203        } else if self.include_root_name {
5204            format!("{}/", self.snapshot.root_name()).into()
5205        } else {
5206            Arc::default()
5207        }
5208    }
5209
5210    fn candidates(&'a self, start: usize) -> Self::Candidates {
5211        PathMatchCandidateSetIter {
5212            traversal: match self.candidates {
5213                Candidates::Directories => self.snapshot.directories(self.include_ignored, start),
5214                Candidates::Files => self.snapshot.files(self.include_ignored, start),
5215                Candidates::Entries => self.snapshot.entries(self.include_ignored, start),
5216            },
5217        }
5218    }
5219}
5220
5221pub struct PathMatchCandidateSetIter<'a> {
5222    traversal: Traversal<'a>,
5223}
5224
5225impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
5226    type Item = fuzzy::PathMatchCandidate<'a>;
5227
5228    fn next(&mut self) -> Option<Self::Item> {
5229        self.traversal
5230            .next()
5231            .map(|entry| fuzzy::PathMatchCandidate {
5232                is_dir: entry.kind.is_dir(),
5233                path: &entry.path,
5234                char_bag: entry.char_bag,
5235            })
5236    }
5237}
5238
5239impl EventEmitter<Event> for Project {}
5240
5241impl<'a> From<&'a ProjectPath> for SettingsLocation<'a> {
5242    fn from(val: &'a ProjectPath) -> Self {
5243        SettingsLocation {
5244            worktree_id: val.worktree_id,
5245            path: val.path.as_ref(),
5246        }
5247    }
5248}
5249
5250impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
5251    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
5252        Self {
5253            worktree_id,
5254            path: path.as_ref().into(),
5255        }
5256    }
5257}
5258
5259pub fn relativize_path(base: &Path, path: &Path) -> PathBuf {
5260    let mut path_components = path.components();
5261    let mut base_components = base.components();
5262    let mut components: Vec<Component> = Vec::new();
5263    loop {
5264        match (path_components.next(), base_components.next()) {
5265            (None, None) => break,
5266            (Some(a), None) => {
5267                components.push(a);
5268                components.extend(path_components.by_ref());
5269                break;
5270            }
5271            (None, _) => components.push(Component::ParentDir),
5272            (Some(a), Some(b)) if components.is_empty() && a == b => (),
5273            (Some(a), Some(Component::CurDir)) => components.push(a),
5274            (Some(a), Some(_)) => {
5275                components.push(Component::ParentDir);
5276                for _ in base_components {
5277                    components.push(Component::ParentDir);
5278                }
5279                components.push(a);
5280                components.extend(path_components.by_ref());
5281                break;
5282            }
5283        }
5284    }
5285    components.iter().map(|c| c.as_os_str()).collect()
5286}
5287
5288fn resolve_path(base: &Path, path: &Path) -> PathBuf {
5289    let mut result = base.to_path_buf();
5290    for component in path.components() {
5291        match component {
5292            Component::ParentDir => {
5293                result.pop();
5294            }
5295            Component::CurDir => (),
5296            _ => result.push(component),
5297        }
5298    }
5299    result
5300}
5301
5302/// ResolvedPath is a path that has been resolved to either a ProjectPath
5303/// or an AbsPath and that *exists*.
5304#[derive(Debug, Clone)]
5305pub enum ResolvedPath {
5306    ProjectPath(ProjectPath),
5307    AbsPath(PathBuf),
5308}
5309
5310impl Item for Buffer {
5311    fn try_open(
5312        project: &Model<Project>,
5313        path: &ProjectPath,
5314        cx: &mut AppContext,
5315    ) -> Option<Task<Result<Model<Self>>>> {
5316        Some(project.update(cx, |project, cx| project.open_buffer(path.clone(), cx)))
5317    }
5318
5319    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
5320        File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
5321    }
5322
5323    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
5324        File::from_dyn(self.file()).map(|file| ProjectPath {
5325            worktree_id: file.worktree_id(cx),
5326            path: file.path().clone(),
5327        })
5328    }
5329}
5330
5331impl Completion {
5332    /// A key that can be used to sort completions when displaying
5333    /// them to the user.
5334    pub fn sort_key(&self) -> (usize, &str) {
5335        let kind_key = match self.lsp_completion.kind {
5336            Some(lsp::CompletionItemKind::KEYWORD) => 0,
5337            Some(lsp::CompletionItemKind::VARIABLE) => 1,
5338            _ => 2,
5339        };
5340        (kind_key, &self.label.text[self.label.filter_range.clone()])
5341    }
5342
5343    /// Whether this completion is a snippet.
5344    pub fn is_snippet(&self) -> bool {
5345        self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
5346    }
5347}
5348
5349#[derive(Debug)]
5350pub struct NoRepositoryError {}
5351
5352impl std::fmt::Display for NoRepositoryError {
5353    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5354        write!(f, "no git repository for worktree found")
5355    }
5356}
5357
5358impl std::error::Error for NoRepositoryError {}
5359
5360fn serialize_location(location: &Location, cx: &AppContext) -> proto::Location {
5361    proto::Location {
5362        buffer_id: location.buffer.read(cx).remote_id().into(),
5363        start: Some(serialize_anchor(&location.range.start)),
5364        end: Some(serialize_anchor(&location.range.end)),
5365    }
5366}
5367
5368fn deserialize_location(
5369    project: &Model<Project>,
5370    location: proto::Location,
5371    cx: &mut AppContext,
5372) -> Task<Result<Location>> {
5373    let buffer_id = match BufferId::new(location.buffer_id) {
5374        Ok(id) => id,
5375        Err(e) => return Task::ready(Err(e)),
5376    };
5377    let buffer_task = project.update(cx, |project, cx| {
5378        project.wait_for_remote_buffer(buffer_id, cx)
5379    });
5380    cx.spawn(|_| async move {
5381        let buffer = buffer_task.await?;
5382        let start = location
5383            .start
5384            .and_then(deserialize_anchor)
5385            .context("missing task context location start")?;
5386        let end = location
5387            .end
5388            .and_then(deserialize_anchor)
5389            .context("missing task context location end")?;
5390        Ok(Location {
5391            buffer,
5392            range: start..end,
5393        })
5394    })
5395}
5396
5397pub fn sort_worktree_entries(entries: &mut [Entry]) {
5398    entries.sort_by(|entry_a, entry_b| {
5399        compare_paths(
5400            (&entry_a.path, entry_a.is_file()),
5401            (&entry_b.path, entry_b.is_file()),
5402        )
5403    });
5404}