aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_lsp_server/src/conv.rs86
-rw-r--r--crates/ra_lsp_server/src/main.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs26
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs45
-rw-r--r--crates/ra_lsp_server/src/world.rs12
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs24
6 files changed, 128 insertions, 67 deletions
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 32e67838e..82c7e757f 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -384,27 +384,53 @@ impl TryConvWith for &NavigationTarget {
384 } 384 }
385} 385}
386 386
387pub fn to_location_link( 387impl TryConvWith for (FileId, RangeInfo<NavigationTarget>) {
388 target: &RangeInfo<NavigationTarget>, 388 type Ctx = WorldSnapshot;
389 world: &WorldSnapshot, 389 type Output = LocationLink;
390 // line index for original range file 390 fn try_conv_with(self, world: &WorldSnapshot) -> Result<LocationLink> {
391 line_index: &LineIndex, 391 let (src_file_id, target) = self;
392) -> Result<LocationLink> { 392
393 let target_uri = target.info.file_id().try_conv_with(world)?; 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()); 394 let src_line_index = world.analysis().file_line_index(src_file_id);
395 395 let tgt_line_index = world.analysis().file_line_index(target.info.file_id());
396 let target_range = target.info.full_range().conv_with(&tgt_line_index); 396
397 397 let target_range = target.info.full_range().conv_with(&tgt_line_index);
398 let target_selection_range = 398
399 target.info.focus_range().map(|it| it.conv_with(&tgt_line_index)).unwrap_or(target_range); 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}
400 414
401 let res = LocationLink { 415impl TryConvWith for (FileId, RangeInfo<Vec<NavigationTarget>>) {
402 origin_selection_range: Some(target.range.conv_with(line_index)), 416 type Ctx = WorldSnapshot;
403 target_uri, 417 type Output = req::GotoDefinitionResponse;
404 target_range, 418 fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::GotoTypeDefinitionResponse> {
405 target_selection_range, 419 let (file_id, RangeInfo { range, info: navs }) = self;
406 }; 420 let links = navs
407 Ok(res) 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 }
408} 434}
409 435
410pub fn to_location( 436pub fn to_location(
@@ -452,3 +478,23 @@ where
452 self.iter.next().map(|item| item.conv_with(self.ctx)) 478 self.iter.next().map(|item| item.conv_with(self.ctx))
453 } 479 }
454} 480}
481
482pub 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
489impl<'a, I> TryConvWithToVec<'a> for I
490where
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}
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index 6aa6dd49f..c1f8243be 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -51,7 +51,7 @@ fn main_inner() -> Result<()> {
51 .and_then(|v| InitializationOptions::deserialize(v).ok()) 51 .and_then(|v| InitializationOptions::deserialize(v).ok())
52 .unwrap_or_default(); 52 .unwrap_or_default();
53 53
54 ra_lsp_server::main_loop(workspace_roots, opts, r, s) 54 ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s)
55 })?; 55 })?;
56 log::info!("shutting down IO..."); 56 log::info!("shutting down IO...");
57 threads.join()?; 57 threads.join()?;
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index c44fc6603..f7becd8fb 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -8,7 +8,7 @@ use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender};
8use gen_lsp_server::{ 8use gen_lsp_server::{
9 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, 9 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
10}; 10};
11use lsp_types::NumberOrString; 11use lsp_types::{ClientCapabilities, NumberOrString};
12use ra_ide_api::{Canceled, FileId, LibraryData}; 12use ra_ide_api::{Canceled, FileId, LibraryData};
13use ra_prof::profile; 13use ra_prof::profile;
14use ra_vfs::VfsTask; 14use ra_vfs::VfsTask;
@@ -22,7 +22,7 @@ use crate::{
22 }, 22 },
23 project_model::workspace_loader, 23 project_model::workspace_loader,
24 req, 24 req,
25 world::{WorldSnapshot, WorldState}, 25 world::{Options, WorldSnapshot, WorldState},
26 InitializationOptions, Result, 26 InitializationOptions, Result,
27}; 27};
28 28
@@ -51,6 +51,7 @@ impl Error for LspError {}
51 51
52pub fn main_loop( 52pub fn main_loop(
53 ws_roots: Vec<PathBuf>, 53 ws_roots: Vec<PathBuf>,
54 client_caps: ClientCapabilities,
54 options: InitializationOptions, 55 options: InitializationOptions,
55 msg_receiver: &Receiver<RawMessage>, 56 msg_receiver: &Receiver<RawMessage>,
56 msg_sender: &Sender<RawMessage>, 57 msg_sender: &Sender<RawMessage>,
@@ -77,7 +78,20 @@ pub fn main_loop(
77 loaded_workspaces 78 loaded_workspaces
78 }; 79 };
79 80
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 );
81 95
82 let pool = ThreadPool::new(THREADPOOL_SIZE); 96 let pool = ThreadPool::new(THREADPOOL_SIZE);
83 let (task_sender, task_receiver) = unbounded::<Task>(); 97 let (task_sender, task_receiver) = unbounded::<Task>();
@@ -85,7 +99,6 @@ pub fn main_loop(
85 99
86 log::info!("server initialized, serving requests"); 100 log::info!("server initialized, serving requests");
87 let main_res = main_loop_inner( 101 let main_res = main_loop_inner(
88 options,
89 &pool, 102 &pool,
90 msg_sender, 103 msg_sender,
91 msg_receiver, 104 msg_receiver,
@@ -159,7 +172,6 @@ impl fmt::Debug for Event {
159} 172}
160 173
161fn main_loop_inner( 174fn main_loop_inner(
162 options: InitializationOptions,
163 pool: &ThreadPool, 175 pool: &ThreadPool,
164 msg_sender: &Sender<RawMessage>, 176 msg_sender: &Sender<RawMessage>,
165 msg_receiver: &Receiver<RawMessage>, 177 msg_receiver: &Receiver<RawMessage>,
@@ -258,7 +270,7 @@ fn main_loop_inner(
258 && in_flight_libraries == 0 270 && in_flight_libraries == 0
259 { 271 {
260 let n_packages: usize = state.workspaces.iter().map(|it| it.count()).sum(); 272 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 {
262 let msg = format!("workspace loaded, {} rust packages", n_packages); 274 let msg = format!("workspace loaded, {} rust packages", n_packages);
263 show_message(req::MessageType::Info, msg, msg_sender); 275 show_message(req::MessageType::Info, msg, msg_sender);
264 } 276 }
@@ -270,7 +282,7 @@ fn main_loop_inner(
270 update_file_notifications_on_threadpool( 282 update_file_notifications_on_threadpool(
271 pool, 283 pool,
272 state.snapshot(), 284 state.snapshot(),
273 options.publish_decorations, 285 state.options.publish_decorations,
274 task_sender.clone(), 286 task_sender.clone(),
275 subs.subscriptions(), 287 subs.subscriptions(),
276 ) 288 )
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 62c8cbf71..ab9ed5080 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -9,8 +9,7 @@ use lsp_types::{
9 TextDocumentIdentifier, TextEdit, WorkspaceEdit, 9 TextDocumentIdentifier, TextEdit, WorkspaceEdit,
10}; 10};
11use ra_ide_api::{ 11use ra_ide_api::{
12 AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, 12 AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity,
13 RunnableKind, Severity,
14}; 13};
15use ra_prof::profile; 14use ra_prof::profile;
16use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; 15use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit};
@@ -21,7 +20,7 @@ use url_serde::Ser;
21 20
22use crate::{ 21use crate::{
23 cargo_target_spec::{runnable_args, CargoTargetSpec}, 22 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},
25 req::{self, Decoration}, 24 req::{self, Decoration},
26 world::WorldSnapshot, 25 world::WorldSnapshot,
27 LspError, Result, 26 LspError, Result,
@@ -263,19 +262,12 @@ pub fn handle_goto_definition(
263 params: req::TextDocumentPositionParams, 262 params: req::TextDocumentPositionParams,
264) -> Result<Option<req::GotoDefinitionResponse>> { 263) -> Result<Option<req::GotoDefinitionResponse>> {
265 let position = params.try_conv_with(&world)?; 264 let position = params.try_conv_with(&world)?;
266 let line_index = world.analysis().file_line_index(position.file_id);
267 let nav_info = match world.analysis().goto_definition(position)? { 265 let nav_info = match world.analysis().goto_definition(position)? {
268 None => return Ok(None), 266 None => return Ok(None),
269 Some(it) => it, 267 Some(it) => it,
270 }; 268 };
271 let nav_range = nav_info.range; 269 let res = (position.file_id, nav_info).try_conv_with(&world)?;
272 let res = nav_info 270 Ok(Some(res))
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()))
279} 271}
280 272
281pub fn handle_goto_implementation( 273pub fn handle_goto_implementation(
@@ -283,19 +275,12 @@ pub fn handle_goto_implementation(
283 params: req::TextDocumentPositionParams, 275 params: req::TextDocumentPositionParams,
284) -> Result<Option<req::GotoImplementationResponse>> { 276) -> Result<Option<req::GotoImplementationResponse>> {
285 let position = params.try_conv_with(&world)?; 277 let position = params.try_conv_with(&world)?;
286 let line_index = world.analysis().file_line_index(position.file_id);
287 let nav_info = match world.analysis().goto_implementation(position)? { 278 let nav_info = match world.analysis().goto_implementation(position)? {
288 None => return Ok(None), 279 None => return Ok(None),
289 Some(it) => it, 280 Some(it) => it,
290 }; 281 };
291 let nav_range = nav_info.range; 282 let res = (position.file_id, nav_info).try_conv_with(&world)?;
292 let res = nav_info 283 Ok(Some(res))
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()))
299} 284}
300 285
301pub fn handle_goto_type_definition( 286pub fn handle_goto_type_definition(
@@ -303,19 +288,12 @@ pub fn handle_goto_type_definition(
303 params: req::TextDocumentPositionParams, 288 params: req::TextDocumentPositionParams,
304) -> Result<Option<req::GotoTypeDefinitionResponse>> { 289) -> Result<Option<req::GotoTypeDefinitionResponse>> {
305 let position = params.try_conv_with(&world)?; 290 let position = params.try_conv_with(&world)?;
306 let line_index = world.analysis().file_line_index(position.file_id);
307 let nav_info = match world.analysis().goto_type_definition(position)? { 291 let nav_info = match world.analysis().goto_type_definition(position)? {
308 None => return Ok(None), 292 None => return Ok(None),
309 Some(it) => it, 293 Some(it) => it,
310 }; 294 };
311 let nav_range = nav_info.range; 295 let res = (position.file_id, nav_info).try_conv_with(&world)?;
312 let res = nav_info 296 Ok(Some(res))
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()))
319} 297}
320 298
321pub fn handle_parent_module( 299pub fn handle_parent_module(
@@ -323,12 +301,7 @@ pub fn handle_parent_module(
323 params: req::TextDocumentPositionParams, 301 params: req::TextDocumentPositionParams,
324) -> Result<Vec<Location>> { 302) -> Result<Vec<Location>> {
325 let position = params.try_conv_with(&world)?; 303 let position = params.try_conv_with(&world)?;
326 world 304 world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world)
327 .analysis()
328 .parent_module(position)?
329 .into_iter()
330 .map(|nav| nav.try_conv_with(&world))
331 .collect::<Result<Vec<_>>>()
332} 305}
333 306
334pub fn handle_runnables( 307pub fn handle_runnables(
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index fdc577622..9fd654305 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -19,6 +19,13 @@ use crate::{
19 LspError, Result, 19 LspError, Result,
20}; 20};
21 21
22#[derive(Debug, Clone)]
23pub struct Options {
24 pub publish_decorations: bool,
25 pub show_workspace_loaded: bool,
26 pub supports_location_link: bool,
27}
28
22/// `WorldState` is the primary mutable state of the language server 29/// `WorldState` is the primary mutable state of the language server
23/// 30///
24/// The most interesting components are `vfs`, which stores a consistent 31/// The most interesting components are `vfs`, which stores a consistent
@@ -26,6 +33,7 @@ use crate::{
26/// incremental salsa database. 33/// incremental salsa database.
27#[derive(Debug)] 34#[derive(Debug)]
28pub struct WorldState { 35pub struct WorldState {
36 pub options: Options,
29 pub roots_to_scan: usize, 37 pub roots_to_scan: usize,
30 pub roots: Vec<PathBuf>, 38 pub roots: Vec<PathBuf>,
31 pub workspaces: Arc<Vec<ProjectWorkspace>>, 39 pub workspaces: Arc<Vec<ProjectWorkspace>>,
@@ -36,6 +44,7 @@ pub struct WorldState {
36 44
37/// An immutable snapshot of the world's state at a point in time. 45/// An immutable snapshot of the world's state at a point in time.
38pub struct WorldSnapshot { 46pub struct WorldSnapshot {
47 pub options: Options,
39 pub workspaces: Arc<Vec<ProjectWorkspace>>, 48 pub workspaces: Arc<Vec<ProjectWorkspace>>,
40 pub analysis: Analysis, 49 pub analysis: Analysis,
41 pub vfs: Arc<RwLock<Vfs>>, 50 pub vfs: Arc<RwLock<Vfs>>,
@@ -47,6 +56,7 @@ impl WorldState {
47 folder_roots: Vec<PathBuf>, 56 folder_roots: Vec<PathBuf>,
48 workspaces: Vec<ProjectWorkspace>, 57 workspaces: Vec<ProjectWorkspace>,
49 lru_capacity: Option<usize>, 58 lru_capacity: Option<usize>,
59 options: Options,
50 ) -> WorldState { 60 ) -> WorldState {
51 let mut change = AnalysisChange::new(); 61 let mut change = AnalysisChange::new();
52 62
@@ -78,6 +88,7 @@ impl WorldState {
78 let mut analysis_host = AnalysisHost::new(lru_capacity); 88 let mut analysis_host = AnalysisHost::new(lru_capacity);
79 analysis_host.apply_change(change); 89 analysis_host.apply_change(change);
80 WorldState { 90 WorldState {
91 options,
81 roots_to_scan, 92 roots_to_scan,
82 roots: folder_roots, 93 roots: folder_roots,
83 workspaces: Arc::new(workspaces), 94 workspaces: Arc::new(workspaces),
@@ -140,6 +151,7 @@ impl WorldState {
140 151
141 pub fn snapshot(&self) -> WorldSnapshot { 152 pub fn snapshot(&self) -> WorldSnapshot {
142 WorldSnapshot { 153 WorldSnapshot {
154 options: self.options.clone(),
143 workspaces: Arc::clone(&self.workspaces), 155 workspaces: Arc::clone(&self.workspaces),
144 analysis: self.analysis_host.analysis(), 156 analysis: self.analysis_host.analysis(),
145 vfs: Arc::clone(&self.vfs), 157 vfs: Arc::clone(&self.vfs),
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index a5e352da1..5dddbbe17 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -13,7 +13,8 @@ use lsp_types::{
13 notification::DidOpenTextDocument, 13 notification::DidOpenTextDocument,
14 notification::{Notification, ShowMessage}, 14 notification::{Notification, ShowMessage},
15 request::{Request, Shutdown}, 15 request::{Request, Shutdown},
16 DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, 16 ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
17 TextDocumentIdentifier, TextDocumentItem, Url,
17}; 18};
18use serde::Serialize; 19use serde::Serialize;
19use serde_json::{to_string_pretty, Value}; 20use serde_json::{to_string_pretty, Value};
@@ -92,8 +93,25 @@ impl Server {
92 "test server", 93 "test server",
93 128, 94 128,
94 move |msg_receiver, msg_sender| { 95 move |msg_receiver, msg_sender| {
95 main_loop(roots, InitializationOptions::default(), &msg_receiver, &msg_sender) 96 main_loop(
96 .unwrap() 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()
97 }, 115 },
98 ); 116 );
99 let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker }; 117 let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };