Document parentModule experimental LSP request

This commit is contained in:
Aleksey Kladov 2020-05-25 15:55:25 +02:00
parent a30bdd9795
commit 0ebb25b29b
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,
"ssr": true,
"onEnter": true,
"parentModule": true,
})),
}
}

View file

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

View file

@ -344,11 +344,8 @@ pub fn handle_goto_definition(
None => return Ok(None),
Some(it) => it,
};
let res = to_proto::goto_definition_response(
&world,
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
Ok(Some(res))
}
@ -362,11 +359,8 @@ pub fn handle_goto_implementation(
None => return Ok(None),
Some(it) => it,
};
let res = to_proto::goto_definition_response(
&world,
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
Ok(Some(res))
}
@ -380,26 +374,20 @@ pub fn handle_goto_type_definition(
None => return Ok(None),
Some(it) => it,
};
let res = to_proto::goto_definition_response(
&world,
FileRange { file_id: position.file_id, range: nav_info.range },
nav_info.info,
)?;
let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?;
Ok(Some(res))
}
pub fn handle_parent_module(
world: WorldSnapshot,
params: lsp_types::TextDocumentPositionParams,
) -> Result<Vec<Location>> {
) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_parent_module");
let position = from_proto::file_position(&world, params)?;
world
.analysis()
.parent_module(position)?
.into_iter()
.map(|it| to_proto::location(&world, it.file_range()))
.collect::<Result<Vec<_>>>()
let navs = world.analysis().parent_module(position)?;
let res = to_proto::goto_definition_response(&world, None, navs)?;
Ok(Some(res))
}
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(
world: &WorldSnapshot,
src: FileRange,
src: Option<FileRange>,
target: NavigationTarget,
) -> 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 res = lsp_types::LocationLink {
origin_selection_range: Some(src_location.range),
origin_selection_range,
target_uri,
target_range,
target_selection_range,
@ -432,7 +439,7 @@ fn location_info(
pub(crate) fn goto_definition_response(
world: &WorldSnapshot,
src: FileRange,
src: Option<FileRange>,
targets: Vec<NavigationTarget>,
) -> Result<lsp_types::GotoDefinitionResponse> {
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?
* 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
**Issue:** https://github.com/microsoft/language-server-protocol/issues/992
@ -108,11 +142,7 @@ interface JoinLinesParams {
}
```
**Response:**
```typescript
TextEdit[]
```
**Response:** `TextEdit[]`
### Example

View file

@ -138,10 +138,10 @@ export function parentModule(ctx: Ctx): Cmd {
),
});
const loc = response[0];
if (loc == null) return;
if (!loc) return;
const uri = client.protocol2CodeConverter.asUri(loc.uri);
const range = client.protocol2CodeConverter.asRange(loc.range);
const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
const range = client.protocol2CodeConverter.asRange(loc.targetRange);
const doc = await vscode.workspace.openTextDocument(uri);
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 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 {
textDocument: lc.TextDocumentIdentifier;