10587 lines · 418.1 KB · Rust
RawDownload
pub mod clangd_ext;pub mod lsp_ext_command;pub mod rust_analyzer_ext; use crate::{    CodeAction, Completion, CompletionResponse, CompletionSource, CoreCompletion, Hover, InlayHint,    LspAction, ProjectItem, ProjectPath, ProjectTransaction, ResolveState, Symbol, ToolchainStore,    buffer_store::{BufferStore, BufferStoreEvent},    environment::ProjectEnvironment,    lsp_command::{self, *},    lsp_store,    manifest_tree::{        AdapterQuery, LanguageServerTree, LanguageServerTreeNode, LaunchDisposition,        ManifestQueryDelegate, ManifestTree,    },    prettier_store::{self, PrettierStore, PrettierStoreEvent},    project_settings::{LspSettings, ProjectSettings},    relativize_path, resolve_path,    toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},    worktree_store::{WorktreeStore, WorktreeStoreEvent},    yarn::YarnPathStore,};use anyhow::{Context as _, Result, anyhow};use async_trait::async_trait;use client::{TypedEnvelope, proto};use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};use futures::{    AsyncWriteExt, Future, FutureExt, StreamExt,    future::{Shared, join_all},    select, select_biased,    stream::FuturesUnordered,};use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};use gpui::{    App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,    WeakEntity,};use http_client::HttpClient;use itertools::Itertools as _;use language::{    Bias, BinaryStatus, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,    DiagnosticEntry, DiagnosticSet, Diff, File as _, Language, LanguageName, LanguageRegistry,    LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate, Patch, PointUtf16,    TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,    language_settings::{        FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,    },    point_to_lsp,    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},    range_from_lsp, range_to_lsp,};use lsp::{    CodeActionKind, CompletionContext, DiagnosticSeverity, DiagnosticTag,    DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,    FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,    LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,    LspRequestFuture, MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,    TextEdit, WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder,    notification::DidRenameFiles,};use node_runtime::read_package_installed_version;use parking_lot::Mutex;use postage::watch;use rand::prelude::*; use rpc::{    AnyProtoClient,    proto::{FromProto, ToProto},};use serde::Serialize;use settings::{Settings, SettingsLocation, SettingsStore};use sha2::{Digest, Sha256};use smol::channel::Sender;use snippet::Snippet;use std::{    any::Any,    borrow::Cow,    cell::RefCell,    cmp::{Ordering, Reverse},    convert::TryInto,    ffi::OsStr,    iter, mem,    ops::{ControlFlow, Range},    path::{self, Path, PathBuf},    rc::Rc,    sync::Arc,    time::{Duration, Instant},};use text::{Anchor, BufferId, LineEnding, OffsetRangeExt};use url::Url;use util::{    ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,    paths::{PathExt, SanitizedPath},    post_inc,}; 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 worktree::{    Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,    UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,}; const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100); #[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum FormatTrigger {    Save,    Manual,} pub enum LspFormatTarget {    Buffers,    Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),} pub type OpenLspBufferHandle = Entity<Entity<Buffer>>; impl FormatTrigger {    fn from_proto(value: i32) -> FormatTrigger {        match value {            0 => FormatTrigger::Save,            1 => FormatTrigger::Manual,            _ => FormatTrigger::Save,        }    }} pub struct LocalLspStore {    weak: WeakEntity<LspStore>,    worktree_store: Entity<WorktreeStore>,    toolchain_store: Entity<ToolchainStore>,    http_client: Arc<dyn HttpClient>,    environment: Entity<ProjectEnvironment>,    fs: Arc<dyn Fs>,    languages: Arc<LanguageRegistry>,    language_server_ids: HashMap<(WorktreeId, LanguageServerName), BTreeSet<LanguageServerId>>,    yarn: Entity<YarnPathStore>,    pub language_servers: HashMap<LanguageServerId, LanguageServerState>,    buffers_being_formatted: HashSet<BufferId>,    last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,    language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,    language_server_paths_watched_for_rename:        HashMap<LanguageServerId, RenamePathsWatchedForServer>,    language_server_watcher_registrations:        HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,    supplementary_language_servers:        HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,    prettier_store: Entity<PrettierStore>,    next_diagnostic_group_id: usize,    diagnostics: HashMap<        WorktreeId,        HashMap<            Arc<Path>,            Vec<(                LanguageServerId,                Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,            )>,        >,    >,    buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots    _subscription: gpui::Subscription,    lsp_tree: Entity<LanguageServerTree>,    registered_buffers: HashMap<BufferId, usize>,} impl LocalLspStore {    /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.    pub fn running_language_server_for_id(        &self,        id: LanguageServerId,    ) -> Option<&Arc<LanguageServer>> {        let language_server_state = self.language_servers.get(&id)?;         match language_server_state {            LanguageServerState::Running { server, .. } => Some(server),            LanguageServerState::Starting { .. } => None,        }    }     fn start_language_server(        &mut self,        worktree_handle: &Entity<Worktree>,        delegate: Arc<LocalLspAdapterDelegate>,        adapter: Arc<CachedLspAdapter>,        settings: Arc<LspSettings>,        cx: &mut App,    ) -> LanguageServerId {        let worktree = worktree_handle.read(cx);        let worktree_id = worktree.id();        let root_path = worktree.abs_path();        let key = (worktree_id, adapter.name.clone());         let override_options = settings.initialization_options.clone();         let stderr_capture = Arc::new(Mutex::new(Some(String::new())));         let server_id = self.languages.next_language_server_id();        log::info!(            "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",            adapter.name.0        );         let binary = self.get_language_server_binary(adapter.clone(), delegate.clone(), true, cx);        let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();        let pending_server = cx.spawn({            let adapter = adapter.clone();            let server_name = adapter.name.clone();            let stderr_capture = stderr_capture.clone();            #[cfg(any(test, feature = "test-support"))]            let lsp_store = self.weak.clone();            let pending_workspace_folders = pending_workspace_folders.clone();            async move |cx| {                let binary = binary.await?;                #[cfg(any(test, feature = "test-support"))]                if let Some(server) = lsp_store                    .update(&mut cx.clone(), |this, cx| {                        this.languages.create_fake_language_server(                            server_id,                            &server_name,                            binary.clone(),                            &mut cx.to_async(),                        )                    })                    .ok()                    .flatten()                {                    return Ok(server);                }                 lsp::LanguageServer::new(                    stderr_capture,                    server_id,                    server_name,                    binary,                    &root_path,                    adapter.code_action_kinds(),                    pending_workspace_folders,                    cx,                )            }        });         let startup = {            let server_name = adapter.name.0.clone();            let delegate = delegate as Arc<dyn LspAdapterDelegate>;            let key = key.clone();            let adapter = adapter.clone();            let this = self.weak.clone();            let pending_workspace_folders = pending_workspace_folders.clone();            let fs = self.fs.clone();            cx.spawn(async move |cx| {                let result = async {                    let toolchains = this.update(cx, |this, cx| this.toolchain_store(cx))?;                    let language_server = pending_server.await?;                     let workspace_config = Self::workspace_configuration_for_adapter(                        adapter.adapter.clone(),                        fs.as_ref(),                        &delegate,                        toolchains.clone(),                        cx,                    )                    .await?;                     let mut initialization_options = Self::initialization_options_for_adapter(                        adapter.adapter.clone(),                        fs.as_ref(),                        &delegate,                    )                    .await?;                     match (&mut initialization_options, override_options) {                        (Some(initialization_options), Some(override_options)) => {                            merge_json_value_into(override_options, initialization_options);                        }                        (None, override_options) => initialization_options = override_options,                        _ => {}                    }                     let initialization_params = cx.update(|cx| {                        let mut params = language_server.default_initialize_params(cx);                        params.initialization_options = initialization_options;                        adapter.adapter.prepare_initialize_params(params, cx)                    })??;                     Self::setup_lsp_messages(                        this.clone(),                        fs,                        &language_server,                        delegate.clone(),                        adapter.clone(),                    );                     let did_change_configuration_params =                        Arc::new(lsp::DidChangeConfigurationParams {                            settings: workspace_config,                        });                    let language_server = cx                        .update(|cx| {                            language_server.initialize(                                initialization_params,                                did_change_configuration_params.clone(),                                cx,                            )                        })?                        .await                        .inspect_err(|_| {                            if let Some(this) = this.upgrade() {                                this.update(cx, |_, cx| {                                    cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))                                })                                .ok();                            }                        })?;                     language_server                        .notify::<lsp::notification::DidChangeConfiguration>(                            &did_change_configuration_params,                        )                        .ok();                     anyhow::Ok(language_server)                }                .await;                 match result {                    Ok(server) => {                        this.update(cx, |this, mut cx| {                            this.insert_newly_running_language_server(                                adapter,                                server.clone(),                                server_id,                                key,                                pending_workspace_folders,                                &mut cx,                            );                        })                        .ok();                        stderr_capture.lock().take();                        Some(server)                    }                     Err(err) => {                        let log = stderr_capture.lock().take().unwrap_or_default();                        delegate.update_status(                            adapter.name(),                            BinaryStatus::Failed {                                error: format!("{err}\n-- stderr--\n{log}"),                            },                        );                        log::error!("Failed to start language server {server_name:?}: {err:#?}");                        log::error!("server stderr: {log}");                        None                    }                }            })        };        let state = LanguageServerState::Starting {            startup,            pending_workspace_folders,        };         self.language_servers.insert(server_id, state);        self.language_server_ids            .entry(key)            .or_default()            .insert(server_id);        server_id    }     fn get_language_server_binary(        &self,        adapter: Arc<CachedLspAdapter>,        delegate: Arc<dyn LspAdapterDelegate>,        allow_binary_download: bool,        cx: &mut App,    ) -> Task<Result<LanguageServerBinary>> {        let settings = ProjectSettings::get(            Some(SettingsLocation {                worktree_id: delegate.worktree_id(),                path: Path::new(""),            }),            cx,        )        .lsp        .get(&adapter.name)        .and_then(|s| s.binary.clone());         if settings.as_ref().is_some_and(|b| b.path.is_some()) {            let settings = settings.unwrap();             return cx.spawn(async move |_| {                let mut env = delegate.shell_env().await;                env.extend(settings.env.unwrap_or_default());                 Ok(LanguageServerBinary {                    path: PathBuf::from(&settings.path.unwrap()),                    env: Some(env),                    arguments: settings                        .arguments                        .unwrap_or_default()                        .iter()                        .map(Into::into)                        .collect(),                })            });        }        let lsp_binary_options = LanguageServerBinaryOptions {            allow_path_lookup: !settings                .as_ref()                .and_then(|b| b.ignore_system_version)                .unwrap_or_default(),            allow_binary_download,        };        let toolchains = self.toolchain_store.read(cx).as_language_toolchain_store();        cx.spawn(async move |cx| {            let binary_result = adapter                .clone()                .get_language_server_command(delegate.clone(), toolchains, lsp_binary_options, cx)                .await;             delegate.update_status(adapter.name.clone(), BinaryStatus::None);             let mut binary = binary_result?;            let mut shell_env = delegate.shell_env().await;             shell_env.extend(binary.env.unwrap_or_default());             if let Some(settings) = settings {                if let Some(arguments) = settings.arguments {                    binary.arguments = arguments.into_iter().map(Into::into).collect();                }                if let Some(env) = settings.env {                    shell_env.extend(env);                }            }             binary.env = Some(shell_env);            Ok(binary)        })    }     fn setup_lsp_messages(        this: WeakEntity<LspStore>,        fs: Arc<dyn Fs>,        language_server: &LanguageServer,        delegate: Arc<dyn LspAdapterDelegate>,        adapter: Arc<CachedLspAdapter>,    ) {        let name = language_server.name();        let server_id = language_server.server_id();        language_server            .on_notification::<lsp::notification::PublishDiagnostics, _>({                let adapter = adapter.clone();                let this = this.clone();                move |mut params, cx| {                    let adapter = adapter.clone();                    if let Some(this) = this.upgrade() {                        this.update(cx, |this, cx| {                            {                                let buffer = params                                    .uri                                    .to_file_path()                                    .map(|file_path| this.get_buffer(&file_path, cx))                                    .ok()                                    .flatten();                                adapter.process_diagnostics(&mut params, server_id, buffer);                            }                             this.merge_diagnostics(                                server_id,                                params,                                &adapter.disk_based_diagnostic_sources,                                |diagnostic, cx| adapter.retain_old_diagnostic(diagnostic, cx),                                cx,                            )                            .log_err();                        })                        .ok();                    }                }            })            .detach();        language_server            .on_request::<lsp::request::WorkspaceConfiguration, _, _>({                let adapter = adapter.adapter.clone();                let delegate = delegate.clone();                let this = this.clone();                let fs = fs.clone();                move |params, cx| {                    let adapter = adapter.clone();                    let delegate = delegate.clone();                    let this = this.clone();                    let fs = fs.clone();                    let mut cx = cx.clone();                    async move {

Lines 1–500 of 10587.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t