5252 lines · 186.4 KB · Rust
RawDownload
pub mod buffer_store;pub mod connection_manager;pub mod debounced_delay;pub mod lsp_command;pub mod lsp_ext_command;pub mod lsp_store;pub mod prettier_store;pub mod project_settings;pub mod search;mod task_inventory;pub mod terminals;pub mod worktree_store; #[cfg(test)]mod project_tests; mod environment;pub mod search_history;mod yarn; use anyhow::{anyhow, Context as _, Result};use buffer_store::{BufferStore, BufferStoreEvent};use client::{    proto, Client, Collaborator, DevServerProjectId, PendingEntitySubscription, ProjectId,    TypedEnvelope, UserStore,};use clock::ReplicaId;use collections::{BTreeSet, HashMap, HashSet};use debounced_delay::DebouncedDelay;pub use environment::ProjectEnvironment;use futures::{    channel::mpsc::{self, UnboundedReceiver},    future::try_join_all,    AsyncWriteExt, FutureExt, StreamExt,}; use git::{blame::Blame, repository::GitRepository};use gpui::{    AnyModel, AppContext, AsyncAppContext, BorrowAppContext, Context, EventEmitter, Model,    ModelContext, SharedString, Task, WeakModel, WindowContext,};use itertools::Itertools;use language::{    language_settings::{        language_settings, FormatOnSave, Formatter, InlayHintKind, LanguageSettings,        SelectedFormatter,    },    proto::{        deserialize_anchor, serialize_anchor, serialize_line_ending, serialize_version,        split_operations,    },    Buffer, BufferEvent, CachedLspAdapter, Capability, CodeLabel, ContextProvider, DiagnosticEntry,    Diff, Documentation, File as _, Language, LanguageRegistry, LanguageServerName, PointUtf16,    ToOffset, ToPointUtf16, Transaction, Unclipped,};use lsp::{CompletionContext, DocumentHighlightKind, LanguageServer, LanguageServerId};use lsp_command::*;use node_runtime::NodeRuntime;use parking_lot::{Mutex, RwLock};use paths::{local_tasks_file_relative_path, local_vscode_tasks_file_relative_path};pub use prettier_store::PrettierStore;use project_settings::{ProjectSettings, SettingsObserver};use remote::SshSession;use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};use search::{SearchInputKind, SearchQuery, SearchResult};use search_history::SearchHistory;use settings::{watch_config_file, Settings, SettingsLocation, SettingsStore};use smol::channel::Receiver;use snippet::Snippet;use snippet_provider::SnippetProvider;use std::{    borrow::Cow,    ops::Range,    path::{Component, Path, PathBuf},    str,    sync::Arc,    time::Duration,};use task::{    static_source::{StaticSource, TrackedFile},    HideStrategy, RevealStrategy, Shell, TaskContext, TaskTemplate, TaskVariables, VariableName,};use terminals::Terminals;use text::{Anchor, BufferId};use util::{defer, paths::compare_paths, ResultExt as _};use worktree::{CreatedEntry, Snapshot, Traversal};use worktree_store::{WorktreeStore, WorktreeStoreEvent}; pub use fs::*;pub use language::Location;#[cfg(any(test, feature = "test-support"))]pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;pub use task_inventory::{    BasicContextProvider, ContextProviderWithTasks, Inventory, TaskSourceKind,};pub use worktree::{    Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,    UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,    FS_WATCH_LATENCY,}; pub use buffer_store::ProjectTransaction;pub use lsp_store::{    DiagnosticSummary, LanguageServerLogType, LanguageServerProgress, LanguageServerPromptRequest,    LanguageServerStatus, LanguageServerToQuery, LspStore, LspStoreEvent,    SERVER_PROGRESS_THROTTLE_TIMEOUT,}; const MAX_PROJECT_SEARCH_HISTORY_SIZE: usize = 500;const MAX_SEARCH_RESULT_FILES: usize = 5_000;const MAX_SEARCH_RESULT_RANGES: usize = 10_000; pub trait Item {    fn try_open(        project: &Model<Project>,        path: &ProjectPath,        cx: &mut AppContext,    ) -> Option<Task<Result<Model<Self>>>>    where        Self: Sized;    fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;} #[derive(Clone)]pub enum OpenedBufferEvent {    Disconnected,    Ok(BufferId),    Err(BufferId, Arc<anyhow::Error>),} /// Semantics-aware entity that is relevant to one or more [`Worktree`] with the files./// `Project` is responsible for tasks, LSP and collab queries, synchronizing worktree states accordingly./// Maps [`Worktree`] entries with its own logic using [`ProjectEntryId`] and [`ProjectPath`] structs.////// Can be either local (for the project opened on the same host) or remote.(for collab projects, browsed by multiple remote users).pub struct Project {    active_entry: Option<ProjectEntryId>,    buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,    languages: Arc<LanguageRegistry>,    client: Arc<client::Client>,    join_project_response_message_id: u32,    user_store: Model<UserStore>,    fs: Arc<dyn Fs>,    ssh_session: Option<Arc<SshSession>>,    client_state: ProjectClientState,    collaborators: HashMap<proto::PeerId, Collaborator>,    client_subscriptions: Vec<client::Subscription>,    worktree_store: Model<WorktreeStore>,    buffer_store: Model<BufferStore>,    lsp_store: Model<LspStore>,    _subscriptions: Vec<gpui::Subscription>,    buffers_needing_diff: HashSet<WeakModel<Buffer>>,    git_diff_debouncer: DebouncedDelay<Self>,    remotely_created_buffers: Arc<Mutex<RemotelyCreatedBuffers>>,    terminals: Terminals,    node: Option<Arc<dyn NodeRuntime>>,    tasks: Model<Inventory>,    hosted_project_id: Option<ProjectId>,    dev_server_project_id: Option<client::DevServerProjectId>,    search_history: SearchHistory,    search_included_history: SearchHistory,    search_excluded_history: SearchHistory,    snippets: Model<SnippetProvider>,    last_formatting_failure: Option<String>,    buffers_being_formatted: HashSet<BufferId>,    environment: Model<ProjectEnvironment>,    settings_observer: Model<SettingsObserver>,} #[derive(Default)]struct RemotelyCreatedBuffers {    buffers: Vec<Model<Buffer>>,    retain_count: usize,} struct RemotelyCreatedBufferGuard {    remote_buffers: std::sync::Weak<Mutex<RemotelyCreatedBuffers>>,} impl Drop for RemotelyCreatedBufferGuard {    fn drop(&mut self) {        if let Some(remote_buffers) = self.remote_buffers.upgrade() {            let mut remote_buffers = remote_buffers.lock();            assert!(                remote_buffers.retain_count > 0,                "RemotelyCreatedBufferGuard dropped too many times"            );            remote_buffers.retain_count -= 1;            if remote_buffers.retain_count == 0 {                remote_buffers.buffers.clear();            }        }    }}/// Message ordered with respect to buffer operations#[derive(Debug)]enum BufferOrderedMessage {    Operation {        buffer_id: BufferId,        operation: proto::Operation,    },    LanguageServerUpdate {        language_server_id: LanguageServerId,        message: proto::update_language_server::Variant,    },    Resync,} #[derive(Debug)]enum ProjectClientState {    Local,    Shared {        remote_id: u64,    },    Remote {        sharing_has_stopped: bool,        capability: Capability,        remote_id: u64,        replica_id: ReplicaId,        in_room: bool,    },} #[derive(Clone, Debug, PartialEq)]pub enum Event {    LanguageServerAdded(LanguageServerId),    LanguageServerRemoved(LanguageServerId),    LanguageServerLog(LanguageServerId, LanguageServerLogType, String),    Notification(String),    LanguageServerPrompt(LanguageServerPromptRequest),    LanguageNotFound(Model<Buffer>),    ActiveEntryChanged(Option<ProjectEntryId>),    ActivateProjectPanel,    WorktreeAdded,    WorktreeOrderChanged,    WorktreeRemoved(WorktreeId),    WorktreeUpdatedEntries(WorktreeId, UpdatedEntriesSet),    WorktreeUpdatedGitRepositories,    DiskBasedDiagnosticsStarted {        language_server_id: LanguageServerId,    },    DiskBasedDiagnosticsFinished {        language_server_id: LanguageServerId,    },    DiagnosticsUpdated {        path: ProjectPath,        language_server_id: LanguageServerId,    },    RemoteIdChanged(Option<u64>),    DisconnectedFromHost,    Closed,    DeletedEntry(ProjectEntryId),    CollaboratorUpdated {        old_peer_id: proto::PeerId,        new_peer_id: proto::PeerId,    },    CollaboratorJoined(proto::PeerId),    CollaboratorLeft(proto::PeerId),    HostReshared,    Reshared,    Rejoined,    RefreshInlayHints,    RevealInProjectPanel(ProjectEntryId),    SnippetEdit(BufferId, Vec<(lsp::Range, Snippet)>),} #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]pub struct ProjectPath {    pub worktree_id: WorktreeId,    pub path: Arc<Path>,} impl ProjectPath {    pub fn from_proto(p: proto::ProjectPath) -> Self {        Self {            worktree_id: WorktreeId::from_proto(p.worktree_id),            path: Arc::from(PathBuf::from(p.path)),        }    }     pub fn to_proto(&self) -> proto::ProjectPath {        proto::ProjectPath {            worktree_id: self.worktree_id.to_proto(),            path: self.path.to_string_lossy().to_string(),        }    }} #[derive(Debug, Clone, PartialEq, Eq)]pub struct InlayHint {    pub position: language::Anchor,    pub label: InlayHintLabel,    pub kind: Option<InlayHintKind>,    pub padding_left: bool,    pub padding_right: bool,    pub tooltip: Option<InlayHintTooltip>,    pub resolve_state: ResolveState,} /// The user's intent behind a given completion confirmation#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]pub enum CompletionIntent {    /// The user intends to 'commit' this result, if possible    /// completion confirmations should run side effects    Complete,    /// The user intends to continue 'composing' this completion    /// completion confirmations should not run side effects and    /// let the user continue composing their action    Compose,} impl CompletionIntent {    pub fn is_complete(&self) -> bool {        self == &Self::Complete    }     pub fn is_compose(&self) -> bool {        self == &Self::Compose    }} /// A completion provided by a language server#[derive(Clone)]pub struct Completion {    /// The range of the buffer that will be replaced.    pub old_range: Range<Anchor>,    /// The new text that will be inserted.    pub new_text: String,    /// A label for this completion that is shown in the menu.    pub label: CodeLabel,    /// The id of the language server that produced this completion.    pub server_id: LanguageServerId,    /// The documentation for this completion.    pub documentation: Option<Documentation>,    /// The raw completion provided by the language server.    pub lsp_completion: lsp::CompletionItem,    /// An optional callback to invoke when this completion is confirmed.    /// Returns, whether new completions should be retriggered after the current one.    /// If `true` is returned, the editor will show a new completion menu after this completion is confirmed.    /// if no confirmation is provided or `false` is returned, the completion will be committed.    pub confirm: Option<Arc<dyn Send + Sync + Fn(CompletionIntent, &mut WindowContext) -> bool>>,} impl std::fmt::Debug for Completion {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        f.debug_struct("Completion")            .field("old_range", &self.old_range)            .field("new_text", &self.new_text)            .field("label", &self.label)            .field("server_id", &self.server_id)            .field("documentation", &self.documentation)            .field("lsp_completion", &self.lsp_completion)            .finish()    }} /// A completion provided by a language server#[derive(Clone, Debug)]pub(crate) struct CoreCompletion {    old_range: Range<Anchor>,    new_text: String,    server_id: LanguageServerId,    lsp_completion: lsp::CompletionItem,} /// A code action provided by a language server.#[derive(Clone, Debug)]pub struct CodeAction {    /// The id of the language server that produced this code action.    pub server_id: LanguageServerId,    /// The range of the buffer where this code action is applicable.    pub range: Range<Anchor>,    /// The raw code action provided by the language server.    pub lsp_action: lsp::CodeAction,} #[derive(Debug, Clone, PartialEq, Eq)]pub enum ResolveState {    Resolved,    CanResolve(LanguageServerId, Option<lsp::LSPAny>),    Resolving,} impl InlayHint {    pub fn text(&self) -> String {        match &self.label {            InlayHintLabel::String(s) => s.to_owned(),            InlayHintLabel::LabelParts(parts) => parts.iter().map(|part| &part.value).join(""),        }    }} #[derive(Debug, Clone, PartialEq, Eq)]pub enum InlayHintLabel {    String(String),    LabelParts(Vec<InlayHintLabelPart>),} #[derive(Debug, Clone, PartialEq, Eq)]pub struct InlayHintLabelPart {    pub value: String,    pub tooltip: Option<InlayHintLabelPartTooltip>,    pub location: Option<(LanguageServerId, lsp::Location)>,} #[derive(Debug, Clone, PartialEq, Eq)]pub enum InlayHintTooltip {    String(String),    MarkupContent(MarkupContent),} #[derive(Debug, Clone, PartialEq, Eq)]pub enum InlayHintLabelPartTooltip {    String(String),    MarkupContent(MarkupContent),} #[derive(Debug, Clone, PartialEq, Eq)]pub struct MarkupContent {    pub kind: HoverBlockKind,    pub value: String,} #[derive(Debug, Clone)]pub struct LocationLink {    pub origin: Option<Location>,    pub target: Location,} #[derive(Debug)]pub struct DocumentHighlight {    pub range: Range<language::Anchor>,    pub kind: DocumentHighlightKind,} #[derive(Clone, Debug)]pub struct Symbol {    pub language_server_name: LanguageServerName,    pub source_worktree_id: WorktreeId,    pub path: ProjectPath,    pub label: CodeLabel,    pub name: String,    pub kind: lsp::SymbolKind,    pub range: Range<Unclipped<PointUtf16>>,    pub signature: [u8; 32],} #[derive(Clone, Debug, PartialEq)]pub struct HoverBlock {    pub text: String,    pub kind: HoverBlockKind,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum HoverBlockKind {    PlainText,    Markdown,    Code { language: String },} #[derive(Debug, Clone)]pub struct Hover {    pub contents: Vec<HoverBlock>,    pub range: Option<Range<language::Anchor>>,    pub language: Option<Arc<Language>>,} impl Hover {    pub fn is_empty(&self) -> bool {        self.contents.iter().all(|block| block.text.is_empty())    }} #[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum FormatTrigger {    Save,    Manual,} // Currently, formatting operations are represented differently depending on// whether they come from a language server or an external command.#[derive(Debug)]enum FormatOperation {    Lsp(Vec<(Range<Anchor>, String)>),    External(Diff),    Prettier(Diff),} impl FormatTrigger {    fn from_proto(value: i32) -> FormatTrigger {        match value {            0 => FormatTrigger::Save,            1 => FormatTrigger::Manual,            _ => FormatTrigger::Save,        }    }} enum EntitySubscription {

Lines 1–500 of 5252.