3071 lines · 108.6 KB · Rust
RawDownload
mod signature_help; use crate::{    lsp_store::LspStore, CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock,    HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip,    InlayHintTooltip, Location, LocationLink, MarkupContent, ProjectTransaction, ResolveState,};use anyhow::{anyhow, Context, Result};use async_trait::async_trait;use client::proto::{self, PeerId};use clock::Global;use collections::HashSet;use futures::future;use gpui::{AppContext, AsyncAppContext, Entity, Model};use language::{    language_settings::{language_settings, InlayHintKind, LanguageSettings},    point_from_lsp, point_to_lsp,    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},    range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind,    OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,};use lsp::{    AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext,    CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind,    LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf,    ServerCapabilities,};use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};use text::{BufferId, LineEnding}; pub use signature_help::{    SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD,}; pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions {    lsp::FormattingOptions {        tab_size: settings.tab_size.into(),        insert_spaces: !settings.hard_tabs,        trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save),        trim_final_newlines: Some(settings.ensure_final_newline_on_save),        insert_final_newline: Some(settings.ensure_final_newline_on_save),        ..lsp::FormattingOptions::default()    }} #[async_trait(?Send)]pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {    type Response: 'static + Default + Send + std::fmt::Debug;    type LspRequest: 'static + Send + lsp::request::Request;    type ProtoRequest: 'static + Send + proto::RequestMessage;     fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {        true    }     fn status(&self) -> Option<String> {        None    }     fn to_lsp(        &self,        path: &Path,        buffer: &Buffer,        language_server: &Arc<LanguageServer>,        cx: &AppContext,    ) -> <Self::LspRequest as lsp::request::Request>::Params;     async fn response_from_lsp(        self,        message: <Self::LspRequest as lsp::request::Request>::Result,        lsp_store: Model<LspStore>,        buffer: Model<Buffer>,        server_id: LanguageServerId,        cx: AsyncAppContext,    ) -> Result<Self::Response>;     fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;     async fn from_proto(        message: Self::ProtoRequest,        lsp_store: Model<LspStore>,        buffer: Model<Buffer>,        cx: AsyncAppContext,    ) -> Result<Self>;     fn response_to_proto(        response: Self::Response,        lsp_store: &mut LspStore,        peer_id: PeerId,        buffer_version: &clock::Global,        cx: &mut AppContext,    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;     async fn response_from_proto(        self,        message: <Self::ProtoRequest as proto::RequestMessage>::Response,        lsp_store: Model<LspStore>,        buffer: Model<Buffer>,        cx: AsyncAppContext,    ) -> Result<Self::Response>;     fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;} #[derive(Debug)]pub(crate) struct PrepareRename {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct PerformRename {    pub position: PointUtf16,    pub new_name: String,    pub push_to_history: bool,} #[derive(Debug)]pub struct GetDefinition {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct GetDeclaration {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct GetTypeDefinition {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct GetImplementation {    pub position: PointUtf16,}#[derive(Debug)]pub(crate) struct GetReferences {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct GetDocumentHighlights {    pub position: PointUtf16,} #[derive(Clone, Debug)]pub(crate) struct GetSignatureHelp {    pub position: PointUtf16,} #[derive(Clone, Debug)]pub(crate) struct GetHover {    pub position: PointUtf16,} #[derive(Debug)]pub(crate) struct GetCompletions {    pub position: PointUtf16,    pub context: CompletionContext,} #[derive(Clone, Debug)]pub(crate) struct GetCodeActions {    pub range: Range<Anchor>,    pub kinds: Option<Vec<lsp::CodeActionKind>>,}#[derive(Debug)]pub(crate) struct OnTypeFormatting {    pub position: PointUtf16,    pub trigger: String,    pub options: lsp::FormattingOptions,    pub push_to_history: bool,}#[derive(Debug)]pub(crate) struct InlayHints {    pub range: Range<Anchor>,}#[derive(Debug)]pub(crate) struct LinkedEditingRange {    pub position: Anchor,} #[async_trait(?Send)]impl LspCommand for PrepareRename {    type Response = Option<Range<Anchor>>;    type LspRequest = lsp::request::PrepareRenameRequest;    type ProtoRequest = proto::PrepareRename;     fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {        if let Some(lsp::OneOf::Right(rename)) = &capabilities.server_capabilities.rename_provider {            rename.prepare_provider == Some(true)        } else {            false        }    }     fn to_lsp(        &self,        path: &Path,        _: &Buffer,        _: &Arc<LanguageServer>,        _: &AppContext,    ) -> lsp::TextDocumentPositionParams {        lsp::TextDocumentPositionParams {            text_document: lsp::TextDocumentIdentifier {                uri: lsp::Url::from_file_path(path).unwrap(),            },            position: point_to_lsp(self.position),        }    }     async fn response_from_lsp(        self,        message: Option<lsp::PrepareRenameResponse>,        _: Model<LspStore>,        buffer: Model<Buffer>,        _: LanguageServerId,        mut cx: AsyncAppContext,    ) -> Result<Option<Range<Anchor>>> {        buffer.update(&mut cx, |buffer, _| {            if let Some(                lsp::PrepareRenameResponse::Range(range)                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },            ) = message            {                let Range { start, end } = range_from_lsp(range);                if buffer.clip_point_utf16(start, Bias::Left) == start.0                    && buffer.clip_point_utf16(end, Bias::Left) == end.0                {                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));                }            }            Ok(None)        })?    }     fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {        proto::PrepareRename {            project_id,            buffer_id: buffer.remote_id().into(),            position: Some(language::proto::serialize_anchor(                &buffer.anchor_before(self.position),            )),            version: serialize_version(&buffer.version()),        }    }     async fn from_proto(        message: proto::PrepareRename,        _: Model<LspStore>,        buffer: Model<Buffer>,        mut cx: AsyncAppContext,    ) -> Result<Self> {        let position = message            .position            .and_then(deserialize_anchor)            .ok_or_else(|| anyhow!("invalid position"))?;        buffer            .update(&mut cx, |buffer, _| {                buffer.wait_for_version(deserialize_version(&message.version))            })?            .await?;         Ok(Self {            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,        })    }     fn response_to_proto(        range: Option<Range<Anchor>>,        _: &mut LspStore,        _: PeerId,        buffer_version: &clock::Global,        _: &mut AppContext,    ) -> proto::PrepareRenameResponse {        proto::PrepareRenameResponse {            can_rename: range.is_some(),            start: range                .as_ref()                .map(|range| language::proto::serialize_anchor(&range.start)),            end: range                .as_ref()                .map(|range| language::proto::serialize_anchor(&range.end)),            version: serialize_version(buffer_version),        }    }     async fn response_from_proto(        self,        message: proto::PrepareRenameResponse,        _: Model<LspStore>,        buffer: Model<Buffer>,        mut cx: AsyncAppContext,    ) -> Result<Option<Range<Anchor>>> {        if message.can_rename {            buffer                .update(&mut cx, |buffer, _| {                    buffer.wait_for_version(deserialize_version(&message.version))                })?                .await?;            let start = message.start.and_then(deserialize_anchor);            let end = message.end.and_then(deserialize_anchor);            Ok(start.zip(end).map(|(start, end)| start..end))        } else {            Ok(None)        }    }     fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {        BufferId::new(message.buffer_id)    }} #[async_trait(?Send)]impl LspCommand for PerformRename {    type Response = ProjectTransaction;    type LspRequest = lsp::request::Rename;    type ProtoRequest = proto::PerformRename;     fn to_lsp(        &self,        path: &Path,        _: &Buffer,        _: &Arc<LanguageServer>,        _: &AppContext,    ) -> lsp::RenameParams {        lsp::RenameParams {            text_document_position: lsp::TextDocumentPositionParams {                text_document: lsp::TextDocumentIdentifier {                    uri: lsp::Url::from_file_path(path).unwrap(),                },                position: point_to_lsp(self.position),            },            new_name: self.new_name.clone(),            work_done_progress_params: Default::default(),        }    }     async fn response_from_lsp(        self,        message: Option<lsp::WorkspaceEdit>,        lsp_store: Model<LspStore>,        buffer: Model<Buffer>,        server_id: LanguageServerId,        mut cx: AsyncAppContext,    ) -> Result<ProjectTransaction> {        if let Some(edit) = message {            let (lsp_adapter, lsp_server) =                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;            LspStore::deserialize_workspace_edit(                lsp_store,                edit,                self.push_to_history,                lsp_adapter,                lsp_server,                &mut cx,            )            .await        } else {            Ok(ProjectTransaction::default())        }    }     fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {        proto::PerformRename {            project_id,            buffer_id: buffer.remote_id().into(),            position: Some(language::proto::serialize_anchor(                &buffer.anchor_before(self.position),            )),            new_name: self.new_name.clone(),            version: serialize_version(&buffer.version()),        }    }     async fn from_proto(        message: proto::PerformRename,        _: Model<LspStore>,        buffer: Model<Buffer>,        mut cx: AsyncAppContext,    ) -> Result<Self> {        let position = message            .position            .and_then(deserialize_anchor)            .ok_or_else(|| anyhow!("invalid position"))?;        buffer            .update(&mut cx, |buffer, _| {                buffer.wait_for_version(deserialize_version(&message.version))            })?            .await?;        Ok(Self {            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,            new_name: message.new_name,            push_to_history: false,        })    }     fn response_to_proto(        response: ProjectTransaction,        lsp_store: &mut LspStore,        peer_id: PeerId,        _: &clock::Global,        cx: &mut AppContext,    ) -> proto::PerformRenameResponse {        let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| {            buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx)        });        proto::PerformRenameResponse {            transaction: Some(transaction),        }    }     async fn response_from_proto(        self,        message: proto::PerformRenameResponse,        lsp_store: Model<LspStore>,        _: Model<Buffer>,        mut cx: AsyncAppContext,    ) -> Result<ProjectTransaction> {        let message = message            .transaction            .ok_or_else(|| anyhow!("missing transaction"))?;        lsp_store            .update(&mut cx, |lsp_store, cx| {                lsp_store.buffer_store().update(cx, |buffer_store, cx| {                    buffer_store.deserialize_project_transaction(message, self.push_to_history, cx)                })            })?            .await    }     fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {        BufferId::new(message.buffer_id)    }} #[async_trait(?Send)]impl LspCommand for GetDefinition {    type Response = Vec<LocationLink>;    type LspRequest = lsp::request::GotoDefinition;    type ProtoRequest = proto::GetDefinition;     fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {        capabilities            .server_capabilities            .definition_provider            .is_some()    }     fn to_lsp(        &self,        path: &Path,        _: &Buffer,        _: &Arc<LanguageServer>,        _: &AppContext,    ) -> lsp::GotoDefinitionParams {        lsp::GotoDefinitionParams {            text_document_position_params: lsp::TextDocumentPositionParams {                text_document: lsp::TextDocumentIdentifier {                    uri: lsp::Url::from_file_path(path).unwrap(),                },                position: point_to_lsp(self.position),            },            work_done_progress_params: Default::default(),            partial_result_params: Default::default(),        }    }     async fn response_from_lsp(        self,        message: Option<lsp::GotoDefinitionResponse>,        lsp_store: Model<LspStore>,        buffer: Model<Buffer>,        server_id: LanguageServerId,        cx: AsyncAppContext,    ) -> Result<Vec<LocationLink>> {        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await    }     fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {        proto::GetDefinition {            project_id,            buffer_id: buffer.remote_id().into(),            position: Some(language::proto::serialize_anchor(                &buffer.anchor_before(self.position),            )),            version: serialize_version(&buffer.version()),        }    }     async fn from_proto(        message: proto::GetDefinition,        _: Model<LspStore>,        buffer: Model<Buffer>,        mut cx: AsyncAppContext,    ) -> Result<Self> {        let position = message            .position            .and_then(deserialize_anchor)

Lines 1–500 of 3071.