project.rs

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