about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDdystopia <alexanderbabak@proton.me>2023-04-28 10:27:16 +0200
committerDdystopia <alexanderbabak@proton.me>2023-05-02 17:13:21 +0200
commit7e19d99d4f0631b141d4d49a49cd5c504726cf9c (patch)
treeecd484c2a116cf9a0adf40a30304ee142e078519
parent4ac39f0c98648b7095332d8b821cf93c935fdc3f (diff)
Add a `localDocs` capability
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs41
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs16
-rw-r--r--docs/dev/lsp-extensions.md22
4 files changed, 61 insertions, 22 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index aa6beb6351a..51874382a8b 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 65541bfe141..b8e7c85b043 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 9c27f6e1c33..4d67c8b305f 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 13407f80b22..bc58aa7220d 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