project.rs

   1pub mod agent_server_store;
   2pub mod buffer_store;
   3mod color_extractor;
   4pub mod connection_manager;
   5pub mod context_server_store;
   6pub mod debounced_delay;
   7pub mod debugger;
   8pub mod git_store;
   9pub mod image_store;
  10pub mod lsp_command;
  11pub mod lsp_store;
  12mod manifest_tree;
  13pub mod prettier_store;
  14pub mod project_search;
  15pub mod project_settings;
  16pub mod search;
  17mod task_inventory;
  18pub mod task_store;
  19pub mod telemetry_snapshot;
  20pub mod terminals;
  21pub mod toolchain_store;
  22pub mod trusted_worktrees;
  23pub mod worktree_store;
  24
  25#[cfg(test)]
  26mod project_tests;
  27
  28mod environment;
  29use buffer_diff::BufferDiff;
  30use context_server_store::ContextServerStore;
  31pub use environment::ProjectEnvironmentEvent;
  32use git::repository::get_git_committer;
  33use git_store::{Repository, RepositoryId};
  34pub mod search_history;
  35mod yarn;
  36
  37use dap::inline_value::{InlineValueLocation, VariableLookupKind, VariableScope};
  38
  39use crate::{
  40    git_store::GitStore,
  41    lsp_store::{SymbolLocation, log_store::LogKind},
  42    project_search::SearchResultsHandle,
  43    trusted_worktrees::{PathTrust, RemoteHostLocation, TrustedWorktrees},
  44};
  45pub use agent_server_store::{AgentServerStore, AgentServersUpdated, ExternalAgentServerName};
  46pub use git_store::{
  47    ConflictRegion, ConflictSet, ConflictSetSnapshot, ConflictSetUpdate,
  48    git_traversal::{ChildEntriesGitIter, GitEntry, GitEntryRef, GitTraversal},
  49};
  50pub use manifest_tree::ManifestTree;
  51pub use project_search::{Search, SearchResults};
  52
  53use anyhow::{Context as _, Result, anyhow};
  54use buffer_store::{BufferStore, BufferStoreEvent};
  55use client::{
  56    Client, Collaborator, PendingEntitySubscription, ProjectId, TypedEnvelope, UserStore, proto,
  57};
  58use clock::ReplicaId;
  59
  60use dap::client::DebugAdapterClient;
  61
  62use collections::{BTreeSet, HashMap, HashSet, IndexSet};
  63use debounced_delay::DebouncedDelay;
  64pub use debugger::breakpoint_store::BreakpointWithPosition;
  65use debugger::{
  66    breakpoint_store::{ActiveStackFrame, BreakpointStore},
  67    dap_store::{DapStore, DapStoreEvent},
  68    session::Session,
  69};
  70use encoding_rs;
  71pub use environment::ProjectEnvironment;
  72#[cfg(test)]
  73use futures::future::join_all;
  74use futures::{
  75    StreamExt,
  76    channel::mpsc::{self, UnboundedReceiver},
  77    future::try_join_all,
  78};
  79pub use image_store::{ImageItem, ImageStore};
  80use image_store::{ImageItemEvent, ImageStoreEvent};
  81
  82use ::git::{blame::Blame, status::FileStatus};
  83use gpui::{
  84    App, AppContext, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Hsla, SharedString,
  85    Task, WeakEntity, Window,
  86};
  87use language::{
  88    Buffer, BufferEvent, Capability, CodeLabel, CursorShape, DiskState, Language, LanguageName,
  89    LanguageRegistry, PointUtf16, ToOffset, ToPointUtf16, Toolchain, ToolchainMetadata,
  90    ToolchainScope, Transaction, Unclipped, language_settings::InlayHintKind,
  91    proto::split_operations,
  92};
  93use lsp::{
  94    CodeActionKind, CompletionContext, CompletionItemKind, DocumentHighlightKind, InsertTextMode,
  95    LanguageServerBinary, LanguageServerId, LanguageServerName, LanguageServerSelector,
  96    MessageActionItem,
  97};
  98use lsp_command::*;
  99use lsp_store::{CompletionDocumentation, LspFormatTarget, OpenLspBufferHandle};
 100pub use manifest_tree::ManifestProvidersStore;
 101use node_runtime::NodeRuntime;
 102use parking_lot::Mutex;
 103pub use prettier_store::PrettierStore;
 104use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent};
 105use remote::{RemoteClient, RemoteConnectionOptions};
 106use rpc::{
 107    AnyProtoClient, ErrorCode,
 108    proto::{LanguageServerPromptResponse, REMOTE_SERVER_PROJECT_ID},
 109};
 110use search::{SearchInputKind, SearchQuery, SearchResult};
 111use search_history::SearchHistory;
 112use settings::{InvalidSettingsError, RegisterSetting, Settings, SettingsLocation, SettingsStore};
 113use snippet::Snippet;
 114pub use snippet_provider;
 115use snippet_provider::SnippetProvider;
 116use std::{
 117    borrow::Cow,
 118    collections::BTreeMap,
 119    ffi::OsString,
 120    ops::{Not as _, Range},
 121    path::{Path, PathBuf},
 122    pin::pin,
 123    str::{self, FromStr},
 124    sync::Arc,
 125    time::Duration,
 126};
 127
 128use task_store::TaskStore;
 129use terminals::Terminals;
 130use text::{Anchor, BufferId, OffsetRangeExt, Point, Rope};
 131use toolchain_store::EmptyToolchainStore;
 132use util::{
 133    ResultExt as _, maybe,
 134    paths::{PathStyle, SanitizedPath, is_absolute},
 135    rel_path::RelPath,
 136};
 137use worktree::{CreatedEntry, Snapshot, Traversal};
 138pub use worktree::{
 139    Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
 140    UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
 141};
 142use worktree_store::{WorktreeStore, WorktreeStoreEvent};
 143
 144pub use fs::*;
 145pub use language::Location;
 146#[cfg(any(test, feature = "test-support"))]
 147pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
 148pub use task_inventory::{
 149    BasicContextProvider, ContextProviderWithTasks, DebugScenarioContext, Inventory, TaskContexts,
 150    TaskSourceKind,
 151};
 152
 153pub use buffer_store::ProjectTransaction;
 154pub use lsp_store::{
 155    DiagnosticSummary, InvalidationStrategy, LanguageServerLogType, LanguageServerProgress,
 156    LanguageServerPromptRequest, LanguageServerStatus, LanguageServerToQuery, LspStore,
 157    LspStoreEvent, ProgressToken, SERVER_PROGRESS_THROTTLE_TIMEOUT,
 158};
 159pub use toolchain_store::{ToolchainStore, Toolchains};
 160const MAX_PROJECT_SEARCH_HISTORY_SIZE: usize = 500;
 161
 162pub trait ProjectItem: 'static {
 163    fn try_open(
 164        project: &Entity<Project>,
 165        path: &ProjectPath,
 166        cx: &mut App,
 167    ) -> Option<Task<Result<Entity<Self>>>>
 168    where
 169        Self: Sized;
 170    fn entry_id(&self, cx: &App) -> Option<ProjectEntryId>;
 171    fn project_path(&self, cx: &App) -> Option<ProjectPath>;
 172    fn is_dirty(&self) -> bool;
 173}
 174
 175#[derive(Clone)]
 176pub enum OpenedBufferEvent {
 177    Disconnected,
 178    Ok(BufferId),
 179    Err(BufferId, Arc<anyhow::Error>),
 180}
 181
 182/// Semantics-aware entity that is relevant to one or more [`Worktree`] with the files.
 183/// `Project` is responsible for tasks, LSP and collab queries, synchronizing worktree states accordingly.
 184/// Maps [`Worktree`] entries with its own logic using [`ProjectEntryId`] and [`ProjectPath`] structs.
 185///
 186/// Can be either local (for the project opened on the same host) or remote.(for collab projects, browsed by multiple remote users).
 187pub struct Project {
 188    active_entry: Option<ProjectEntryId>,
 189    buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
 190    languages: Arc<LanguageRegistry>,
 191    dap_store: Entity<DapStore>,
 192    agent_server_store: Entity<AgentServerStore>,
 193
 194    breakpoint_store: Entity<BreakpointStore>,
 195    collab_client: Arc<client::Client>,
 196    join_project_response_message_id: u32,
 197    task_store: Entity<TaskStore>,
 198    user_store: Entity<UserStore>,
 199    fs: Arc<dyn Fs>,
 200    remote_client: Option<Entity<RemoteClient>>,
 201    client_state: ProjectClientState,
 202    git_store: Entity<GitStore>,
 203    collaborators: HashMap<proto::PeerId, Collaborator>,
 204    client_subscriptions: Vec<client::Subscription>,
 205    worktree_store: Entity<WorktreeStore>,
 206    buffer_store: Entity<BufferStore>,
 207    context_server_store: Entity<ContextServerStore>,
 208    image_store: Entity<ImageStore>,
 209    lsp_store: Entity<LspStore>,
 210    _subscriptions: Vec<gpui::Subscription>,
 211    buffers_needing_diff: HashSet<WeakEntity<Buffer>>,
 212    git_diff_debouncer: DebouncedDelay<Self>,
 213    remotely_created_models: Arc<Mutex<RemotelyCreatedModels>>,
 214    terminals: Terminals,
 215    node: Option<NodeRuntime>,
 216    search_history: SearchHistory,
 217    search_included_history: SearchHistory,
 218    search_excluded_history: SearchHistory,
 219    snippets: Entity<SnippetProvider>,
 220    environment: Entity<ProjectEnvironment>,
 221    settings_observer: Entity<SettingsObserver>,
 222    toolchain_store: Option<Entity<ToolchainStore>>,
 223    agent_location: Option<AgentLocation>,
 224}
 225
 226#[derive(Clone, Debug, PartialEq, Eq)]
 227pub struct AgentLocation {
 228    pub buffer: WeakEntity<Buffer>,
 229    pub position: Anchor,
 230}
 231
 232#[derive(Default)]
 233struct RemotelyCreatedModels {
 234    worktrees: Vec<Entity<Worktree>>,
 235    buffers: Vec<Entity<Buffer>>,
 236    retain_count: usize,
 237}
 238
 239struct RemotelyCreatedModelGuard {
 240    remote_models: std::sync::Weak<Mutex<RemotelyCreatedModels>>,
 241}
 242
 243impl Drop for RemotelyCreatedModelGuard {
 244    fn drop(&mut self) {
 245        if let Some(remote_models) = self.remote_models.upgrade() {
 246            let mut remote_models = remote_models.lock();
 247            assert!(
 248                remote_models.retain_count > 0,
 249                "RemotelyCreatedModelGuard dropped too many times"
 250            );
 251            remote_models.retain_count -= 1;
 252            if remote_models.retain_count == 0 {
 253                remote_models.buffers.clear();
 254                remote_models.worktrees.clear();
 255            }
 256        }
 257    }
 258}
 259/// Message ordered with respect to buffer operations
 260#[derive(Debug)]
 261enum BufferOrderedMessage {
 262    Operation {
 263        buffer_id: BufferId,
 264        operation: proto::Operation,
 265    },
 266    LanguageServerUpdate {
 267        language_server_id: LanguageServerId,
 268        message: proto::update_language_server::Variant,
 269        name: Option<LanguageServerName>,
 270    },
 271    Resync,
 272}
 273
 274#[derive(Debug)]
 275enum ProjectClientState {
 276    /// Single-player mode.
 277    Local,
 278    /// Multi-player mode but still a local project.
 279    Shared { remote_id: u64 },
 280    /// Multi-player mode but working on a remote project.
 281    Remote {
 282        sharing_has_stopped: bool,
 283        capability: Capability,
 284        remote_id: u64,
 285        replica_id: ReplicaId,
 286    },
 287}
 288
 289#[derive(Clone, Debug, PartialEq)]
 290pub enum Event {
 291    LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
 292    LanguageServerRemoved(LanguageServerId),
 293    LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
 294    // [`lsp::notification::DidOpenTextDocument`] was sent to this server using the buffer data.
 295    // Zed's buffer-related data is updated accordingly.
 296    LanguageServerBufferRegistered {
 297        server_id: LanguageServerId,
 298        buffer_id: BufferId,
 299        buffer_abs_path: PathBuf,
 300        name: Option<LanguageServerName>,
 301    },
 302    ToggleLspLogs {
 303        server_id: LanguageServerId,
 304        enabled: bool,
 305        toggled_log_kind: LogKind,
 306    },
 307    Toast {
 308        notification_id: SharedString,
 309        message: String,
 310    },
 311    HideToast {
 312        notification_id: SharedString,
 313    },
 314    LanguageServerPrompt(LanguageServerPromptRequest),
 315    LanguageNotFound(Entity<Buffer>),
 316    ActiveEntryChanged(Option<ProjectEntryId>),
 317    ActivateProjectPanel,
 318    WorktreeAdded(WorktreeId),
 319    WorktreeOrderChanged,
 320    WorktreeRemoved(WorktreeId),
 321    WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet),
 322    DiskBasedDiagnosticsStarted {
 323        language_server_id: LanguageServerId,
 324    },
 325    DiskBasedDiagnosticsFinished {
 326        language_server_id: LanguageServerId,
 327    },
 328    DiagnosticsUpdated {
 329        paths: Vec<ProjectPath>,
 330        language_server_id: LanguageServerId,
 331    },
 332    RemoteIdChanged(Option<u64>),
 333    DisconnectedFromHost,
 334    DisconnectedFromRemote,
 335    Closed,
 336    DeletedEntry(WorktreeId, ProjectEntryId),
 337    CollaboratorUpdated {
 338        old_peer_id: proto::PeerId,
 339        new_peer_id: proto::PeerId,
 340    },
 341    CollaboratorJoined(proto::PeerId),
 342    CollaboratorLeft(proto::PeerId),
 343    HostReshared,
 344    Reshared,
 345    Rejoined,
 346    RefreshInlayHints {
 347        server_id: LanguageServerId,
 348        request_id: Option<usize>,
 349    },
 350    RefreshCodeLens,
 351    RevealInProjectPanel(ProjectEntryId),
 352    SnippetEdit(BufferId, Vec<(lsp::Range, Snippet)>),
 353    ExpandedAllForEntry(WorktreeId, ProjectEntryId),
 354    EntryRenamed(ProjectTransaction, ProjectPath, PathBuf),
 355    WorkspaceEditApplied(ProjectTransaction),
 356    AgentLocationChanged,
 357    BufferEdited,
 358}
 359
 360pub struct AgentLocationChanged;
 361
 362pub enum DebugAdapterClientState {
 363    Starting(Task<Option<Arc<DebugAdapterClient>>>),
 364    Running(Arc<DebugAdapterClient>),
 365}
 366
 367#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
 368pub struct ProjectPath {
 369    pub worktree_id: WorktreeId,
 370    pub path: Arc<RelPath>,
 371}
 372
 373impl ProjectPath {
 374    pub fn from_file(value: &dyn language::File, cx: &App) -> Self {
 375        ProjectPath {
 376            worktree_id: value.worktree_id(cx),
 377            path: value.path().clone(),
 378        }
 379    }
 380
 381    pub fn from_proto(p: proto::ProjectPath) -> Option<Self> {
 382        Some(Self {
 383            worktree_id: WorktreeId::from_proto(p.worktree_id),
 384            path: RelPath::from_proto(&p.path).log_err()?,
 385        })
 386    }
 387
 388    pub fn to_proto(&self) -> proto::ProjectPath {
 389        proto::ProjectPath {
 390            worktree_id: self.worktree_id.to_proto(),
 391            path: self.path.as_ref().to_proto(),
 392        }
 393    }
 394
 395    pub fn root_path(worktree_id: WorktreeId) -> Self {
 396        Self {
 397            worktree_id,
 398            path: RelPath::empty().into(),
 399        }
 400    }
 401
 402    pub fn starts_with(&self, other: &ProjectPath) -> bool {
 403        self.worktree_id == other.worktree_id && self.path.starts_with(&other.path)
 404    }
 405}
 406
 407#[derive(Debug, Default)]
 408pub enum PrepareRenameResponse {
 409    Success(Range<Anchor>),
 410    OnlyUnpreparedRenameSupported,
 411    #[default]
 412    InvalidPosition,
 413}
 414
 415#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 416pub enum InlayId {
 417    EditPrediction(usize),
 418    DebuggerValue(usize),
 419    // LSP
 420    Hint(usize),
 421    Color(usize),
 422    ReplResult(usize),
 423}
 424
 425impl InlayId {
 426    pub fn id(&self) -> usize {
 427        match self {
 428            Self::EditPrediction(id) => *id,
 429            Self::DebuggerValue(id) => *id,
 430            Self::Hint(id) => *id,
 431            Self::Color(id) => *id,
 432            Self::ReplResult(id) => *id,
 433        }
 434    }
 435}
 436
 437#[derive(Debug, Clone, PartialEq, Eq)]
 438pub struct InlayHint {
 439    pub position: language::Anchor,
 440    pub label: InlayHintLabel,
 441    pub kind: Option<InlayHintKind>,
 442    pub padding_left: bool,
 443    pub padding_right: bool,
 444    pub tooltip: Option<InlayHintTooltip>,
 445    pub resolve_state: ResolveState,
 446}
 447
 448/// The user's intent behind a given completion confirmation
 449#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
 450pub enum CompletionIntent {
 451    /// The user intends to 'commit' this result, if possible
 452    /// completion confirmations should run side effects.
 453    ///
 454    /// For LSP completions, will respect the setting `completions.lsp_insert_mode`.
 455    Complete,
 456    /// Similar to [Self::Complete], but behaves like `lsp_insert_mode` is set to `insert`.
 457    CompleteWithInsert,
 458    /// Similar to [Self::Complete], but behaves like `lsp_insert_mode` is set to `replace`.
 459    CompleteWithReplace,
 460    /// The user intends to continue 'composing' this completion
 461    /// completion confirmations should not run side effects and
 462    /// let the user continue composing their action
 463    Compose,
 464}
 465
 466impl CompletionIntent {
 467    pub fn is_complete(&self) -> bool {
 468        self == &Self::Complete
 469    }
 470
 471    pub fn is_compose(&self) -> bool {
 472        self == &Self::Compose
 473    }
 474}
 475
 476/// Similar to `CoreCompletion`, but with extra metadata attached.
 477#[derive(Clone)]
 478pub struct Completion {
 479    /// The range of text that will be replaced by this completion.
 480    pub replace_range: Range<Anchor>,
 481    /// The new text that will be inserted.
 482    pub new_text: String,
 483    /// A label for this completion that is shown in the menu.
 484    pub label: CodeLabel,
 485    /// The documentation for this completion.
 486    pub documentation: Option<CompletionDocumentation>,
 487    /// Completion data source which it was constructed from.
 488    pub source: CompletionSource,
 489    /// A path to an icon for this completion that is shown in the menu.
 490    pub icon_path: Option<SharedString>,
 491    /// Text starting here and ending at the cursor will be used as the query for filtering this completion.
 492    ///
 493    /// If None, the start of the surrounding word is used.
 494    pub match_start: Option<text::Anchor>,
 495    /// Key used for de-duplicating snippets. If None, always considered unique.
 496    pub snippet_deduplication_key: Option<(usize, usize)>,
 497    /// Whether to adjust indentation (the default) or not.
 498    pub insert_text_mode: Option<InsertTextMode>,
 499    /// An optional callback to invoke when this completion is confirmed.
 500    /// Returns, whether new completions should be retriggered after the current one.
 501    /// If `true` is returned, the editor will show a new completion menu after this completion is confirmed.
 502    /// if no confirmation is provided or `false` is returned, the completion will be committed.
 503    pub confirm: Option<Arc<dyn Send + Sync + Fn(CompletionIntent, &mut Window, &mut App) -> bool>>,
 504}
 505
 506#[derive(Debug, Clone)]
 507pub enum CompletionSource {
 508    Lsp {
 509        /// The alternate `insert` range, if provided by the LSP server.
 510        insert_range: Option<Range<Anchor>>,
 511        /// The id of the language server that produced this completion.
 512        server_id: LanguageServerId,
 513        /// The raw completion provided by the language server.
 514        lsp_completion: Box<lsp::CompletionItem>,
 515        /// A set of defaults for this completion item.
 516        lsp_defaults: Option<Arc<lsp::CompletionListItemDefaults>>,
 517        /// Whether this completion has been resolved, to ensure it happens once per completion.
 518        resolved: bool,
 519    },
 520    Dap {
 521        /// The sort text for this completion.
 522        sort_text: String,
 523    },
 524    Custom,
 525    BufferWord {
 526        word_range: Range<Anchor>,
 527        resolved: bool,
 528    },
 529}
 530
 531impl CompletionSource {
 532    pub fn server_id(&self) -> Option<LanguageServerId> {
 533        if let CompletionSource::Lsp { server_id, .. } = self {
 534            Some(*server_id)
 535        } else {
 536            None
 537        }
 538    }
 539
 540    pub fn lsp_completion(&self, apply_defaults: bool) -> Option<Cow<'_, lsp::CompletionItem>> {
 541        if let Self::Lsp {
 542            lsp_completion,
 543            lsp_defaults,
 544            ..
 545        } = self
 546        {
 547            if apply_defaults && let Some(lsp_defaults) = lsp_defaults {
 548                let mut completion_with_defaults = *lsp_completion.clone();
 549                let default_commit_characters = lsp_defaults.commit_characters.as_ref();
 550                let default_edit_range = lsp_defaults.edit_range.as_ref();
 551                let default_insert_text_format = lsp_defaults.insert_text_format.as_ref();
 552                let default_insert_text_mode = lsp_defaults.insert_text_mode.as_ref();
 553
 554                if default_commit_characters.is_some()
 555                    || default_edit_range.is_some()
 556                    || default_insert_text_format.is_some()
 557                    || default_insert_text_mode.is_some()
 558                {
 559                    if completion_with_defaults.commit_characters.is_none()
 560                        && default_commit_characters.is_some()
 561                    {
 562                        completion_with_defaults.commit_characters =
 563                            default_commit_characters.cloned()
 564                    }
 565                    if completion_with_defaults.text_edit.is_none() {
 566                        match default_edit_range {
 567                            Some(lsp::CompletionListItemDefaultsEditRange::Range(range)) => {
 568                                completion_with_defaults.text_edit =
 569                                    Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
 570                                        range: *range,
 571                                        new_text: completion_with_defaults.label.clone(),
 572                                    }))
 573                            }
 574                            Some(lsp::CompletionListItemDefaultsEditRange::InsertAndReplace {
 575                                insert,
 576                                replace,
 577                            }) => {
 578                                completion_with_defaults.text_edit =
 579                                    Some(lsp::CompletionTextEdit::InsertAndReplace(
 580                                        lsp::InsertReplaceEdit {
 581                                            new_text: completion_with_defaults.label.clone(),
 582                                            insert: *insert,
 583                                            replace: *replace,
 584                                        },
 585                                    ))
 586                            }
 587                            None => {}
 588                        }
 589                    }
 590                    if completion_with_defaults.insert_text_format.is_none()
 591                        && default_insert_text_format.is_some()
 592                    {
 593                        completion_with_defaults.insert_text_format =
 594                            default_insert_text_format.cloned()
 595                    }
 596                    if completion_with_defaults.insert_text_mode.is_none()
 597                        && default_insert_text_mode.is_some()
 598                    {
 599                        completion_with_defaults.insert_text_mode =
 600                            default_insert_text_mode.cloned()
 601                    }
 602                }
 603                return Some(Cow::Owned(completion_with_defaults));
 604            }
 605            Some(Cow::Borrowed(lsp_completion))
 606        } else {
 607            None
 608        }
 609    }
 610}
 611
 612impl std::fmt::Debug for Completion {
 613    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 614        f.debug_struct("Completion")
 615            .field("replace_range", &self.replace_range)
 616            .field("new_text", &self.new_text)
 617            .field("label", &self.label)
 618            .field("documentation", &self.documentation)
 619            .field("source", &self.source)
 620            .finish()
 621    }
 622}
 623
 624/// Response from a source of completions.
 625pub struct CompletionResponse {
 626    pub completions: Vec<Completion>,
 627    pub display_options: CompletionDisplayOptions,
 628    /// When false, indicates that the list is complete and so does not need to be re-queried if it
 629    /// can be filtered instead.
 630    pub is_incomplete: bool,
 631}
 632
 633#[derive(Default)]
 634pub struct CompletionDisplayOptions {
 635    pub dynamic_width: bool,
 636}
 637
 638impl CompletionDisplayOptions {
 639    pub fn merge(&mut self, other: &CompletionDisplayOptions) {
 640        self.dynamic_width = self.dynamic_width && other.dynamic_width;
 641    }
 642}
 643
 644/// Response from language server completion request.
 645#[derive(Clone, Debug, Default)]
 646pub(crate) struct CoreCompletionResponse {
 647    pub completions: Vec<CoreCompletion>,
 648    /// When false, indicates that the list is complete and so does not need to be re-queried if it
 649    /// can be filtered instead.
 650    pub is_incomplete: bool,
 651}
 652
 653/// A generic completion that can come from different sources.
 654#[derive(Clone, Debug)]
 655pub(crate) struct CoreCompletion {
 656    replace_range: Range<Anchor>,
 657    new_text: String,
 658    source: CompletionSource,
 659}
 660
 661/// A code action provided by a language server.
 662#[derive(Clone, Debug, PartialEq)]
 663pub struct CodeAction {
 664    /// The id of the language server that produced this code action.
 665    pub server_id: LanguageServerId,
 666    /// The range of the buffer where this code action is applicable.
 667    pub range: Range<Anchor>,
 668    /// The raw code action provided by the language server.
 669    /// Can be either an action or a command.
 670    pub lsp_action: LspAction,
 671    /// Whether the action needs to be resolved using the language server.
 672    pub resolved: bool,
 673}
 674
 675/// An action sent back by a language server.
 676#[derive(Clone, Debug, PartialEq)]
 677pub enum LspAction {
 678    /// An action with the full data, may have a command or may not.
 679    /// May require resolving.
 680    Action(Box<lsp::CodeAction>),
 681    /// A command data to run as an action.
 682    Command(lsp::Command),
 683    /// A code lens data to run as an action.
 684    CodeLens(lsp::CodeLens),
 685}
 686
 687impl LspAction {
 688    pub fn title(&self) -> &str {
 689        match self {
 690            Self::Action(action) => &action.title,
 691            Self::Command(command) => &command.title,
 692            Self::CodeLens(lens) => lens
 693                .command
 694                .as_ref()
 695                .map(|command| command.title.as_str())
 696                .unwrap_or("Unknown command"),
 697        }
 698    }
 699
 700    fn action_kind(&self) -> Option<lsp::CodeActionKind> {
 701        match self {
 702            Self::Action(action) => action.kind.clone(),
 703            Self::Command(_) => Some(lsp::CodeActionKind::new("command")),
 704            Self::CodeLens(_) => Some(lsp::CodeActionKind::new("code lens")),
 705        }
 706    }
 707
 708    fn edit(&self) -> Option<&lsp::WorkspaceEdit> {
 709        match self {
 710            Self::Action(action) => action.edit.as_ref(),
 711            Self::Command(_) => None,
 712            Self::CodeLens(_) => None,
 713        }
 714    }
 715
 716    fn command(&self) -> Option<&lsp::Command> {
 717        match self {
 718            Self::Action(action) => action.command.as_ref(),
 719            Self::Command(command) => Some(command),
 720            Self::CodeLens(lens) => lens.command.as_ref(),
 721        }
 722    }
 723}
 724
 725#[derive(Debug, Clone, PartialEq, Eq)]
 726pub enum ResolveState {
 727    Resolved,
 728    CanResolve(LanguageServerId, Option<lsp::LSPAny>),
 729    Resolving,
 730}
 731impl InlayHint {
 732    pub fn text(&self) -> Rope {
 733        match &self.label {
 734            InlayHintLabel::String(s) => Rope::from(s),
 735            InlayHintLabel::LabelParts(parts) => parts.iter().map(|part| &*part.value).collect(),
 736        }
 737    }
 738}
 739
 740#[derive(Debug, Clone, PartialEq, Eq)]
 741pub enum InlayHintLabel {
 742    String(String),
 743    LabelParts(Vec<InlayHintLabelPart>),
 744}
 745
 746#[derive(Debug, Clone, PartialEq, Eq)]
 747pub struct InlayHintLabelPart {
 748    pub value: String,
 749    pub tooltip: Option<InlayHintLabelPartTooltip>,
 750    pub location: Option<(LanguageServerId, lsp::Location)>,
 751}
 752
 753#[derive(Debug, Clone, PartialEq, Eq)]
 754pub enum InlayHintTooltip {
 755    String(String),
 756    MarkupContent(MarkupContent),
 757}
 758
 759#[derive(Debug, Clone, PartialEq, Eq)]
 760pub enum InlayHintLabelPartTooltip {
 761    String(String),
 762    MarkupContent(MarkupContent),
 763}
 764
 765#[derive(Debug, Clone, PartialEq, Eq)]
 766pub struct MarkupContent {
 767    pub kind: HoverBlockKind,
 768    pub value: String,
 769}
 770
 771#[derive(Debug, Clone, PartialEq)]
 772pub struct LocationLink {
 773    pub origin: Option<Location>,
 774    pub target: Location,
 775}
 776
 777#[derive(Debug)]
 778pub struct DocumentHighlight {
 779    pub range: Range<language::Anchor>,
 780    pub kind: DocumentHighlightKind,
 781}
 782
 783#[derive(Clone, Debug)]
 784pub struct Symbol {
 785    pub language_server_name: LanguageServerName,
 786    pub source_worktree_id: WorktreeId,
 787    pub source_language_server_id: LanguageServerId,
 788    pub path: SymbolLocation,
 789    pub label: CodeLabel,
 790    pub name: String,
 791    pub kind: lsp::SymbolKind,
 792    pub range: Range<Unclipped<PointUtf16>>,
 793}
 794
 795#[derive(Clone, Debug)]
 796pub struct DocumentSymbol {
 797    pub name: String,
 798    pub kind: lsp::SymbolKind,
 799    pub range: Range<Unclipped<PointUtf16>>,
 800    pub selection_range: Range<Unclipped<PointUtf16>>,
 801    pub children: Vec<DocumentSymbol>,
 802}
 803
 804#[derive(Clone, Debug, PartialEq)]
 805pub struct HoverBlock {
 806    pub text: String,
 807    pub kind: HoverBlockKind,
 808}
 809
 810#[derive(Clone, Debug, PartialEq, Eq)]
 811pub enum HoverBlockKind {
 812    PlainText,
 813    Markdown,
 814    Code { language: String },
 815}
 816
 817#[derive(Debug, Clone)]
 818pub struct Hover {
 819    pub contents: Vec<HoverBlock>,
 820    pub range: Option<Range<language::Anchor>>,
 821    pub language: Option<Arc<Language>>,
 822}
 823
 824impl Hover {
 825    pub fn is_empty(&self) -> bool {
 826        self.contents.iter().all(|block| block.text.is_empty())
 827    }
 828}
 829
 830enum EntitySubscription {
 831    Project(PendingEntitySubscription<Project>),
 832    BufferStore(PendingEntitySubscription<BufferStore>),
 833    GitStore(PendingEntitySubscription<GitStore>),
 834    WorktreeStore(PendingEntitySubscription<WorktreeStore>),
 835    LspStore(PendingEntitySubscription<LspStore>),
 836    SettingsObserver(PendingEntitySubscription<SettingsObserver>),
 837    DapStore(PendingEntitySubscription<DapStore>),
 838    BreakpointStore(PendingEntitySubscription<BreakpointStore>),
 839}
 840
 841#[derive(Debug, Clone)]
 842pub struct DirectoryItem {
 843    pub path: PathBuf,
 844    pub is_dir: bool,
 845}
 846
 847#[derive(Clone, Debug, PartialEq)]
 848pub struct DocumentColor {
 849    pub lsp_range: lsp::Range,
 850    pub color: lsp::Color,
 851    pub resolved: bool,
 852    pub color_presentations: Vec<ColorPresentation>,
 853}
 854
 855impl Eq for DocumentColor {}
 856
 857impl std::hash::Hash for DocumentColor {
 858    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 859        self.lsp_range.hash(state);
 860        self.color.red.to_bits().hash(state);
 861        self.color.green.to_bits().hash(state);
 862        self.color.blue.to_bits().hash(state);
 863        self.color.alpha.to_bits().hash(state);
 864        self.resolved.hash(state);
 865        self.color_presentations.hash(state);
 866    }
 867}
 868
 869#[derive(Clone, Debug, PartialEq, Eq)]
 870pub struct ColorPresentation {
 871    pub label: SharedString,
 872    pub text_edit: Option<lsp::TextEdit>,
 873    pub additional_text_edits: Vec<lsp::TextEdit>,
 874}
 875
 876impl std::hash::Hash for ColorPresentation {
 877    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 878        self.label.hash(state);
 879        if let Some(ref edit) = self.text_edit {
 880            edit.range.hash(state);
 881            edit.new_text.hash(state);
 882        }
 883        self.additional_text_edits.len().hash(state);
 884        for edit in &self.additional_text_edits {
 885            edit.range.hash(state);
 886            edit.new_text.hash(state);
 887        }
 888    }
 889}
 890
 891#[derive(Clone)]
 892pub enum DirectoryLister {
 893    Project(Entity<Project>),
 894    Local(Entity<Project>, Arc<dyn Fs>),
 895}
 896
 897impl std::fmt::Debug for DirectoryLister {
 898    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 899        match self {
 900            DirectoryLister::Project(project) => {
 901                write!(f, "DirectoryLister::Project({project:?})")
 902            }
 903            DirectoryLister::Local(project, _) => {
 904                write!(f, "DirectoryLister::Local({project:?})")
 905            }
 906        }
 907    }
 908}
 909
 910impl DirectoryLister {
 911    pub fn is_local(&self, cx: &App) -> bool {
 912        match self {
 913            DirectoryLister::Local(..) => true,
 914            DirectoryLister::Project(project) => project.read(cx).is_local(),
 915        }
 916    }
 917
 918    pub fn resolve_tilde<'a>(&self, path: &'a String, cx: &App) -> Cow<'a, str> {
 919        if self.is_local(cx) {
 920            shellexpand::tilde(path)
 921        } else {
 922            Cow::from(path)
 923        }
 924    }
 925
 926    pub fn default_query(&self, cx: &mut App) -> String {
 927        let project = match self {
 928            DirectoryLister::Project(project) => project,
 929            DirectoryLister::Local(project, _) => project,
 930        }
 931        .read(cx);
 932        let path_style = project.path_style(cx);
 933        project
 934            .visible_worktrees(cx)
 935            .next()
 936            .map(|worktree| worktree.read(cx).abs_path().to_string_lossy().into_owned())
 937            .or_else(|| std::env::home_dir().map(|dir| dir.to_string_lossy().into_owned()))
 938            .map(|mut s| {
 939                s.push_str(path_style.primary_separator());
 940                s
 941            })
 942            .unwrap_or_else(|| {
 943                if path_style.is_windows() {
 944                    "C:\\"
 945                } else {
 946                    "~/"
 947                }
 948                .to_string()
 949            })
 950    }
 951
 952    pub fn list_directory(&self, path: String, cx: &mut App) -> Task<Result<Vec<DirectoryItem>>> {
 953        match self {
 954            DirectoryLister::Project(project) => {
 955                project.update(cx, |project, cx| project.list_directory(path, cx))
 956            }
 957            DirectoryLister::Local(_, fs) => {
 958                let fs = fs.clone();
 959                cx.background_spawn(async move {
 960                    let mut results = vec![];
 961                    let expanded = shellexpand::tilde(&path);
 962                    let query = Path::new(expanded.as_ref());
 963                    let mut response = fs.read_dir(query).await?;
 964                    while let Some(path) = response.next().await {
 965                        let path = path?;
 966                        if let Some(file_name) = path.file_name() {
 967                            results.push(DirectoryItem {
 968                                path: PathBuf::from(file_name.to_os_string()),
 969                                is_dir: fs.is_dir(&path).await,
 970                            });
 971                        }
 972                    }
 973                    Ok(results)
 974                })
 975            }
 976        }
 977    }
 978
 979    pub fn path_style(&self, cx: &App) -> PathStyle {
 980        match self {
 981            Self::Local(project, ..) | Self::Project(project, ..) => {
 982                project.read(cx).path_style(cx)
 983            }
 984        }
 985    }
 986}
 987
 988#[cfg(any(test, feature = "test-support"))]
 989pub const DEFAULT_COMPLETION_CONTEXT: CompletionContext = CompletionContext {
 990    trigger_kind: lsp::CompletionTriggerKind::INVOKED,
 991    trigger_character: None,
 992};
 993
 994/// An LSP diagnostics associated with a certain language server.
 995#[derive(Clone, Debug, Default)]
 996pub enum LspPullDiagnostics {
 997    #[default]
 998    Default,
 999    Response {
1000        /// The id of the language server that produced diagnostics.
1001        server_id: LanguageServerId,
1002        /// URI of the resource,
1003        uri: lsp::Uri,
1004        /// The ID provided by the dynamic registration that produced diagnostics.
1005        registration_id: Option<SharedString>,
1006        /// The diagnostics produced by this language server.
1007        diagnostics: PulledDiagnostics,
1008    },
1009}
1010
1011#[derive(Clone, Debug)]
1012pub enum PulledDiagnostics {
1013    Unchanged {
1014        /// An ID the current pulled batch for this file.
1015        /// If given, can be used to query workspace diagnostics partially.
1016        result_id: SharedString,
1017    },
1018    Changed {
1019        result_id: Option<SharedString>,
1020        diagnostics: Vec<lsp::Diagnostic>,
1021    },
1022}
1023
1024/// Whether to disable all AI features in Zed.
1025///
1026/// Default: false
1027#[derive(Copy, Clone, Debug, RegisterSetting)]
1028pub struct DisableAiSettings {
1029    pub disable_ai: bool,
1030}
1031
1032impl settings::Settings for DisableAiSettings {
1033    fn from_settings(content: &settings::SettingsContent) -> Self {
1034        Self {
1035            disable_ai: content.disable_ai.unwrap().0,
1036        }
1037    }
1038}
1039
1040impl Project {
1041    pub fn init(client: &Arc<Client>, cx: &mut App) {
1042        connection_manager::init(client.clone(), cx);
1043
1044        let client: AnyProtoClient = client.clone().into();
1045        client.add_entity_message_handler(Self::handle_add_collaborator);
1046        client.add_entity_message_handler(Self::handle_update_project_collaborator);
1047        client.add_entity_message_handler(Self::handle_remove_collaborator);
1048        client.add_entity_message_handler(Self::handle_update_project);
1049        client.add_entity_message_handler(Self::handle_unshare_project);
1050        client.add_entity_request_handler(Self::handle_update_buffer);
1051        client.add_entity_message_handler(Self::handle_update_worktree);
1052        client.add_entity_request_handler(Self::handle_synchronize_buffers);
1053
1054        client.add_entity_request_handler(Self::handle_search_candidate_buffers);
1055        client.add_entity_request_handler(Self::handle_open_buffer_by_id);
1056        client.add_entity_request_handler(Self::handle_open_buffer_by_path);
1057        client.add_entity_request_handler(Self::handle_open_new_buffer);
1058        client.add_entity_message_handler(Self::handle_create_buffer_for_peer);
1059        client.add_entity_message_handler(Self::handle_toggle_lsp_logs);
1060        client.add_entity_message_handler(Self::handle_create_image_for_peer);
1061        client.add_entity_request_handler(Self::handle_find_search_candidates_chunk);
1062        client.add_entity_message_handler(Self::handle_find_search_candidates_cancel);
1063
1064        WorktreeStore::init(&client);
1065        BufferStore::init(&client);
1066        LspStore::init(&client);
1067        GitStore::init(&client);
1068        SettingsObserver::init(&client);
1069        TaskStore::init(Some(&client));
1070        ToolchainStore::init(&client);
1071        DapStore::init(&client, cx);
1072        BreakpointStore::init(&client);
1073        context_server_store::init(cx);
1074    }
1075
1076    pub fn local(
1077        client: Arc<Client>,
1078        node: NodeRuntime,
1079        user_store: Entity<UserStore>,
1080        languages: Arc<LanguageRegistry>,
1081        fs: Arc<dyn Fs>,
1082        env: Option<HashMap<String, String>>,
1083        init_worktree_trust: bool,
1084        cx: &mut App,
1085    ) -> Entity<Self> {
1086        cx.new(|cx: &mut Context<Self>| {
1087            let (tx, rx) = mpsc::unbounded();
1088            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
1089                .detach();
1090            let snippets = SnippetProvider::new(fs.clone(), BTreeSet::from_iter([]), cx);
1091            let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone()));
1092            if init_worktree_trust {
1093                trusted_worktrees::track_worktree_trust(
1094                    worktree_store.clone(),
1095                    None,
1096                    None,
1097                    None,
1098                    cx,
1099                );
1100            }
1101            cx.subscribe(&worktree_store, Self::on_worktree_store_event)
1102                .detach();
1103
1104            let weak_self = cx.weak_entity();
1105            let context_server_store = cx.new(|cx| {
1106                ContextServerStore::local(
1107                    worktree_store.clone(),
1108                    Some(weak_self.clone()),
1109                    false,
1110                    cx,
1111                )
1112            });
1113
1114            let environment = cx.new(|cx| {
1115                ProjectEnvironment::new(env, worktree_store.downgrade(), None, false, cx)
1116            });
1117            let manifest_tree = ManifestTree::new(worktree_store.clone(), cx);
1118            let toolchain_store = cx.new(|cx| {
1119                ToolchainStore::local(
1120                    languages.clone(),
1121                    worktree_store.clone(),
1122                    environment.clone(),
1123                    manifest_tree.clone(),
1124                    fs.clone(),
1125                    cx,
1126                )
1127            });
1128
1129            let buffer_store = cx.new(|cx| BufferStore::local(worktree_store.clone(), cx));
1130            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
1131                .detach();
1132
1133            let breakpoint_store =
1134                cx.new(|_| BreakpointStore::local(worktree_store.clone(), buffer_store.clone()));
1135
1136            let dap_store = cx.new(|cx| {
1137                DapStore::new_local(
1138                    client.http_client(),
1139                    node.clone(),
1140                    fs.clone(),
1141                    environment.clone(),
1142                    toolchain_store.read(cx).as_language_toolchain_store(),
1143                    worktree_store.clone(),
1144                    breakpoint_store.clone(),
1145                    false,
1146                    cx,
1147                )
1148            });
1149            cx.subscribe(&dap_store, Self::on_dap_store_event).detach();
1150
1151            let image_store = cx.new(|cx| ImageStore::local(worktree_store.clone(), cx));
1152            cx.subscribe(&image_store, Self::on_image_store_event)
1153                .detach();
1154
1155            let prettier_store = cx.new(|cx| {
1156                PrettierStore::new(
1157                    node.clone(),
1158                    fs.clone(),
1159                    languages.clone(),
1160                    worktree_store.clone(),
1161                    cx,
1162                )
1163            });
1164
1165            let task_store = cx.new(|cx| {
1166                TaskStore::local(
1167                    buffer_store.downgrade(),
1168                    worktree_store.clone(),
1169                    toolchain_store.read(cx).as_language_toolchain_store(),
1170                    environment.clone(),
1171                    cx,
1172                )
1173            });
1174
1175            let settings_observer = cx.new(|cx| {
1176                SettingsObserver::new_local(
1177                    fs.clone(),
1178                    worktree_store.clone(),
1179                    task_store.clone(),
1180                    cx,
1181                )
1182            });
1183            cx.subscribe(&settings_observer, Self::on_settings_observer_event)
1184                .detach();
1185
1186            let lsp_store = cx.new(|cx| {
1187                LspStore::new_local(
1188                    buffer_store.clone(),
1189                    worktree_store.clone(),
1190                    prettier_store.clone(),
1191                    toolchain_store
1192                        .read(cx)
1193                        .as_local_store()
1194                        .expect("Toolchain store to be local")
1195                        .clone(),
1196                    environment.clone(),
1197                    manifest_tree,
1198                    languages.clone(),
1199                    client.http_client(),
1200                    fs.clone(),
1201                    cx,
1202                )
1203            });
1204
1205            let git_store = cx.new(|cx| {
1206                GitStore::local(
1207                    &worktree_store,
1208                    buffer_store.clone(),
1209                    environment.clone(),
1210                    fs.clone(),
1211                    cx,
1212                )
1213            });
1214
1215            let agent_server_store = cx.new(|cx| {
1216                AgentServerStore::local(
1217                    node.clone(),
1218                    fs.clone(),
1219                    environment.clone(),
1220                    client.http_client(),
1221                    cx,
1222                )
1223            });
1224
1225            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
1226
1227            Self {
1228                buffer_ordered_messages_tx: tx,
1229                collaborators: Default::default(),
1230                worktree_store,
1231                buffer_store,
1232                image_store,
1233                lsp_store,
1234                context_server_store,
1235                join_project_response_message_id: 0,
1236                client_state: ProjectClientState::Local,
1237                git_store,
1238                client_subscriptions: Vec::new(),
1239                _subscriptions: vec![cx.on_release(Self::release)],
1240                active_entry: None,
1241                snippets,
1242                languages,
1243                collab_client: client,
1244                task_store,
1245                user_store,
1246                settings_observer,
1247                fs,
1248                remote_client: None,
1249                breakpoint_store,
1250                dap_store,
1251                agent_server_store,
1252
1253                buffers_needing_diff: Default::default(),
1254                git_diff_debouncer: DebouncedDelay::new(),
1255                terminals: Terminals {
1256                    local_handles: Vec::new(),
1257                },
1258                node: Some(node),
1259                search_history: Self::new_search_history(),
1260                environment,
1261                remotely_created_models: Default::default(),
1262
1263                search_included_history: Self::new_search_history(),
1264                search_excluded_history: Self::new_search_history(),
1265
1266                toolchain_store: Some(toolchain_store),
1267
1268                agent_location: None,
1269            }
1270        })
1271    }
1272
1273    pub fn remote(
1274        remote: Entity<RemoteClient>,
1275        client: Arc<Client>,
1276        node: NodeRuntime,
1277        user_store: Entity<UserStore>,
1278        languages: Arc<LanguageRegistry>,
1279        fs: Arc<dyn Fs>,
1280        init_worktree_trust: bool,
1281        cx: &mut App,
1282    ) -> Entity<Self> {
1283        cx.new(|cx: &mut Context<Self>| {
1284            let (tx, rx) = mpsc::unbounded();
1285            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
1286                .detach();
1287            let snippets = SnippetProvider::new(fs.clone(), BTreeSet::from_iter([]), cx);
1288
1289            let (remote_proto, path_style, connection_options) =
1290                remote.read_with(cx, |remote, _| {
1291                    (
1292                        remote.proto_client(),
1293                        remote.path_style(),
1294                        remote.connection_options(),
1295                    )
1296                });
1297            let worktree_store = cx.new(|_| {
1298                WorktreeStore::remote(
1299                    false,
1300                    remote_proto.clone(),
1301                    REMOTE_SERVER_PROJECT_ID,
1302                    path_style,
1303                )
1304            });
1305
1306            cx.subscribe(&worktree_store, Self::on_worktree_store_event)
1307                .detach();
1308            if init_worktree_trust {
1309                trusted_worktrees::track_worktree_trust(
1310                    worktree_store.clone(),
1311                    Some(RemoteHostLocation::from(connection_options)),
1312                    None,
1313                    Some((remote_proto.clone(), ProjectId(REMOTE_SERVER_PROJECT_ID))),
1314                    cx,
1315                );
1316            }
1317
1318            let weak_self = cx.weak_entity();
1319
1320            let buffer_store = cx.new(|cx| {
1321                BufferStore::remote(
1322                    worktree_store.clone(),
1323                    remote.read(cx).proto_client(),
1324                    REMOTE_SERVER_PROJECT_ID,
1325                    cx,
1326                )
1327            });
1328            let image_store = cx.new(|cx| {
1329                ImageStore::remote(
1330                    worktree_store.clone(),
1331                    remote.read(cx).proto_client(),
1332                    REMOTE_SERVER_PROJECT_ID,
1333                    cx,
1334                )
1335            });
1336            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
1337                .detach();
1338            let toolchain_store = cx.new(|cx| {
1339                ToolchainStore::remote(
1340                    REMOTE_SERVER_PROJECT_ID,
1341                    worktree_store.clone(),
1342                    remote.read(cx).proto_client(),
1343                    cx,
1344                )
1345            });
1346
1347            let task_store = cx.new(|cx| {
1348                TaskStore::remote(
1349                    buffer_store.downgrade(),
1350                    worktree_store.clone(),
1351                    toolchain_store.read(cx).as_language_toolchain_store(),
1352                    remote.read(cx).proto_client(),
1353                    REMOTE_SERVER_PROJECT_ID,
1354                    cx,
1355                )
1356            });
1357
1358            let settings_observer = cx.new(|cx| {
1359                SettingsObserver::new_remote(
1360                    fs.clone(),
1361                    worktree_store.clone(),
1362                    task_store.clone(),
1363                    Some(remote_proto.clone()),
1364                    false,
1365                    cx,
1366                )
1367            });
1368            cx.subscribe(&settings_observer, Self::on_settings_observer_event)
1369                .detach();
1370
1371            let context_server_store = cx.new(|cx| {
1372                ContextServerStore::remote(
1373                    rpc::proto::REMOTE_SERVER_PROJECT_ID,
1374                    remote.clone(),
1375                    worktree_store.clone(),
1376                    Some(weak_self.clone()),
1377                    cx,
1378                )
1379            });
1380
1381            let environment = cx.new(|cx| {
1382                ProjectEnvironment::new(
1383                    None,
1384                    worktree_store.downgrade(),
1385                    Some(remote.downgrade()),
1386                    false,
1387                    cx,
1388                )
1389            });
1390
1391            let lsp_store = cx.new(|cx| {
1392                LspStore::new_remote(
1393                    buffer_store.clone(),
1394                    worktree_store.clone(),
1395                    languages.clone(),
1396                    remote_proto.clone(),
1397                    REMOTE_SERVER_PROJECT_ID,
1398                    cx,
1399                )
1400            });
1401            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
1402
1403            let breakpoint_store = cx.new(|_| {
1404                BreakpointStore::remote(
1405                    REMOTE_SERVER_PROJECT_ID,
1406                    remote_proto.clone(),
1407                    buffer_store.clone(),
1408                    worktree_store.clone(),
1409                )
1410            });
1411
1412            let dap_store = cx.new(|cx| {
1413                DapStore::new_remote(
1414                    REMOTE_SERVER_PROJECT_ID,
1415                    remote.clone(),
1416                    breakpoint_store.clone(),
1417                    worktree_store.clone(),
1418                    node.clone(),
1419                    client.http_client(),
1420                    fs.clone(),
1421                    cx,
1422                )
1423            });
1424
1425            let git_store = cx.new(|cx| {
1426                GitStore::remote(
1427                    &worktree_store,
1428                    buffer_store.clone(),
1429                    remote_proto.clone(),
1430                    REMOTE_SERVER_PROJECT_ID,
1431                    cx,
1432                )
1433            });
1434
1435            let agent_server_store =
1436                cx.new(|_| AgentServerStore::remote(REMOTE_SERVER_PROJECT_ID, remote.clone()));
1437
1438            cx.subscribe(&remote, Self::on_remote_client_event).detach();
1439
1440            let this = Self {
1441                buffer_ordered_messages_tx: tx,
1442                collaborators: Default::default(),
1443                worktree_store,
1444                buffer_store,
1445                image_store,
1446                lsp_store,
1447                context_server_store,
1448                breakpoint_store,
1449                dap_store,
1450                join_project_response_message_id: 0,
1451                client_state: ProjectClientState::Local,
1452                git_store,
1453                agent_server_store,
1454                client_subscriptions: Vec::new(),
1455                _subscriptions: vec![
1456                    cx.on_release(Self::release),
1457                    cx.on_app_quit(|this, cx| {
1458                        let shutdown = this.remote_client.take().and_then(|client| {
1459                            client.update(cx, |client, cx| {
1460                                client.shutdown_processes(
1461                                    Some(proto::ShutdownRemoteServer {}),
1462                                    cx.background_executor().clone(),
1463                                )
1464                            })
1465                        });
1466
1467                        cx.background_executor().spawn(async move {
1468                            if let Some(shutdown) = shutdown {
1469                                shutdown.await;
1470                            }
1471                        })
1472                    }),
1473                ],
1474                active_entry: None,
1475                snippets,
1476                languages,
1477                collab_client: client,
1478                task_store,
1479                user_store,
1480                settings_observer,
1481                fs,
1482                remote_client: Some(remote.clone()),
1483                buffers_needing_diff: Default::default(),
1484                git_diff_debouncer: DebouncedDelay::new(),
1485                terminals: Terminals {
1486                    local_handles: Vec::new(),
1487                },
1488                node: Some(node),
1489                search_history: Self::new_search_history(),
1490                environment,
1491                remotely_created_models: Default::default(),
1492
1493                search_included_history: Self::new_search_history(),
1494                search_excluded_history: Self::new_search_history(),
1495
1496                toolchain_store: Some(toolchain_store),
1497                agent_location: None,
1498            };
1499
1500            // remote server -> local machine handlers
1501            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &cx.entity());
1502            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.buffer_store);
1503            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.worktree_store);
1504            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.lsp_store);
1505            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.dap_store);
1506            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.breakpoint_store);
1507            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.settings_observer);
1508            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.git_store);
1509            remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.agent_server_store);
1510
1511            remote_proto.add_entity_message_handler(Self::handle_create_buffer_for_peer);
1512            remote_proto.add_entity_message_handler(Self::handle_create_image_for_peer);
1513            remote_proto.add_entity_message_handler(Self::handle_update_worktree);
1514            remote_proto.add_entity_message_handler(Self::handle_update_project);
1515            remote_proto.add_entity_message_handler(Self::handle_toast);
1516            remote_proto.add_entity_request_handler(Self::handle_language_server_prompt_request);
1517            remote_proto.add_entity_message_handler(Self::handle_hide_toast);
1518            remote_proto.add_entity_request_handler(Self::handle_update_buffer_from_remote_server);
1519            remote_proto.add_entity_request_handler(Self::handle_trust_worktrees);
1520            remote_proto.add_entity_request_handler(Self::handle_restrict_worktrees);
1521            remote_proto.add_entity_request_handler(Self::handle_find_search_candidates_chunk);
1522
1523            remote_proto.add_entity_message_handler(Self::handle_find_search_candidates_cancel);
1524            BufferStore::init(&remote_proto);
1525            LspStore::init(&remote_proto);
1526            SettingsObserver::init(&remote_proto);
1527            TaskStore::init(Some(&remote_proto));
1528            ToolchainStore::init(&remote_proto);
1529            DapStore::init(&remote_proto, cx);
1530            BreakpointStore::init(&remote_proto);
1531            GitStore::init(&remote_proto);
1532            AgentServerStore::init_remote(&remote_proto);
1533
1534            this
1535        })
1536    }
1537
1538    pub async fn in_room(
1539        remote_id: u64,
1540        client: Arc<Client>,
1541        user_store: Entity<UserStore>,
1542        languages: Arc<LanguageRegistry>,
1543        fs: Arc<dyn Fs>,
1544        cx: AsyncApp,
1545    ) -> Result<Entity<Self>> {
1546        client.connect(true, &cx).await.into_response()?;
1547
1548        let subscriptions = [
1549            EntitySubscription::Project(client.subscribe_to_entity::<Self>(remote_id)?),
1550            EntitySubscription::BufferStore(client.subscribe_to_entity::<BufferStore>(remote_id)?),
1551            EntitySubscription::GitStore(client.subscribe_to_entity::<GitStore>(remote_id)?),
1552            EntitySubscription::WorktreeStore(
1553                client.subscribe_to_entity::<WorktreeStore>(remote_id)?,
1554            ),
1555            EntitySubscription::LspStore(client.subscribe_to_entity::<LspStore>(remote_id)?),
1556            EntitySubscription::SettingsObserver(
1557                client.subscribe_to_entity::<SettingsObserver>(remote_id)?,
1558            ),
1559            EntitySubscription::DapStore(client.subscribe_to_entity::<DapStore>(remote_id)?),
1560            EntitySubscription::BreakpointStore(
1561                client.subscribe_to_entity::<BreakpointStore>(remote_id)?,
1562            ),
1563        ];
1564        let committer = get_git_committer(&cx).await;
1565        let response = client
1566            .request_envelope(proto::JoinProject {
1567                project_id: remote_id,
1568                committer_email: committer.email,
1569                committer_name: committer.name,
1570            })
1571            .await?;
1572        Self::from_join_project_response(
1573            response,
1574            subscriptions,
1575            client,
1576            false,
1577            user_store,
1578            languages,
1579            fs,
1580            cx,
1581        )
1582        .await
1583    }
1584
1585    async fn from_join_project_response(
1586        response: TypedEnvelope<proto::JoinProjectResponse>,
1587        subscriptions: [EntitySubscription; 8],
1588        client: Arc<Client>,
1589        run_tasks: bool,
1590        user_store: Entity<UserStore>,
1591        languages: Arc<LanguageRegistry>,
1592        fs: Arc<dyn Fs>,
1593        mut cx: AsyncApp,
1594    ) -> Result<Entity<Self>> {
1595        let remote_id = response.payload.project_id;
1596        let role = response.payload.role();
1597
1598        let path_style = if response.payload.windows_paths {
1599            PathStyle::Windows
1600        } else {
1601            PathStyle::Posix
1602        };
1603
1604        let worktree_store = cx.new(|_| {
1605            WorktreeStore::remote(
1606                true,
1607                client.clone().into(),
1608                response.payload.project_id,
1609                path_style,
1610            )
1611        });
1612        let buffer_store = cx.new(|cx| {
1613            BufferStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
1614        });
1615        let image_store = cx.new(|cx| {
1616            ImageStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
1617        });
1618
1619        let environment =
1620            cx.new(|cx| ProjectEnvironment::new(None, worktree_store.downgrade(), None, true, cx));
1621        let breakpoint_store = cx.new(|_| {
1622            BreakpointStore::remote(
1623                remote_id,
1624                client.clone().into(),
1625                buffer_store.clone(),
1626                worktree_store.clone(),
1627            )
1628        });
1629        let dap_store = cx.new(|cx| {
1630            DapStore::new_collab(
1631                remote_id,
1632                client.clone().into(),
1633                breakpoint_store.clone(),
1634                worktree_store.clone(),
1635                fs.clone(),
1636                cx,
1637            )
1638        });
1639
1640        let lsp_store = cx.new(|cx| {
1641            LspStore::new_remote(
1642                buffer_store.clone(),
1643                worktree_store.clone(),
1644                languages.clone(),
1645                client.clone().into(),
1646                remote_id,
1647                cx,
1648            )
1649        });
1650
1651        let task_store = cx.new(|cx| {
1652            if run_tasks {
1653                TaskStore::remote(
1654                    buffer_store.downgrade(),
1655                    worktree_store.clone(),
1656                    Arc::new(EmptyToolchainStore),
1657                    client.clone().into(),
1658                    remote_id,
1659                    cx,
1660                )
1661            } else {
1662                TaskStore::Noop
1663            }
1664        });
1665
1666        let settings_observer = cx.new(|cx| {
1667            SettingsObserver::new_remote(
1668                fs.clone(),
1669                worktree_store.clone(),
1670                task_store.clone(),
1671                None,
1672                true,
1673                cx,
1674            )
1675        });
1676
1677        let git_store = cx.new(|cx| {
1678            GitStore::remote(
1679                // In this remote case we pass None for the environment
1680                &worktree_store,
1681                buffer_store.clone(),
1682                client.clone().into(),
1683                remote_id,
1684                cx,
1685            )
1686        });
1687
1688        let agent_server_store = cx.new(|cx| AgentServerStore::collab(cx));
1689        let replica_id = ReplicaId::new(response.payload.replica_id as u16);
1690
1691        let project = cx.new(|cx| {
1692            let snippets = SnippetProvider::new(fs.clone(), BTreeSet::from_iter([]), cx);
1693
1694            let weak_self = cx.weak_entity();
1695            let context_server_store = cx.new(|cx| {
1696                ContextServerStore::local(worktree_store.clone(), Some(weak_self), false, cx)
1697            });
1698
1699            let mut worktrees = Vec::new();
1700            for worktree in response.payload.worktrees {
1701                let worktree = Worktree::remote(
1702                    remote_id,
1703                    replica_id,
1704                    worktree,
1705                    client.clone().into(),
1706                    path_style,
1707                    cx,
1708                );
1709                worktrees.push(worktree);
1710            }
1711
1712            let (tx, rx) = mpsc::unbounded();
1713            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
1714                .detach();
1715
1716            cx.subscribe(&worktree_store, Self::on_worktree_store_event)
1717                .detach();
1718
1719            cx.subscribe(&buffer_store, Self::on_buffer_store_event)
1720                .detach();
1721            cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
1722            cx.subscribe(&settings_observer, Self::on_settings_observer_event)
1723                .detach();
1724
1725            cx.subscribe(&dap_store, Self::on_dap_store_event).detach();
1726
1727            let mut project = Self {
1728                buffer_ordered_messages_tx: tx,
1729                buffer_store: buffer_store.clone(),
1730                image_store,
1731                worktree_store: worktree_store.clone(),
1732                lsp_store: lsp_store.clone(),
1733                context_server_store,
1734                active_entry: None,
1735                collaborators: Default::default(),
1736                join_project_response_message_id: response.message_id,
1737                languages,
1738                user_store: user_store.clone(),
1739                task_store,
1740                snippets,
1741                fs,
1742                remote_client: None,
1743                settings_observer: settings_observer.clone(),
1744                client_subscriptions: Default::default(),
1745                _subscriptions: vec![cx.on_release(Self::release)],
1746                collab_client: client.clone(),
1747                client_state: ProjectClientState::Remote {
1748                    sharing_has_stopped: false,
1749                    capability: Capability::ReadWrite,
1750                    remote_id,
1751                    replica_id,
1752                },
1753                breakpoint_store: breakpoint_store.clone(),
1754                dap_store: dap_store.clone(),
1755                git_store: git_store.clone(),
1756                agent_server_store,
1757                buffers_needing_diff: Default::default(),
1758                git_diff_debouncer: DebouncedDelay::new(),
1759                terminals: Terminals {
1760                    local_handles: Vec::new(),
1761                },
1762                node: None,
1763                search_history: Self::new_search_history(),
1764                search_included_history: Self::new_search_history(),
1765                search_excluded_history: Self::new_search_history(),
1766                environment,
1767                remotely_created_models: Arc::new(Mutex::new(RemotelyCreatedModels::default())),
1768                toolchain_store: None,
1769                agent_location: None,
1770            };
1771            project.set_role(role, cx);
1772            for worktree in worktrees {
1773                project.add_worktree(&worktree, cx);
1774            }
1775            project
1776        });
1777
1778        let weak_project = project.downgrade();
1779        lsp_store.update(&mut cx, |lsp_store, cx| {
1780            lsp_store.set_language_server_statuses_from_proto(
1781                weak_project,
1782                response.payload.language_servers,
1783                response.payload.language_server_capabilities,
1784                cx,
1785            );
1786        });
1787
1788        let subscriptions = subscriptions
1789            .into_iter()
1790            .map(|s| match s {
1791                EntitySubscription::BufferStore(subscription) => {
1792                    subscription.set_entity(&buffer_store, &cx)
1793                }
1794                EntitySubscription::WorktreeStore(subscription) => {
1795                    subscription.set_entity(&worktree_store, &cx)
1796                }
1797                EntitySubscription::GitStore(subscription) => {
1798                    subscription.set_entity(&git_store, &cx)
1799                }
1800                EntitySubscription::SettingsObserver(subscription) => {
1801                    subscription.set_entity(&settings_observer, &cx)
1802                }
1803                EntitySubscription::Project(subscription) => subscription.set_entity(&project, &cx),
1804                EntitySubscription::LspStore(subscription) => {
1805                    subscription.set_entity(&lsp_store, &cx)
1806                }
1807                EntitySubscription::DapStore(subscription) => {
1808                    subscription.set_entity(&dap_store, &cx)
1809                }
1810                EntitySubscription::BreakpointStore(subscription) => {
1811                    subscription.set_entity(&breakpoint_store, &cx)
1812                }
1813            })
1814            .collect::<Vec<_>>();
1815
1816        let user_ids = response
1817            .payload
1818            .collaborators
1819            .iter()
1820            .map(|peer| peer.user_id)
1821            .collect();
1822        user_store
1823            .update(&mut cx, |user_store, cx| user_store.get_users(user_ids, cx))
1824            .await?;
1825
1826        project.update(&mut cx, |this, cx| {
1827            this.set_collaborators_from_proto(response.payload.collaborators, cx)?;
1828            this.client_subscriptions.extend(subscriptions);
1829            anyhow::Ok(())
1830        })?;
1831
1832        Ok(project)
1833    }
1834
1835    fn new_search_history() -> SearchHistory {
1836        SearchHistory::new(
1837            Some(MAX_PROJECT_SEARCH_HISTORY_SIZE),
1838            search_history::QueryInsertionBehavior::AlwaysInsert,
1839        )
1840    }
1841
1842    fn release(&mut self, cx: &mut App) {
1843        if let Some(client) = self.remote_client.take() {
1844            let shutdown = client.update(cx, |client, cx| {
1845                client.shutdown_processes(
1846                    Some(proto::ShutdownRemoteServer {}),
1847                    cx.background_executor().clone(),
1848                )
1849            });
1850
1851            cx.background_spawn(async move {
1852                if let Some(shutdown) = shutdown {
1853                    shutdown.await;
1854                }
1855            })
1856            .detach()
1857        }
1858
1859        match &self.client_state {
1860            ProjectClientState::Local => {}
1861            ProjectClientState::Shared { .. } => {
1862                let _ = self.unshare_internal(cx);
1863            }
1864            ProjectClientState::Remote { remote_id, .. } => {
1865                let _ = self.collab_client.send(proto::LeaveProject {
1866                    project_id: *remote_id,
1867                });
1868                self.disconnected_from_host_internal(cx);
1869            }
1870        }
1871    }
1872
1873    #[cfg(any(test, feature = "test-support"))]
1874    pub async fn example(
1875        root_paths: impl IntoIterator<Item = &Path>,
1876        cx: &mut AsyncApp,
1877    ) -> Entity<Project> {
1878        use clock::FakeSystemClock;
1879
1880        let fs = Arc::new(RealFs::new(None, cx.background_executor().clone()));
1881        let languages = LanguageRegistry::test(cx.background_executor().clone());
1882        let clock = Arc::new(FakeSystemClock::new());
1883        let http_client = http_client::FakeHttpClient::with_404_response();
1884        let client = cx.update(|cx| client::Client::new(clock, http_client.clone(), cx));
1885        let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
1886        let project = cx.update(|cx| {
1887            Project::local(
1888                client,
1889                node_runtime::NodeRuntime::unavailable(),
1890                user_store,
1891                Arc::new(languages),
1892                fs,
1893                None,
1894                false,
1895                cx,
1896            )
1897        });
1898        for path in root_paths {
1899            let (tree, _): (Entity<Worktree>, _) = project
1900                .update(cx, |project, cx| {
1901                    project.find_or_create_worktree(path, true, cx)
1902                })
1903                .await
1904                .unwrap();
1905            tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
1906                .await;
1907        }
1908        project
1909    }
1910
1911    #[cfg(any(test, feature = "test-support"))]
1912    pub async fn test(
1913        fs: Arc<dyn Fs>,
1914        root_paths: impl IntoIterator<Item = &Path>,
1915        cx: &mut gpui::TestAppContext,
1916    ) -> Entity<Project> {
1917        Self::test_project(fs, root_paths, false, cx).await
1918    }
1919
1920    #[cfg(any(test, feature = "test-support"))]
1921    pub async fn test_with_worktree_trust(
1922        fs: Arc<dyn Fs>,
1923        root_paths: impl IntoIterator<Item = &Path>,
1924        cx: &mut gpui::TestAppContext,
1925    ) -> Entity<Project> {
1926        Self::test_project(fs, root_paths, true, cx).await
1927    }
1928
1929    #[cfg(any(test, feature = "test-support"))]
1930    async fn test_project(
1931        fs: Arc<dyn Fs>,
1932        root_paths: impl IntoIterator<Item = &Path>,
1933        init_worktree_trust: bool,
1934        cx: &mut gpui::TestAppContext,
1935    ) -> Entity<Project> {
1936        use clock::FakeSystemClock;
1937
1938        let languages = LanguageRegistry::test(cx.executor());
1939        let clock = Arc::new(FakeSystemClock::new());
1940        let http_client = http_client::FakeHttpClient::with_404_response();
1941        let client = cx.update(|cx| client::Client::new(clock, http_client.clone(), cx));
1942        let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
1943        let project = cx.update(|cx| {
1944            Project::local(
1945                client,
1946                node_runtime::NodeRuntime::unavailable(),
1947                user_store,
1948                Arc::new(languages),
1949                fs,
1950                None,
1951                init_worktree_trust,
1952                cx,
1953            )
1954        });
1955        for path in root_paths {
1956            let (tree, _) = project
1957                .update(cx, |project, cx| {
1958                    project.find_or_create_worktree(path, true, cx)
1959                })
1960                .await
1961                .unwrap();
1962
1963            tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
1964                .await;
1965        }
1966        project
1967    }
1968
1969    #[inline]
1970    pub fn dap_store(&self) -> Entity<DapStore> {
1971        self.dap_store.clone()
1972    }
1973
1974    #[inline]
1975    pub fn breakpoint_store(&self) -> Entity<BreakpointStore> {
1976        self.breakpoint_store.clone()
1977    }
1978
1979    pub fn active_debug_session(&self, cx: &App) -> Option<(Entity<Session>, ActiveStackFrame)> {
1980        let active_position = self.breakpoint_store.read(cx).active_position()?;
1981        let session = self
1982            .dap_store
1983            .read(cx)
1984            .session_by_id(active_position.session_id)?;
1985        Some((session, active_position.clone()))
1986    }
1987
1988    #[inline]
1989    pub fn lsp_store(&self) -> Entity<LspStore> {
1990        self.lsp_store.clone()
1991    }
1992
1993    #[inline]
1994    pub fn worktree_store(&self) -> Entity<WorktreeStore> {
1995        self.worktree_store.clone()
1996    }
1997
1998    #[inline]
1999    pub fn context_server_store(&self) -> Entity<ContextServerStore> {
2000        self.context_server_store.clone()
2001    }
2002
2003    #[inline]
2004    pub fn buffer_for_id(&self, remote_id: BufferId, cx: &App) -> Option<Entity<Buffer>> {
2005        self.buffer_store.read(cx).get(remote_id)
2006    }
2007
2008    #[inline]
2009    pub fn languages(&self) -> &Arc<LanguageRegistry> {
2010        &self.languages
2011    }
2012
2013    #[inline]
2014    pub fn client(&self) -> Arc<Client> {
2015        self.collab_client.clone()
2016    }
2017
2018    #[inline]
2019    pub fn remote_client(&self) -> Option<Entity<RemoteClient>> {
2020        self.remote_client.clone()
2021    }
2022
2023    #[inline]
2024    pub fn user_store(&self) -> Entity<UserStore> {
2025        self.user_store.clone()
2026    }
2027
2028    #[inline]
2029    pub fn node_runtime(&self) -> Option<&NodeRuntime> {
2030        self.node.as_ref()
2031    }
2032
2033    #[inline]
2034    pub fn opened_buffers(&self, cx: &App) -> Vec<Entity<Buffer>> {
2035        self.buffer_store.read(cx).buffers().collect()
2036    }
2037
2038    #[inline]
2039    pub fn environment(&self) -> &Entity<ProjectEnvironment> {
2040        &self.environment
2041    }
2042
2043    #[inline]
2044    pub fn cli_environment(&self, cx: &App) -> Option<HashMap<String, String>> {
2045        self.environment.read(cx).get_cli_environment()
2046    }
2047
2048    #[inline]
2049    pub fn peek_environment_error<'a>(&'a self, cx: &'a App) -> Option<&'a String> {
2050        self.environment.read(cx).peek_environment_error()
2051    }
2052
2053    #[inline]
2054    pub fn pop_environment_error(&mut self, cx: &mut Context<Self>) {
2055        self.environment.update(cx, |environment, _| {
2056            environment.pop_environment_error();
2057        });
2058    }
2059
2060    #[cfg(any(test, feature = "test-support"))]
2061    #[inline]
2062    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &App) -> bool {
2063        self.buffer_store
2064            .read(cx)
2065            .get_by_path(&path.into())
2066            .is_some()
2067    }
2068
2069    #[inline]
2070    pub fn fs(&self) -> &Arc<dyn Fs> {
2071        &self.fs
2072    }
2073
2074    #[inline]
2075    pub fn remote_id(&self) -> Option<u64> {
2076        match self.client_state {
2077            ProjectClientState::Local => None,
2078            ProjectClientState::Shared { remote_id, .. }
2079            | ProjectClientState::Remote { remote_id, .. } => Some(remote_id),
2080        }
2081    }
2082
2083    #[inline]
2084    pub fn supports_terminal(&self, _cx: &App) -> bool {
2085        if self.is_local() {
2086            return true;
2087        }
2088        if self.is_via_remote_server() {
2089            return true;
2090        }
2091
2092        false
2093    }
2094
2095    #[inline]
2096    pub fn remote_connection_state(&self, cx: &App) -> Option<remote::ConnectionState> {
2097        self.remote_client
2098            .as_ref()
2099            .map(|remote| remote.read(cx).connection_state())
2100    }
2101
2102    #[inline]
2103    pub fn remote_connection_options(&self, cx: &App) -> Option<RemoteConnectionOptions> {
2104        self.remote_client
2105            .as_ref()
2106            .map(|remote| remote.read(cx).connection_options())
2107    }
2108
2109    #[inline]
2110    pub fn replica_id(&self) -> ReplicaId {
2111        match self.client_state {
2112            ProjectClientState::Remote { replica_id, .. } => replica_id,
2113            _ => {
2114                if self.remote_client.is_some() {
2115                    ReplicaId::REMOTE_SERVER
2116                } else {
2117                    ReplicaId::LOCAL
2118                }
2119            }
2120        }
2121    }
2122
2123    #[inline]
2124    pub fn task_store(&self) -> &Entity<TaskStore> {
2125        &self.task_store
2126    }
2127
2128    #[inline]
2129    pub fn snippets(&self) -> &Entity<SnippetProvider> {
2130        &self.snippets
2131    }
2132
2133    #[inline]
2134    pub fn search_history(&self, kind: SearchInputKind) -> &SearchHistory {
2135        match kind {
2136            SearchInputKind::Query => &self.search_history,
2137            SearchInputKind::Include => &self.search_included_history,
2138            SearchInputKind::Exclude => &self.search_excluded_history,
2139        }
2140    }
2141
2142    #[inline]
2143    pub fn search_history_mut(&mut self, kind: SearchInputKind) -> &mut SearchHistory {
2144        match kind {
2145            SearchInputKind::Query => &mut self.search_history,
2146            SearchInputKind::Include => &mut self.search_included_history,
2147            SearchInputKind::Exclude => &mut self.search_excluded_history,
2148        }
2149    }
2150
2151    #[inline]
2152    pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> {
2153        &self.collaborators
2154    }
2155
2156    #[inline]
2157    pub fn host(&self) -> Option<&Collaborator> {
2158        self.collaborators.values().find(|c| c.is_host)
2159    }
2160
2161    #[inline]
2162    pub fn set_worktrees_reordered(&mut self, worktrees_reordered: bool, cx: &mut App) {
2163        self.worktree_store.update(cx, |store, _| {
2164            store.set_worktrees_reordered(worktrees_reordered);
2165        });
2166    }
2167
2168    /// Collect all worktrees, including ones that don't appear in the project panel
2169    #[inline]
2170    pub fn worktrees<'a>(
2171        &self,
2172        cx: &'a App,
2173    ) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
2174        self.worktree_store.read(cx).worktrees()
2175    }
2176
2177    /// Collect all user-visible worktrees, the ones that appear in the project panel.
2178    #[inline]
2179    pub fn visible_worktrees<'a>(
2180        &'a self,
2181        cx: &'a App,
2182    ) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
2183        self.worktree_store.read(cx).visible_worktrees(cx)
2184    }
2185
2186    #[inline]
2187    pub fn worktree_for_root_name(&self, root_name: &str, cx: &App) -> Option<Entity<Worktree>> {
2188        self.visible_worktrees(cx)
2189            .find(|tree| tree.read(cx).root_name() == root_name)
2190    }
2191
2192    #[inline]
2193    pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
2194        self.visible_worktrees(cx)
2195            .map(|tree| tree.read(cx).root_name().as_unix_str())
2196    }
2197
2198    #[inline]
2199    pub fn worktree_for_id(&self, id: WorktreeId, cx: &App) -> Option<Entity<Worktree>> {
2200        self.worktree_store.read(cx).worktree_for_id(id, cx)
2201    }
2202
2203    pub fn worktree_for_entry(
2204        &self,
2205        entry_id: ProjectEntryId,
2206        cx: &App,
2207    ) -> Option<Entity<Worktree>> {
2208        self.worktree_store
2209            .read(cx)
2210            .worktree_for_entry(entry_id, cx)
2211    }
2212
2213    #[inline]
2214    pub fn worktree_id_for_entry(&self, entry_id: ProjectEntryId, cx: &App) -> Option<WorktreeId> {
2215        self.worktree_for_entry(entry_id, cx)
2216            .map(|worktree| worktree.read(cx).id())
2217    }
2218
2219    /// Checks if the entry is the root of a worktree.
2220    #[inline]
2221    pub fn entry_is_worktree_root(&self, entry_id: ProjectEntryId, cx: &App) -> bool {
2222        self.worktree_for_entry(entry_id, cx)
2223            .map(|worktree| {
2224                worktree
2225                    .read(cx)
2226                    .root_entry()
2227                    .is_some_and(|e| e.id == entry_id)
2228            })
2229            .unwrap_or(false)
2230    }
2231
2232    #[inline]
2233    pub fn project_path_git_status(
2234        &self,
2235        project_path: &ProjectPath,
2236        cx: &App,
2237    ) -> Option<FileStatus> {
2238        self.git_store
2239            .read(cx)
2240            .project_path_git_status(project_path, cx)
2241    }
2242
2243    #[inline]
2244    pub fn visibility_for_paths(
2245        &self,
2246        paths: &[PathBuf],
2247        metadatas: &[Metadata],
2248        exclude_sub_dirs: bool,
2249        cx: &App,
2250    ) -> Option<bool> {
2251        paths
2252            .iter()
2253            .zip(metadatas)
2254            .map(|(path, metadata)| self.visibility_for_path(path, metadata, exclude_sub_dirs, cx))
2255            .max()
2256            .flatten()
2257    }
2258
2259    pub fn visibility_for_path(
2260        &self,
2261        path: &Path,
2262        metadata: &Metadata,
2263        exclude_sub_dirs: bool,
2264        cx: &App,
2265    ) -> Option<bool> {
2266        let path = SanitizedPath::new(path).as_path();
2267        self.worktrees(cx)
2268            .filter_map(|worktree| {
2269                let worktree = worktree.read(cx);
2270                let abs_path = worktree.as_local()?.abs_path();
2271                let contains = path == abs_path.as_ref()
2272                    || (path.starts_with(abs_path) && (!exclude_sub_dirs || !metadata.is_dir));
2273                contains.then(|| worktree.is_visible())
2274            })
2275            .max()
2276    }
2277
2278    pub fn create_entry(
2279        &mut self,
2280        project_path: impl Into<ProjectPath>,
2281        is_directory: bool,
2282        cx: &mut Context<Self>,
2283    ) -> Task<Result<CreatedEntry>> {
2284        let project_path = project_path.into();
2285        let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) else {
2286            return Task::ready(Err(anyhow!(format!(
2287                "No worktree for path {project_path:?}"
2288            ))));
2289        };
2290        worktree.update(cx, |worktree, cx| {
2291            worktree.create_entry(project_path.path, is_directory, None, cx)
2292        })
2293    }
2294
2295    #[inline]
2296    pub fn copy_entry(
2297        &mut self,
2298        entry_id: ProjectEntryId,
2299        new_project_path: ProjectPath,
2300        cx: &mut Context<Self>,
2301    ) -> Task<Result<Option<Entry>>> {
2302        self.worktree_store.update(cx, |worktree_store, cx| {
2303            worktree_store.copy_entry(entry_id, new_project_path, cx)
2304        })
2305    }
2306
2307    /// Renames the project entry with given `entry_id`.
2308    ///
2309    /// `new_path` is a relative path to worktree root.
2310    /// If root entry is renamed then its new root name is used instead.
2311    pub fn rename_entry(
2312        &mut self,
2313        entry_id: ProjectEntryId,
2314        new_path: ProjectPath,
2315        cx: &mut Context<Self>,
2316    ) -> Task<Result<CreatedEntry>> {
2317        let worktree_store = self.worktree_store.clone();
2318        let Some((worktree, old_path, is_dir)) = worktree_store
2319            .read(cx)
2320            .worktree_and_entry_for_id(entry_id, cx)
2321            .map(|(worktree, entry)| (worktree, entry.path.clone(), entry.is_dir()))
2322        else {
2323            return Task::ready(Err(anyhow!(format!("No worktree for entry {entry_id:?}"))));
2324        };
2325
2326        let worktree_id = worktree.read(cx).id();
2327        let is_root_entry = self.entry_is_worktree_root(entry_id, cx);
2328
2329        let lsp_store = self.lsp_store().downgrade();
2330        cx.spawn(async move |project, cx| {
2331            let (old_abs_path, new_abs_path) = {
2332                let root_path = worktree.read_with(cx, |this, _| this.abs_path());
2333                let new_abs_path = if is_root_entry {
2334                    root_path
2335                        .parent()
2336                        .unwrap()
2337                        .join(new_path.path.as_std_path())
2338                } else {
2339                    root_path.join(&new_path.path.as_std_path())
2340                };
2341                (root_path.join(old_path.as_std_path()), new_abs_path)
2342            };
2343            let transaction = LspStore::will_rename_entry(
2344                lsp_store.clone(),
2345                worktree_id,
2346                &old_abs_path,
2347                &new_abs_path,
2348                is_dir,
2349                cx.clone(),
2350            )
2351            .await;
2352
2353            let entry = worktree_store
2354                .update(cx, |worktree_store, cx| {
2355                    worktree_store.rename_entry(entry_id, new_path.clone(), cx)
2356                })
2357                .await?;
2358
2359            project
2360                .update(cx, |_, cx| {
2361                    cx.emit(Event::EntryRenamed(
2362                        transaction,
2363                        new_path.clone(),
2364                        new_abs_path.clone(),
2365                    ));
2366                })
2367                .ok();
2368
2369            lsp_store
2370                .read_with(cx, |this, _| {
2371                    this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
2372                })
2373                .ok();
2374            Ok(entry)
2375        })
2376    }
2377
2378    #[inline]
2379    pub fn delete_file(
2380        &mut self,
2381        path: ProjectPath,
2382        trash: bool,
2383        cx: &mut Context<Self>,
2384    ) -> Option<Task<Result<()>>> {
2385        let entry = self.entry_for_path(&path, cx)?;
2386        self.delete_entry(entry.id, trash, cx)
2387    }
2388
2389    #[inline]
2390    pub fn delete_entry(
2391        &mut self,
2392        entry_id: ProjectEntryId,
2393        trash: bool,
2394        cx: &mut Context<Self>,
2395    ) -> Option<Task<Result<()>>> {
2396        let worktree = self.worktree_for_entry(entry_id, cx)?;
2397        cx.emit(Event::DeletedEntry(worktree.read(cx).id(), entry_id));
2398        worktree.update(cx, |worktree, cx| {
2399            worktree.delete_entry(entry_id, trash, cx)
2400        })
2401    }
2402
2403    #[inline]
2404    pub fn expand_entry(
2405        &mut self,
2406        worktree_id: WorktreeId,
2407        entry_id: ProjectEntryId,
2408        cx: &mut Context<Self>,
2409    ) -> Option<Task<Result<()>>> {
2410        let worktree = self.worktree_for_id(worktree_id, cx)?;
2411        worktree.update(cx, |worktree, cx| worktree.expand_entry(entry_id, cx))
2412    }
2413
2414    pub fn expand_all_for_entry(
2415        &mut self,
2416        worktree_id: WorktreeId,
2417        entry_id: ProjectEntryId,
2418        cx: &mut Context<Self>,
2419    ) -> Option<Task<Result<()>>> {
2420        let worktree = self.worktree_for_id(worktree_id, cx)?;
2421        let task = worktree.update(cx, |worktree, cx| {
2422            worktree.expand_all_for_entry(entry_id, cx)
2423        });
2424        Some(cx.spawn(async move |this, cx| {
2425            task.context("no task")?.await?;
2426            this.update(cx, |_, cx| {
2427                cx.emit(Event::ExpandedAllForEntry(worktree_id, entry_id));
2428            })?;
2429            Ok(())
2430        }))
2431    }
2432
2433    pub fn shared(&mut self, project_id: u64, cx: &mut Context<Self>) -> Result<()> {
2434        anyhow::ensure!(
2435            matches!(self.client_state, ProjectClientState::Local),
2436            "project was already shared"
2437        );
2438
2439        self.client_subscriptions.extend([
2440            self.collab_client
2441                .subscribe_to_entity(project_id)?
2442                .set_entity(&cx.entity(), &cx.to_async()),
2443            self.collab_client
2444                .subscribe_to_entity(project_id)?
2445                .set_entity(&self.worktree_store, &cx.to_async()),
2446            self.collab_client
2447                .subscribe_to_entity(project_id)?
2448                .set_entity(&self.buffer_store, &cx.to_async()),
2449            self.collab_client
2450                .subscribe_to_entity(project_id)?
2451                .set_entity(&self.lsp_store, &cx.to_async()),
2452            self.collab_client
2453                .subscribe_to_entity(project_id)?
2454                .set_entity(&self.settings_observer, &cx.to_async()),
2455            self.collab_client
2456                .subscribe_to_entity(project_id)?
2457                .set_entity(&self.dap_store, &cx.to_async()),
2458            self.collab_client
2459                .subscribe_to_entity(project_id)?
2460                .set_entity(&self.breakpoint_store, &cx.to_async()),
2461            self.collab_client
2462                .subscribe_to_entity(project_id)?
2463                .set_entity(&self.git_store, &cx.to_async()),
2464        ]);
2465
2466        self.buffer_store.update(cx, |buffer_store, cx| {
2467            buffer_store.shared(project_id, self.collab_client.clone().into(), cx)
2468        });
2469        self.worktree_store.update(cx, |worktree_store, cx| {
2470            worktree_store.shared(project_id, self.collab_client.clone().into(), cx);
2471        });
2472        self.lsp_store.update(cx, |lsp_store, cx| {
2473            lsp_store.shared(project_id, self.collab_client.clone().into(), cx)
2474        });
2475        self.breakpoint_store.update(cx, |breakpoint_store, _| {
2476            breakpoint_store.shared(project_id, self.collab_client.clone().into())
2477        });
2478        self.dap_store.update(cx, |dap_store, cx| {
2479            dap_store.shared(project_id, self.collab_client.clone().into(), cx);
2480        });
2481        self.task_store.update(cx, |task_store, cx| {
2482            task_store.shared(project_id, self.collab_client.clone().into(), cx);
2483        });
2484        self.settings_observer.update(cx, |settings_observer, cx| {
2485            settings_observer.shared(project_id, self.collab_client.clone().into(), cx)
2486        });
2487        self.git_store.update(cx, |git_store, cx| {
2488            git_store.shared(project_id, self.collab_client.clone().into(), cx)
2489        });
2490
2491        self.client_state = ProjectClientState::Shared {
2492            remote_id: project_id,
2493        };
2494
2495        cx.emit(Event::RemoteIdChanged(Some(project_id)));
2496        Ok(())
2497    }
2498
2499    pub fn reshared(
2500        &mut self,
2501        message: proto::ResharedProject,
2502        cx: &mut Context<Self>,
2503    ) -> Result<()> {
2504        self.buffer_store
2505            .update(cx, |buffer_store, _| buffer_store.forget_shared_buffers());
2506        self.set_collaborators_from_proto(message.collaborators, cx)?;
2507
2508        self.worktree_store.update(cx, |worktree_store, cx| {
2509            worktree_store.send_project_updates(cx);
2510        });
2511        if let Some(remote_id) = self.remote_id() {
2512            self.git_store.update(cx, |git_store, cx| {
2513                git_store.shared(remote_id, self.collab_client.clone().into(), cx)
2514            });
2515        }
2516        cx.emit(Event::Reshared);
2517        Ok(())
2518    }
2519
2520    pub fn rejoined(
2521        &mut self,
2522        message: proto::RejoinedProject,
2523        message_id: u32,
2524        cx: &mut Context<Self>,
2525    ) -> Result<()> {
2526        cx.update_global::<SettingsStore, _>(|store, cx| {
2527            for worktree_metadata in &message.worktrees {
2528                store
2529                    .clear_local_settings(WorktreeId::from_proto(worktree_metadata.id), cx)
2530                    .log_err();
2531            }
2532        });
2533
2534        self.join_project_response_message_id = message_id;
2535        self.set_worktrees_from_proto(message.worktrees, cx)?;
2536        self.set_collaborators_from_proto(message.collaborators, cx)?;
2537
2538        let project = cx.weak_entity();
2539        self.lsp_store.update(cx, |lsp_store, cx| {
2540            lsp_store.set_language_server_statuses_from_proto(
2541                project,
2542                message.language_servers,
2543                message.language_server_capabilities,
2544                cx,
2545            )
2546        });
2547        self.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
2548            .unwrap();
2549        cx.emit(Event::Rejoined);
2550        Ok(())
2551    }
2552
2553    #[inline]
2554    pub fn unshare(&mut self, cx: &mut Context<Self>) -> Result<()> {
2555        self.unshare_internal(cx)?;
2556        cx.emit(Event::RemoteIdChanged(None));
2557        Ok(())
2558    }
2559
2560    fn unshare_internal(&mut self, cx: &mut App) -> Result<()> {
2561        anyhow::ensure!(
2562            !self.is_via_collab(),
2563            "attempted to unshare a remote project"
2564        );
2565
2566        if let ProjectClientState::Shared { remote_id, .. } = self.client_state {
2567            self.client_state = ProjectClientState::Local;
2568            self.collaborators.clear();
2569            self.client_subscriptions.clear();
2570            self.worktree_store.update(cx, |store, cx| {
2571                store.unshared(cx);
2572            });
2573            self.buffer_store.update(cx, |buffer_store, cx| {
2574                buffer_store.forget_shared_buffers();
2575                buffer_store.unshared(cx)
2576            });
2577            self.task_store.update(cx, |task_store, cx| {
2578                task_store.unshared(cx);
2579            });
2580            self.breakpoint_store.update(cx, |breakpoint_store, cx| {
2581                breakpoint_store.unshared(cx);
2582            });
2583            self.dap_store.update(cx, |dap_store, cx| {
2584                dap_store.unshared(cx);
2585            });
2586            self.settings_observer.update(cx, |settings_observer, cx| {
2587                settings_observer.unshared(cx);
2588            });
2589            self.git_store.update(cx, |git_store, cx| {
2590                git_store.unshared(cx);
2591            });
2592
2593            self.collab_client
2594                .send(proto::UnshareProject {
2595                    project_id: remote_id,
2596                })
2597                .ok();
2598            Ok(())
2599        } else {
2600            anyhow::bail!("attempted to unshare an unshared project");
2601        }
2602    }
2603
2604    pub fn disconnected_from_host(&mut self, cx: &mut Context<Self>) {
2605        if self.is_disconnected(cx) {
2606            return;
2607        }
2608        self.disconnected_from_host_internal(cx);
2609        cx.emit(Event::DisconnectedFromHost);
2610    }
2611
2612    pub fn set_role(&mut self, role: proto::ChannelRole, cx: &mut Context<Self>) {
2613        let new_capability =
2614            if role == proto::ChannelRole::Member || role == proto::ChannelRole::Admin {
2615                Capability::ReadWrite
2616            } else {
2617                Capability::ReadOnly
2618            };
2619        if let ProjectClientState::Remote { capability, .. } = &mut self.client_state {
2620            if *capability == new_capability {
2621                return;
2622            }
2623
2624            *capability = new_capability;
2625            for buffer in self.opened_buffers(cx) {
2626                buffer.update(cx, |buffer, cx| buffer.set_capability(new_capability, cx));
2627            }
2628        }
2629    }
2630
2631    fn disconnected_from_host_internal(&mut self, cx: &mut App) {
2632        if let ProjectClientState::Remote {
2633            sharing_has_stopped,
2634            ..
2635        } = &mut self.client_state
2636        {
2637            *sharing_has_stopped = true;
2638            self.collaborators.clear();
2639            self.worktree_store.update(cx, |store, cx| {
2640                store.disconnected_from_host(cx);
2641            });
2642            self.buffer_store.update(cx, |buffer_store, cx| {
2643                buffer_store.disconnected_from_host(cx)
2644            });
2645            self.lsp_store
2646                .update(cx, |lsp_store, _cx| lsp_store.disconnected_from_host());
2647        }
2648    }
2649
2650    #[inline]
2651    pub fn close(&mut self, cx: &mut Context<Self>) {
2652        cx.emit(Event::Closed);
2653    }
2654
2655    #[inline]
2656    pub fn is_disconnected(&self, cx: &App) -> bool {
2657        match &self.client_state {
2658            ProjectClientState::Remote {
2659                sharing_has_stopped,
2660                ..
2661            } => *sharing_has_stopped,
2662            ProjectClientState::Local if self.is_via_remote_server() => {
2663                self.remote_client_is_disconnected(cx)
2664            }
2665            _ => false,
2666        }
2667    }
2668
2669    #[inline]
2670    fn remote_client_is_disconnected(&self, cx: &App) -> bool {
2671        self.remote_client
2672            .as_ref()
2673            .map(|remote| remote.read(cx).is_disconnected())
2674            .unwrap_or(false)
2675    }
2676
2677    #[inline]
2678    pub fn capability(&self) -> Capability {
2679        match &self.client_state {
2680            ProjectClientState::Remote { capability, .. } => *capability,
2681            ProjectClientState::Shared { .. } | ProjectClientState::Local => Capability::ReadWrite,
2682        }
2683    }
2684
2685    #[inline]
2686    pub fn is_read_only(&self, cx: &App) -> bool {
2687        self.is_disconnected(cx) || !self.capability().editable()
2688    }
2689
2690    #[inline]
2691    pub fn is_local(&self) -> bool {
2692        match &self.client_state {
2693            ProjectClientState::Local | ProjectClientState::Shared { .. } => {
2694                self.remote_client.is_none()
2695            }
2696            ProjectClientState::Remote { .. } => false,
2697        }
2698    }
2699
2700    /// Whether this project is a remote server (not counting collab).
2701    #[inline]
2702    pub fn is_via_remote_server(&self) -> bool {
2703        match &self.client_state {
2704            ProjectClientState::Local | ProjectClientState::Shared { .. } => {
2705                self.remote_client.is_some()
2706            }
2707            ProjectClientState::Remote { .. } => false,
2708        }
2709    }
2710
2711    /// Whether this project is from collab (not counting remote servers).
2712    #[inline]
2713    pub fn is_via_collab(&self) -> bool {
2714        match &self.client_state {
2715            ProjectClientState::Local | ProjectClientState::Shared { .. } => false,
2716            ProjectClientState::Remote { .. } => true,
2717        }
2718    }
2719
2720    /// `!self.is_local()`
2721    #[inline]
2722    pub fn is_remote(&self) -> bool {
2723        debug_assert_eq!(
2724            !self.is_local(),
2725            self.is_via_collab() || self.is_via_remote_server()
2726        );
2727        !self.is_local()
2728    }
2729
2730    pub fn disable_worktree_scanner(&mut self, cx: &mut Context<Self>) {
2731        self.worktree_store.update(cx, |worktree_store, _cx| {
2732            worktree_store.disable_scanner();
2733        });
2734    }
2735
2736    #[inline]
2737    pub fn create_buffer(
2738        &mut self,
2739        searchable: bool,
2740        cx: &mut Context<Self>,
2741    ) -> Task<Result<Entity<Buffer>>> {
2742        self.buffer_store.update(cx, |buffer_store, cx| {
2743            buffer_store.create_buffer(searchable, cx)
2744        })
2745    }
2746
2747    #[inline]
2748    pub fn create_local_buffer(
2749        &mut self,
2750        text: &str,
2751        language: Option<Arc<Language>>,
2752        project_searchable: bool,
2753        cx: &mut Context<Self>,
2754    ) -> Entity<Buffer> {
2755        if self.is_remote() {
2756            panic!("called create_local_buffer on a remote project")
2757        }
2758        self.buffer_store.update(cx, |buffer_store, cx| {
2759            buffer_store.create_local_buffer(text, language, project_searchable, cx)
2760        })
2761    }
2762
2763    pub fn open_path(
2764        &mut self,
2765        path: ProjectPath,
2766        cx: &mut Context<Self>,
2767    ) -> Task<Result<(Option<ProjectEntryId>, Entity<Buffer>)>> {
2768        let task = self.open_buffer(path, cx);
2769        cx.spawn(async move |_project, cx| {
2770            let buffer = task.await?;
2771            let project_entry_id = buffer.read_with(cx, |buffer, _cx| {
2772                File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id())
2773            });
2774
2775            Ok((project_entry_id, buffer))
2776        })
2777    }
2778
2779    pub fn open_local_buffer(
2780        &mut self,
2781        abs_path: impl AsRef<Path>,
2782        cx: &mut Context<Self>,
2783    ) -> Task<Result<Entity<Buffer>>> {
2784        let worktree_task = self.find_or_create_worktree(abs_path.as_ref(), false, cx);
2785        cx.spawn(async move |this, cx| {
2786            let (worktree, relative_path) = worktree_task.await?;
2787            this.update(cx, |this, cx| {
2788                this.open_buffer((worktree.read(cx).id(), relative_path), cx)
2789            })?
2790            .await
2791        })
2792    }
2793
2794    #[cfg(any(test, feature = "test-support"))]
2795    pub fn open_local_buffer_with_lsp(
2796        &mut self,
2797        abs_path: impl AsRef<Path>,
2798        cx: &mut Context<Self>,
2799    ) -> Task<Result<(Entity<Buffer>, lsp_store::OpenLspBufferHandle)>> {
2800        if let Some((worktree, relative_path)) = self.find_worktree(abs_path.as_ref(), cx) {
2801            self.open_buffer_with_lsp((worktree.read(cx).id(), relative_path), cx)
2802        } else {
2803            Task::ready(Err(anyhow!("no such path")))
2804        }
2805    }
2806
2807    pub fn open_buffer(
2808        &mut self,
2809        path: impl Into<ProjectPath>,
2810        cx: &mut App,
2811    ) -> Task<Result<Entity<Buffer>>> {
2812        if self.is_disconnected(cx) {
2813            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
2814        }
2815
2816        self.buffer_store.update(cx, |buffer_store, cx| {
2817            buffer_store.open_buffer(path.into(), cx)
2818        })
2819    }
2820
2821    #[cfg(any(test, feature = "test-support"))]
2822    pub fn open_buffer_with_lsp(
2823        &mut self,
2824        path: impl Into<ProjectPath>,
2825        cx: &mut Context<Self>,
2826    ) -> Task<Result<(Entity<Buffer>, lsp_store::OpenLspBufferHandle)>> {
2827        let buffer = self.open_buffer(path, cx);
2828        cx.spawn(async move |this, cx| {
2829            let buffer = buffer.await?;
2830            let handle = this.update(cx, |project, cx| {
2831                project.register_buffer_with_language_servers(&buffer, cx)
2832            })?;
2833            Ok((buffer, handle))
2834        })
2835    }
2836
2837    pub fn register_buffer_with_language_servers(
2838        &self,
2839        buffer: &Entity<Buffer>,
2840        cx: &mut App,
2841    ) -> OpenLspBufferHandle {
2842        self.lsp_store.update(cx, |lsp_store, cx| {
2843            lsp_store.register_buffer_with_language_servers(buffer, HashSet::default(), false, cx)
2844        })
2845    }
2846
2847    pub fn open_unstaged_diff(
2848        &mut self,
2849        buffer: Entity<Buffer>,
2850        cx: &mut Context<Self>,
2851    ) -> Task<Result<Entity<BufferDiff>>> {
2852        if self.is_disconnected(cx) {
2853            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
2854        }
2855        self.git_store
2856            .update(cx, |git_store, cx| git_store.open_unstaged_diff(buffer, cx))
2857    }
2858
2859    pub fn open_uncommitted_diff(
2860        &mut self,
2861        buffer: Entity<Buffer>,
2862        cx: &mut Context<Self>,
2863    ) -> Task<Result<Entity<BufferDiff>>> {
2864        if self.is_disconnected(cx) {
2865            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
2866        }
2867        self.git_store.update(cx, |git_store, cx| {
2868            git_store.open_uncommitted_diff(buffer, cx)
2869        })
2870    }
2871
2872    pub fn open_buffer_by_id(
2873        &mut self,
2874        id: BufferId,
2875        cx: &mut Context<Self>,
2876    ) -> Task<Result<Entity<Buffer>>> {
2877        if let Some(buffer) = self.buffer_for_id(id, cx) {
2878            Task::ready(Ok(buffer))
2879        } else if self.is_local() || self.is_via_remote_server() {
2880            Task::ready(Err(anyhow!("buffer {id} does not exist")))
2881        } else if let Some(project_id) = self.remote_id() {
2882            let request = self.collab_client.request(proto::OpenBufferById {
2883                project_id,
2884                id: id.into(),
2885            });
2886            cx.spawn(async move |project, cx| {
2887                let buffer_id = BufferId::new(request.await?.buffer_id)?;
2888                project
2889                    .update(cx, |project, cx| {
2890                        project.buffer_store.update(cx, |buffer_store, cx| {
2891                            buffer_store.wait_for_remote_buffer(buffer_id, cx)
2892                        })
2893                    })?
2894                    .await
2895            })
2896        } else {
2897            Task::ready(Err(anyhow!("cannot open buffer while disconnected")))
2898        }
2899    }
2900
2901    pub fn save_buffers(
2902        &self,
2903        buffers: HashSet<Entity<Buffer>>,
2904        cx: &mut Context<Self>,
2905    ) -> Task<Result<()>> {
2906        cx.spawn(async move |this, cx| {
2907            let save_tasks = buffers.into_iter().filter_map(|buffer| {
2908                this.update(cx, |this, cx| this.save_buffer(buffer, cx))
2909                    .ok()
2910            });
2911            try_join_all(save_tasks).await?;
2912            Ok(())
2913        })
2914    }
2915
2916    pub fn save_buffer(&self, buffer: Entity<Buffer>, cx: &mut Context<Self>) -> Task<Result<()>> {
2917        self.buffer_store
2918            .update(cx, |buffer_store, cx| buffer_store.save_buffer(buffer, cx))
2919    }
2920
2921    pub fn save_buffer_as(
2922        &mut self,
2923        buffer: Entity<Buffer>,
2924        path: ProjectPath,
2925        cx: &mut Context<Self>,
2926    ) -> Task<Result<()>> {
2927        self.buffer_store.update(cx, |buffer_store, cx| {
2928            buffer_store.save_buffer_as(buffer.clone(), path, cx)
2929        })
2930    }
2931
2932    pub fn get_open_buffer(&self, path: &ProjectPath, cx: &App) -> Option<Entity<Buffer>> {
2933        self.buffer_store.read(cx).get_by_path(path)
2934    }
2935
2936    fn register_buffer(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
2937        {
2938            let mut remotely_created_models = self.remotely_created_models.lock();
2939            if remotely_created_models.retain_count > 0 {
2940                remotely_created_models.buffers.push(buffer.clone())
2941            }
2942        }
2943
2944        self.request_buffer_diff_recalculation(buffer, cx);
2945
2946        cx.subscribe(buffer, |this, buffer, event, cx| {
2947            this.on_buffer_event(buffer, event, cx);
2948        })
2949        .detach();
2950
2951        Ok(())
2952    }
2953
2954    pub fn open_image(
2955        &mut self,
2956        path: impl Into<ProjectPath>,
2957        cx: &mut Context<Self>,
2958    ) -> Task<Result<Entity<ImageItem>>> {
2959        if self.is_disconnected(cx) {
2960            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
2961        }
2962
2963        let open_image_task = self.image_store.update(cx, |image_store, cx| {
2964            image_store.open_image(path.into(), cx)
2965        });
2966
2967        let weak_project = cx.entity().downgrade();
2968        cx.spawn(async move |_, cx| {
2969            let image_item = open_image_task.await?;
2970
2971            // Check if metadata already exists (e.g., for remote images)
2972            let needs_metadata =
2973                cx.read_entity(&image_item, |item, _| item.image_metadata.is_none());
2974
2975            if needs_metadata {
2976                let project = weak_project.upgrade().context("Project dropped")?;
2977                let metadata =
2978                    ImageItem::load_image_metadata(image_item.clone(), project, cx).await?;
2979                image_item.update(cx, |image_item, cx| {
2980                    image_item.image_metadata = Some(metadata);
2981                    cx.emit(ImageItemEvent::MetadataUpdated);
2982                });
2983            }
2984
2985            Ok(image_item)
2986        })
2987    }
2988
2989    async fn send_buffer_ordered_messages(
2990        project: WeakEntity<Self>,
2991        rx: UnboundedReceiver<BufferOrderedMessage>,
2992        cx: &mut AsyncApp,
2993    ) -> Result<()> {
2994        const MAX_BATCH_SIZE: usize = 128;
2995
2996        let mut operations_by_buffer_id = HashMap::default();
2997        async fn flush_operations(
2998            this: &WeakEntity<Project>,
2999            operations_by_buffer_id: &mut HashMap<BufferId, Vec<proto::Operation>>,
3000            needs_resync_with_host: &mut bool,
3001            is_local: bool,
3002            cx: &mut AsyncApp,
3003        ) -> Result<()> {
3004            for (buffer_id, operations) in operations_by_buffer_id.drain() {
3005                let request = this.read_with(cx, |this, _| {
3006                    let project_id = this.remote_id()?;
3007                    Some(this.collab_client.request(proto::UpdateBuffer {
3008                        buffer_id: buffer_id.into(),
3009                        project_id,
3010                        operations,
3011                    }))
3012                })?;
3013                if let Some(request) = request
3014                    && request.await.is_err()
3015                    && !is_local
3016                {
3017                    *needs_resync_with_host = true;
3018                    break;
3019                }
3020            }
3021            Ok(())
3022        }
3023
3024        let mut needs_resync_with_host = false;
3025        let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
3026
3027        while let Some(changes) = changes.next().await {
3028            let is_local = project.read_with(cx, |this, _| this.is_local())?;
3029
3030            for change in changes {
3031                match change {
3032                    BufferOrderedMessage::Operation {
3033                        buffer_id,
3034                        operation,
3035                    } => {
3036                        if needs_resync_with_host {
3037                            continue;
3038                        }
3039
3040                        operations_by_buffer_id
3041                            .entry(buffer_id)
3042                            .or_insert(Vec::new())
3043                            .push(operation);
3044                    }
3045
3046                    BufferOrderedMessage::Resync => {
3047                        operations_by_buffer_id.clear();
3048                        if project
3049                            .update(cx, |this, cx| this.synchronize_remote_buffers(cx))?
3050                            .await
3051                            .is_ok()
3052                        {
3053                            needs_resync_with_host = false;
3054                        }
3055                    }
3056
3057                    BufferOrderedMessage::LanguageServerUpdate {
3058                        language_server_id,
3059                        message,
3060                        name,
3061                    } => {
3062                        flush_operations(
3063                            &project,
3064                            &mut operations_by_buffer_id,
3065                            &mut needs_resync_with_host,
3066                            is_local,
3067                            cx,
3068                        )
3069                        .await?;
3070
3071                        project.read_with(cx, |project, _| {
3072                            if let Some(project_id) = project.remote_id() {
3073                                project
3074                                    .collab_client
3075                                    .send(proto::UpdateLanguageServer {
3076                                        project_id,
3077                                        server_name: name.map(|name| String::from(name.0)),
3078                                        language_server_id: language_server_id.to_proto(),
3079                                        variant: Some(message),
3080                                    })
3081                                    .log_err();
3082                            }
3083                        })?;
3084                    }
3085                }
3086            }
3087
3088            flush_operations(
3089                &project,
3090                &mut operations_by_buffer_id,
3091                &mut needs_resync_with_host,
3092                is_local,
3093                cx,
3094            )
3095            .await?;
3096        }
3097
3098        Ok(())
3099    }
3100
3101    fn on_buffer_store_event(
3102        &mut self,
3103        _: Entity<BufferStore>,
3104        event: &BufferStoreEvent,
3105        cx: &mut Context<Self>,
3106    ) {
3107        match event {
3108            BufferStoreEvent::BufferAdded(buffer) => {
3109                self.register_buffer(buffer, cx).log_err();
3110            }
3111            BufferStoreEvent::BufferDropped(buffer_id) => {
3112                if let Some(ref remote_client) = self.remote_client {
3113                    remote_client
3114                        .read(cx)
3115                        .proto_client()
3116                        .send(proto::CloseBuffer {
3117                            project_id: 0,
3118                            buffer_id: buffer_id.to_proto(),
3119                        })
3120                        .log_err();
3121                }
3122            }
3123            _ => {}
3124        }
3125    }
3126
3127    fn on_image_store_event(
3128        &mut self,
3129        _: Entity<ImageStore>,
3130        event: &ImageStoreEvent,
3131        cx: &mut Context<Self>,
3132    ) {
3133        match event {
3134            ImageStoreEvent::ImageAdded(image) => {
3135                cx.subscribe(image, |this, image, event, cx| {
3136                    this.on_image_event(image, event, cx);
3137                })
3138                .detach();
3139            }
3140        }
3141    }
3142
3143    fn on_dap_store_event(
3144        &mut self,
3145        _: Entity<DapStore>,
3146        event: &DapStoreEvent,
3147        cx: &mut Context<Self>,
3148    ) {
3149        if let DapStoreEvent::Notification(message) = event {
3150            cx.emit(Event::Toast {
3151                notification_id: "dap".into(),
3152                message: message.clone(),
3153            });
3154        }
3155    }
3156
3157    fn on_lsp_store_event(
3158        &mut self,
3159        _: Entity<LspStore>,
3160        event: &LspStoreEvent,
3161        cx: &mut Context<Self>,
3162    ) {
3163        match event {
3164            LspStoreEvent::DiagnosticsUpdated { server_id, paths } => {
3165                cx.emit(Event::DiagnosticsUpdated {
3166                    paths: paths.clone(),
3167                    language_server_id: *server_id,
3168                })
3169            }
3170            LspStoreEvent::LanguageServerAdded(server_id, name, worktree_id) => cx.emit(
3171                Event::LanguageServerAdded(*server_id, name.clone(), *worktree_id),
3172            ),
3173            LspStoreEvent::LanguageServerRemoved(server_id) => {
3174                cx.emit(Event::LanguageServerRemoved(*server_id))
3175            }
3176            LspStoreEvent::LanguageServerLog(server_id, log_type, string) => cx.emit(
3177                Event::LanguageServerLog(*server_id, log_type.clone(), string.clone()),
3178            ),
3179            LspStoreEvent::LanguageDetected {
3180                buffer,
3181                new_language,
3182            } => {
3183                let Some(_) = new_language else {
3184                    cx.emit(Event::LanguageNotFound(buffer.clone()));
3185                    return;
3186                };
3187            }
3188            LspStoreEvent::RefreshInlayHints {
3189                server_id,
3190                request_id,
3191            } => cx.emit(Event::RefreshInlayHints {
3192                server_id: *server_id,
3193                request_id: *request_id,
3194            }),
3195            LspStoreEvent::RefreshCodeLens => cx.emit(Event::RefreshCodeLens),
3196            LspStoreEvent::LanguageServerPrompt(prompt) => {
3197                cx.emit(Event::LanguageServerPrompt(prompt.clone()))
3198            }
3199            LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id } => {
3200                cx.emit(Event::DiskBasedDiagnosticsStarted {
3201                    language_server_id: *language_server_id,
3202                });
3203            }
3204            LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id } => {
3205                cx.emit(Event::DiskBasedDiagnosticsFinished {
3206                    language_server_id: *language_server_id,
3207                });
3208            }
3209            LspStoreEvent::LanguageServerUpdate {
3210                language_server_id,
3211                name,
3212                message,
3213            } => {
3214                if self.is_local() {
3215                    self.enqueue_buffer_ordered_message(
3216                        BufferOrderedMessage::LanguageServerUpdate {
3217                            language_server_id: *language_server_id,
3218                            message: message.clone(),
3219                            name: name.clone(),
3220                        },
3221                    )
3222                    .ok();
3223                }
3224
3225                match message {
3226                    proto::update_language_server::Variant::MetadataUpdated(update) => {
3227                        self.lsp_store.update(cx, |lsp_store, _| {
3228                            if let Some(capabilities) = update
3229                                .capabilities
3230                                .as_ref()
3231                                .and_then(|capabilities| serde_json::from_str(capabilities).ok())
3232                            {
3233                                lsp_store
3234                                    .lsp_server_capabilities
3235                                    .insert(*language_server_id, capabilities);
3236                            }
3237
3238                            if let Some(language_server_status) = lsp_store
3239                                .language_server_statuses
3240                                .get_mut(language_server_id)
3241                            {
3242                                if let Some(binary) = &update.binary {
3243                                    language_server_status.binary = Some(LanguageServerBinary {
3244                                        path: PathBuf::from(&binary.path),
3245                                        arguments: binary
3246                                            .arguments
3247                                            .iter()
3248                                            .map(OsString::from)
3249                                            .collect(),
3250                                        env: None,
3251                                    });
3252                                }
3253
3254                                language_server_status.configuration = update
3255                                    .configuration
3256                                    .as_ref()
3257                                    .and_then(|config_str| serde_json::from_str(config_str).ok());
3258
3259                                language_server_status.workspace_folders = update
3260                                    .workspace_folders
3261                                    .iter()
3262                                    .filter_map(|uri_str| lsp::Uri::from_str(uri_str).ok())
3263                                    .collect();
3264                            }
3265                        });
3266                    }
3267                    proto::update_language_server::Variant::RegisteredForBuffer(update) => {
3268                        if let Some(buffer_id) = BufferId::new(update.buffer_id).ok() {
3269                            cx.emit(Event::LanguageServerBufferRegistered {
3270                                buffer_id,
3271                                server_id: *language_server_id,
3272                                buffer_abs_path: PathBuf::from(&update.buffer_abs_path),
3273                                name: name.clone(),
3274                            });
3275                        }
3276                    }
3277                    _ => (),
3278                }
3279            }
3280            LspStoreEvent::Notification(message) => cx.emit(Event::Toast {
3281                notification_id: "lsp".into(),
3282                message: message.clone(),
3283            }),
3284            LspStoreEvent::SnippetEdit {
3285                buffer_id,
3286                edits,
3287                most_recent_edit,
3288            } => {
3289                if most_recent_edit.replica_id == self.replica_id() {
3290                    cx.emit(Event::SnippetEdit(*buffer_id, edits.clone()))
3291                }
3292            }
3293            LspStoreEvent::WorkspaceEditApplied(transaction) => {
3294                cx.emit(Event::WorkspaceEditApplied(transaction.clone()))
3295            }
3296        }
3297    }
3298
3299    fn on_remote_client_event(
3300        &mut self,
3301        _: Entity<RemoteClient>,
3302        event: &remote::RemoteClientEvent,
3303        cx: &mut Context<Self>,
3304    ) {
3305        match event {
3306            remote::RemoteClientEvent::Disconnected => {
3307                self.worktree_store.update(cx, |store, cx| {
3308                    store.disconnected_from_host(cx);
3309                });
3310                self.buffer_store.update(cx, |buffer_store, cx| {
3311                    buffer_store.disconnected_from_host(cx)
3312                });
3313                self.lsp_store.update(cx, |lsp_store, _cx| {
3314                    lsp_store.disconnected_from_ssh_remote()
3315                });
3316                cx.emit(Event::DisconnectedFromRemote);
3317            }
3318        }
3319    }
3320
3321    fn on_settings_observer_event(
3322        &mut self,
3323        _: Entity<SettingsObserver>,
3324        event: &SettingsObserverEvent,
3325        cx: &mut Context<Self>,
3326    ) {
3327        match event {
3328            SettingsObserverEvent::LocalSettingsUpdated(result) => match result {
3329                Err(InvalidSettingsError::LocalSettings { message, path }) => {
3330                    let message = format!("Failed to set local settings in {path:?}:\n{message}");
3331                    cx.emit(Event::Toast {
3332                        notification_id: format!("local-settings-{path:?}").into(),
3333                        message,
3334                    });
3335                }
3336                Ok(path) => cx.emit(Event::HideToast {
3337                    notification_id: format!("local-settings-{path:?}").into(),
3338                }),
3339                Err(_) => {}
3340            },
3341            SettingsObserverEvent::LocalTasksUpdated(result) => match result {
3342                Err(InvalidSettingsError::Tasks { message, path }) => {
3343                    let message = format!("Failed to set local tasks in {path:?}:\n{message}");
3344                    cx.emit(Event::Toast {
3345                        notification_id: format!("local-tasks-{path:?}").into(),
3346                        message,
3347                    });
3348                }
3349                Ok(path) => cx.emit(Event::HideToast {
3350                    notification_id: format!("local-tasks-{path:?}").into(),
3351                }),
3352                Err(_) => {}
3353            },
3354            SettingsObserverEvent::LocalDebugScenariosUpdated(result) => match result {
3355                Err(InvalidSettingsError::Debug { message, path }) => {
3356                    let message =
3357                        format!("Failed to set local debug scenarios in {path:?}:\n{message}");
3358                    cx.emit(Event::Toast {
3359                        notification_id: format!("local-debug-scenarios-{path:?}").into(),
3360                        message,
3361                    });
3362                }
3363                Ok(path) => cx.emit(Event::HideToast {
3364                    notification_id: format!("local-debug-scenarios-{path:?}").into(),
3365                }),
3366                Err(_) => {}
3367            },
3368        }
3369    }
3370
3371    fn on_worktree_store_event(
3372        &mut self,
3373        _: Entity<WorktreeStore>,
3374        event: &WorktreeStoreEvent,
3375        cx: &mut Context<Self>,
3376    ) {
3377        match event {
3378            WorktreeStoreEvent::WorktreeAdded(worktree) => {
3379                self.on_worktree_added(worktree, cx);
3380                cx.emit(Event::WorktreeAdded(worktree.read(cx).id()));
3381            }
3382            WorktreeStoreEvent::WorktreeRemoved(_, id) => {
3383                cx.emit(Event::WorktreeRemoved(*id));
3384            }
3385            WorktreeStoreEvent::WorktreeReleased(_, id) => {
3386                self.on_worktree_released(*id, cx);
3387            }
3388            WorktreeStoreEvent::WorktreeOrderChanged => cx.emit(Event::WorktreeOrderChanged),
3389            WorktreeStoreEvent::WorktreeUpdateSent(_) => {}
3390            WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
3391                self.client()
3392                    .telemetry()
3393                    .report_discovered_project_type_events(*worktree_id, changes);
3394                cx.emit(Event::WorktreeUpdatedEntries(*worktree_id, changes.clone()))
3395            }
3396            WorktreeStoreEvent::WorktreeDeletedEntry(worktree_id, id) => {
3397                cx.emit(Event::DeletedEntry(*worktree_id, *id))
3398            }
3399            // Listen to the GitStore instead.
3400            WorktreeStoreEvent::WorktreeUpdatedGitRepositories(_, _) => {}
3401        }
3402    }
3403
3404    fn on_worktree_added(&mut self, worktree: &Entity<Worktree>, _: &mut Context<Self>) {
3405        let mut remotely_created_models = self.remotely_created_models.lock();
3406        if remotely_created_models.retain_count > 0 {
3407            remotely_created_models.worktrees.push(worktree.clone())
3408        }
3409    }
3410
3411    fn on_worktree_released(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
3412        if let Some(remote) = &self.remote_client {
3413            remote
3414                .read(cx)
3415                .proto_client()
3416                .send(proto::RemoveWorktree {
3417                    worktree_id: id_to_remove.to_proto(),
3418                })
3419                .log_err();
3420        }
3421    }
3422
3423    fn on_buffer_event(
3424        &mut self,
3425        buffer: Entity<Buffer>,
3426        event: &BufferEvent,
3427        cx: &mut Context<Self>,
3428    ) -> Option<()> {
3429        if matches!(event, BufferEvent::Edited | BufferEvent::Reloaded) {
3430            self.request_buffer_diff_recalculation(&buffer, cx);
3431        }
3432
3433        if matches!(event, BufferEvent::Edited) {
3434            cx.emit(Event::BufferEdited);
3435        }
3436
3437        let buffer_id = buffer.read(cx).remote_id();
3438        match event {
3439            BufferEvent::ReloadNeeded => {
3440                if !self.is_via_collab() {
3441                    self.reload_buffers([buffer.clone()].into_iter().collect(), true, cx)
3442                        .detach_and_log_err(cx);
3443                }
3444            }
3445            BufferEvent::Operation {
3446                operation,
3447                is_local: true,
3448            } => {
3449                let operation = language::proto::serialize_operation(operation);
3450
3451                if let Some(remote) = &self.remote_client {
3452                    remote
3453                        .read(cx)
3454                        .proto_client()
3455                        .send(proto::UpdateBuffer {
3456                            project_id: 0,
3457                            buffer_id: buffer_id.to_proto(),
3458                            operations: vec![operation.clone()],
3459                        })
3460                        .ok();
3461                }
3462
3463                self.enqueue_buffer_ordered_message(BufferOrderedMessage::Operation {
3464                    buffer_id,
3465                    operation,
3466                })
3467                .ok();
3468            }
3469
3470            _ => {}
3471        }
3472
3473        None
3474    }
3475
3476    fn on_image_event(
3477        &mut self,
3478        image: Entity<ImageItem>,
3479        event: &ImageItemEvent,
3480        cx: &mut Context<Self>,
3481    ) -> Option<()> {
3482        // TODO: handle image events from remote
3483        if let ImageItemEvent::ReloadNeeded = event
3484            && !self.is_via_collab()
3485        {
3486            self.reload_images([image].into_iter().collect(), cx)
3487                .detach_and_log_err(cx);
3488        }
3489
3490        None
3491    }
3492
3493    fn request_buffer_diff_recalculation(
3494        &mut self,
3495        buffer: &Entity<Buffer>,
3496        cx: &mut Context<Self>,
3497    ) {
3498        self.buffers_needing_diff.insert(buffer.downgrade());
3499        let first_insertion = self.buffers_needing_diff.len() == 1;
3500        let settings = ProjectSettings::get_global(cx);
3501        let delay = settings.git.gutter_debounce;
3502
3503        if delay == 0 {
3504            if first_insertion {
3505                let this = cx.weak_entity();
3506                cx.defer(move |cx| {
3507                    if let Some(this) = this.upgrade() {
3508                        this.update(cx, |this, cx| {
3509                            this.recalculate_buffer_diffs(cx).detach();
3510                        });
3511                    }
3512                });
3513            }
3514            return;
3515        }
3516
3517        const MIN_DELAY: u64 = 50;
3518        let delay = delay.max(MIN_DELAY);
3519        let duration = Duration::from_millis(delay);
3520
3521        self.git_diff_debouncer
3522            .fire_new(duration, cx, move |this, cx| {
3523                this.recalculate_buffer_diffs(cx)
3524            });
3525    }
3526
3527    fn recalculate_buffer_diffs(&mut self, cx: &mut Context<Self>) -> Task<()> {
3528        cx.spawn(async move |this, cx| {
3529            loop {
3530                let task = this
3531                    .update(cx, |this, cx| {
3532                        let buffers = this
3533                            .buffers_needing_diff
3534                            .drain()
3535                            .filter_map(|buffer| buffer.upgrade())
3536                            .collect::<Vec<_>>();
3537                        if buffers.is_empty() {
3538                            None
3539                        } else {
3540                            Some(this.git_store.update(cx, |git_store, cx| {
3541                                git_store.recalculate_buffer_diffs(buffers, cx)
3542                            }))
3543                        }
3544                    })
3545                    .ok()
3546                    .flatten();
3547
3548                if let Some(task) = task {
3549                    task.await;
3550                } else {
3551                    break;
3552                }
3553            }
3554        })
3555    }
3556
3557    pub fn set_language_for_buffer(
3558        &mut self,
3559        buffer: &Entity<Buffer>,
3560        new_language: Arc<Language>,
3561        cx: &mut Context<Self>,
3562    ) {
3563        self.lsp_store.update(cx, |lsp_store, cx| {
3564            lsp_store.set_language_for_buffer(buffer, new_language, cx)
3565        })
3566    }
3567
3568    pub fn restart_language_servers_for_buffers(
3569        &mut self,
3570        buffers: Vec<Entity<Buffer>>,
3571        only_restart_servers: HashSet<LanguageServerSelector>,
3572        cx: &mut Context<Self>,
3573    ) {
3574        self.lsp_store.update(cx, |lsp_store, cx| {
3575            lsp_store.restart_language_servers_for_buffers(buffers, only_restart_servers, cx)
3576        })
3577    }
3578
3579    pub fn stop_language_servers_for_buffers(
3580        &mut self,
3581        buffers: Vec<Entity<Buffer>>,
3582        also_restart_servers: HashSet<LanguageServerSelector>,
3583        cx: &mut Context<Self>,
3584    ) {
3585        self.lsp_store
3586            .update(cx, |lsp_store, cx| {
3587                lsp_store.stop_language_servers_for_buffers(buffers, also_restart_servers, cx)
3588            })
3589            .detach_and_log_err(cx);
3590    }
3591
3592    pub fn cancel_language_server_work_for_buffers(
3593        &mut self,
3594        buffers: impl IntoIterator<Item = Entity<Buffer>>,
3595        cx: &mut Context<Self>,
3596    ) {
3597        self.lsp_store.update(cx, |lsp_store, cx| {
3598            lsp_store.cancel_language_server_work_for_buffers(buffers, cx)
3599        })
3600    }
3601
3602    pub fn cancel_language_server_work(
3603        &mut self,
3604        server_id: LanguageServerId,
3605        token_to_cancel: Option<ProgressToken>,
3606        cx: &mut Context<Self>,
3607    ) {
3608        self.lsp_store.update(cx, |lsp_store, cx| {
3609            lsp_store.cancel_language_server_work(server_id, token_to_cancel, cx)
3610        })
3611    }
3612
3613    fn enqueue_buffer_ordered_message(&mut self, message: BufferOrderedMessage) -> Result<()> {
3614        self.buffer_ordered_messages_tx
3615            .unbounded_send(message)
3616            .map_err(|e| anyhow!(e))
3617    }
3618
3619    pub fn available_toolchains(
3620        &self,
3621        path: ProjectPath,
3622        language_name: LanguageName,
3623        cx: &App,
3624    ) -> Task<Option<Toolchains>> {
3625        if let Some(toolchain_store) = self.toolchain_store.as_ref().map(Entity::downgrade) {
3626            cx.spawn(async move |cx| {
3627                toolchain_store
3628                    .update(cx, |this, cx| this.list_toolchains(path, language_name, cx))
3629                    .ok()?
3630                    .await
3631            })
3632        } else {
3633            Task::ready(None)
3634        }
3635    }
3636
3637    pub async fn toolchain_metadata(
3638        languages: Arc<LanguageRegistry>,
3639        language_name: LanguageName,
3640    ) -> Option<ToolchainMetadata> {
3641        languages
3642            .language_for_name(language_name.as_ref())
3643            .await
3644            .ok()?
3645            .toolchain_lister()
3646            .map(|lister| lister.meta())
3647    }
3648
3649    pub fn add_toolchain(
3650        &self,
3651        toolchain: Toolchain,
3652        scope: ToolchainScope,
3653        cx: &mut Context<Self>,
3654    ) {
3655        maybe!({
3656            self.toolchain_store.as_ref()?.update(cx, |this, cx| {
3657                this.add_toolchain(toolchain, scope, cx);
3658            });
3659            Some(())
3660        });
3661    }
3662
3663    pub fn remove_toolchain(
3664        &self,
3665        toolchain: Toolchain,
3666        scope: ToolchainScope,
3667        cx: &mut Context<Self>,
3668    ) {
3669        maybe!({
3670            self.toolchain_store.as_ref()?.update(cx, |this, cx| {
3671                this.remove_toolchain(toolchain, scope, cx);
3672            });
3673            Some(())
3674        });
3675    }
3676
3677    pub fn user_toolchains(
3678        &self,
3679        cx: &App,
3680    ) -> Option<BTreeMap<ToolchainScope, IndexSet<Toolchain>>> {
3681        Some(self.toolchain_store.as_ref()?.read(cx).user_toolchains())
3682    }
3683
3684    pub fn resolve_toolchain(
3685        &self,
3686        path: PathBuf,
3687        language_name: LanguageName,
3688        cx: &App,
3689    ) -> Task<Result<Toolchain>> {
3690        if let Some(toolchain_store) = self.toolchain_store.as_ref().map(Entity::downgrade) {
3691            cx.spawn(async move |cx| {
3692                toolchain_store
3693                    .update(cx, |this, cx| {
3694                        this.resolve_toolchain(path, language_name, cx)
3695                    })?
3696                    .await
3697            })
3698        } else {
3699            Task::ready(Err(anyhow!("This project does not support toolchains")))
3700        }
3701    }
3702
3703    pub fn toolchain_store(&self) -> Option<Entity<ToolchainStore>> {
3704        self.toolchain_store.clone()
3705    }
3706    pub fn activate_toolchain(
3707        &self,
3708        path: ProjectPath,
3709        toolchain: Toolchain,
3710        cx: &mut App,
3711    ) -> Task<Option<()>> {
3712        let Some(toolchain_store) = self.toolchain_store.clone() else {
3713            return Task::ready(None);
3714        };
3715        toolchain_store.update(cx, |this, cx| this.activate_toolchain(path, toolchain, cx))
3716    }
3717    pub fn active_toolchain(
3718        &self,
3719        path: ProjectPath,
3720        language_name: LanguageName,
3721        cx: &App,
3722    ) -> Task<Option<Toolchain>> {
3723        let Some(toolchain_store) = self.toolchain_store.clone() else {
3724            return Task::ready(None);
3725        };
3726        toolchain_store
3727            .read(cx)
3728            .active_toolchain(path, language_name, cx)
3729    }
3730    pub fn language_server_statuses<'a>(
3731        &'a self,
3732        cx: &'a App,
3733    ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &'a LanguageServerStatus)> {
3734        self.lsp_store.read(cx).language_server_statuses()
3735    }
3736
3737    pub fn last_formatting_failure<'a>(&self, cx: &'a App) -> Option<&'a str> {
3738        self.lsp_store.read(cx).last_formatting_failure()
3739    }
3740
3741    pub fn reset_last_formatting_failure(&self, cx: &mut App) {
3742        self.lsp_store
3743            .update(cx, |store, _| store.reset_last_formatting_failure());
3744    }
3745
3746    pub fn reload_buffers(
3747        &self,
3748        buffers: HashSet<Entity<Buffer>>,
3749        push_to_history: bool,
3750        cx: &mut Context<Self>,
3751    ) -> Task<Result<ProjectTransaction>> {
3752        self.buffer_store.update(cx, |buffer_store, cx| {
3753            buffer_store.reload_buffers(buffers, push_to_history, cx)
3754        })
3755    }
3756
3757    pub fn reload_images(
3758        &self,
3759        images: HashSet<Entity<ImageItem>>,
3760        cx: &mut Context<Self>,
3761    ) -> Task<Result<()>> {
3762        self.image_store
3763            .update(cx, |image_store, cx| image_store.reload_images(images, cx))
3764    }
3765
3766    pub fn format(
3767        &mut self,
3768        buffers: HashSet<Entity<Buffer>>,
3769        target: LspFormatTarget,
3770        push_to_history: bool,
3771        trigger: lsp_store::FormatTrigger,
3772        cx: &mut Context<Project>,
3773    ) -> Task<anyhow::Result<ProjectTransaction>> {
3774        self.lsp_store.update(cx, |lsp_store, cx| {
3775            lsp_store.format(buffers, target, push_to_history, trigger, cx)
3776        })
3777    }
3778
3779    pub fn definitions<T: ToPointUtf16>(
3780        &mut self,
3781        buffer: &Entity<Buffer>,
3782        position: T,
3783        cx: &mut Context<Self>,
3784    ) -> Task<Result<Option<Vec<LocationLink>>>> {
3785        let position = position.to_point_utf16(buffer.read(cx));
3786        let guard = self.retain_remotely_created_models(cx);
3787        let task = self.lsp_store.update(cx, |lsp_store, cx| {
3788            lsp_store.definitions(buffer, position, cx)
3789        });
3790        cx.background_spawn(async move {
3791            let result = task.await;
3792            drop(guard);
3793            result
3794        })
3795    }
3796
3797    pub fn declarations<T: ToPointUtf16>(
3798        &mut self,
3799        buffer: &Entity<Buffer>,
3800        position: T,
3801        cx: &mut Context<Self>,
3802    ) -> Task<Result<Option<Vec<LocationLink>>>> {
3803        let position = position.to_point_utf16(buffer.read(cx));
3804        let guard = self.retain_remotely_created_models(cx);
3805        let task = self.lsp_store.update(cx, |lsp_store, cx| {
3806            lsp_store.declarations(buffer, position, cx)
3807        });
3808        cx.background_spawn(async move {
3809            let result = task.await;
3810            drop(guard);
3811            result
3812        })
3813    }
3814
3815    pub fn type_definitions<T: ToPointUtf16>(
3816        &mut self,
3817        buffer: &Entity<Buffer>,
3818        position: T,
3819        cx: &mut Context<Self>,
3820    ) -> Task<Result<Option<Vec<LocationLink>>>> {
3821        let position = position.to_point_utf16(buffer.read(cx));
3822        let guard = self.retain_remotely_created_models(cx);
3823        let task = self.lsp_store.update(cx, |lsp_store, cx| {
3824            lsp_store.type_definitions(buffer, position, cx)
3825        });
3826        cx.background_spawn(async move {
3827            let result = task.await;
3828            drop(guard);
3829            result
3830        })
3831    }
3832
3833    pub fn implementations<T: ToPointUtf16>(
3834        &mut self,
3835        buffer: &Entity<Buffer>,
3836        position: T,
3837        cx: &mut Context<Self>,
3838    ) -> Task<Result<Option<Vec<LocationLink>>>> {
3839        let position = position.to_point_utf16(buffer.read(cx));
3840        let guard = self.retain_remotely_created_models(cx);
3841        let task = self.lsp_store.update(cx, |lsp_store, cx| {
3842            lsp_store.implementations(buffer, position, cx)
3843        });
3844        cx.background_spawn(async move {
3845            let result = task.await;
3846            drop(guard);
3847            result
3848        })
3849    }
3850
3851    pub fn references<T: ToPointUtf16>(
3852        &mut self,
3853        buffer: &Entity<Buffer>,
3854        position: T,
3855        cx: &mut Context<Self>,
3856    ) -> Task<Result<Option<Vec<Location>>>> {
3857        let position = position.to_point_utf16(buffer.read(cx));
3858        let guard = self.retain_remotely_created_models(cx);
3859        let task = self.lsp_store.update(cx, |lsp_store, cx| {
3860            lsp_store.references(buffer, position, cx)
3861        });
3862        cx.background_spawn(async move {
3863            let result = task.await;
3864            drop(guard);
3865            result
3866        })
3867    }
3868
3869    pub fn document_highlights<T: ToPointUtf16>(
3870        &mut self,
3871        buffer: &Entity<Buffer>,
3872        position: T,
3873        cx: &mut Context<Self>,
3874    ) -> Task<Result<Vec<DocumentHighlight>>> {
3875        let position = position.to_point_utf16(buffer.read(cx));
3876        self.request_lsp(
3877            buffer.clone(),
3878            LanguageServerToQuery::FirstCapable,
3879            GetDocumentHighlights { position },
3880            cx,
3881        )
3882    }
3883
3884    pub fn document_symbols(
3885        &mut self,
3886        buffer: &Entity<Buffer>,
3887        cx: &mut Context<Self>,
3888    ) -> Task<Result<Vec<DocumentSymbol>>> {
3889        self.request_lsp(
3890            buffer.clone(),
3891            LanguageServerToQuery::FirstCapable,
3892            GetDocumentSymbols,
3893            cx,
3894        )
3895    }
3896
3897    pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
3898        self.lsp_store
3899            .update(cx, |lsp_store, cx| lsp_store.symbols(query, cx))
3900    }
3901
3902    pub fn open_buffer_for_symbol(
3903        &mut self,
3904        symbol: &Symbol,
3905        cx: &mut Context<Self>,
3906    ) -> Task<Result<Entity<Buffer>>> {
3907        self.lsp_store.update(cx, |lsp_store, cx| {
3908            lsp_store.open_buffer_for_symbol(symbol, cx)
3909        })
3910    }
3911
3912    pub fn open_server_settings(&mut self, cx: &mut Context<Self>) -> Task<Result<Entity<Buffer>>> {
3913        let guard = self.retain_remotely_created_models(cx);
3914        let Some(remote) = self.remote_client.as_ref() else {
3915            return Task::ready(Err(anyhow!("not an ssh project")));
3916        };
3917
3918        let proto_client = remote.read(cx).proto_client();
3919
3920        cx.spawn(async move |project, cx| {
3921            let buffer = proto_client
3922                .request(proto::OpenServerSettings {
3923                    project_id: REMOTE_SERVER_PROJECT_ID,
3924                })
3925                .await?;
3926
3927            let buffer = project
3928                .update(cx, |project, cx| {
3929                    project.buffer_store.update(cx, |buffer_store, cx| {
3930                        anyhow::Ok(
3931                            buffer_store
3932                                .wait_for_remote_buffer(BufferId::new(buffer.buffer_id)?, cx),
3933                        )
3934                    })
3935                })??
3936                .await;
3937
3938            drop(guard);
3939            buffer
3940        })
3941    }
3942
3943    pub fn open_local_buffer_via_lsp(
3944        &mut self,
3945        abs_path: lsp::Uri,
3946        language_server_id: LanguageServerId,
3947        cx: &mut Context<Self>,
3948    ) -> Task<Result<Entity<Buffer>>> {
3949        self.lsp_store.update(cx, |lsp_store, cx| {
3950            lsp_store.open_local_buffer_via_lsp(abs_path, language_server_id, cx)
3951        })
3952    }
3953
3954    pub fn hover<T: ToPointUtf16>(
3955        &self,
3956        buffer: &Entity<Buffer>,
3957        position: T,
3958        cx: &mut Context<Self>,
3959    ) -> Task<Option<Vec<Hover>>> {
3960        let position = position.to_point_utf16(buffer.read(cx));
3961        self.lsp_store
3962            .update(cx, |lsp_store, cx| lsp_store.hover(buffer, position, cx))
3963    }
3964
3965    pub fn linked_edits(
3966        &self,
3967        buffer: &Entity<Buffer>,
3968        position: Anchor,
3969        cx: &mut Context<Self>,
3970    ) -> Task<Result<Vec<Range<Anchor>>>> {
3971        self.lsp_store.update(cx, |lsp_store, cx| {
3972            lsp_store.linked_edits(buffer, position, cx)
3973        })
3974    }
3975
3976    pub fn completions<T: ToOffset + ToPointUtf16>(
3977        &self,
3978        buffer: &Entity<Buffer>,
3979        position: T,
3980        context: CompletionContext,
3981        cx: &mut Context<Self>,
3982    ) -> Task<Result<Vec<CompletionResponse>>> {
3983        let position = position.to_point_utf16(buffer.read(cx));
3984        self.lsp_store.update(cx, |lsp_store, cx| {
3985            lsp_store.completions(buffer, position, context, cx)
3986        })
3987    }
3988
3989    pub fn code_actions<T: Clone + ToOffset>(
3990        &mut self,
3991        buffer_handle: &Entity<Buffer>,
3992        range: Range<T>,
3993        kinds: Option<Vec<CodeActionKind>>,
3994        cx: &mut Context<Self>,
3995    ) -> Task<Result<Option<Vec<CodeAction>>>> {
3996        let buffer = buffer_handle.read(cx);
3997        let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
3998        self.lsp_store.update(cx, |lsp_store, cx| {
3999            lsp_store.code_actions(buffer_handle, range, kinds, cx)
4000        })
4001    }
4002
4003    pub fn code_lens_actions<T: Clone + ToOffset>(
4004        &mut self,
4005        buffer: &Entity<Buffer>,
4006        range: Range<T>,
4007        cx: &mut Context<Self>,
4008    ) -> Task<Result<Option<Vec<CodeAction>>>> {
4009        let snapshot = buffer.read(cx).snapshot();
4010        let range = range.to_point(&snapshot);
4011        let range_start = snapshot.anchor_before(range.start);
4012        let range_end = if range.start == range.end {
4013            range_start
4014        } else {
4015            snapshot.anchor_after(range.end)
4016        };
4017        let range = range_start..range_end;
4018        let code_lens_actions = self
4019            .lsp_store
4020            .update(cx, |lsp_store, cx| lsp_store.code_lens_actions(buffer, cx));
4021
4022        cx.background_spawn(async move {
4023            let mut code_lens_actions = code_lens_actions
4024                .await
4025                .map_err(|e| anyhow!("code lens fetch failed: {e:#}"))?;
4026            if let Some(code_lens_actions) = &mut code_lens_actions {
4027                code_lens_actions.retain(|code_lens_action| {
4028                    range
4029                        .start
4030                        .cmp(&code_lens_action.range.start, &snapshot)
4031                        .is_ge()
4032                        && range
4033                            .end
4034                            .cmp(&code_lens_action.range.end, &snapshot)
4035                            .is_le()
4036                });
4037            }
4038            Ok(code_lens_actions)
4039        })
4040    }
4041
4042    pub fn apply_code_action(
4043        &self,
4044        buffer_handle: Entity<Buffer>,
4045        action: CodeAction,
4046        push_to_history: bool,
4047        cx: &mut Context<Self>,
4048    ) -> Task<Result<ProjectTransaction>> {
4049        self.lsp_store.update(cx, |lsp_store, cx| {
4050            lsp_store.apply_code_action(buffer_handle, action, push_to_history, cx)
4051        })
4052    }
4053
4054    pub fn apply_code_action_kind(
4055        &self,
4056        buffers: HashSet<Entity<Buffer>>,
4057        kind: CodeActionKind,
4058        push_to_history: bool,
4059        cx: &mut Context<Self>,
4060    ) -> Task<Result<ProjectTransaction>> {
4061        self.lsp_store.update(cx, |lsp_store, cx| {
4062            lsp_store.apply_code_action_kind(buffers, kind, push_to_history, cx)
4063        })
4064    }
4065
4066    pub fn prepare_rename<T: ToPointUtf16>(
4067        &mut self,
4068        buffer: Entity<Buffer>,
4069        position: T,
4070        cx: &mut Context<Self>,
4071    ) -> Task<Result<PrepareRenameResponse>> {
4072        let position = position.to_point_utf16(buffer.read(cx));
4073        self.request_lsp(
4074            buffer,
4075            LanguageServerToQuery::FirstCapable,
4076            PrepareRename { position },
4077            cx,
4078        )
4079    }
4080
4081    pub fn perform_rename<T: ToPointUtf16>(
4082        &mut self,
4083        buffer: Entity<Buffer>,
4084        position: T,
4085        new_name: String,
4086        cx: &mut Context<Self>,
4087    ) -> Task<Result<ProjectTransaction>> {
4088        let push_to_history = true;
4089        let position = position.to_point_utf16(buffer.read(cx));
4090        self.request_lsp(
4091            buffer,
4092            LanguageServerToQuery::FirstCapable,
4093            PerformRename {
4094                position,
4095                new_name,
4096                push_to_history,
4097            },
4098            cx,
4099        )
4100    }
4101
4102    pub fn on_type_format<T: ToPointUtf16>(
4103        &mut self,
4104        buffer: Entity<Buffer>,
4105        position: T,
4106        trigger: String,
4107        push_to_history: bool,
4108        cx: &mut Context<Self>,
4109    ) -> Task<Result<Option<Transaction>>> {
4110        self.lsp_store.update(cx, |lsp_store, cx| {
4111            lsp_store.on_type_format(buffer, position, trigger, push_to_history, cx)
4112        })
4113    }
4114
4115    pub fn inline_values(
4116        &mut self,
4117        session: Entity<Session>,
4118        active_stack_frame: ActiveStackFrame,
4119        buffer_handle: Entity<Buffer>,
4120        range: Range<text::Anchor>,
4121        cx: &mut Context<Self>,
4122    ) -> Task<anyhow::Result<Vec<InlayHint>>> {
4123        let snapshot = buffer_handle.read(cx).snapshot();
4124
4125        let captures =
4126            snapshot.debug_variables_query(Anchor::min_for_buffer(snapshot.remote_id())..range.end);
4127
4128        let row = snapshot
4129            .summary_for_anchor::<text::PointUtf16>(&range.end)
4130            .row as usize;
4131
4132        let inline_value_locations = provide_inline_values(captures, &snapshot, row);
4133
4134        let stack_frame_id = active_stack_frame.stack_frame_id;
4135        cx.spawn(async move |this, cx| {
4136            this.update(cx, |project, cx| {
4137                project.dap_store().update(cx, |dap_store, cx| {
4138                    dap_store.resolve_inline_value_locations(
4139                        session,
4140                        stack_frame_id,
4141                        buffer_handle,
4142                        inline_value_locations,
4143                        cx,
4144                    )
4145                })
4146            })?
4147            .await
4148        })
4149    }
4150
4151    fn search_impl(&mut self, query: SearchQuery, cx: &mut Context<Self>) -> SearchResultsHandle {
4152        let client: Option<(AnyProtoClient, _)> = if let Some(ssh_client) = &self.remote_client {
4153            Some((ssh_client.read(cx).proto_client(), 0))
4154        } else if let Some(remote_id) = self.remote_id() {
4155            self.is_local()
4156                .not()
4157                .then(|| (self.collab_client.clone().into(), remote_id))
4158        } else {
4159            None
4160        };
4161        let searcher = if query.is_opened_only() {
4162            project_search::Search::open_buffers_only(
4163                self.buffer_store.clone(),
4164                self.worktree_store.clone(),
4165                project_search::Search::MAX_SEARCH_RESULT_FILES + 1,
4166            )
4167        } else {
4168            match client {
4169                Some((client, remote_id)) => project_search::Search::remote(
4170                    self.buffer_store.clone(),
4171                    self.worktree_store.clone(),
4172                    project_search::Search::MAX_SEARCH_RESULT_FILES + 1,
4173                    (client, remote_id, self.remotely_created_models.clone()),
4174                ),
4175                None => project_search::Search::local(
4176                    self.fs.clone(),
4177                    self.buffer_store.clone(),
4178                    self.worktree_store.clone(),
4179                    project_search::Search::MAX_SEARCH_RESULT_FILES + 1,
4180                    cx,
4181                ),
4182            }
4183        };
4184        searcher.into_handle(query, cx)
4185    }
4186
4187    pub fn search(
4188        &mut self,
4189        query: SearchQuery,
4190        cx: &mut Context<Self>,
4191    ) -> SearchResults<SearchResult> {
4192        self.search_impl(query, cx).results(cx)
4193    }
4194
4195    pub fn request_lsp<R: LspCommand>(
4196        &mut self,
4197        buffer_handle: Entity<Buffer>,
4198        server: LanguageServerToQuery,
4199        request: R,
4200        cx: &mut Context<Self>,
4201    ) -> Task<Result<R::Response>>
4202    where
4203        <R::LspRequest as lsp::request::Request>::Result: Send,
4204        <R::LspRequest as lsp::request::Request>::Params: Send,
4205    {
4206        let guard = self.retain_remotely_created_models(cx);
4207        let task = self.lsp_store.update(cx, |lsp_store, cx| {
4208            lsp_store.request_lsp(buffer_handle, server, request, cx)
4209        });
4210        cx.background_spawn(async move {
4211            let result = task.await;
4212            drop(guard);
4213            result
4214        })
4215    }
4216
4217    /// Move a worktree to a new position in the worktree order.
4218    ///
4219    /// The worktree will moved to the opposite side of the destination worktree.
4220    ///
4221    /// # Example
4222    ///
4223    /// Given the worktree order `[11, 22, 33]` and a call to move worktree `22` to `33`,
4224    /// worktree_order will be updated to produce the indexes `[11, 33, 22]`.
4225    ///
4226    /// Given the worktree order `[11, 22, 33]` and a call to move worktree `22` to `11`,
4227    /// worktree_order will be updated to produce the indexes `[22, 11, 33]`.
4228    ///
4229    /// # Errors
4230    ///
4231    /// An error will be returned if the worktree or destination worktree are not found.
4232    pub fn move_worktree(
4233        &mut self,
4234        source: WorktreeId,
4235        destination: WorktreeId,
4236        cx: &mut Context<Self>,
4237    ) -> Result<()> {
4238        self.worktree_store.update(cx, |worktree_store, cx| {
4239            worktree_store.move_worktree(source, destination, cx)
4240        })
4241    }
4242
4243    pub fn find_or_create_worktree(
4244        &mut self,
4245        abs_path: impl AsRef<Path>,
4246        visible: bool,
4247        cx: &mut Context<Self>,
4248    ) -> Task<Result<(Entity<Worktree>, Arc<RelPath>)>> {
4249        self.worktree_store.update(cx, |worktree_store, cx| {
4250            worktree_store.find_or_create_worktree(abs_path, visible, cx)
4251        })
4252    }
4253
4254    pub fn find_worktree(
4255        &self,
4256        abs_path: &Path,
4257        cx: &App,
4258    ) -> Option<(Entity<Worktree>, Arc<RelPath>)> {
4259        self.worktree_store.read(cx).find_worktree(abs_path, cx)
4260    }
4261
4262    pub fn is_shared(&self) -> bool {
4263        match &self.client_state {
4264            ProjectClientState::Shared { .. } => true,
4265            ProjectClientState::Local => false,
4266            ProjectClientState::Remote { .. } => true,
4267        }
4268    }
4269
4270    /// Returns the resolved version of `path`, that was found in `buffer`, if it exists.
4271    pub fn resolve_path_in_buffer(
4272        &self,
4273        path: &str,
4274        buffer: &Entity<Buffer>,
4275        cx: &mut Context<Self>,
4276    ) -> Task<Option<ResolvedPath>> {
4277        if util::paths::is_absolute(path, self.path_style(cx)) || path.starts_with("~") {
4278            self.resolve_abs_path(path, cx)
4279        } else {
4280            self.resolve_path_in_worktrees(path, buffer, cx)
4281        }
4282    }
4283
4284    pub fn resolve_abs_file_path(
4285        &self,
4286        path: &str,
4287        cx: &mut Context<Self>,
4288    ) -> Task<Option<ResolvedPath>> {
4289        let resolve_task = self.resolve_abs_path(path, cx);
4290        cx.background_spawn(async move {
4291            let resolved_path = resolve_task.await;
4292            resolved_path.filter(|path| path.is_file())
4293        })
4294    }
4295
4296    pub fn resolve_abs_path(&self, path: &str, cx: &App) -> Task<Option<ResolvedPath>> {
4297        if self.is_local() {
4298            let expanded = PathBuf::from(shellexpand::tilde(&path).into_owned());
4299            let fs = self.fs.clone();
4300            cx.background_spawn(async move {
4301                let metadata = fs.metadata(&expanded).await.ok().flatten();
4302
4303                metadata.map(|metadata| ResolvedPath::AbsPath {
4304                    path: expanded.to_string_lossy().into_owned(),
4305                    is_dir: metadata.is_dir,
4306                })
4307            })
4308        } else if let Some(ssh_client) = self.remote_client.as_ref() {
4309            let request = ssh_client
4310                .read(cx)
4311                .proto_client()
4312                .request(proto::GetPathMetadata {
4313                    project_id: REMOTE_SERVER_PROJECT_ID,
4314                    path: path.into(),
4315                });
4316            cx.background_spawn(async move {
4317                let response = request.await.log_err()?;
4318                if response.exists {
4319                    Some(ResolvedPath::AbsPath {
4320                        path: response.path,
4321                        is_dir: response.is_dir,
4322                    })
4323                } else {
4324                    None
4325                }
4326            })
4327        } else {
4328            Task::ready(None)
4329        }
4330    }
4331
4332    fn resolve_path_in_worktrees(
4333        &self,
4334        path: &str,
4335        buffer: &Entity<Buffer>,
4336        cx: &mut Context<Self>,
4337    ) -> Task<Option<ResolvedPath>> {
4338        let mut candidates = vec![];
4339        let path_style = self.path_style(cx);
4340        if let Ok(path) = RelPath::new(path.as_ref(), path_style) {
4341            candidates.push(path.into_arc());
4342        }
4343
4344        if let Some(file) = buffer.read(cx).file()
4345            && let Some(dir) = file.path().parent()
4346        {
4347            if let Some(joined) = path_style.join(&*dir.display(path_style), path)
4348                && let Some(joined) = RelPath::new(joined.as_ref(), path_style).ok()
4349            {
4350                candidates.push(joined.into_arc());
4351            }
4352        }
4353
4354        let buffer_worktree_id = buffer.read(cx).file().map(|file| file.worktree_id(cx));
4355        let worktrees_with_ids: Vec<_> = self
4356            .worktrees(cx)
4357            .map(|worktree| {
4358                let id = worktree.read(cx).id();
4359                (worktree, id)
4360            })
4361            .collect();
4362
4363        cx.spawn(async move |_, cx| {
4364            if let Some(buffer_worktree_id) = buffer_worktree_id
4365                && let Some((worktree, _)) = worktrees_with_ids
4366                    .iter()
4367                    .find(|(_, id)| *id == buffer_worktree_id)
4368            {
4369                for candidate in candidates.iter() {
4370                    if let Some(path) = Self::resolve_path_in_worktree(worktree, candidate, cx) {
4371                        return Some(path);
4372                    }
4373                }
4374            }
4375            for (worktree, id) in worktrees_with_ids {
4376                if Some(id) == buffer_worktree_id {
4377                    continue;
4378                }
4379                for candidate in candidates.iter() {
4380                    if let Some(path) = Self::resolve_path_in_worktree(&worktree, candidate, cx) {
4381                        return Some(path);
4382                    }
4383                }
4384            }
4385            None
4386        })
4387    }
4388
4389    fn resolve_path_in_worktree(
4390        worktree: &Entity<Worktree>,
4391        path: &RelPath,
4392        cx: &mut AsyncApp,
4393    ) -> Option<ResolvedPath> {
4394        worktree.read_with(cx, |worktree, _| {
4395            worktree.entry_for_path(path).map(|entry| {
4396                let project_path = ProjectPath {
4397                    worktree_id: worktree.id(),
4398                    path: entry.path.clone(),
4399                };
4400                ResolvedPath::ProjectPath {
4401                    project_path,
4402                    is_dir: entry.is_dir(),
4403                }
4404            })
4405        })
4406    }
4407
4408    pub fn list_directory(
4409        &self,
4410        query: String,
4411        cx: &mut Context<Self>,
4412    ) -> Task<Result<Vec<DirectoryItem>>> {
4413        if self.is_local() {
4414            DirectoryLister::Local(cx.entity(), self.fs.clone()).list_directory(query, cx)
4415        } else if let Some(session) = self.remote_client.as_ref() {
4416            let request = proto::ListRemoteDirectory {
4417                dev_server_id: REMOTE_SERVER_PROJECT_ID,
4418                path: query,
4419                config: Some(proto::ListRemoteDirectoryConfig { is_dir: true }),
4420            };
4421
4422            let response = session.read(cx).proto_client().request(request);
4423            cx.background_spawn(async move {
4424                let proto::ListRemoteDirectoryResponse {
4425                    entries,
4426                    entry_info,
4427                } = response.await?;
4428                Ok(entries
4429                    .into_iter()
4430                    .zip(entry_info)
4431                    .map(|(entry, info)| DirectoryItem {
4432                        path: PathBuf::from(entry),
4433                        is_dir: info.is_dir,
4434                    })
4435                    .collect())
4436            })
4437        } else {
4438            Task::ready(Err(anyhow!("cannot list directory in remote project")))
4439        }
4440    }
4441
4442    pub fn create_worktree(
4443        &mut self,
4444        abs_path: impl AsRef<Path>,
4445        visible: bool,
4446        cx: &mut Context<Self>,
4447    ) -> Task<Result<Entity<Worktree>>> {
4448        self.worktree_store.update(cx, |worktree_store, cx| {
4449            worktree_store.create_worktree(abs_path, visible, cx)
4450        })
4451    }
4452
4453    pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
4454        self.worktree_store.update(cx, |worktree_store, cx| {
4455            worktree_store.remove_worktree(id_to_remove, cx);
4456        });
4457    }
4458
4459    fn add_worktree(&mut self, worktree: &Entity<Worktree>, cx: &mut Context<Self>) {
4460        self.worktree_store.update(cx, |worktree_store, cx| {
4461            worktree_store.add(worktree, cx);
4462        });
4463    }
4464
4465    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut Context<Self>) {
4466        let new_active_entry = entry.and_then(|project_path| {
4467            let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
4468            let entry = worktree.read(cx).entry_for_path(&project_path.path)?;
4469            Some(entry.id)
4470        });
4471        if new_active_entry != self.active_entry {
4472            self.active_entry = new_active_entry;
4473            self.lsp_store.update(cx, |lsp_store, _| {
4474                lsp_store.set_active_entry(new_active_entry);
4475            });
4476            cx.emit(Event::ActiveEntryChanged(new_active_entry));
4477        }
4478    }
4479
4480    pub fn language_servers_running_disk_based_diagnostics<'a>(
4481        &'a self,
4482        cx: &'a App,
4483    ) -> impl Iterator<Item = LanguageServerId> + 'a {
4484        self.lsp_store
4485            .read(cx)
4486            .language_servers_running_disk_based_diagnostics()
4487    }
4488
4489    pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
4490        self.lsp_store
4491            .read(cx)
4492            .diagnostic_summary(include_ignored, cx)
4493    }
4494
4495    /// Returns a summary of the diagnostics for the provided project path only.
4496    pub fn diagnostic_summary_for_path(&self, path: &ProjectPath, cx: &App) -> DiagnosticSummary {
4497        self.lsp_store
4498            .read(cx)
4499            .diagnostic_summary_for_path(path, cx)
4500    }
4501
4502    pub fn diagnostic_summaries<'a>(
4503        &'a self,
4504        include_ignored: bool,
4505        cx: &'a App,
4506    ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
4507        self.lsp_store
4508            .read(cx)
4509            .diagnostic_summaries(include_ignored, cx)
4510    }
4511
4512    pub fn active_entry(&self) -> Option<ProjectEntryId> {
4513        self.active_entry
4514    }
4515
4516    pub fn entry_for_path<'a>(&'a self, path: &ProjectPath, cx: &'a App) -> Option<&'a Entry> {
4517        self.worktree_store.read(cx).entry_for_path(path, cx)
4518    }
4519
4520    pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &App) -> Option<ProjectPath> {
4521        let worktree = self.worktree_for_entry(entry_id, cx)?;
4522        let worktree = worktree.read(cx);
4523        let worktree_id = worktree.id();
4524        let path = worktree.entry_for_id(entry_id)?.path.clone();
4525        Some(ProjectPath { worktree_id, path })
4526    }
4527
4528    pub fn absolute_path(&self, project_path: &ProjectPath, cx: &App) -> Option<PathBuf> {
4529        Some(
4530            self.worktree_for_id(project_path.worktree_id, cx)?
4531                .read(cx)
4532                .absolutize(&project_path.path),
4533        )
4534    }
4535
4536    /// Attempts to find a `ProjectPath` corresponding to the given path. If the path
4537    /// is a *full path*, meaning it starts with the root name of a worktree, we'll locate
4538    /// it in that worktree. Otherwise, we'll attempt to find it as a relative path in
4539    /// the first visible worktree that has an entry for that relative path.
4540    ///
4541    /// We use this to resolve edit steps, when there's a chance an LLM may omit the workree
4542    /// root name from paths.
4543    ///
4544    /// # Arguments
4545    ///
4546    /// * `path` - An absolute path, or a full path that starts with a worktree root name, or a
4547    ///   relative path within a visible worktree.
4548    /// * `cx` - A reference to the `AppContext`.
4549    ///
4550    /// # Returns
4551    ///
4552    /// Returns `Some(ProjectPath)` if a matching worktree is found, otherwise `None`.
4553    pub fn find_project_path(&self, path: impl AsRef<Path>, cx: &App) -> Option<ProjectPath> {
4554        let path_style = self.path_style(cx);
4555        let path = path.as_ref();
4556        let worktree_store = self.worktree_store.read(cx);
4557
4558        if is_absolute(&path.to_string_lossy(), path_style) {
4559            for worktree in worktree_store.visible_worktrees(cx) {
4560                let worktree_abs_path = worktree.read(cx).abs_path();
4561
4562                if let Ok(relative_path) = path.strip_prefix(worktree_abs_path)
4563                    && let Ok(path) = RelPath::new(relative_path, path_style)
4564                {
4565                    return Some(ProjectPath {
4566                        worktree_id: worktree.read(cx).id(),
4567                        path: path.into_arc(),
4568                    });
4569                }
4570            }
4571        } else {
4572            for worktree in worktree_store.visible_worktrees(cx) {
4573                let worktree = worktree.read(cx);
4574                if let Ok(rel_path) = RelPath::new(path, path_style) {
4575                    if let Some(entry) = worktree.entry_for_path(&rel_path) {
4576                        return Some(ProjectPath {
4577                            worktree_id: worktree.id(),
4578                            path: entry.path.clone(),
4579                        });
4580                    }
4581                }
4582            }
4583
4584            for worktree in worktree_store.visible_worktrees(cx) {
4585                let worktree_root_name = worktree.read(cx).root_name();
4586                if let Ok(relative_path) = path.strip_prefix(worktree_root_name.as_std_path())
4587                    && let Ok(path) = RelPath::new(relative_path, path_style)
4588                {
4589                    return Some(ProjectPath {
4590                        worktree_id: worktree.read(cx).id(),
4591                        path: path.into_arc(),
4592                    });
4593                }
4594            }
4595        }
4596
4597        None
4598    }
4599
4600    /// If there's only one visible worktree, returns the given worktree-relative path with no prefix.
4601    ///
4602    /// Otherwise, returns the full path for the project path (obtained by prefixing the worktree-relative path with the name of the worktree).
4603    pub fn short_full_path_for_project_path(
4604        &self,
4605        project_path: &ProjectPath,
4606        cx: &App,
4607    ) -> Option<String> {
4608        let path_style = self.path_style(cx);
4609        if self.visible_worktrees(cx).take(2).count() < 2 {
4610            return Some(project_path.path.display(path_style).to_string());
4611        }
4612        self.worktree_for_id(project_path.worktree_id, cx)
4613            .map(|worktree| {
4614                let worktree_name = worktree.read(cx).root_name();
4615                worktree_name
4616                    .join(&project_path.path)
4617                    .display(path_style)
4618                    .to_string()
4619            })
4620    }
4621
4622    pub fn project_path_for_absolute_path(&self, abs_path: &Path, cx: &App) -> Option<ProjectPath> {
4623        self.worktree_store
4624            .read(cx)
4625            .project_path_for_absolute_path(abs_path, cx)
4626    }
4627
4628    pub fn get_workspace_root(&self, project_path: &ProjectPath, cx: &App) -> Option<PathBuf> {
4629        Some(
4630            self.worktree_for_id(project_path.worktree_id, cx)?
4631                .read(cx)
4632                .abs_path()
4633                .to_path_buf(),
4634        )
4635    }
4636
4637    pub fn blame_buffer(
4638        &self,
4639        buffer: &Entity<Buffer>,
4640        version: Option<clock::Global>,
4641        cx: &mut App,
4642    ) -> Task<Result<Option<Blame>>> {
4643        self.git_store.update(cx, |git_store, cx| {
4644            git_store.blame_buffer(buffer, version, cx)
4645        })
4646    }
4647
4648    pub fn get_permalink_to_line(
4649        &self,
4650        buffer: &Entity<Buffer>,
4651        selection: Range<u32>,
4652        cx: &mut App,
4653    ) -> Task<Result<url::Url>> {
4654        self.git_store.update(cx, |git_store, cx| {
4655            git_store.get_permalink_to_line(buffer, selection, cx)
4656        })
4657    }
4658
4659    // RPC message handlers
4660
4661    async fn handle_unshare_project(
4662        this: Entity<Self>,
4663        _: TypedEnvelope<proto::UnshareProject>,
4664        mut cx: AsyncApp,
4665    ) -> Result<()> {
4666        this.update(&mut cx, |this, cx| {
4667            if this.is_local() || this.is_via_remote_server() {
4668                this.unshare(cx)?;
4669            } else {
4670                this.disconnected_from_host(cx);
4671            }
4672            Ok(())
4673        })
4674    }
4675
4676    async fn handle_add_collaborator(
4677        this: Entity<Self>,
4678        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4679        mut cx: AsyncApp,
4680    ) -> Result<()> {
4681        let collaborator = envelope
4682            .payload
4683            .collaborator
4684            .take()
4685            .context("empty collaborator")?;
4686
4687        let collaborator = Collaborator::from_proto(collaborator)?;
4688        this.update(&mut cx, |this, cx| {
4689            this.buffer_store.update(cx, |buffer_store, _| {
4690                buffer_store.forget_shared_buffers_for(&collaborator.peer_id);
4691            });
4692            this.breakpoint_store.read(cx).broadcast();
4693            cx.emit(Event::CollaboratorJoined(collaborator.peer_id));
4694            this.collaborators
4695                .insert(collaborator.peer_id, collaborator);
4696        });
4697
4698        Ok(())
4699    }
4700
4701    async fn handle_update_project_collaborator(
4702        this: Entity<Self>,
4703        envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
4704        mut cx: AsyncApp,
4705    ) -> Result<()> {
4706        let old_peer_id = envelope
4707            .payload
4708            .old_peer_id
4709            .context("missing old peer id")?;
4710        let new_peer_id = envelope
4711            .payload
4712            .new_peer_id
4713            .context("missing new peer id")?;
4714        this.update(&mut cx, |this, cx| {
4715            let collaborator = this
4716                .collaborators
4717                .remove(&old_peer_id)
4718                .context("received UpdateProjectCollaborator for unknown peer")?;
4719            let is_host = collaborator.is_host;
4720            this.collaborators.insert(new_peer_id, collaborator);
4721
4722            log::info!("peer {} became {}", old_peer_id, new_peer_id,);
4723            this.buffer_store.update(cx, |buffer_store, _| {
4724                buffer_store.update_peer_id(&old_peer_id, new_peer_id)
4725            });
4726
4727            if is_host {
4728                this.buffer_store
4729                    .update(cx, |buffer_store, _| buffer_store.discard_incomplete());
4730                this.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
4731                    .unwrap();
4732                cx.emit(Event::HostReshared);
4733            }
4734
4735            cx.emit(Event::CollaboratorUpdated {
4736                old_peer_id,
4737                new_peer_id,
4738            });
4739            Ok(())
4740        })
4741    }
4742
4743    async fn handle_remove_collaborator(
4744        this: Entity<Self>,
4745        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4746        mut cx: AsyncApp,
4747    ) -> Result<()> {
4748        this.update(&mut cx, |this, cx| {
4749            let peer_id = envelope.payload.peer_id.context("invalid peer id")?;
4750            let replica_id = this
4751                .collaborators
4752                .remove(&peer_id)
4753                .with_context(|| format!("unknown peer {peer_id:?}"))?
4754                .replica_id;
4755            this.buffer_store.update(cx, |buffer_store, cx| {
4756                buffer_store.forget_shared_buffers_for(&peer_id);
4757                for buffer in buffer_store.buffers() {
4758                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4759                }
4760            });
4761            this.git_store.update(cx, |git_store, _| {
4762                git_store.forget_shared_diffs_for(&peer_id);
4763            });
4764
4765            cx.emit(Event::CollaboratorLeft(peer_id));
4766            Ok(())
4767        })
4768    }
4769
4770    async fn handle_update_project(
4771        this: Entity<Self>,
4772        envelope: TypedEnvelope<proto::UpdateProject>,
4773        mut cx: AsyncApp,
4774    ) -> Result<()> {
4775        this.update(&mut cx, |this, cx| {
4776            // Don't handle messages that were sent before the response to us joining the project
4777            if envelope.message_id > this.join_project_response_message_id {
4778                cx.update_global::<SettingsStore, _>(|store, cx| {
4779                    for worktree_metadata in &envelope.payload.worktrees {
4780                        store
4781                            .clear_local_settings(WorktreeId::from_proto(worktree_metadata.id), cx)
4782                            .log_err();
4783                    }
4784                });
4785
4786                this.set_worktrees_from_proto(envelope.payload.worktrees, cx)?;
4787            }
4788            Ok(())
4789        })
4790    }
4791
4792    async fn handle_toast(
4793        this: Entity<Self>,
4794        envelope: TypedEnvelope<proto::Toast>,
4795        mut cx: AsyncApp,
4796    ) -> Result<()> {
4797        this.update(&mut cx, |_, cx| {
4798            cx.emit(Event::Toast {
4799                notification_id: envelope.payload.notification_id.into(),
4800                message: envelope.payload.message,
4801            });
4802            Ok(())
4803        })
4804    }
4805
4806    async fn handle_language_server_prompt_request(
4807        this: Entity<Self>,
4808        envelope: TypedEnvelope<proto::LanguageServerPromptRequest>,
4809        mut cx: AsyncApp,
4810    ) -> Result<proto::LanguageServerPromptResponse> {
4811        let (tx, rx) = smol::channel::bounded(1);
4812        let actions: Vec<_> = envelope
4813            .payload
4814            .actions
4815            .into_iter()
4816            .map(|action| MessageActionItem {
4817                title: action,
4818                properties: Default::default(),
4819            })
4820            .collect();
4821        this.update(&mut cx, |_, cx| {
4822            cx.emit(Event::LanguageServerPrompt(LanguageServerPromptRequest {
4823                level: proto_to_prompt(envelope.payload.level.context("Invalid prompt level")?),
4824                message: envelope.payload.message,
4825                actions: actions.clone(),
4826                lsp_name: envelope.payload.lsp_name,
4827                response_channel: tx,
4828            }));
4829
4830            anyhow::Ok(())
4831        })?;
4832
4833        // We drop `this` to avoid holding a reference in this future for too
4834        // long.
4835        // If we keep the reference, we might not drop the `Project` early
4836        // enough when closing a window and it will only get releases on the
4837        // next `flush_effects()` call.
4838        drop(this);
4839
4840        let mut rx = pin!(rx);
4841        let answer = rx.next().await;
4842
4843        Ok(LanguageServerPromptResponse {
4844            action_response: answer.and_then(|answer| {
4845                actions
4846                    .iter()
4847                    .position(|action| *action == answer)
4848                    .map(|index| index as u64)
4849            }),
4850        })
4851    }
4852
4853    async fn handle_hide_toast(
4854        this: Entity<Self>,
4855        envelope: TypedEnvelope<proto::HideToast>,
4856        mut cx: AsyncApp,
4857    ) -> Result<()> {
4858        this.update(&mut cx, |_, cx| {
4859            cx.emit(Event::HideToast {
4860                notification_id: envelope.payload.notification_id.into(),
4861            });
4862            Ok(())
4863        })
4864    }
4865
4866    // Collab sends UpdateWorktree protos as messages
4867    async fn handle_update_worktree(
4868        this: Entity<Self>,
4869        envelope: TypedEnvelope<proto::UpdateWorktree>,
4870        mut cx: AsyncApp,
4871    ) -> Result<()> {
4872        this.update(&mut cx, |project, cx| {
4873            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4874            if let Some(worktree) = project.worktree_for_id(worktree_id, cx) {
4875                worktree.update(cx, |worktree, _| {
4876                    let worktree = worktree.as_remote_mut().unwrap();
4877                    worktree.update_from_remote(envelope.payload);
4878                });
4879            }
4880            Ok(())
4881        })
4882    }
4883
4884    async fn handle_update_buffer_from_remote_server(
4885        this: Entity<Self>,
4886        envelope: TypedEnvelope<proto::UpdateBuffer>,
4887        cx: AsyncApp,
4888    ) -> Result<proto::Ack> {
4889        let buffer_store = this.read_with(&cx, |this, cx| {
4890            if let Some(remote_id) = this.remote_id() {
4891                let mut payload = envelope.payload.clone();
4892                payload.project_id = remote_id;
4893                cx.background_spawn(this.collab_client.request(payload))
4894                    .detach_and_log_err(cx);
4895            }
4896            this.buffer_store.clone()
4897        });
4898        BufferStore::handle_update_buffer(buffer_store, envelope, cx).await
4899    }
4900
4901    async fn handle_trust_worktrees(
4902        this: Entity<Self>,
4903        envelope: TypedEnvelope<proto::TrustWorktrees>,
4904        mut cx: AsyncApp,
4905    ) -> Result<proto::Ack> {
4906        if this.read_with(&cx, |project, _| project.is_via_collab()) {
4907            return Ok(proto::Ack {});
4908        }
4909
4910        let trusted_worktrees = cx
4911            .update(|cx| TrustedWorktrees::try_get_global(cx))
4912            .context("missing trusted worktrees")?;
4913        trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
4914            trusted_worktrees.trust(
4915                &this.read(cx).worktree_store(),
4916                envelope
4917                    .payload
4918                    .trusted_paths
4919                    .into_iter()
4920                    .filter_map(|proto_path| PathTrust::from_proto(proto_path))
4921                    .collect(),
4922                cx,
4923            );
4924        });
4925        Ok(proto::Ack {})
4926    }
4927
4928    async fn handle_restrict_worktrees(
4929        this: Entity<Self>,
4930        envelope: TypedEnvelope<proto::RestrictWorktrees>,
4931        mut cx: AsyncApp,
4932    ) -> Result<proto::Ack> {
4933        if this.read_with(&cx, |project, _| project.is_via_collab()) {
4934            return Ok(proto::Ack {});
4935        }
4936
4937        let trusted_worktrees = cx
4938            .update(|cx| TrustedWorktrees::try_get_global(cx))
4939            .context("missing trusted worktrees")?;
4940        trusted_worktrees.update(&mut cx, |trusted_worktrees, cx| {
4941            let worktree_store = this.read(cx).worktree_store().downgrade();
4942            let restricted_paths = envelope
4943                .payload
4944                .worktree_ids
4945                .into_iter()
4946                .map(WorktreeId::from_proto)
4947                .map(PathTrust::Worktree)
4948                .collect::<HashSet<_>>();
4949            trusted_worktrees.restrict(worktree_store, restricted_paths, cx);
4950        });
4951        Ok(proto::Ack {})
4952    }
4953
4954    // Goes from host to client.
4955    async fn handle_find_search_candidates_chunk(
4956        this: Entity<Self>,
4957        envelope: TypedEnvelope<proto::FindSearchCandidatesChunk>,
4958        mut cx: AsyncApp,
4959    ) -> Result<proto::Ack> {
4960        let buffer_store = this.read_with(&mut cx, |this, _| this.buffer_store.clone());
4961        BufferStore::handle_find_search_candidates_chunk(buffer_store, envelope, cx).await
4962    }
4963
4964    // Goes from client to host.
4965    async fn handle_find_search_candidates_cancel(
4966        this: Entity<Self>,
4967        envelope: TypedEnvelope<proto::FindSearchCandidatesCancelled>,
4968        mut cx: AsyncApp,
4969    ) -> Result<()> {
4970        let buffer_store = this.read_with(&mut cx, |this, _| this.buffer_store.clone());
4971        BufferStore::handle_find_search_candidates_cancel(buffer_store, envelope, cx).await
4972    }
4973
4974    async fn handle_update_buffer(
4975        this: Entity<Self>,
4976        envelope: TypedEnvelope<proto::UpdateBuffer>,
4977        cx: AsyncApp,
4978    ) -> Result<proto::Ack> {
4979        let buffer_store = this.read_with(&cx, |this, cx| {
4980            if let Some(ssh) = &this.remote_client {
4981                let mut payload = envelope.payload.clone();
4982                payload.project_id = REMOTE_SERVER_PROJECT_ID;
4983                cx.background_spawn(ssh.read(cx).proto_client().request(payload))
4984                    .detach_and_log_err(cx);
4985            }
4986            this.buffer_store.clone()
4987        });
4988        BufferStore::handle_update_buffer(buffer_store, envelope, cx).await
4989    }
4990
4991    fn retain_remotely_created_models(
4992        &mut self,
4993        cx: &mut Context<Self>,
4994    ) -> RemotelyCreatedModelGuard {
4995        Self::retain_remotely_created_models_impl(
4996            &self.remotely_created_models,
4997            &self.buffer_store,
4998            &self.worktree_store,
4999            cx,
5000        )
5001    }
5002
5003    fn retain_remotely_created_models_impl(
5004        models: &Arc<Mutex<RemotelyCreatedModels>>,
5005        buffer_store: &Entity<BufferStore>,
5006        worktree_store: &Entity<WorktreeStore>,
5007        cx: &mut App,
5008    ) -> RemotelyCreatedModelGuard {
5009        {
5010            let mut remotely_create_models = models.lock();
5011            if remotely_create_models.retain_count == 0 {
5012                remotely_create_models.buffers = buffer_store.read(cx).buffers().collect();
5013                remotely_create_models.worktrees = worktree_store.read(cx).worktrees().collect();
5014            }
5015            remotely_create_models.retain_count += 1;
5016        }
5017        RemotelyCreatedModelGuard {
5018            remote_models: Arc::downgrade(&models),
5019        }
5020    }
5021
5022    async fn handle_create_buffer_for_peer(
5023        this: Entity<Self>,
5024        envelope: TypedEnvelope<proto::CreateBufferForPeer>,
5025        mut cx: AsyncApp,
5026    ) -> Result<()> {
5027        this.update(&mut cx, |this, cx| {
5028            this.buffer_store.update(cx, |buffer_store, cx| {
5029                buffer_store.handle_create_buffer_for_peer(
5030                    envelope,
5031                    this.replica_id(),
5032                    this.capability(),
5033                    cx,
5034                )
5035            })
5036        })
5037    }
5038
5039    async fn handle_toggle_lsp_logs(
5040        project: Entity<Self>,
5041        envelope: TypedEnvelope<proto::ToggleLspLogs>,
5042        mut cx: AsyncApp,
5043    ) -> Result<()> {
5044        let toggled_log_kind =
5045            match proto::toggle_lsp_logs::LogType::from_i32(envelope.payload.log_type)
5046                .context("invalid log type")?
5047            {
5048                proto::toggle_lsp_logs::LogType::Log => LogKind::Logs,
5049                proto::toggle_lsp_logs::LogType::Trace => LogKind::Trace,
5050                proto::toggle_lsp_logs::LogType::Rpc => LogKind::Rpc,
5051            };
5052        project.update(&mut cx, |_, cx| {
5053            cx.emit(Event::ToggleLspLogs {
5054                server_id: LanguageServerId::from_proto(envelope.payload.server_id),
5055                enabled: envelope.payload.enabled,
5056                toggled_log_kind,
5057            })
5058        });
5059        Ok(())
5060    }
5061
5062    async fn handle_synchronize_buffers(
5063        this: Entity<Self>,
5064        envelope: TypedEnvelope<proto::SynchronizeBuffers>,
5065        mut cx: AsyncApp,
5066    ) -> Result<proto::SynchronizeBuffersResponse> {
5067        let response = this.update(&mut cx, |this, cx| {
5068            let client = this.collab_client.clone();
5069            this.buffer_store.update(cx, |this, cx| {
5070                this.handle_synchronize_buffers(envelope, cx, client)
5071            })
5072        })?;
5073
5074        Ok(response)
5075    }
5076
5077    // Goes from client to host.
5078    async fn handle_search_candidate_buffers(
5079        this: Entity<Self>,
5080        envelope: TypedEnvelope<proto::FindSearchCandidates>,
5081        mut cx: AsyncApp,
5082    ) -> Result<proto::Ack> {
5083        let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
5084        let message = envelope.payload;
5085        let project_id = message.project_id;
5086        let path_style = this.read_with(&cx, |this, cx| this.path_style(cx));
5087        let query =
5088            SearchQuery::from_proto(message.query.context("missing query field")?, path_style)?;
5089
5090        let handle = message.handle;
5091        let buffer_store = this.read_with(&cx, |this, _| this.buffer_store().clone());
5092        let client = this.read_with(&cx, |this, _| this.client());
5093        let task = cx.spawn(async move |cx| {
5094            let results = this.update(cx, |this, cx| {
5095                this.search_impl(query, cx).matching_buffers(cx)
5096            });
5097            let (batcher, batches) = project_search::AdaptiveBatcher::new(cx.background_executor());
5098            let mut new_matches = Box::pin(results.rx);
5099
5100            let sender_task = cx.background_executor().spawn({
5101                let client = client.clone();
5102                async move {
5103                    let mut batches = std::pin::pin!(batches);
5104                    while let Some(buffer_ids) = batches.next().await {
5105                        client
5106                            .request(proto::FindSearchCandidatesChunk {
5107                                handle,
5108                                peer_id: Some(peer_id),
5109                                project_id,
5110                                variant: Some(
5111                                    proto::find_search_candidates_chunk::Variant::Matches(
5112                                        proto::FindSearchCandidatesMatches { buffer_ids },
5113                                    ),
5114                                ),
5115                            })
5116                            .await?;
5117                    }
5118                    anyhow::Ok(())
5119                }
5120            });
5121
5122            while let Some(buffer) = new_matches.next().await {
5123                let buffer_id = this.update(cx, |this, cx| {
5124                    this.create_buffer_for_peer(&buffer, peer_id, cx).to_proto()
5125                });
5126                batcher.push(buffer_id).await;
5127            }
5128            batcher.flush().await;
5129
5130            sender_task.await?;
5131
5132            let _ = client
5133                .request(proto::FindSearchCandidatesChunk {
5134                    handle,
5135                    peer_id: Some(peer_id),
5136                    project_id,
5137                    variant: Some(proto::find_search_candidates_chunk::Variant::Done(
5138                        proto::FindSearchCandidatesDone {},
5139                    )),
5140                })
5141                .await?;
5142            anyhow::Ok(())
5143        });
5144        buffer_store.update(&mut cx, |this, _| {
5145            this.register_ongoing_project_search((peer_id, handle), task);
5146        });
5147
5148        Ok(proto::Ack {})
5149    }
5150
5151    async fn handle_open_buffer_by_id(
5152        this: Entity<Self>,
5153        envelope: TypedEnvelope<proto::OpenBufferById>,
5154        mut cx: AsyncApp,
5155    ) -> Result<proto::OpenBufferResponse> {
5156        let peer_id = envelope.original_sender_id()?;
5157        let buffer_id = BufferId::new(envelope.payload.id)?;
5158        let buffer = this
5159            .update(&mut cx, |this, cx| this.open_buffer_by_id(buffer_id, cx))
5160            .await?;
5161        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
5162    }
5163
5164    async fn handle_open_buffer_by_path(
5165        this: Entity<Self>,
5166        envelope: TypedEnvelope<proto::OpenBufferByPath>,
5167        mut cx: AsyncApp,
5168    ) -> Result<proto::OpenBufferResponse> {
5169        let peer_id = envelope.original_sender_id()?;
5170        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5171        let path = RelPath::from_proto(&envelope.payload.path)?;
5172        let open_buffer = this
5173            .update(&mut cx, |this, cx| {
5174                this.open_buffer(ProjectPath { worktree_id, path }, cx)
5175            })
5176            .await?;
5177        Project::respond_to_open_buffer_request(this, open_buffer, peer_id, &mut cx)
5178    }
5179
5180    async fn handle_open_new_buffer(
5181        this: Entity<Self>,
5182        envelope: TypedEnvelope<proto::OpenNewBuffer>,
5183        mut cx: AsyncApp,
5184    ) -> Result<proto::OpenBufferResponse> {
5185        let buffer = this
5186            .update(&mut cx, |this, cx| this.create_buffer(true, cx))
5187            .await?;
5188        let peer_id = envelope.original_sender_id()?;
5189
5190        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
5191    }
5192
5193    fn respond_to_open_buffer_request(
5194        this: Entity<Self>,
5195        buffer: Entity<Buffer>,
5196        peer_id: proto::PeerId,
5197        cx: &mut AsyncApp,
5198    ) -> Result<proto::OpenBufferResponse> {
5199        this.update(cx, |this, cx| {
5200            let is_private = buffer
5201                .read(cx)
5202                .file()
5203                .map(|f| f.is_private())
5204                .unwrap_or_default();
5205            anyhow::ensure!(!is_private, ErrorCode::UnsharedItem);
5206            Ok(proto::OpenBufferResponse {
5207                buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx).into(),
5208            })
5209        })
5210    }
5211
5212    fn create_buffer_for_peer(
5213        &mut self,
5214        buffer: &Entity<Buffer>,
5215        peer_id: proto::PeerId,
5216        cx: &mut App,
5217    ) -> BufferId {
5218        self.buffer_store
5219            .update(cx, |buffer_store, cx| {
5220                buffer_store.create_buffer_for_peer(buffer, peer_id, cx)
5221            })
5222            .detach_and_log_err(cx);
5223        buffer.read(cx).remote_id()
5224    }
5225
5226    async fn handle_create_image_for_peer(
5227        this: Entity<Self>,
5228        envelope: TypedEnvelope<proto::CreateImageForPeer>,
5229        mut cx: AsyncApp,
5230    ) -> Result<()> {
5231        this.update(&mut cx, |this, cx| {
5232            this.image_store.update(cx, |image_store, cx| {
5233                image_store.handle_create_image_for_peer(envelope, cx)
5234            })
5235        })
5236    }
5237
5238    fn synchronize_remote_buffers(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
5239        let project_id = match self.client_state {
5240            ProjectClientState::Remote {
5241                sharing_has_stopped,
5242                remote_id,
5243                ..
5244            } => {
5245                if sharing_has_stopped {
5246                    return Task::ready(Err(anyhow!(
5247                        "can't synchronize remote buffers on a readonly project"
5248                    )));
5249                } else {
5250                    remote_id
5251                }
5252            }
5253            ProjectClientState::Shared { .. } | ProjectClientState::Local => {
5254                return Task::ready(Err(anyhow!(
5255                    "can't synchronize remote buffers on a local project"
5256                )));
5257            }
5258        };
5259
5260        let client = self.collab_client.clone();
5261        cx.spawn(async move |this, cx| {
5262            let (buffers, incomplete_buffer_ids) = this.update(cx, |this, cx| {
5263                this.buffer_store.read(cx).buffer_version_info(cx)
5264            })?;
5265            let response = client
5266                .request(proto::SynchronizeBuffers {
5267                    project_id,
5268                    buffers,
5269                })
5270                .await?;
5271
5272            let send_updates_for_buffers = this.update(cx, |this, cx| {
5273                response
5274                    .buffers
5275                    .into_iter()
5276                    .map(|buffer| {
5277                        let client = client.clone();
5278                        let buffer_id = match BufferId::new(buffer.id) {
5279                            Ok(id) => id,
5280                            Err(e) => {
5281                                return Task::ready(Err(e));
5282                            }
5283                        };
5284                        let remote_version = language::proto::deserialize_version(&buffer.version);
5285                        if let Some(buffer) = this.buffer_for_id(buffer_id, cx) {
5286                            let operations =
5287                                buffer.read(cx).serialize_ops(Some(remote_version), cx);
5288                            cx.background_spawn(async move {
5289                                let operations = operations.await;
5290                                for chunk in split_operations(operations) {
5291                                    client
5292                                        .request(proto::UpdateBuffer {
5293                                            project_id,
5294                                            buffer_id: buffer_id.into(),
5295                                            operations: chunk,
5296                                        })
5297                                        .await?;
5298                                }
5299                                anyhow::Ok(())
5300                            })
5301                        } else {
5302                            Task::ready(Ok(()))
5303                        }
5304                    })
5305                    .collect::<Vec<_>>()
5306            })?;
5307
5308            // Any incomplete buffers have open requests waiting. Request that the host sends
5309            // creates these buffers for us again to unblock any waiting futures.
5310            for id in incomplete_buffer_ids {
5311                cx.background_spawn(client.request(proto::OpenBufferById {
5312                    project_id,
5313                    id: id.into(),
5314                }))
5315                .detach();
5316            }
5317
5318            futures::future::join_all(send_updates_for_buffers)
5319                .await
5320                .into_iter()
5321                .collect()
5322        })
5323    }
5324
5325    pub fn worktree_metadata_protos(&self, cx: &App) -> Vec<proto::WorktreeMetadata> {
5326        self.worktree_store.read(cx).worktree_metadata_protos(cx)
5327    }
5328
5329    /// Iterator of all open buffers that have unsaved changes
5330    pub fn dirty_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = ProjectPath> + 'a {
5331        self.buffer_store.read(cx).buffers().filter_map(|buf| {
5332            let buf = buf.read(cx);
5333            if buf.is_dirty() {
5334                buf.project_path(cx)
5335            } else {
5336                None
5337            }
5338        })
5339    }
5340
5341    fn set_worktrees_from_proto(
5342        &mut self,
5343        worktrees: Vec<proto::WorktreeMetadata>,
5344        cx: &mut Context<Project>,
5345    ) -> Result<()> {
5346        self.worktree_store.update(cx, |worktree_store, cx| {
5347            worktree_store.set_worktrees_from_proto(worktrees, self.replica_id(), cx)
5348        })
5349    }
5350
5351    fn set_collaborators_from_proto(
5352        &mut self,
5353        messages: Vec<proto::Collaborator>,
5354        cx: &mut Context<Self>,
5355    ) -> Result<()> {
5356        let mut collaborators = HashMap::default();
5357        for message in messages {
5358            let collaborator = Collaborator::from_proto(message)?;
5359            collaborators.insert(collaborator.peer_id, collaborator);
5360        }
5361        for old_peer_id in self.collaborators.keys() {
5362            if !collaborators.contains_key(old_peer_id) {
5363                cx.emit(Event::CollaboratorLeft(*old_peer_id));
5364            }
5365        }
5366        self.collaborators = collaborators;
5367        Ok(())
5368    }
5369
5370    pub fn supplementary_language_servers<'a>(
5371        &'a self,
5372        cx: &'a App,
5373    ) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName)> {
5374        self.lsp_store.read(cx).supplementary_language_servers()
5375    }
5376
5377    pub fn any_language_server_supports_inlay_hints(&self, buffer: &Buffer, cx: &mut App) -> bool {
5378        let Some(language) = buffer.language().cloned() else {
5379            return false;
5380        };
5381        self.lsp_store.update(cx, |lsp_store, _| {
5382            let relevant_language_servers = lsp_store
5383                .languages
5384                .lsp_adapters(&language.name())
5385                .into_iter()
5386                .map(|lsp_adapter| lsp_adapter.name())
5387                .collect::<HashSet<_>>();
5388            lsp_store
5389                .language_server_statuses()
5390                .filter_map(|(server_id, server_status)| {
5391                    relevant_language_servers
5392                        .contains(&server_status.name)
5393                        .then_some(server_id)
5394                })
5395                .filter_map(|server_id| lsp_store.lsp_server_capabilities.get(&server_id))
5396                .any(InlayHints::check_capabilities)
5397        })
5398    }
5399
5400    pub fn language_server_id_for_name(
5401        &self,
5402        buffer: &Buffer,
5403        name: &LanguageServerName,
5404        cx: &App,
5405    ) -> Option<LanguageServerId> {
5406        let language = buffer.language()?;
5407        let relevant_language_servers = self
5408            .languages
5409            .lsp_adapters(&language.name())
5410            .into_iter()
5411            .map(|lsp_adapter| lsp_adapter.name())
5412            .collect::<HashSet<_>>();
5413        if !relevant_language_servers.contains(name) {
5414            return None;
5415        }
5416        self.language_server_statuses(cx)
5417            .filter(|(_, server_status)| relevant_language_servers.contains(&server_status.name))
5418            .find_map(|(server_id, server_status)| {
5419                if &server_status.name == name {
5420                    Some(server_id)
5421                } else {
5422                    None
5423                }
5424            })
5425    }
5426
5427    #[cfg(any(test, feature = "test-support"))]
5428    pub fn has_language_servers_for(&self, buffer: &Buffer, cx: &mut App) -> bool {
5429        self.lsp_store.update(cx, |this, cx| {
5430            this.running_language_servers_for_local_buffer(buffer, cx)
5431                .next()
5432                .is_some()
5433        })
5434    }
5435
5436    pub fn git_init(
5437        &self,
5438        path: Arc<Path>,
5439        fallback_branch_name: String,
5440        cx: &App,
5441    ) -> Task<Result<()>> {
5442        self.git_store
5443            .read(cx)
5444            .git_init(path, fallback_branch_name, cx)
5445    }
5446
5447    pub fn buffer_store(&self) -> &Entity<BufferStore> {
5448        &self.buffer_store
5449    }
5450
5451    pub fn git_store(&self) -> &Entity<GitStore> {
5452        &self.git_store
5453    }
5454
5455    pub fn agent_server_store(&self) -> &Entity<AgentServerStore> {
5456        &self.agent_server_store
5457    }
5458
5459    #[cfg(test)]
5460    fn git_scans_complete(&self, cx: &Context<Self>) -> Task<()> {
5461        cx.spawn(async move |this, cx| {
5462            let scans_complete = this
5463                .read_with(cx, |this, cx| {
5464                    this.worktrees(cx)
5465                        .filter_map(|worktree| Some(worktree.read(cx).as_local()?.scan_complete()))
5466                        .collect::<Vec<_>>()
5467                })
5468                .unwrap();
5469            join_all(scans_complete).await;
5470            let barriers = this
5471                .update(cx, |this, cx| {
5472                    let repos = this.repositories(cx).values().cloned().collect::<Vec<_>>();
5473                    repos
5474                        .into_iter()
5475                        .map(|repo| repo.update(cx, |repo, _| repo.barrier()))
5476                        .collect::<Vec<_>>()
5477                })
5478                .unwrap();
5479            join_all(barriers).await;
5480        })
5481    }
5482
5483    pub fn active_repository(&self, cx: &App) -> Option<Entity<Repository>> {
5484        self.git_store.read(cx).active_repository()
5485    }
5486
5487    pub fn repositories<'a>(&self, cx: &'a App) -> &'a HashMap<RepositoryId, Entity<Repository>> {
5488        self.git_store.read(cx).repositories()
5489    }
5490
5491    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
5492        self.git_store.read(cx).status_for_buffer_id(buffer_id, cx)
5493    }
5494
5495    pub fn set_agent_location(
5496        &mut self,
5497        new_location: Option<AgentLocation>,
5498        cx: &mut Context<Self>,
5499    ) {
5500        if let Some(old_location) = self.agent_location.as_ref() {
5501            old_location
5502                .buffer
5503                .update(cx, |buffer, cx| buffer.remove_agent_selections(cx))
5504                .ok();
5505        }
5506
5507        if let Some(location) = new_location.as_ref() {
5508            location
5509                .buffer
5510                .update(cx, |buffer, cx| {
5511                    buffer.set_agent_selections(
5512                        Arc::from([language::Selection {
5513                            id: 0,
5514                            start: location.position,
5515                            end: location.position,
5516                            reversed: false,
5517                            goal: language::SelectionGoal::None,
5518                        }]),
5519                        false,
5520                        CursorShape::Hollow,
5521                        cx,
5522                    )
5523                })
5524                .ok();
5525        }
5526
5527        self.agent_location = new_location;
5528        cx.emit(Event::AgentLocationChanged);
5529    }
5530
5531    pub fn agent_location(&self) -> Option<AgentLocation> {
5532        self.agent_location.clone()
5533    }
5534
5535    pub fn path_style(&self, cx: &App) -> PathStyle {
5536        self.worktree_store.read(cx).path_style()
5537    }
5538
5539    pub fn contains_local_settings_file(
5540        &self,
5541        worktree_id: WorktreeId,
5542        rel_path: &RelPath,
5543        cx: &App,
5544    ) -> bool {
5545        self.worktree_for_id(worktree_id, cx)
5546            .map_or(false, |worktree| {
5547                worktree.read(cx).entry_for_path(rel_path).is_some()
5548            })
5549    }
5550
5551    pub fn update_local_settings_file(
5552        &self,
5553        worktree_id: WorktreeId,
5554        rel_path: Arc<RelPath>,
5555        cx: &mut App,
5556        update: impl 'static + Send + FnOnce(&mut settings::SettingsContent, &App),
5557    ) {
5558        let Some(worktree) = self.worktree_for_id(worktree_id, cx) else {
5559            // todo(settings_ui) error?
5560            return;
5561        };
5562        cx.spawn(async move |cx| {
5563            let file = worktree
5564                .update(cx, |worktree, cx| worktree.load_file(&rel_path, cx))
5565                .await
5566                .context("Failed to load settings file")?;
5567
5568            let has_bom = file.has_bom;
5569
5570            let new_text = cx.read_global::<SettingsStore, _>(|store, cx| {
5571                store.new_text_for_update(file.text, move |settings| update(settings, cx))
5572            });
5573            worktree
5574                .update(cx, |worktree, cx| {
5575                    let line_ending = text::LineEnding::detect(&new_text);
5576                    worktree.write_file(
5577                        rel_path.clone(),
5578                        new_text.into(),
5579                        line_ending,
5580                        encoding_rs::UTF_8,
5581                        has_bom,
5582                        cx,
5583                    )
5584                })
5585                .await
5586                .context("Failed to write settings file")?;
5587
5588            anyhow::Ok(())
5589        })
5590        .detach_and_log_err(cx);
5591    }
5592}
5593
5594pub struct PathMatchCandidateSet {
5595    pub snapshot: Snapshot,
5596    pub include_ignored: bool,
5597    pub include_root_name: bool,
5598    pub candidates: Candidates,
5599}
5600
5601pub enum Candidates {
5602    /// Only consider directories.
5603    Directories,
5604    /// Only consider files.
5605    Files,
5606    /// Consider directories and files.
5607    Entries,
5608}
5609
5610impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
5611    type Candidates = PathMatchCandidateSetIter<'a>;
5612
5613    fn id(&self) -> usize {
5614        self.snapshot.id().to_usize()
5615    }
5616
5617    fn len(&self) -> usize {
5618        match self.candidates {
5619            Candidates::Files => {
5620                if self.include_ignored {
5621                    self.snapshot.file_count()
5622                } else {
5623                    self.snapshot.visible_file_count()
5624                }
5625            }
5626
5627            Candidates::Directories => {
5628                if self.include_ignored {
5629                    self.snapshot.dir_count()
5630                } else {
5631                    self.snapshot.visible_dir_count()
5632                }
5633            }
5634
5635            Candidates::Entries => {
5636                if self.include_ignored {
5637                    self.snapshot.entry_count()
5638                } else {
5639                    self.snapshot.visible_entry_count()
5640                }
5641            }
5642        }
5643    }
5644
5645    fn prefix(&self) -> Arc<RelPath> {
5646        if self.snapshot.root_entry().is_some_and(|e| e.is_file()) || self.include_root_name {
5647            self.snapshot.root_name().into()
5648        } else {
5649            RelPath::empty().into()
5650        }
5651    }
5652
5653    fn root_is_file(&self) -> bool {
5654        self.snapshot.root_entry().is_some_and(|f| f.is_file())
5655    }
5656
5657    fn path_style(&self) -> PathStyle {
5658        self.snapshot.path_style()
5659    }
5660
5661    fn candidates(&'a self, start: usize) -> Self::Candidates {
5662        PathMatchCandidateSetIter {
5663            traversal: match self.candidates {
5664                Candidates::Directories => self.snapshot.directories(self.include_ignored, start),
5665                Candidates::Files => self.snapshot.files(self.include_ignored, start),
5666                Candidates::Entries => self.snapshot.entries(self.include_ignored, start),
5667            },
5668        }
5669    }
5670}
5671
5672pub struct PathMatchCandidateSetIter<'a> {
5673    traversal: Traversal<'a>,
5674}
5675
5676impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
5677    type Item = fuzzy::PathMatchCandidate<'a>;
5678
5679    fn next(&mut self) -> Option<Self::Item> {
5680        self.traversal
5681            .next()
5682            .map(|entry| fuzzy::PathMatchCandidate {
5683                is_dir: entry.kind.is_dir(),
5684                path: &entry.path,
5685                char_bag: entry.char_bag,
5686            })
5687    }
5688}
5689
5690impl EventEmitter<Event> for Project {}
5691
5692impl<'a> From<&'a ProjectPath> for SettingsLocation<'a> {
5693    fn from(val: &'a ProjectPath) -> Self {
5694        SettingsLocation {
5695            worktree_id: val.worktree_id,
5696            path: val.path.as_ref(),
5697        }
5698    }
5699}
5700
5701impl<P: Into<Arc<RelPath>>> From<(WorktreeId, P)> for ProjectPath {
5702    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
5703        Self {
5704            worktree_id,
5705            path: path.into(),
5706        }
5707    }
5708}
5709
5710/// ResolvedPath is a path that has been resolved to either a ProjectPath
5711/// or an AbsPath and that *exists*.
5712#[derive(Debug, Clone)]
5713pub enum ResolvedPath {
5714    ProjectPath {
5715        project_path: ProjectPath,
5716        is_dir: bool,
5717    },
5718    AbsPath {
5719        path: String,
5720        is_dir: bool,
5721    },
5722}
5723
5724impl ResolvedPath {
5725    pub fn abs_path(&self) -> Option<&str> {
5726        match self {
5727            Self::AbsPath { path, .. } => Some(path),
5728            _ => None,
5729        }
5730    }
5731
5732    pub fn into_abs_path(self) -> Option<String> {
5733        match self {
5734            Self::AbsPath { path, .. } => Some(path),
5735            _ => None,
5736        }
5737    }
5738
5739    pub fn project_path(&self) -> Option<&ProjectPath> {
5740        match self {
5741            Self::ProjectPath { project_path, .. } => Some(project_path),
5742            _ => None,
5743        }
5744    }
5745
5746    pub fn is_file(&self) -> bool {
5747        !self.is_dir()
5748    }
5749
5750    pub fn is_dir(&self) -> bool {
5751        match self {
5752            Self::ProjectPath { is_dir, .. } => *is_dir,
5753            Self::AbsPath { is_dir, .. } => *is_dir,
5754        }
5755    }
5756}
5757
5758impl ProjectItem for Buffer {
5759    fn try_open(
5760        project: &Entity<Project>,
5761        path: &ProjectPath,
5762        cx: &mut App,
5763    ) -> Option<Task<Result<Entity<Self>>>> {
5764        Some(project.update(cx, |project, cx| project.open_buffer(path.clone(), cx)))
5765    }
5766
5767    fn entry_id(&self, _cx: &App) -> Option<ProjectEntryId> {
5768        File::from_dyn(self.file()).and_then(|file| file.project_entry_id())
5769    }
5770
5771    fn project_path(&self, cx: &App) -> Option<ProjectPath> {
5772        let file = self.file()?;
5773
5774        (!matches!(file.disk_state(), DiskState::Historic { .. })).then(|| ProjectPath {
5775            worktree_id: file.worktree_id(cx),
5776            path: file.path().clone(),
5777        })
5778    }
5779
5780    fn is_dirty(&self) -> bool {
5781        self.is_dirty()
5782    }
5783}
5784
5785impl Completion {
5786    pub fn kind(&self) -> Option<CompletionItemKind> {
5787        self.source
5788            // `lsp::CompletionListItemDefaults` has no `kind` field
5789            .lsp_completion(false)
5790            .and_then(|lsp_completion| lsp_completion.kind)
5791    }
5792
5793    pub fn label(&self) -> Option<String> {
5794        self.source
5795            .lsp_completion(false)
5796            .map(|lsp_completion| lsp_completion.label.clone())
5797    }
5798
5799    /// A key that can be used to sort completions when displaying
5800    /// them to the user.
5801    pub fn sort_key(&self) -> (usize, &str) {
5802        const DEFAULT_KIND_KEY: usize = 4;
5803        let kind_key = self
5804            .kind()
5805            .and_then(|lsp_completion_kind| match lsp_completion_kind {
5806                lsp::CompletionItemKind::KEYWORD => Some(0),
5807                lsp::CompletionItemKind::VARIABLE => Some(1),
5808                lsp::CompletionItemKind::CONSTANT => Some(2),
5809                lsp::CompletionItemKind::PROPERTY => Some(3),
5810                _ => None,
5811            })
5812            .unwrap_or(DEFAULT_KIND_KEY);
5813        (kind_key, self.label.filter_text())
5814    }
5815
5816    /// Whether this completion is a snippet.
5817    pub fn is_snippet_kind(&self) -> bool {
5818        matches!(
5819            &self.source,
5820            CompletionSource::Lsp { lsp_completion, .. }
5821            if lsp_completion.kind == Some(CompletionItemKind::SNIPPET)
5822        )
5823    }
5824
5825    /// Whether this completion is a snippet or snippet-style LSP completion.
5826    pub fn is_snippet(&self) -> bool {
5827        self.source
5828            // `lsp::CompletionListItemDefaults` has `insert_text_format` field
5829            .lsp_completion(true)
5830            .is_some_and(|lsp_completion| {
5831                lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
5832            })
5833    }
5834
5835    /// Returns the corresponding color for this completion.
5836    ///
5837    /// Will return `None` if this completion's kind is not [`CompletionItemKind::COLOR`].
5838    pub fn color(&self) -> Option<Hsla> {
5839        // `lsp::CompletionListItemDefaults` has no `kind` field
5840        let lsp_completion = self.source.lsp_completion(false)?;
5841        if lsp_completion.kind? == CompletionItemKind::COLOR {
5842            return color_extractor::extract_color(&lsp_completion);
5843        }
5844        None
5845    }
5846}
5847
5848fn proto_to_prompt(level: proto::language_server_prompt_request::Level) -> gpui::PromptLevel {
5849    match level {
5850        proto::language_server_prompt_request::Level::Info(_) => gpui::PromptLevel::Info,
5851        proto::language_server_prompt_request::Level::Warning(_) => gpui::PromptLevel::Warning,
5852        proto::language_server_prompt_request::Level::Critical(_) => gpui::PromptLevel::Critical,
5853    }
5854}
5855
5856fn provide_inline_values(
5857    captures: impl Iterator<Item = (Range<usize>, language::DebuggerTextObject)>,
5858    snapshot: &language::BufferSnapshot,
5859    max_row: usize,
5860) -> Vec<InlineValueLocation> {
5861    let mut variables = Vec::new();
5862    let mut variable_position = HashSet::default();
5863    let mut scopes = Vec::new();
5864
5865    let active_debug_line_offset = snapshot.point_to_offset(Point::new(max_row as u32, 0));
5866
5867    for (capture_range, capture_kind) in captures {
5868        match capture_kind {
5869            language::DebuggerTextObject::Variable => {
5870                let variable_name = snapshot
5871                    .text_for_range(capture_range.clone())
5872                    .collect::<String>();
5873                let point = snapshot.offset_to_point(capture_range.end);
5874
5875                while scopes
5876                    .last()
5877                    .is_some_and(|scope: &Range<_>| !scope.contains(&capture_range.start))
5878                {
5879                    scopes.pop();
5880                }
5881
5882                if point.row as usize > max_row {
5883                    break;
5884                }
5885
5886                let scope = if scopes
5887                    .last()
5888                    .is_none_or(|scope| !scope.contains(&active_debug_line_offset))
5889                {
5890                    VariableScope::Global
5891                } else {
5892                    VariableScope::Local
5893                };
5894
5895                if variable_position.insert(capture_range.end) {
5896                    variables.push(InlineValueLocation {
5897                        variable_name,
5898                        scope,
5899                        lookup: VariableLookupKind::Variable,
5900                        row: point.row as usize,
5901                        column: point.column as usize,
5902                    });
5903                }
5904            }
5905            language::DebuggerTextObject::Scope => {
5906                while scopes.last().map_or_else(
5907                    || false,
5908                    |scope: &Range<usize>| {
5909                        !(scope.contains(&capture_range.start)
5910                            && scope.contains(&capture_range.end))
5911                    },
5912                ) {
5913                    scopes.pop();
5914                }
5915                scopes.push(capture_range);
5916            }
5917        }
5918    }
5919
5920    variables
5921}
5922
5923#[cfg(test)]
5924mod disable_ai_settings_tests {
5925    use super::*;
5926    use gpui::TestAppContext;
5927    use settings::Settings;
5928
5929    #[gpui::test]
5930    async fn test_disable_ai_settings_security(cx: &mut TestAppContext) {
5931        cx.update(|cx| {
5932            settings::init(cx);
5933
5934            // Test 1: Default is false (AI enabled)
5935            assert!(
5936                !DisableAiSettings::get_global(cx).disable_ai,
5937                "Default should allow AI"
5938            );
5939        });
5940
5941        let disable_true = serde_json::json!({
5942            "disable_ai": true
5943        })
5944        .to_string();
5945        let disable_false = serde_json::json!({
5946            "disable_ai": false
5947        })
5948        .to_string();
5949
5950        cx.update_global::<SettingsStore, _>(|store, cx| {
5951            store.set_user_settings(&disable_false, cx).unwrap();
5952            store.set_global_settings(&disable_true, cx).unwrap();
5953        });
5954        cx.update(|cx| {
5955            assert!(
5956                DisableAiSettings::get_global(cx).disable_ai,
5957                "Local false cannot override global true"
5958            );
5959        });
5960
5961        cx.update_global::<SettingsStore, _>(|store, cx| {
5962            store.set_global_settings(&disable_false, cx).unwrap();
5963            store.set_user_settings(&disable_true, cx).unwrap();
5964        });
5965
5966        cx.update(|cx| {
5967            assert!(
5968                DisableAiSettings::get_global(cx).disable_ai,
5969                "Local false cannot override global true"
5970            );
5971        });
5972    }
5973}