Unnamed repository; edit this file 'description' to name the repository.
Add a `localDocs` capability
| -rw-r--r-- | crates/rust-analyzer/src/config.rs | 4 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/handlers/request.rs | 41 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/lsp_ext.rs | 16 | ||||
| -rw-r--r-- | docs/dev/lsp-extensions.md | 22 |
4 files changed, 61 insertions, 22 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index aa6beb6351..51874382a8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1036,6 +1036,10 @@ impl Config { self.experimental("codeActionGroup") } + pub fn local_docs(&self) -> bool { + self.experimental("localDocs") + } + pub fn open_server_logs(&self) -> bool { self.experimental("openServerLogs") } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 65541bfe14..b8e7c85b04 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -40,8 +40,8 @@ use crate::{ global_state::{GlobalState, GlobalStateSnapshot}, line_index::LineEndings, lsp_ext::{ - self, CrateInfoResult, FetchDependencyListParams, FetchDependencyListResult, - PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams, + self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams, + FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams, }, lsp_utils::{all_edits_are_disjoint, invalid_params_error}, to_proto, LspError, Result, @@ -1534,34 +1534,43 @@ pub(crate) fn handle_semantic_tokens_range( pub(crate) fn handle_open_docs( snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, - ) -> Result<(Option<lsp_types::Url>, Option<lsp_types::Url>)> { + params: lsp_types::TextDocumentPositionParams, +) -> Result<ExternalDocsResponse> { let _p = profile::span("handle_open_docs"); let position = from_proto::file_position(&snap, params)?; let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws { - ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())), - ProjectWorkspace::Json { .. } => None, - ProjectWorkspace::DetachedFiles { .. } => None, - }); + ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())), + ProjectWorkspace::Json { .. } => None, + ProjectWorkspace::DetachedFiles { .. } => None, + }); let (cargo, sysroot) = match ws_and_sysroot { - Some((ws, Some(sysroot))) => (Some(ws), Some(sysroot)), - _ => (None, None), - }; + Some((ws, Some(sysroot))) => (Some(ws), Some(sysroot)), + _ => (None, None), + }; let sysroot = sysroot.map(|p| p.root().as_os_str()); let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_os_str()); - let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else { return Ok((None, None)); }; + let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else { + return if snap.config.local_docs() { + Ok(ExternalDocsResponse::WithLocal(Default::default())) + } else { + Ok(ExternalDocsResponse::Simple(None)) + } + }; - let web_url = remote_urls.web_url.and_then(|it| Url::parse(&it).ok()); - let local_url = remote_urls.local_url.and_then(|it| Url::parse(&it).ok()); + let web = remote_urls.web_url.and_then(|it| Url::parse(&it).ok()); + let local = remote_urls.local_url.and_then(|it| Url::parse(&it).ok()); - Ok((web_url, local_url)) + if snap.config.local_docs() { + Ok(ExternalDocsResponse::WithLocal(ExternalDocsPair { web, local })) + } else { + Ok(ExternalDocsResponse::Simple(web)) + } } - pub(crate) fn handle_open_cargo_toml( snap: GlobalStateSnapshot, params: lsp_ext::OpenCargoTomlParams, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 9c27f6e1c3..4d67c8b305 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -508,10 +508,24 @@ pub enum ExternalDocs {} impl Request for ExternalDocs { type Params = lsp_types::TextDocumentPositionParams; - type Result = (Option<lsp_types::Url>, Option<lsp_types::Url>); + type Result = ExternalDocsResponse; const METHOD: &'static str = "experimental/externalDocs"; } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum ExternalDocsResponse { + Simple(Option<lsp_types::Url>), + WithLocal(ExternalDocsPair), +} + +#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ExternalDocsPair { + pub web: Option<lsp_types::Url>, + pub local: Option<lsp_types::Url>, +} + pub enum OpenCargoToml {} impl Request for OpenCargoToml { diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 13407f80b2..bc58aa7220 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp_ext.rs hash: 4e825bd8f3921c87 +lsp_ext.rs hash: 2d60bbffe70ae198 If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: @@ -386,14 +386,26 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look ## Open External Documentation -This request is sent from client to server to get a web and local URL(s) to documentation for the symbol under the cursor, if available. +This request is sent from the client to the server to obtain web and local URL(s) for documentation related to the symbol under the cursor, if available. -**Method** `experimental/externalDocs` +**Method:** `experimental/externalDocs` -**Request:**: `TextDocumentPositionParams` +**Request:** `TextDocumentPositionParams` + +**Response:** `string | null` + +## Local Documentation -**Response** `[string | null, string | null]` +**Experimental Client Capability:** `{ "localDocs": boolean }` +If this capability is set, the `Open External Documentation` request returned from the server will have the following structure: + +```typescript +interface ExternalDocsResponse { + web?: string; + local?: string; +} +``` ## Analyzer Status |