11585 lines · 440.2 KB · Rust
RawDownload
pub mod buffer_store;pub mod connection_manager;pub mod debounced_delay;pub mod lsp_command;pub mod lsp_ext_command;mod prettier_support;pub mod project_settings;pub mod search;mod task_inventory;pub mod terminals;pub mod worktree_store; #[cfg(test)]mod project_tests; pub mod search_history;mod yarn; use anyhow::{anyhow, bail, Context as _, Result};use async_trait::async_trait;use buffer_store::{BufferStore, BufferStoreEvent};use client::{    proto, Client, Collaborator, DevServerProjectId, PendingEntitySubscription, ProjectId,    TypedEnvelope, UserStore,};use clock::ReplicaId;use collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};use debounced_delay::DebouncedDelay;use futures::{    channel::mpsc::{self, UnboundedReceiver},    future::{join_all, try_join_all, Shared},    select,    stream::FuturesUnordered,    AsyncWriteExt, Future, FutureExt, StreamExt,}; use git::{blame::Blame, repository::GitRepository};use globset::{Glob, GlobSet, GlobSetBuilder};use gpui::{    AnyModel, AppContext, AsyncAppContext, BackgroundExecutor, BorrowAppContext, Context, Entity,    EventEmitter, Model, ModelContext, PromptLevel, SharedString, Task, WeakModel, WindowContext,};use http_client::HttpClient;use itertools::Itertools;use language::{    language_settings::{        language_settings, AllLanguageSettings, FormatOnSave, Formatter, InlayHintKind,        LanguageSettings, SelectedFormatter,    },    markdown, point_to_lsp, prepare_completion_documentation,    proto::{        deserialize_anchor, deserialize_version, serialize_anchor, serialize_line_ending,        serialize_version, split_operations,    },    range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,    ContextProvider, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, Documentation,    Event as BufferEvent, File as _, Language, LanguageRegistry, LanguageServerName, LocalFile,    LspAdapterDelegate, Patch, PendingLanguageServer, PointUtf16, TextBufferSnapshot, ToOffset,    ToPointUtf16, Transaction, Unclipped,};use log::error;use lsp::{    CompletionContext, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,    DocumentHighlightKind, Edit, FileSystemWatcher, InsertTextFormat, LanguageServer,    LanguageServerBinary, LanguageServerId, LspRequestFuture, MessageActionItem, OneOf,    ServerHealthStatus, ServerStatus, TextEdit, WorkDoneProgressCancelParams,};use lsp_command::*;use node_runtime::NodeRuntime;use parking_lot::{Mutex, RwLock};use paths::{    local_settings_file_relative_path, local_tasks_file_relative_path,    local_vscode_tasks_file_relative_path,};use postage::watch;use prettier_support::{DefaultPrettier, PrettierInstance};use project_settings::{DirenvSettings, LspSettings, ProjectSettings};use rand::prelude::*;use remote::SshSession;use rpc::{proto::AddWorktree, ErrorCode};use search::SearchQuery;use search_history::SearchHistory;use serde::Serialize;use settings::{watch_config_file, Settings, SettingsLocation, SettingsStore};use sha2::{Digest, Sha256};use similar::{ChangeTag, TextDiff};use smol::{    channel::{Receiver, Sender},    lock::Semaphore,};use snippet::Snippet;use snippet_provider::SnippetProvider;use std::{    borrow::Cow,    cell::RefCell,    cmp::{self, Ordering},    convert::TryInto,    env,    ffi::OsStr,    hash::Hash,    iter, mem,    ops::Range,    path::{self, Component, Path, PathBuf},    process::Stdio,    str,    sync::{        atomic::{AtomicUsize, Ordering::SeqCst},        Arc,    },    time::{Duration, Instant},};use task::{    static_source::{StaticSource, TrackedFile},    HideStrategy, RevealStrategy, Shell, TaskContext, TaskTemplate, TaskVariables, VariableName,};use terminals::Terminals;use text::{Anchor, BufferId, LineEnding};use util::{    debug_panic, defer, maybe, merge_json_value_into, parse_env_output, paths::compare_paths,    post_inc, ResultExt, TryFutureExt as _,};use worktree::{CreatedEntry, Snapshot, Traversal};use worktree_store::{WorktreeStore, WorktreeStoreEvent};use yarn::YarnPathStore; 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,}; const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4;const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100); const MAX_PROJECT_SEARCH_HISTORY_SIZE: usize = 500; 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>,    supplementary_language_servers:        HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,    language_servers: HashMap<LanguageServerId, LanguageServerState>,    language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,    language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,    last_formatting_failure: Option<String>,    last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,    language_server_watched_paths: HashMap<LanguageServerId, HashMap<WorktreeId, GlobSet>>,    language_server_watcher_registrations:        HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,    client: Arc<client::Client>,    next_entry_id: Arc<AtomicUsize>,    join_project_response_message_id: u32,    next_diagnostic_group_id: usize,    diagnostic_summaries:        HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,    diagnostics: HashMap<        WorktreeId,        HashMap<            Arc<Path>,            Vec<(                LanguageServerId,                Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,            )>,        >,    >,    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>,    _subscriptions: Vec<gpui::Subscription>,    shared_buffers: HashMap<proto::PeerId, HashSet<BufferId>>,    #[allow(clippy::type_complexity)]    loading_worktrees:        HashMap<Arc<Path>, Shared<Task<Result<Model<Worktree>, Arc<anyhow::Error>>>>>,    buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots    buffers_being_formatted: HashSet<BufferId>,    buffers_needing_diff: HashSet<WeakModel<Buffer>>,    git_diff_debouncer: DebouncedDelay<Self>,    nonce: u128,    _maintain_buffer_languages: Task<()>,    _maintain_workspace_config: Task<Result<()>>,    terminals: Terminals,    current_lsp_settings: HashMap<Arc<str>, LspSettings>,    node: Option<Arc<dyn NodeRuntime>>,    default_prettier: DefaultPrettier,    prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>,    prettier_instances: HashMap<PathBuf, PrettierInstance>,    tasks: Model<Inventory>,    hosted_project_id: Option<ProjectId>,    dev_server_project_id: Option<client::DevServerProjectId>,    search_history: SearchHistory,    snippets: Model<SnippetProvider>,    yarn: Model<YarnPathStore>,    cached_shell_environments: HashMap<WorktreeId, HashMap<String, String>>,} #[derive(Debug)]pub enum LanguageServerToQuery {    Primary,    Other(LanguageServerId),} struct LspBufferSnapshot {    version: i32,    snapshot: TextBufferSnapshot,} /// 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 LocalProjectUpdate {    WorktreesChanged,    CreateBufferForPeer {        peer_id: proto::PeerId,        buffer_id: BufferId,    },} #[derive(Debug)]enum ProjectClientState {    Local,    Shared {        remote_id: u64,        updates_tx: mpsc::UnboundedSender<LocalProjectUpdate>,        _send_updates: Task<Result<()>>,    },    Remote {        sharing_has_stopped: bool,        capability: Capability,        remote_id: u64,        replica_id: ReplicaId,        in_room: bool,    },} /// A prompt requested by LSP server.#[derive(Clone, Debug)]pub struct LanguageServerPromptRequest {    pub level: PromptLevel,    pub message: String,    pub actions: Vec<MessageActionItem>,    pub lsp_name: String,    response_channel: Sender<MessageActionItem>,} impl LanguageServerPromptRequest {    pub async fn respond(self, index: usize) -> Option<()> {        if let Some(response) = self.actions.into_iter().nth(index) {            self.response_channel.send(response).await.ok()        } else {            None        }    }}impl PartialEq for LanguageServerPromptRequest {    fn eq(&self, other: &Self) -> bool {        self.message == other.message && self.actions == other.actions    }} #[derive(Clone, Debug, PartialEq)]pub enum Event {    LanguageServerAdded(LanguageServerId),    LanguageServerRemoved(LanguageServerId),    LanguageServerLog(LanguageServerId, 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)>),} pub enum LanguageServerState {    Starting(Task<Option<Arc<LanguageServer>>>),     Running {        language: Arc<Language>,        adapter: Arc<CachedLspAdapter>,        server: Arc<LanguageServer>,        simulate_disk_based_diagnostics_completion: Option<Task<()>>,    },} #[derive(Clone, Debug, Serialize)]pub struct LanguageServerStatus {    pub name: String,    pub pending_work: BTreeMap<String, LanguageServerProgress>,    pub has_pending_diagnostic_updates: bool,    progress_tokens: HashSet<String>,} #[derive(Clone, Debug, Serialize)]pub struct LanguageServerProgress {    pub is_disk_based_diagnostics_progress: bool,    pub is_cancellable: bool,    pub title: Option<String>,    pub message: Option<String>,    pub percentage: Option<usize>,    #[serde(skip_serializing)]    pub last_update_at: Instant,} #[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)]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,} 

Lines 1–500 of 11585.