Skip to content

Commit 64b718b

Browse files
bors[bot]matklad
andcommitted
Merge #1511
1511: Send old-style responsed to goto definition unless the client explicitelly opts in r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 5ce2b48 + e075e09 commit 64b718b

File tree

6 files changed

+128
-67
lines changed

6 files changed

+128
-67
lines changed

crates/ra_lsp_server/src/conv.rs

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -384,27 +384,53 @@ impl TryConvWith for &NavigationTarget {
384384
}
385385
}
386386

387-
pub fn to_location_link(
388-
target: &RangeInfo<NavigationTarget>,
389-
world: &WorldSnapshot,
390-
// line index for original range file
391-
line_index: &LineIndex,
392-
) -> Result<LocationLink> {
393-
let target_uri = target.info.file_id().try_conv_with(world)?;
394-
let tgt_line_index = world.analysis().file_line_index(target.info.file_id());
395-
396-
let target_range = target.info.full_range().conv_with(&tgt_line_index);
397-
398-
let target_selection_range =
399-
target.info.focus_range().map(|it| it.conv_with(&tgt_line_index)).unwrap_or(target_range);
387+
impl TryConvWith for (FileId, RangeInfo<NavigationTarget>) {
388+
type Ctx = WorldSnapshot;
389+
type Output = LocationLink;
390+
fn try_conv_with(self, world: &WorldSnapshot) -> Result<LocationLink> {
391+
let (src_file_id, target) = self;
392+
393+
let target_uri = target.info.file_id().try_conv_with(world)?;
394+
let src_line_index = world.analysis().file_line_index(src_file_id);
395+
let tgt_line_index = world.analysis().file_line_index(target.info.file_id());
396+
397+
let target_range = target.info.full_range().conv_with(&tgt_line_index);
398+
399+
let target_selection_range = target
400+
.info
401+
.focus_range()
402+
.map(|it| it.conv_with(&tgt_line_index))
403+
.unwrap_or(target_range);
404+
405+
let res = LocationLink {
406+
origin_selection_range: Some(target.range.conv_with(&src_line_index)),
407+
target_uri,
408+
target_range,
409+
target_selection_range,
410+
};
411+
Ok(res)
412+
}
413+
}
400414

401-
let res = LocationLink {
402-
origin_selection_range: Some(target.range.conv_with(line_index)),
403-
target_uri,
404-
target_range,
405-
target_selection_range,
406-
};
407-
Ok(res)
415+
impl TryConvWith for (FileId, RangeInfo<Vec<NavigationTarget>>) {
416+
type Ctx = WorldSnapshot;
417+
type Output = req::GotoDefinitionResponse;
418+
fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::GotoTypeDefinitionResponse> {
419+
let (file_id, RangeInfo { range, info: navs }) = self;
420+
let links = navs
421+
.into_iter()
422+
.map(|nav| (file_id, RangeInfo::new(range, nav)))
423+
.try_conv_with_to_vec(world)?;
424+
if world.options.supports_location_link {
425+
Ok(links.into())
426+
} else {
427+
let locations: Vec<Location> = links
428+
.into_iter()
429+
.map(|link| Location { uri: link.target_uri, range: link.target_selection_range })
430+
.collect();
431+
Ok(locations.into())
432+
}
433+
}
408434
}
409435

410436
pub fn to_location(
@@ -452,3 +478,23 @@ where
452478
self.iter.next().map(|item| item.conv_with(self.ctx))
453479
}
454480
}
481+
482+
pub trait TryConvWithToVec<'a>: Sized + 'a {
483+
type Ctx;
484+
type Output;
485+
486+
fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result<Vec<Self::Output>>;
487+
}
488+
489+
impl<'a, I> TryConvWithToVec<'a> for I
490+
where
491+
I: Iterator + 'a,
492+
I::Item: TryConvWith,
493+
{
494+
type Ctx = <I::Item as TryConvWith>::Ctx;
495+
type Output = <I::Item as TryConvWith>::Output;
496+
497+
fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result<Vec<Self::Output>> {
498+
self.map(|it| it.try_conv_with(ctx)).collect()
499+
}
500+
}

crates/ra_lsp_server/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn main_inner() -> Result<()> {
5151
.and_then(|v| InitializationOptions::deserialize(v).ok())
5252
.unwrap_or_default();
5353

54-
ra_lsp_server::main_loop(workspace_roots, opts, r, s)
54+
ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s)
5555
})?;
5656
log::info!("shutting down IO...");
5757
threads.join()?;

crates/ra_lsp_server/src/main_loop.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender};
88
use gen_lsp_server::{
99
handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
1010
};
11-
use lsp_types::NumberOrString;
11+
use lsp_types::{ClientCapabilities, NumberOrString};
1212
use ra_ide_api::{Canceled, FileId, LibraryData};
1313
use ra_prof::profile;
1414
use ra_vfs::VfsTask;
@@ -22,7 +22,7 @@ use crate::{
2222
},
2323
project_model::workspace_loader,
2424
req,
25-
world::{WorldSnapshot, WorldState},
25+
world::{Options, WorldSnapshot, WorldState},
2626
InitializationOptions, Result,
2727
};
2828

