project.rs

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