4611: Document `parentModule` experimental LSP request r=matklad a=matklad



bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-05-25 14:00:24 +00:00 committed by GitHub
commit 19700b2e31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 64 additions and 38 deletions

View file

@ -86,6 +86,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
"joinLines": true, "joinLines": true,
"ssr": true, "ssr": true,
"onEnter": true, "onEnter": true,
"parentModule": true,
})), })),
} }
} }

View file

@ -3,7 +3,7 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use lsp_types::request::Request; use lsp_types::request::Request;
use lsp_types::{Location, Position, Range, TextDocumentIdentifier}; use lsp_types::{Position, Range, TextDocumentIdentifier};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -79,8 +79,8 @@ pub enum ParentModule {}
impl Request for ParentModule { impl Request for ParentModule {
type Params = lsp_types::TextDocumentPositionParams; type Params = lsp_types::TextDocumentPositionParams;
type Result = Vec<Location>; type Result = Option<lsp_types::GotoDefinitionResponse>;
const METHOD: &'static str = "rust-analyzer/parentModule"; const METHOD: &'static str = "experimental/parentModule";
} }
pub enum JoinLines {} pub enum JoinLines {}

View file

@ -344,11 +344,8 @@ pub fn handle_goto_definition(
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let res = to_proto::goto_definition_response( let src = FileRange { file_id: position.file_id, range: nav_info.range };
&world, let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
Ok(Some(res)) Ok(Some(res))
} }
@ -362,11 +359,8 @@ pub fn handle_goto_implementation(
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let res = to_proto::goto_definition_response( let src = FileRange { file_id: position.file_id, range: nav_info.range };
&world, let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
Ok(Some(res)) Ok(Some(res))
} }
@ -380,26 +374,20 @@ pub fn handle_goto_type_definition(
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let res = to_proto::goto_definition_response( let src = FileRange { file_id: position.file_id, range: nav_info.range };
&world, let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_parent_module( pub fn handle_parent_module(
world: WorldSnapshot, world: WorldSnapshot,
params: lsp_types::TextDocumentPositionParams, params: lsp_types::TextDocumentPositionParams,
) -> Result<Vec<Location>> { ) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_parent_module"); let _p = profile("handle_parent_module");
let position = from_proto::file_position(&world, params)?; let position = from_proto::file_position(&world, params)?;
world let navs = world.analysis().parent_module(position)?;
.analysis() let res = to_proto::goto_definition_response(&world, None, navs)?;
.parent_module(position)? Ok(Some(res))
.into_iter()
.map(|it| to_proto::location(&world, it.file_range()))
.collect::<Result<Vec<_>>>()
} }
pub fn handle_runnables( pub fn handle_runnables(

View file

@ -403,13 +403,20 @@ pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_t
pub(crate) fn location_link( pub(crate) fn location_link(
world: &WorldSnapshot, world: &WorldSnapshot,
src: FileRange, src: Option<FileRange>,
target: NavigationTarget, target: NavigationTarget,
) -> Result<lsp_types::LocationLink> { ) -> Result<lsp_types::LocationLink> {
let src_location = location(world, src)?; let origin_selection_range = match src {
Some(src) => {
let line_index = world.analysis().file_line_index(src.file_id)?;
let range = range(&line_index, src.range);
Some(range)
}
None => None,
};
let (target_uri, target_range, target_selection_range) = location_info(world, target)?; let (target_uri, target_range, target_selection_range) = location_info(world, target)?;
let res = lsp_types::LocationLink { let res = lsp_types::LocationLink {
origin_selection_range: Some(src_location.range), origin_selection_range,
target_uri, target_uri,
target_range, target_range,
target_selection_range, target_selection_range,
@ -432,7 +439,7 @@ fn location_info(
pub(crate) fn goto_definition_response( pub(crate) fn goto_definition_response(
world: &WorldSnapshot, world: &WorldSnapshot,
src: FileRange, src: Option<FileRange>,
targets: Vec<NavigationTarget>, targets: Vec<NavigationTarget>,
) -> Result<lsp_types::GotoDefinitionResponse> { ) -> Result<lsp_types::GotoDefinitionResponse> {
if world.config.client_caps.location_link { if world.config.client_caps.location_link {

View file

@ -87,6 +87,40 @@ Invoking code action at this position will yield two code actions for importing
* Is a fixed two-level structure enough? * Is a fixed two-level structure enough?
* Should we devise a general way to encode custom interaction protocols for GUI refactorings? * Should we devise a general way to encode custom interaction protocols for GUI refactorings?
## Parent Module
**Issue:** https://github.com/microsoft/language-server-protocol/issues/1002
**Server Capability:** `{ "parentModule": boolean }`
This request is send from client to server to handle "Goto Parent Module" editor action.
**Method:** `experimental/parentModule`
**Request:** `TextDocumentPositionParams`
**Response:** `Location | Location[] | LocationLink[] | null`
### Example
```rust
// src/main.rs
mod foo;
// src/foo.rs
/* cursor here*/
```
`experimental/parentModule` returns a single `Link` to the `mod foo;` declaration.
### Unresolved Question
* An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules.
This is the approach IntelliJ Rust is takeing.
However, experience shows that super module (which generally has a feeling of navigation between files) should be separate.
If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising.
## Join Lines ## Join Lines
**Issue:** https://github.com/microsoft/language-server-protocol/issues/992 **Issue:** https://github.com/microsoft/language-server-protocol/issues/992
@ -108,11 +142,7 @@ interface JoinLinesParams {
} }
``` ```
**Response:** **Response:** `TextEdit[]`
```typescript
TextEdit[]
```
### Example ### Example

View file

@ -138,10 +138,10 @@ export function parentModule(ctx: Ctx): Cmd {
), ),
}); });
const loc = response[0]; const loc = response[0];
if (loc == null) return; if (!loc) return;
const uri = client.protocol2CodeConverter.asUri(loc.uri); const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
const range = client.protocol2CodeConverter.asRange(loc.range); const range = client.protocol2CodeConverter.asRange(loc.targetRange);
const doc = await vscode.workspace.openTextDocument(uri); const doc = await vscode.workspace.openTextDocument(uri);
const e = await vscode.window.showTextDocument(doc); const e = await vscode.window.showTextDocument(doc);

View file

@ -31,7 +31,7 @@ export interface MatchingBraceParams {
} }
export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace"); export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace");
export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.Location[], void>("rust-analyzer/parentModule"); export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule");
export interface JoinLinesParams { export interface JoinLinesParams {
textDocument: lc.TextDocumentIdentifier; textDocument: lc.TextDocumentIdentifier;