mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #4611
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:
commit
19700b2e31
7 changed files with 64 additions and 38 deletions
|
@ -86,6 +86,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
|
|||
"joinLines": true,
|
||||
"ssr": true,
|
||||
"onEnter": true,
|
||||
"parentModule": true,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue