project.rs

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