Add a localDocs capability

This commit is contained in:
Ddystopia 2023-04-28 10:27:16 +02:00
parent 4ac39f0c98
commit 7e19d99d4f
No known key found for this signature in database
GPG key ID: 109875EC11535212
4 changed files with 61 additions and 22 deletions

View file

@ -1036,6 +1036,10 @@ impl Config {
self.experimental("codeActionGroup") self.experimental("codeActionGroup")
} }
pub fn local_docs(&self) -> bool {
self.experimental("localDocs")
}
pub fn open_server_logs(&self) -> bool { pub fn open_server_logs(&self) -> bool {
self.experimental("openServerLogs") self.experimental("openServerLogs")
} }

View file

@ -40,8 +40,8 @@ use crate::{
global_state::{GlobalState, GlobalStateSnapshot}, global_state::{GlobalState, GlobalStateSnapshot},
line_index::LineEndings, line_index::LineEndings,
lsp_ext::{ lsp_ext::{
self, CrateInfoResult, FetchDependencyListParams, FetchDependencyListResult, self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams, FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
}, },
lsp_utils::{all_edits_are_disjoint, invalid_params_error}, lsp_utils::{all_edits_are_disjoint, invalid_params_error},
to_proto, LspError, Result, to_proto, LspError, Result,
@ -1534,34 +1534,43 @@ pub(crate) fn handle_semantic_tokens_range(
pub(crate) fn handle_open_docs( pub(crate) fn handle_open_docs(
snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams, params: lsp_types::TextDocumentPositionParams,
) -> Result<(Option<lsp_types::Url>, Option<lsp_types::Url>)> { ) -> Result<ExternalDocsResponse> {
let _p = profile::span("handle_open_docs"); let _p = profile::span("handle_open_docs");
let position = from_proto::file_position(&snap, params)?; let position = from_proto::file_position(&snap, params)?;
let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws { let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws {
ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())), ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())),
ProjectWorkspace::Json { .. } => None, ProjectWorkspace::Json { .. } => None,
ProjectWorkspace::DetachedFiles { .. } => None, ProjectWorkspace::DetachedFiles { .. } => None,
}); });
let (cargo, sysroot) = match ws_and_sysroot { let (cargo, sysroot) = match ws_and_sysroot {
Some((ws, Some(sysroot))) => (Some(ws), Some(sysroot)), Some((ws, Some(sysroot))) => (Some(ws), Some(sysroot)),
_ => (None, None), _ => (None, None),
}; };
let sysroot = sysroot.map(|p| p.root().as_os_str()); 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 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 web = 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 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( pub(crate) fn handle_open_cargo_toml(
snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::OpenCargoTomlParams, params: lsp_ext::OpenCargoTomlParams,

View file

@ -508,10 +508,24 @@ pub enum ExternalDocs {}
impl Request for ExternalDocs { impl Request for ExternalDocs {
type Params = lsp_types::TextDocumentPositionParams; type Params = lsp_types::TextDocumentPositionParams;
type Result = (Option<lsp_types::Url>, Option<lsp_types::Url>); type Result = ExternalDocsResponse;
const METHOD: &'static str = "experimental/externalDocs"; 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 {} pub enum OpenCargoToml {}
impl Request for OpenCargoToml { impl Request for OpenCargoToml {

View file

@ -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 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: 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 ## 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, string | null]` **Response:** `string | null`
## Local Documentation
**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 ## Analyzer Status