@@ -51,6 +51,7 @@ impl Error for LspError {}
5151

5252
pub fn main_loop(
5353
ws_roots: Vec<PathBuf>,
54+
client_caps: ClientCapabilities,
5455
options: InitializationOptions,
5556
msg_receiver: &Receiver<RawMessage>,
5657
msg_sender: &Sender<RawMessage>,
@@ -77,15 +78,27 @@ pub fn main_loop(
7778
loaded_workspaces
7879
};
7980

80-
let mut state = WorldState::new(ws_roots, workspaces, options.lru_capacity);
81+
let mut state = WorldState::new(
82+
ws_roots,
83+
workspaces,
84+
options.lru_capacity,
85+
Options {
86+
publish_decorations: options.publish_decorations,
87+
show_workspace_loaded: options.show_workspace_loaded,
88+
supports_location_link: client_caps
89+
.text_document
90+
.and_then(|it| it.definition)
91+
.and_then(|it| it.link_support)
92+
.unwrap_or(false),
93+
},
94+
);
8195

8296
let pool = ThreadPool::new(THREADPOOL_SIZE);
8397
let (task_sender, task_receiver) = unbounded::<Task>();
8498
let mut pending_requests = PendingRequests::default();
8599

86100
log::info!("server initialized, serving requests");
87101
let main_res = main_loop_inner(
88-
options,
89102
&pool,
90103
msg_sender,
91104
msg_receiver,
@@ -159,7 +172,6 @@ impl fmt::Debug for Event {
159172
}
160173

161174
fn main_loop_inner(
162-
options: InitializationOptions,
163175
pool: &ThreadPool,
164176
msg_sender: &Sender<RawMessage>,
165177
msg_receiver: &Receiver<RawMessage>,
@@ -258,7 +270,7 @@ fn main_loop_inner(
258270
&& in_flight_libraries == 0
259271
{
260272
let n_packages: usize = state.workspaces.iter().map(|it| it.count()).sum();
261-
if options.show_workspace_loaded {
273+
if state.options.show_workspace_loaded {
262274
let msg = format!("workspace loaded, {} rust packages", n_packages);
263275
show_message(req::MessageType::Info, msg, msg_sender);
264276
}
@@ -270,7 +282,7 @@ fn main_loop_inner(
270282
update_file_notifications_on_threadpool(
271283
pool,
272284
state.snapshot(),
273-
options.publish_decorations,
285+
state.options.publish_decorations,
274286
task_sender.clone(),
275287
subs.subscriptions(),
276288
)

crates/ra_lsp_server/src/main_loop/handlers.rs

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ use lsp_types::{
99
TextDocumentIdentifier, TextEdit, WorkspaceEdit,
1010
};
1111
use ra_ide_api::{
12-
AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo,
13-
RunnableKind, Severity,
12+
AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity,
1413
};
1514
use ra_prof::profile;
1615
use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit};
@@ -21,7 +20,7 @@ use url_serde::Ser;
2120

2221
use crate::{
2322
cargo_target_spec::{runnable_args, CargoTargetSpec},
24-
conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith},
23+
conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith, TryConvWithToVec},
2524
req::{self, Decoration},
2625
world::WorldSnapshot,
2726
LspError, Result,
@@ -263,72 +262,46 @@ pub fn handle_goto_definition(
263262
params: req::TextDocumentPositionParams,
264263
) -> Result<Option<req::GotoDefinitionResponse>> {
265264
let position = params.try_conv_with(&world)?;
266-
let line_index = world.analysis().file_line_index(position.file_id);
267265
let nav_info = match world.analysis().goto_definition(position)? {
268266
None => return Ok(None),
269267
Some(it) => it,
270268
};
271-
let nav_range = nav_info.range;
272-
let res = nav_info
273-
.info
274-
.into_iter()
275-
.map(|nav| RangeInfo::new(nav_range, nav))
276-
.map(|nav| to_location_link(&nav, &world, &line_index))
277-
.collect::<Result<Vec<_>>>()?;
278-
Ok(Some(res.into()))
269+
let res = (position.file_id, nav_info).try_conv_with(&world)?;
270+
Ok(Some(res))
279271
}
280272

281273
pub fn handle_goto_implementation(
282274
world: WorldSnapshot,
283275
params: req::TextDocumentPositionParams,
284276
) -> Result<Option<req::GotoImplementationResponse>> {
285277
let position = params.try_conv_with(&world)?;
286-
let line_index = world.analysis().file_line_index(position.file_id);
287278
let nav_info = match world.analysis().goto_implementation(position)? {
288279
None => return Ok(None),
289280
Some(it) => it,
290281
};
291-
let nav_range = nav_info.range;
292-
let res = nav_info
293-
.info
294-
.into_iter()
295-
.map(|nav| RangeInfo::new(nav_range, nav))
296-
.map(|nav| to_location_link(&nav, &world, &line_index))
297-
.collect::<Result<Vec<_>>>()?;
298-
Ok(Some(res.into()))
282+
let res = (position.file_id, nav_info).try_conv_with(&world)?;
283+
Ok(Some(res))
299284
}
300285

301286
pub fn handle_goto_type_definition(
302287
world: WorldSnapshot,
303288
params: req::TextDocumentPositionParams,
304289
) -> Result<Option<req::GotoTypeDefinitionResponse>> {
305290
let position = params.try_conv_with(&world)?;
306-
let line_index = world.analysis().file_line_index(position.file_id);
307291
let nav_info = match world.analysis().goto_type_definition(position)? {
308292
None => return Ok(None),
309293
Some(it) => it,
310294
};
311-
let nav_range = nav_info.range;
312-
let res = nav_info
313-
.info
314-
.into_iter()
315-
.map(|nav| RangeInfo::new(nav_range, nav))
316-
.map(|nav| to_location_link(&nav, &world, &line_index))
317-
.collect::<Result<Vec<_>>>()?;
318-
Ok(Some(res.into()))
295+
let res = (position.file_id, nav_info).try_conv_with(&world)?;
296+
Ok(Some(res))
319297
}
320298

321299
pub fn handle_parent_module(
322300
world: WorldSnapshot,
323301
params: req::TextDocumentPositionParams,
324302
) -> Result<Vec<Location>> {
325303
let position = params.try_conv_with(&world)?;
326-
world
327-
.analysis()
328-
.parent_module(position)?
329-
.into_iter()
330-
.map(|nav| nav.try_conv_with(&world))
331-
.collect::<Result<Vec<_>>>()
304+
world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world)
332305
}
333306

334307
pub fn handle_runnables(

crates/ra_lsp_server/src/world.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,21 @@ use crate::{
1919
LspError, Result,
2020
};
2121

22+
#[derive(Debug, Clone)]
23+
pub struct Options {
24+
pub publish_decorations: bool,
25+
pub show_workspace_loaded: bool,
26+
pub supports_location_link: bool,
27+
}
28+
2229
/// `WorldState` is the primary mutable state of the language server
2330
///
2431
/// The most interesting components are `vfs`, which stores a consistent
2532
/// snapshot of the file systems, and `analysis_host`, which stores our
2633
/// incremental salsa database.
2734
#[derive(Debug)]
2835
pub struct WorldState {
36+
pub options: Options,
2937
pub roots_to_scan: usize,
3038
pub roots: Vec<PathBuf>,
3139
pub workspaces: Arc<Vec<ProjectWorkspace>>,
@@ -36,6 +44,7 @@ pub struct WorldState {
3644

3745
/// An immutable snapshot of the world's state at a point in time.
3846
pub struct WorldSnapshot {
47+
pub options: Options,
3948
pub workspaces: Arc<Vec<ProjectWorkspace>>,
4049
pub analysis: Analysis,
4150
pub vfs: Arc<RwLock<Vfs>>,
@@ -47,6 +56,7 @@ impl WorldState {
4756
folder_roots: Vec<PathBuf>,
4857
workspaces: Vec<ProjectWorkspace>,
4958
lru_capacity: Option<usize>,
59+
options: Options,
5060
) -> WorldState {
5161
let mut change = AnalysisChange::new();
5262

@@ -78,6 +88,7 @@ impl WorldState {
7888
let mut analysis_host = AnalysisHost::new(lru_capacity);
7989
analysis_host.apply_change(change);
8090
WorldState {
91+
options,
8192
roots_to_scan,
8293
roots: folder_roots,
8394
workspaces: Arc::new(workspaces),
@@ -140,6 +151,7 @@ impl WorldState {
140151

141152
pub fn snapshot(&self) -> WorldSnapshot {
142153
WorldSnapshot {
154+
options: self.options.clone(),
143155
workspaces: Arc::clone(&self.workspaces),
144156
analysis: self.analysis_host.analysis(),
145157
vfs: Arc::clone(&self.vfs),

crates/ra_lsp_server/tests/heavy_tests/support.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use lsp_types::{
1313
notification::DidOpenTextDocument,
1414
notification::{Notification, ShowMessage},
1515
request::{Request, Shutdown},
16-
DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
16+
ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
17+
TextDocumentIdentifier, TextDocumentItem, Url,
1718
};
1819
use serde::Serialize;
1920
use serde_json::{to_string_pretty, Value};
@@ -92,8 +93,25 @@ impl Server {
9293
"test server",
9394
128,
9495
move |msg_receiver, msg_sender| {
95-
main_loop(roots, InitializationOptions::default(), &msg_receiver, &msg_sender)
96-
.unwrap()
96+
main_loop(
97+
roots,
98+
ClientCapabilities {
99+
workspace: None,
100+
text_document: Some(TextDocumentClientCapabilities {
101+
definition: Some(GotoCapability {
102+
dynamic_registration: None,
103+
link_support: Some(true),
104+
}),
105+
..Default::default()
106+
}),
107+
window: None,
108+
experimental: None,
109+
},
110+
InitializationOptions::default(),
111+
&msg_receiver,
112+
&msg_sender,
113+
)
114+
.unwrap()
97115
},
98116
);
99117
let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

0 commit comments

Comments
 (0)