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: &App,
4139    ) -> Task<Result<Option<Blame>>> {
4140        self.git_store.read(cx).blame_buffer(buffer, version, cx)
4141    }
4142
4143    pub fn get_permalink_to_line(
4144        &self,
4145        buffer: &Entity<Buffer>,
4146        selection: Range<u32>,
4147        cx: &App,
4148    ) -> Task<Result<url::Url>> {
4149        self.git_store
4150            .read(cx)
4151            .get_permalink_to_line(buffer, selection, cx)
4152    }
4153
4154    // RPC message handlers
4155
4156    async fn handle_unshare_project(
4157        this: Entity<Self>,
4158        _: TypedEnvelope<proto::UnshareProject>,
4159        mut cx: AsyncApp,
4160    ) -> Result<()> {
4161        this.update(&mut cx, |this, cx| {
4162            if this.is_local() || this.is_via_ssh() {
4163                this.unshare(cx)?;
4164            } else {
4165                this.disconnected_from_host(cx);
4166            }
4167            Ok(())
4168        })?
4169    }
4170
4171    async fn handle_add_collaborator(
4172        this: Entity<Self>,
4173        mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4174        mut cx: AsyncApp,
4175    ) -> Result<()> {
4176        let collaborator = envelope
4177            .payload
4178            .collaborator
4179            .take()
4180            .ok_or_else(|| anyhow!("empty collaborator"))?;
4181
4182        let collaborator = Collaborator::from_proto(collaborator)?;
4183        this.update(&mut cx, |this, cx| {
4184            this.buffer_store.update(cx, |buffer_store, _| {
4185                buffer_store.forget_shared_buffers_for(&collaborator.peer_id);
4186            });
4187            this.breakpoint_store.read(cx).broadcast();
4188            cx.emit(Event::CollaboratorJoined(collaborator.peer_id));
4189            this.collaborators
4190                .insert(collaborator.peer_id, collaborator);
4191        })?;
4192
4193        Ok(())
4194    }
4195
4196    async fn handle_update_project_collaborator(
4197        this: Entity<Self>,
4198        envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
4199        mut cx: AsyncApp,
4200    ) -> Result<()> {
4201        let old_peer_id = envelope
4202            .payload
4203            .old_peer_id
4204            .ok_or_else(|| anyhow!("missing old peer id"))?;
4205        let new_peer_id = envelope
4206            .payload
4207            .new_peer_id
4208            .ok_or_else(|| anyhow!("missing new peer id"))?;
4209        this.update(&mut cx, |this, cx| {
4210            let collaborator = this
4211                .collaborators
4212                .remove(&old_peer_id)
4213                .ok_or_else(|| anyhow!("received UpdateProjectCollaborator for unknown peer"))?;
4214            let is_host = collaborator.is_host;
4215            this.collaborators.insert(new_peer_id, collaborator);
4216
4217            log::info!("peer {} became {}", old_peer_id, new_peer_id,);
4218            this.buffer_store.update(cx, |buffer_store, _| {
4219                buffer_store.update_peer_id(&old_peer_id, new_peer_id)
4220            });
4221
4222            if is_host {
4223                this.buffer_store
4224                    .update(cx, |buffer_store, _| buffer_store.discard_incomplete());
4225                this.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync)
4226                    .unwrap();
4227                cx.emit(Event::HostReshared);
4228            }
4229
4230            cx.emit(Event::CollaboratorUpdated {
4231                old_peer_id,
4232                new_peer_id,
4233            });
4234            Ok(())
4235        })?
4236    }
4237
4238    async fn handle_remove_collaborator(
4239        this: Entity<Self>,
4240        envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4241        mut cx: AsyncApp,
4242    ) -> Result<()> {
4243        this.update(&mut cx, |this, cx| {
4244            let peer_id = envelope
4245                .payload
4246                .peer_id
4247                .ok_or_else(|| anyhow!("invalid peer id"))?;
4248            let replica_id = this
4249                .collaborators
4250                .remove(&peer_id)
4251                .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4252                .replica_id;
4253            this.buffer_store.update(cx, |buffer_store, cx| {
4254                buffer_store.forget_shared_buffers_for(&peer_id);
4255                for buffer in buffer_store.buffers() {
4256                    buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4257                }
4258            });
4259            this.git_store.update(cx, |git_store, _| {
4260                git_store.forget_shared_diffs_for(&peer_id);
4261            });
4262
4263            cx.emit(Event::CollaboratorLeft(peer_id));
4264            Ok(())
4265        })?
4266    }
4267
4268    async fn handle_update_project(
4269        this: Entity<Self>,
4270        envelope: TypedEnvelope<proto::UpdateProject>,
4271        mut cx: AsyncApp,
4272    ) -> Result<()> {
4273        this.update(&mut cx, |this, cx| {
4274            // Don't handle messages that were sent before the response to us joining the project
4275            if envelope.message_id > this.join_project_response_message_id {
4276                this.set_worktrees_from_proto(envelope.payload.worktrees, cx)?;
4277            }
4278            Ok(())
4279        })?
4280    }
4281
4282    async fn handle_toast(
4283        this: Entity<Self>,
4284        envelope: TypedEnvelope<proto::Toast>,
4285        mut cx: AsyncApp,
4286    ) -> Result<()> {
4287        this.update(&mut cx, |_, cx| {
4288            cx.emit(Event::Toast {
4289                notification_id: envelope.payload.notification_id.into(),
4290                message: envelope.payload.message,
4291            });
4292            Ok(())
4293        })?
4294    }
4295
4296    async fn handle_language_server_prompt_request(
4297        this: Entity<Self>,
4298        envelope: TypedEnvelope<proto::LanguageServerPromptRequest>,
4299        mut cx: AsyncApp,
4300    ) -> Result<proto::LanguageServerPromptResponse> {
4301        let (tx, mut rx) = smol::channel::bounded(1);
4302        let actions: Vec<_> = envelope
4303            .payload
4304            .actions
4305            .into_iter()
4306            .map(|action| MessageActionItem {
4307                title: action,
4308                properties: Default::default(),
4309            })
4310            .collect();
4311        this.update(&mut cx, |_, cx| {
4312            cx.emit(Event::LanguageServerPrompt(LanguageServerPromptRequest {
4313                level: proto_to_prompt(envelope.payload.level.context("Invalid prompt level")?),
4314                message: envelope.payload.message,
4315                actions: actions.clone(),
4316                lsp_name: envelope.payload.lsp_name,
4317                response_channel: tx,
4318            }));
4319
4320            anyhow::Ok(())
4321        })??;
4322
4323        // We drop `this` to avoid holding a reference in this future for too
4324        // long.
4325        // If we keep the reference, we might not drop the `Project` early
4326        // enough when closing a window and it will only get releases on the
4327        // next `flush_effects()` call.
4328        drop(this);
4329
4330        let mut rx = pin!(rx);
4331        let answer = rx.next().await;
4332
4333        Ok(LanguageServerPromptResponse {
4334            action_response: answer.and_then(|answer| {
4335                actions
4336                    .iter()
4337                    .position(|action| *action == answer)
4338                    .map(|index| index as u64)
4339            }),
4340        })
4341    }
4342
4343    async fn handle_hide_toast(
4344        this: Entity<Self>,
4345        envelope: TypedEnvelope<proto::HideToast>,
4346        mut cx: AsyncApp,
4347    ) -> Result<()> {
4348        this.update(&mut cx, |_, cx| {
4349            cx.emit(Event::HideToast {
4350                notification_id: envelope.payload.notification_id.into(),
4351            });
4352            Ok(())
4353        })?
4354    }
4355
4356    // Collab sends UpdateWorktree protos as messages
4357    async fn handle_update_worktree(
4358        this: Entity<Self>,
4359        envelope: TypedEnvelope<proto::UpdateWorktree>,
4360        mut cx: AsyncApp,
4361    ) -> Result<()> {
4362        this.update(&mut cx, |this, cx| {
4363            let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4364            if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4365                worktree.update(cx, |worktree, _| {
4366                    let worktree = worktree.as_remote_mut().unwrap();
4367                    worktree.update_from_remote(envelope.payload);
4368                });
4369            }
4370            Ok(())
4371        })?
4372    }
4373
4374    async fn handle_update_buffer_from_ssh(
4375        this: Entity<Self>,
4376        envelope: TypedEnvelope<proto::UpdateBuffer>,
4377        cx: AsyncApp,
4378    ) -> Result<proto::Ack> {
4379        let buffer_store = this.read_with(&cx, |this, cx| {
4380            if let Some(remote_id) = this.remote_id() {
4381                let mut payload = envelope.payload.clone();
4382                payload.project_id = remote_id;
4383                cx.background_spawn(this.client.request(payload))
4384                    .detach_and_log_err(cx);
4385            }
4386            this.buffer_store.clone()
4387        })?;
4388        BufferStore::handle_update_buffer(buffer_store, envelope, cx).await
4389    }
4390
4391    async fn handle_update_buffer(
4392        this: Entity<Self>,
4393        envelope: TypedEnvelope<proto::UpdateBuffer>,
4394        cx: AsyncApp,
4395    ) -> Result<proto::Ack> {
4396        let buffer_store = this.read_with(&cx, |this, cx| {
4397            if let Some(ssh) = &this.ssh_client {
4398                let mut payload = envelope.payload.clone();
4399                payload.project_id = SSH_PROJECT_ID;
4400                cx.background_spawn(ssh.read(cx).proto_client().request(payload))
4401                    .detach_and_log_err(cx);
4402            }
4403            this.buffer_store.clone()
4404        })?;
4405        BufferStore::handle_update_buffer(buffer_store, envelope, cx).await
4406    }
4407
4408    fn retain_remotely_created_models(
4409        &mut self,
4410        cx: &mut Context<Self>,
4411    ) -> RemotelyCreatedModelGuard {
4412        {
4413            let mut remotely_create_models = self.remotely_created_models.lock();
4414            if remotely_create_models.retain_count == 0 {
4415                remotely_create_models.buffers = self.buffer_store.read(cx).buffers().collect();
4416                remotely_create_models.worktrees =
4417                    self.worktree_store.read(cx).worktrees().collect();
4418            }
4419            remotely_create_models.retain_count += 1;
4420        }
4421        RemotelyCreatedModelGuard {
4422            remote_models: Arc::downgrade(&self.remotely_created_models),
4423        }
4424    }
4425
4426    async fn handle_create_buffer_for_peer(
4427        this: Entity<Self>,
4428        envelope: TypedEnvelope<proto::CreateBufferForPeer>,
4429        mut cx: AsyncApp,
4430    ) -> Result<()> {
4431        this.update(&mut cx, |this, cx| {
4432            this.buffer_store.update(cx, |buffer_store, cx| {
4433                buffer_store.handle_create_buffer_for_peer(
4434                    envelope,
4435                    this.replica_id(),
4436                    this.capability(),
4437                    cx,
4438                )
4439            })
4440        })?
4441    }
4442
4443    async fn handle_synchronize_buffers(
4444        this: Entity<Self>,
4445        envelope: TypedEnvelope<proto::SynchronizeBuffers>,
4446        mut cx: AsyncApp,
4447    ) -> Result<proto::SynchronizeBuffersResponse> {
4448        let response = this.update(&mut cx, |this, cx| {
4449            let client = this.client.clone();
4450            this.buffer_store.update(cx, |this, cx| {
4451                this.handle_synchronize_buffers(envelope, cx, client)
4452            })
4453        })??;
4454
4455        Ok(response)
4456    }
4457
4458    async fn handle_search_candidate_buffers(
4459        this: Entity<Self>,
4460        envelope: TypedEnvelope<proto::FindSearchCandidates>,
4461        mut cx: AsyncApp,
4462    ) -> Result<proto::FindSearchCandidatesResponse> {
4463        let peer_id = envelope.original_sender_id()?;
4464        let message = envelope.payload;
4465        let query = SearchQuery::from_proto(
4466            message
4467                .query
4468                .ok_or_else(|| anyhow!("missing query field"))?,
4469        )?;
4470        let results = this.update(&mut cx, |this, cx| {
4471            this.find_search_candidate_buffers(&query, message.limit as _, cx)
4472        })?;
4473
4474        let mut response = proto::FindSearchCandidatesResponse {
4475            buffer_ids: Vec::new(),
4476        };
4477
4478        while let Ok(buffer) = results.recv().await {
4479            this.update(&mut cx, |this, cx| {
4480                let buffer_id = this.create_buffer_for_peer(&buffer, peer_id, cx);
4481                response.buffer_ids.push(buffer_id.to_proto());
4482            })?;
4483        }
4484
4485        Ok(response)
4486    }
4487
4488    async fn handle_open_buffer_by_id(
4489        this: Entity<Self>,
4490        envelope: TypedEnvelope<proto::OpenBufferById>,
4491        mut cx: AsyncApp,
4492    ) -> Result<proto::OpenBufferResponse> {
4493        let peer_id = envelope.original_sender_id()?;
4494        let buffer_id = BufferId::new(envelope.payload.id)?;
4495        let buffer = this
4496            .update(&mut cx, |this, cx| this.open_buffer_by_id(buffer_id, cx))?
4497            .await?;
4498        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4499    }
4500
4501    async fn handle_open_buffer_by_path(
4502        this: Entity<Self>,
4503        envelope: TypedEnvelope<proto::OpenBufferByPath>,
4504        mut cx: AsyncApp,
4505    ) -> Result<proto::OpenBufferResponse> {
4506        let peer_id = envelope.original_sender_id()?;
4507        let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4508        let open_buffer = this.update(&mut cx, |this, cx| {
4509            this.open_buffer(
4510                ProjectPath {
4511                    worktree_id,
4512                    path: Arc::<Path>::from_proto(envelope.payload.path),
4513                },
4514                cx,
4515            )
4516        })?;
4517
4518        let buffer = open_buffer.await?;
4519        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4520    }
4521
4522    async fn handle_open_new_buffer(
4523        this: Entity<Self>,
4524        envelope: TypedEnvelope<proto::OpenNewBuffer>,
4525        mut cx: AsyncApp,
4526    ) -> Result<proto::OpenBufferResponse> {
4527        let buffer = this
4528            .update(&mut cx, |this, cx| this.create_buffer(cx))?
4529            .await?;
4530        let peer_id = envelope.original_sender_id()?;
4531
4532        Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
4533    }
4534
4535    fn respond_to_open_buffer_request(
4536        this: Entity<Self>,
4537        buffer: Entity<Buffer>,
4538        peer_id: proto::PeerId,
4539        cx: &mut AsyncApp,
4540    ) -> Result<proto::OpenBufferResponse> {
4541        this.update(cx, |this, cx| {
4542            let is_private = buffer
4543                .read(cx)
4544                .file()
4545                .map(|f| f.is_private())
4546                .unwrap_or_default();
4547            if is_private {
4548                Err(anyhow!(ErrorCode::UnsharedItem))
4549            } else {
4550                Ok(proto::OpenBufferResponse {
4551                    buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx).into(),
4552                })
4553            }
4554        })?
4555    }
4556
4557    fn create_buffer_for_peer(
4558        &mut self,
4559        buffer: &Entity<Buffer>,
4560        peer_id: proto::PeerId,
4561        cx: &mut App,
4562    ) -> BufferId {
4563        self.buffer_store
4564            .update(cx, |buffer_store, cx| {
4565                buffer_store.create_buffer_for_peer(buffer, peer_id, cx)
4566            })
4567            .detach_and_log_err(cx);
4568        buffer.read(cx).remote_id()
4569    }
4570
4571    fn synchronize_remote_buffers(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
4572        let project_id = match self.client_state {
4573            ProjectClientState::Remote {
4574                sharing_has_stopped,
4575                remote_id,
4576                ..
4577            } => {
4578                if sharing_has_stopped {
4579                    return Task::ready(Err(anyhow!(
4580                        "can't synchronize remote buffers on a readonly project"
4581                    )));
4582                } else {
4583                    remote_id
4584                }
4585            }
4586            ProjectClientState::Shared { .. } | ProjectClientState::Local => {
4587                return Task::ready(Err(anyhow!(
4588                    "can't synchronize remote buffers on a local project"
4589                )));
4590            }
4591        };
4592
4593        let client = self.client.clone();
4594        cx.spawn(async move |this, cx| {
4595            let (buffers, incomplete_buffer_ids) = this.update(cx, |this, cx| {
4596                this.buffer_store.read(cx).buffer_version_info(cx)
4597            })?;
4598            let response = client
4599                .request(proto::SynchronizeBuffers {
4600                    project_id,
4601                    buffers,
4602                })
4603                .await?;
4604
4605            let send_updates_for_buffers = this.update(cx, |this, cx| {
4606                response
4607                    .buffers
4608                    .into_iter()
4609                    .map(|buffer| {
4610                        let client = client.clone();
4611                        let buffer_id = match BufferId::new(buffer.id) {
4612                            Ok(id) => id,
4613                            Err(e) => {
4614                                return Task::ready(Err(e));
4615                            }
4616                        };
4617                        let remote_version = language::proto::deserialize_version(&buffer.version);
4618                        if let Some(buffer) = this.buffer_for_id(buffer_id, cx) {
4619                            let operations =
4620                                buffer.read(cx).serialize_ops(Some(remote_version), cx);
4621                            cx.background_spawn(async move {
4622                                let operations = operations.await;
4623                                for chunk in split_operations(operations) {
4624                                    client
4625                                        .request(proto::UpdateBuffer {
4626                                            project_id,
4627                                            buffer_id: buffer_id.into(),
4628                                            operations: chunk,
4629                                        })
4630                                        .await?;
4631                                }
4632                                anyhow::Ok(())
4633                            })
4634                        } else {
4635                            Task::ready(Ok(()))
4636                        }
4637                    })
4638                    .collect::<Vec<_>>()
4639            })?;
4640
4641            // Any incomplete buffers have open requests waiting. Request that the host sends
4642            // creates these buffers for us again to unblock any waiting futures.
4643            for id in incomplete_buffer_ids {
4644                cx.background_spawn(client.request(proto::OpenBufferById {
4645                    project_id,
4646                    id: id.into(),
4647                }))
4648                .detach();
4649            }
4650
4651            futures::future::join_all(send_updates_for_buffers)
4652                .await
4653                .into_iter()
4654                .collect()
4655        })
4656    }
4657
4658    pub fn worktree_metadata_protos(&self, cx: &App) -> Vec<proto::WorktreeMetadata> {
4659        self.worktree_store.read(cx).worktree_metadata_protos(cx)
4660    }
4661
4662    /// Iterator of all open buffers that have unsaved changes
4663    pub fn dirty_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = ProjectPath> + 'a {
4664        self.buffer_store.read(cx).buffers().filter_map(|buf| {
4665            let buf = buf.read(cx);
4666            if buf.is_dirty() {
4667                buf.project_path(cx)
4668            } else {
4669                None
4670            }
4671        })
4672    }
4673
4674    fn set_worktrees_from_proto(
4675        &mut self,
4676        worktrees: Vec<proto::WorktreeMetadata>,
4677        cx: &mut Context<Project>,
4678    ) -> Result<()> {
4679        self.worktree_store.update(cx, |worktree_store, cx| {
4680            worktree_store.set_worktrees_from_proto(worktrees, self.replica_id(), cx)
4681        })
4682    }
4683
4684    fn set_collaborators_from_proto(
4685        &mut self,
4686        messages: Vec<proto::Collaborator>,
4687        cx: &mut Context<Self>,
4688    ) -> Result<()> {
4689        let mut collaborators = HashMap::default();
4690        for message in messages {
4691            let collaborator = Collaborator::from_proto(message)?;
4692            collaborators.insert(collaborator.peer_id, collaborator);
4693        }
4694        for old_peer_id in self.collaborators.keys() {
4695            if !collaborators.contains_key(old_peer_id) {
4696                cx.emit(Event::CollaboratorLeft(*old_peer_id));
4697            }
4698        }
4699        self.collaborators = collaborators;
4700        Ok(())
4701    }
4702
4703    pub fn supplementary_language_servers<'a>(
4704        &'a self,
4705        cx: &'a App,
4706    ) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName)> {
4707        self.lsp_store.read(cx).supplementary_language_servers()
4708    }
4709
4710    pub fn any_language_server_supports_inlay_hints(&self, buffer: &Buffer, cx: &mut App) -> bool {
4711        self.lsp_store.update(cx, |this, cx| {
4712            this.language_servers_for_local_buffer(buffer, cx)
4713                .any(
4714                    |(_, server)| match server.capabilities().inlay_hint_provider {
4715                        Some(lsp::OneOf::Left(enabled)) => enabled,
4716                        Some(lsp::OneOf::Right(_)) => true,
4717                        None => false,
4718                    },
4719                )
4720        })
4721    }
4722
4723    pub fn language_server_id_for_name(
4724        &self,
4725        buffer: &Buffer,
4726        name: &str,
4727        cx: &mut App,
4728    ) -> Task<Option<LanguageServerId>> {
4729        if self.is_local() {
4730            Task::ready(self.lsp_store.update(cx, |lsp_store, cx| {
4731                lsp_store
4732                    .language_servers_for_local_buffer(buffer, cx)
4733                    .find_map(|(adapter, server)| {
4734                        if adapter.name.0 == name {
4735                            Some(server.server_id())
4736                        } else {
4737                            None
4738                        }
4739                    })
4740            }))
4741        } else if let Some(project_id) = self.remote_id() {
4742            let request = self.client.request(proto::LanguageServerIdForName {
4743                project_id,
4744                buffer_id: buffer.remote_id().to_proto(),
4745                name: name.to_string(),
4746            });
4747            cx.background_spawn(async move {
4748                let response = request.await.log_err()?;
4749                response.server_id.map(LanguageServerId::from_proto)
4750            })
4751        } else if let Some(ssh_client) = self.ssh_client.as_ref() {
4752            let request =
4753                ssh_client
4754                    .read(cx)
4755                    .proto_client()
4756                    .request(proto::LanguageServerIdForName {
4757                        project_id: SSH_PROJECT_ID,
4758                        buffer_id: buffer.remote_id().to_proto(),
4759                        name: name.to_string(),
4760                    });
4761            cx.background_spawn(async move {
4762                let response = request.await.log_err()?;
4763                response.server_id.map(LanguageServerId::from_proto)
4764            })
4765        } else {
4766            Task::ready(None)
4767        }
4768    }
4769
4770    pub fn has_language_servers_for(&self, buffer: &Buffer, cx: &mut App) -> bool {
4771        self.lsp_store.update(cx, |this, cx| {
4772            this.language_servers_for_local_buffer(buffer, cx)
4773                .next()
4774                .is_some()
4775        })
4776    }
4777
4778    pub fn git_init(
4779        &self,
4780        path: Arc<Path>,
4781        fallback_branch_name: String,
4782        cx: &App,
4783    ) -> Task<Result<()>> {
4784        self.git_store
4785            .read(cx)
4786            .git_init(path, fallback_branch_name, cx)
4787    }
4788
4789    pub fn buffer_store(&self) -> &Entity<BufferStore> {
4790        &self.buffer_store
4791    }
4792
4793    pub fn git_store(&self) -> &Entity<GitStore> {
4794        &self.git_store
4795    }
4796
4797    pub fn active_repository(&self, cx: &App) -> Option<Entity<Repository>> {
4798        self.git_store.read(cx).active_repository()
4799    }
4800
4801    pub fn repositories<'a>(&self, cx: &'a App) -> &'a HashMap<RepositoryId, Entity<Repository>> {
4802        self.git_store.read(cx).repositories()
4803    }
4804
4805    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
4806        self.git_store.read(cx).status_for_buffer_id(buffer_id, cx)
4807    }
4808}
4809
4810pub struct PathMatchCandidateSet {
4811    pub snapshot: Snapshot,
4812    pub include_ignored: bool,
4813    pub include_root_name: bool,
4814    pub candidates: Candidates,
4815}
4816
4817pub enum Candidates {
4818    /// Only consider directories.
4819    Directories,
4820    /// Only consider files.
4821    Files,
4822    /// Consider directories and files.
4823    Entries,
4824}
4825
4826impl<'a> fuzzy::PathMatchCandidateSet<'a> for PathMatchCandidateSet {
4827    type Candidates = PathMatchCandidateSetIter<'a>;
4828
4829    fn id(&self) -> usize {
4830        self.snapshot.id().to_usize()
4831    }
4832
4833    fn len(&self) -> usize {
4834        match self.candidates {
4835            Candidates::Files => {
4836                if self.include_ignored {
4837                    self.snapshot.file_count()
4838                } else {
4839                    self.snapshot.visible_file_count()
4840                }
4841            }
4842
4843            Candidates::Directories => {
4844                if self.include_ignored {
4845                    self.snapshot.dir_count()
4846                } else {
4847                    self.snapshot.visible_dir_count()
4848                }
4849            }
4850
4851            Candidates::Entries => {
4852                if self.include_ignored {
4853                    self.snapshot.entry_count()
4854                } else {
4855                    self.snapshot.visible_entry_count()
4856                }
4857            }
4858        }
4859    }
4860
4861    fn prefix(&self) -> Arc<str> {
4862        if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
4863            self.snapshot.root_name().into()
4864        } else if self.include_root_name {
4865            format!("{}{}", self.snapshot.root_name(), std::path::MAIN_SEPARATOR).into()
4866        } else {
4867            Arc::default()
4868        }
4869    }
4870
4871    fn candidates(&'a self, start: usize) -> Self::Candidates {
4872        PathMatchCandidateSetIter {
4873            traversal: match self.candidates {
4874                Candidates::Directories => self.snapshot.directories(self.include_ignored, start),
4875                Candidates::Files => self.snapshot.files(self.include_ignored, start),
4876                Candidates::Entries => self.snapshot.entries(self.include_ignored, start),
4877            },
4878        }
4879    }
4880}
4881
4882pub struct PathMatchCandidateSetIter<'a> {
4883    traversal: Traversal<'a>,
4884}
4885
4886impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
4887    type Item = fuzzy::PathMatchCandidate<'a>;
4888
4889    fn next(&mut self) -> Option<Self::Item> {
4890        self.traversal
4891            .next()
4892            .map(|entry| fuzzy::PathMatchCandidate {
4893                is_dir: entry.kind.is_dir(),
4894                path: &entry.path,
4895                char_bag: entry.char_bag,
4896            })
4897    }
4898}
4899
4900impl EventEmitter<Event> for Project {}
4901
4902impl<'a> From<&'a ProjectPath> for SettingsLocation<'a> {
4903    fn from(val: &'a ProjectPath) -> Self {
4904        SettingsLocation {
4905            worktree_id: val.worktree_id,
4906            path: val.path.as_ref(),
4907        }
4908    }
4909}
4910
4911impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
4912    fn from((worktree_id, path): (WorktreeId, P)) -> Self {
4913        Self {
4914            worktree_id,
4915            path: path.as_ref().into(),
4916        }
4917    }
4918}
4919
4920pub fn relativize_path(base: &Path, path: &Path) -> PathBuf {
4921    let mut path_components = path.components();
4922    let mut base_components = base.components();
4923    let mut components: Vec<Component> = Vec::new();
4924    loop {
4925        match (path_components.next(), base_components.next()) {
4926            (None, None) => break,
4927            (Some(a), None) => {
4928                components.push(a);
4929                components.extend(path_components.by_ref());
4930                break;
4931            }
4932            (None, _) => components.push(Component::ParentDir),
4933            (Some(a), Some(b)) if components.is_empty() && a == b => (),
4934            (Some(a), Some(Component::CurDir)) => components.push(a),
4935            (Some(a), Some(_)) => {
4936                components.push(Component::ParentDir);
4937                for _ in base_components {
4938                    components.push(Component::ParentDir);
4939                }
4940                components.push(a);
4941                components.extend(path_components.by_ref());
4942                break;
4943            }
4944        }
4945    }
4946    components.iter().map(|c| c.as_os_str()).collect()
4947}
4948
4949fn resolve_path(base: &Path, path: &Path) -> PathBuf {
4950    let mut result = base.to_path_buf();
4951    for component in path.components() {
4952        match component {
4953            Component::ParentDir => {
4954                result.pop();
4955            }
4956            Component::CurDir => (),
4957            _ => result.push(component),
4958        }
4959    }
4960    result
4961}
4962
4963/// ResolvedPath is a path that has been resolved to either a ProjectPath
4964/// or an AbsPath and that *exists*.
4965#[derive(Debug, Clone)]
4966pub enum ResolvedPath {
4967    ProjectPath {
4968        project_path: ProjectPath,
4969        is_dir: bool,
4970    },
4971    AbsPath {
4972        path: PathBuf,
4973        is_dir: bool,
4974    },
4975}
4976
4977impl ResolvedPath {
4978    pub fn abs_path(&self) -> Option<&Path> {
4979        match self {
4980            Self::AbsPath { path, .. } => Some(path.as_path()),
4981            _ => None,
4982        }
4983    }
4984
4985    pub fn project_path(&self) -> Option<&ProjectPath> {
4986        match self {
4987            Self::ProjectPath { project_path, .. } => Some(&project_path),
4988            _ => None,
4989        }
4990    }
4991
4992    pub fn is_file(&self) -> bool {
4993        !self.is_dir()
4994    }
4995
4996    pub fn is_dir(&self) -> bool {
4997        match self {
4998            Self::ProjectPath { is_dir, .. } => *is_dir,
4999            Self::AbsPath { is_dir, .. } => *is_dir,
5000        }
5001    }
5002}
5003
5004impl ProjectItem for Buffer {
5005    fn try_open(
5006        project: &Entity<Project>,
5007        path: &ProjectPath,
5008        cx: &mut App,
5009    ) -> Option<Task<Result<Entity<Self>>>> {
5010        Some(project.update(cx, |project, cx| project.open_buffer(path.clone(), cx)))
5011    }
5012
5013    fn entry_id(&self, cx: &App) -> Option<ProjectEntryId> {
5014        File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
5015    }
5016
5017    fn project_path(&self, cx: &App) -> Option<ProjectPath> {
5018        self.file().map(|file| ProjectPath {
5019            worktree_id: file.worktree_id(cx),
5020            path: file.path().clone(),
5021        })
5022    }
5023
5024    fn is_dirty(&self) -> bool {
5025        self.is_dirty()
5026    }
5027}
5028
5029impl Completion {
5030    /// A key that can be used to sort completions when displaying
5031    /// them to the user.
5032    pub fn sort_key(&self) -> (usize, &str) {
5033        const DEFAULT_KIND_KEY: usize = 2;
5034        let kind_key = self
5035            .source
5036            // `lsp::CompletionListItemDefaults` has no `kind` field
5037            .lsp_completion(false)
5038            .and_then(|lsp_completion| lsp_completion.kind)
5039            .and_then(|lsp_completion_kind| match lsp_completion_kind {
5040                lsp::CompletionItemKind::KEYWORD => Some(0),
5041                lsp::CompletionItemKind::VARIABLE => Some(1),
5042                _ => None,
5043            })
5044            .unwrap_or(DEFAULT_KIND_KEY);
5045        (kind_key, &self.label.text[self.label.filter_range.clone()])
5046    }
5047
5048    /// Whether this completion is a snippet.
5049    pub fn is_snippet(&self) -> bool {
5050        self.source
5051            // `lsp::CompletionListItemDefaults` has `insert_text_format` field
5052            .lsp_completion(true)
5053            .map_or(false, |lsp_completion| {
5054                lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
5055            })
5056    }
5057
5058    /// Returns the corresponding color for this completion.
5059    ///
5060    /// Will return `None` if this completion's kind is not [`CompletionItemKind::COLOR`].
5061    pub fn color(&self) -> Option<Hsla> {
5062        // `lsp::CompletionListItemDefaults` has no `kind` field
5063        let lsp_completion = self.source.lsp_completion(false)?;
5064        if lsp_completion.kind? == CompletionItemKind::COLOR {
5065            return color_extractor::extract_color(&lsp_completion);
5066        }
5067        None
5068    }
5069}
5070
5071pub fn sort_worktree_entries(entries: &mut [impl AsRef<Entry>]) {
5072    entries.sort_by(|entry_a, entry_b| {
5073        let entry_a = entry_a.as_ref();
5074        let entry_b = entry_b.as_ref();
5075        compare_paths(
5076            (&entry_a.path, entry_a.is_file()),
5077            (&entry_b.path, entry_b.is_file()),
5078        )
5079    });
5080}
5081
5082fn proto_to_prompt(level: proto::language_server_prompt_request::Level) -> gpui::PromptLevel {
5083    match level {
5084        proto::language_server_prompt_request::Level::Info(_) => gpui::PromptLevel::Info,
5085        proto::language_server_prompt_request::Level::Warning(_) => gpui::PromptLevel::Warning,
5086        proto::language_server_prompt_request::Level::Critical(_) => gpui::PromptLevel::Critical,
5087    }
5088}