Skip to content

Commit

Permalink
Add a localDocs capability
Browse files Browse the repository at this point in the history
  • Loading branch information
Ddystopia committed May 2, 2023
1 parent 4ac39f0 commit 7e19d99
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 22 deletions.
4 changes: 4 additions & 0 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
41 changes: 25 additions & 16 deletions crates/rust-analyzer/src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 15 additions & 1 deletion crates/rust-analyzer/src/lsp_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 17 additions & 5 deletions docs/dev/lsp-extensions.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 7e19d99

Please sign in to comment.