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