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