diff options
author | Aleksey Kladov <[email protected]> | 2020-05-25 14:55:25 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-05-25 14:59:49 +0100 |
commit | 0ebb25b29b0988be89f42091fd373ea58d7ff9fb (patch) | |
tree | 06bb2df01d20d94ab38f2216d88555df03a826c9 | |
parent | a30bdd9795770329e4562d8bfca60ebe2e52dea1 (diff) |
Document `parentModule` experimental LSP request
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_ext.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 32 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 15 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 40 | ||||
-rw-r--r-- | editors/code/src/commands.ts | 6 | ||||
-rw-r--r-- | editors/code/src/lsp_ext.ts | 2 |
7 files changed, 64 insertions, 38 deletions
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index d55cbb15f..345693524 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -86,6 +86,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
86 | "joinLines": true, | 86 | "joinLines": true, |
87 | "ssr": true, | 87 | "ssr": true, |
88 | "onEnter": true, | 88 | "onEnter": true, |
89 | "parentModule": true, | ||
89 | })), | 90 | })), |
90 | } | 91 | } |
91 | } | 92 | } |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index c571c62ae..acb1dacb6 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::{collections::HashMap, path::PathBuf}; | 3 | use std::{collections::HashMap, path::PathBuf}; |
4 | 4 | ||
5 | use lsp_types::request::Request; | 5 | use lsp_types::request::Request; |
6 | use lsp_types::{Location, Position, Range, TextDocumentIdentifier}; | 6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use serde::{Deserialize, Serialize}; | 8 | use serde::{Deserialize, Serialize}; |
9 | 9 | ||
@@ -79,8 +79,8 @@ pub enum ParentModule {} | |||
79 | 79 | ||
80 | impl Request for ParentModule { | 80 | impl Request for ParentModule { |
81 | type Params = lsp_types::TextDocumentPositionParams; | 81 | type Params = lsp_types::TextDocumentPositionParams; |
82 | type Result = Vec<Location>; | 82 | type Result = Option<lsp_types::GotoDefinitionResponse>; |
83 | const METHOD: &'static str = "rust-analyzer/parentModule"; | 83 | const METHOD: &'static str = "experimental/parentModule"; |
84 | } | 84 | } |
85 | 85 | ||
86 | pub enum JoinLines {} | 86 | pub enum JoinLines {} |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 3ccc95c23..1f910ff82 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -344,11 +344,8 @@ pub fn handle_goto_definition( | |||
344 | None => return Ok(None), | 344 | None => return Ok(None), |
345 | Some(it) => it, | 345 | Some(it) => it, |
346 | }; | 346 | }; |
347 | let res = to_proto::goto_definition_response( | 347 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
348 | &world, | 348 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
349 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
350 | nav_info.info, | ||
351 | )?; | ||
352 | Ok(Some(res)) | 349 | Ok(Some(res)) |
353 | } | 350 | } |
354 | 351 | ||
@@ -362,11 +359,8 @@ pub fn handle_goto_implementation( | |||
362 | None => return Ok(None), | 359 | None => return Ok(None), |
363 | Some(it) => it, | 360 | Some(it) => it, |
364 | }; | 361 | }; |
365 | let res = to_proto::goto_definition_response( | 362 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
366 | &world, | 363 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
367 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
368 | nav_info.info, | ||
369 | )?; | ||
370 | Ok(Some(res)) | 364 | Ok(Some(res)) |
371 | } | 365 | } |
372 | 366 | ||
@@ -380,26 +374,20 @@ pub fn handle_goto_type_definition( | |||
380 | None => return Ok(None), | 374 | None => return Ok(None), |
381 | Some(it) => it, | 375 | Some(it) => it, |
382 | }; | 376 | }; |
383 | let res = to_proto::goto_definition_response( | 377 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
384 | &world, | 378 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
385 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
386 | nav_info.info, | ||
387 | )?; | ||
388 | Ok(Some(res)) | 379 | Ok(Some(res)) |
389 | } | 380 | } |
390 | 381 | ||
391 | pub fn handle_parent_module( | 382 | pub fn handle_parent_module( |
392 | world: WorldSnapshot, | 383 | world: WorldSnapshot, |
393 | params: lsp_types::TextDocumentPositionParams, | 384 | params: lsp_types::TextDocumentPositionParams, |
394 | ) -> Result<Vec<Location>> { | 385 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { |
395 | let _p = profile("handle_parent_module"); | 386 | let _p = profile("handle_parent_module"); |
396 | let position = from_proto::file_position(&world, params)?; | 387 | let position = from_proto::file_position(&world, params)?; |
397 | world | 388 | let navs = world.analysis().parent_module(position)?; |
398 | .analysis() | 389 | let res = to_proto::goto_definition_response(&world, None, navs)?; |
399 | .parent_module(position)? | 390 | Ok(Some(res)) |
400 | .into_iter() | ||
401 | .map(|it| to_proto::location(&world, it.file_range())) | ||
402 | .collect::<Result<Vec<_>>>() | ||
403 | } | 391 | } |
404 | 392 | ||
405 | pub fn handle_runnables( | 393 | pub fn handle_runnables( |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 39d58f1e0..bb7594dbf 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -403,13 +403,20 @@ pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_t | |||
403 | 403 | ||
404 | pub(crate) fn location_link( | 404 | pub(crate) fn location_link( |
405 | world: &WorldSnapshot, | 405 | world: &WorldSnapshot, |
406 | src: FileRange, | 406 | src: Option<FileRange>, |
407 | target: NavigationTarget, | 407 | target: NavigationTarget, |
408 | ) -> Result<lsp_types::LocationLink> { | 408 | ) -> Result<lsp_types::LocationLink> { |
409 | let src_location = location(world, src)?; | 409 | let origin_selection_range = match src { |
410 | Some(src) => { | ||
411 | let line_index = world.analysis().file_line_index(src.file_id)?; | ||
412 | let range = range(&line_index, src.range); | ||
413 | Some(range) | ||
414 | } | ||
415 | None => None, | ||
416 | }; | ||
410 | let (target_uri, target_range, target_selection_range) = location_info(world, target)?; | 417 | let (target_uri, target_range, target_selection_range) = location_info(world, target)?; |
411 | let res = lsp_types::LocationLink { | 418 | let res = lsp_types::LocationLink { |
412 | origin_selection_range: Some(src_location.range), | 419 | origin_selection_range, |
413 | target_uri, | 420 | target_uri, |
414 | target_range, | 421 | target_range, |
415 | target_selection_range, | 422 | target_selection_range, |
@@ -432,7 +439,7 @@ fn location_info( | |||
432 | 439 | ||
433 | pub(crate) fn goto_definition_response( | 440 | pub(crate) fn goto_definition_response( |
434 | world: &WorldSnapshot, | 441 | world: &WorldSnapshot, |
435 | src: FileRange, | 442 | src: Option<FileRange>, |
436 | targets: Vec<NavigationTarget>, | 443 | targets: Vec<NavigationTarget>, |
437 | ) -> Result<lsp_types::GotoDefinitionResponse> { | 444 | ) -> Result<lsp_types::GotoDefinitionResponse> { |
438 | if world.config.client_caps.location_link { | 445 | if world.config.client_caps.location_link { |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 48147b173..209f470eb 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -87,6 +87,40 @@ Invoking code action at this position will yield two code actions for importing | |||
87 | * Is a fixed two-level structure enough? | 87 | * Is a fixed two-level structure enough? |
88 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | 88 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? |
89 | 89 | ||
90 | ## Parent Module | ||
91 | |||
92 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 | ||
93 | |||
94 | **Server Capability:** `{ "parentModule": boolean }` | ||
95 | |||
96 | This request is send from client to server to handle "Goto Parent Module" editor action. | ||
97 | |||
98 | **Method:** `experimental/parentModule` | ||
99 | |||
100 | **Request:** `TextDocumentPositionParams` | ||
101 | |||
102 | **Response:** `Location | Location[] | LocationLink[] | null` | ||
103 | |||
104 | |||
105 | ### Example | ||
106 | |||
107 | ```rust | ||
108 | // src/main.rs | ||
109 | mod foo; | ||
110 | // src/foo.rs | ||
111 | |||
112 | /* cursor here*/ | ||
113 | ``` | ||
114 | |||
115 | `experimental/parentModule` returns a single `Link` to the `mod foo;` declaration. | ||
116 | |||
117 | ### Unresolved Question | ||
118 | |||
119 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. | ||
120 | This is the approach IntelliJ Rust is takeing. | ||
121 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. | ||
122 | If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. | ||
123 | |||
90 | ## Join Lines | 124 | ## Join Lines |
91 | 125 | ||
92 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 | 126 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 |
@@ -108,11 +142,7 @@ interface JoinLinesParams { | |||
108 | } | 142 | } |
109 | ``` | 143 | ``` |
110 | 144 | ||
111 | **Response:** | 145 | **Response:** `TextEdit[]` |
112 | |||
113 | ```typescript | ||
114 | TextEdit[] | ||
115 | ``` | ||
116 | 146 | ||
117 | ### Example | 147 | ### Example |
118 | 148 | ||
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 49e3845d5..86302db37 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -138,10 +138,10 @@ export function parentModule(ctx: Ctx): Cmd { | |||
138 | ), | 138 | ), |
139 | }); | 139 | }); |
140 | const loc = response[0]; | 140 | const loc = response[0]; |
141 | if (loc == null) return; | 141 | if (!loc) return; |
142 | 142 | ||
143 | const uri = client.protocol2CodeConverter.asUri(loc.uri); | 143 | const uri = client.protocol2CodeConverter.asUri(loc.targetUri); |
144 | const range = client.protocol2CodeConverter.asRange(loc.range); | 144 | const range = client.protocol2CodeConverter.asRange(loc.targetRange); |
145 | 145 | ||
146 | const doc = await vscode.workspace.openTextDocument(uri); | 146 | const doc = await vscode.workspace.openTextDocument(uri); |
147 | const e = await vscode.window.showTextDocument(doc); | 147 | const e = await vscode.window.showTextDocument(doc); |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 2a0663261..4da12eb30 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -31,7 +31,7 @@ export interface MatchingBraceParams { | |||
31 | } | 31 | } |
32 | export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace"); | 32 | export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace"); |
33 | 33 | ||
34 | export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.Location[], void>("rust-analyzer/parentModule"); | 34 | export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule"); |
35 | 35 | ||
36 | export interface JoinLinesParams { | 36 | export interface JoinLinesParams { |
37 | textDocument: lc.TextDocumentIdentifier; | 37 | textDocument: lc.TextDocumentIdentifier; |