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