From 227bc0b6d478564c45f49cb47dac963d9c37a528 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jul 2019 13:39:16 +0300 Subject: [PATCH 1/3] add try_conv_with_to_vec --- crates/ra_lsp_server/src/conv.rs | 61 +++++++++++++------ .../ra_lsp_server/src/main_loop/handlers.rs | 27 +++----- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 32e67838e0..fc01b1c0e4 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -384,27 +384,32 @@ impl TryConvWith for &NavigationTarget { } } -pub fn to_location_link( - target: &RangeInfo, - world: &WorldSnapshot, - // line index for original range file - line_index: &LineIndex, -) -> Result { - let target_uri = target.info.file_id().try_conv_with(world)?; - let tgt_line_index = world.analysis().file_line_index(target.info.file_id()); +impl TryConvWith for (FileId, RangeInfo) { + type Ctx = WorldSnapshot; + type Output = LocationLink; + fn try_conv_with(self, world: &WorldSnapshot) -> Result { + let (src_file_id, target) = self; - let target_range = target.info.full_range().conv_with(&tgt_line_index); + let target_uri = target.info.file_id().try_conv_with(world)?; + let src_line_index = world.analysis().file_line_index(src_file_id); + let tgt_line_index = world.analysis().file_line_index(target.info.file_id()); - let target_selection_range = - target.info.focus_range().map(|it| it.conv_with(&tgt_line_index)).unwrap_or(target_range); + let target_range = target.info.full_range().conv_with(&tgt_line_index); - let res = LocationLink { - origin_selection_range: Some(target.range.conv_with(line_index)), - target_uri, - target_range, - target_selection_range, - }; - Ok(res) + let target_selection_range = target + .info + .focus_range() + .map(|it| it.conv_with(&tgt_line_index)) + .unwrap_or(target_range); + + let res = LocationLink { + origin_selection_range: Some(target.range.conv_with(&src_line_index)), + target_uri, + target_range, + target_selection_range, + }; + Ok(res) + } } pub fn to_location( @@ -452,3 +457,23 @@ where self.iter.next().map(|item| item.conv_with(self.ctx)) } } + +pub trait TryConvWithToVec<'a>: Sized + 'a { + type Ctx; + type Output; + + fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result>; +} + +impl<'a, I> TryConvWithToVec<'a> for I +where + I: Iterator + 'a, + I::Item: TryConvWith, +{ + type Ctx = ::Ctx; + type Output = ::Output; + + fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result> { + self.map(|it| it.try_conv_with(ctx)).collect() + } +} diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 62c8cbf710..8f07f50277 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -21,7 +21,7 @@ use url_serde::Ser; use crate::{ cargo_target_spec::{runnable_args, CargoTargetSpec}, - conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, + conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith, TryConvWithToVec}, req::{self, Decoration}, world::WorldSnapshot, LspError, Result, @@ -263,7 +263,6 @@ pub fn handle_goto_definition( params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; - let line_index = world.analysis().file_line_index(position.file_id); let nav_info = match world.analysis().goto_definition(position)? { None => return Ok(None), Some(it) => it, @@ -272,9 +271,8 @@ pub fn handle_goto_definition( let res = nav_info .info .into_iter() - .map(|nav| RangeInfo::new(nav_range, nav)) - .map(|nav| to_location_link(&nav, &world, &line_index)) - .collect::>>()?; + .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) + .try_conv_with_to_vec(&world)?; Ok(Some(res.into())) } @@ -283,7 +281,6 @@ pub fn handle_goto_implementation( params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; - let line_index = world.analysis().file_line_index(position.file_id); let nav_info = match world.analysis().goto_implementation(position)? { None => return Ok(None), Some(it) => it, @@ -292,9 +289,8 @@ pub fn handle_goto_implementation( let res = nav_info .info .into_iter() - .map(|nav| RangeInfo::new(nav_range, nav)) - .map(|nav| to_location_link(&nav, &world, &line_index)) - .collect::>>()?; + .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) + .try_conv_with_to_vec(&world)?; Ok(Some(res.into())) } @@ -303,7 +299,6 @@ pub fn handle_goto_type_definition( params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; - let line_index = world.analysis().file_line_index(position.file_id); let nav_info = match world.analysis().goto_type_definition(position)? { None => return Ok(None), Some(it) => it, @@ -312,9 +307,8 @@ pub fn handle_goto_type_definition( let res = nav_info .info .into_iter() - .map(|nav| RangeInfo::new(nav_range, nav)) - .map(|nav| to_location_link(&nav, &world, &line_index)) - .collect::>>()?; + .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) + .try_conv_with_to_vec(&world)?; Ok(Some(res.into())) } @@ -323,12 +317,7 @@ pub fn handle_parent_module( params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; - world - .analysis() - .parent_module(position)? - .into_iter() - .map(|nav| nav.try_conv_with(&world)) - .collect::>>() + world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world) } pub fn handle_runnables( From b042faeb64d858c26b05dbf543925bf626454282 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jul 2019 13:47:02 +0300 Subject: [PATCH 2/3] simplify --- crates/ra_lsp_server/src/conv.rs | 13 ++++++++ .../ra_lsp_server/src/main_loop/handlers.rs | 30 +++++-------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index fc01b1c0e4..d0bdc94aa6 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -412,6 +412,19 @@ impl TryConvWith for (FileId, RangeInfo) { } } +impl TryConvWith for (FileId, RangeInfo>) { + type Ctx = WorldSnapshot; + type Output = req::GotoDefinitionResponse; + fn try_conv_with(self, world: &WorldSnapshot) -> Result { + let (file_id, RangeInfo { range, info: navs }) = self; + let links = navs + .into_iter() + .map(|nav| (file_id, RangeInfo::new(range, nav))) + .try_conv_with_to_vec(world)?; + Ok(links.into()) + } +} + pub fn to_location( file_id: FileId, range: TextRange, diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 8f07f50277..ab9ed50806 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::{ TextDocumentIdentifier, TextEdit, WorkspaceEdit, }; use ra_ide_api::{ - AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, - RunnableKind, Severity, + AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, }; use ra_prof::profile; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; @@ -267,13 +266,8 @@ pub fn handle_goto_definition( None => return Ok(None), Some(it) => it, }; - let nav_range = nav_info.range; - let res = nav_info - .info - .into_iter() - .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) - .try_conv_with_to_vec(&world)?; - Ok(Some(res.into())) + let res = (position.file_id, nav_info).try_conv_with(&world)?; + Ok(Some(res)) } pub fn handle_goto_implementation( @@ -285,13 +279,8 @@ pub fn handle_goto_implementation( None => return Ok(None), Some(it) => it, }; - let nav_range = nav_info.range; - let res = nav_info - .info - .into_iter() - .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) - .try_conv_with_to_vec(&world)?; - Ok(Some(res.into())) + let res = (position.file_id, nav_info).try_conv_with(&world)?; + Ok(Some(res)) } pub fn handle_goto_type_definition( @@ -303,13 +292,8 @@ pub fn handle_goto_type_definition( None => return Ok(None), Some(it) => it, }; - let nav_range = nav_info.range; - let res = nav_info - .info - .into_iter() - .map(|nav| (position.file_id, RangeInfo::new(nav_range, nav))) - .try_conv_with_to_vec(&world)?; - Ok(Some(res.into())) + let res = (position.file_id, nav_info).try_conv_with(&world)?; + Ok(Some(res)) } pub fn handle_parent_module( From e075e096cf4970014d2c0829476fd7a45a3f32b1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 8 Jul 2019 14:09:38 +0300 Subject: [PATCH 3/3] don't send LocationLink unless the client opts-in closes #1474 --- crates/ra_lsp_server/src/conv.rs | 10 ++++++- crates/ra_lsp_server/src/main.rs | 2 +- crates/ra_lsp_server/src/main_loop.rs | 26 ++++++++++++++----- crates/ra_lsp_server/src/world.rs | 12 +++++++++ .../tests/heavy_tests/support.rs | 24 ++++++++++++++--- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index d0bdc94aa6..82c7e757fa 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -421,7 +421,15 @@ impl TryConvWith for (FileId, RangeInfo>) { .into_iter() .map(|nav| (file_id, RangeInfo::new(range, nav))) .try_conv_with_to_vec(world)?; - Ok(links.into()) + if world.options.supports_location_link { + Ok(links.into()) + } else { + let locations: Vec = links + .into_iter() + .map(|link| Location { uri: link.target_uri, range: link.target_selection_range }) + .collect(); + Ok(locations.into()) + } } } diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index 6aa6dd49fb..c1f8243be2 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<()> { .and_then(|v| InitializationOptions::deserialize(v).ok()) .unwrap_or_default(); - ra_lsp_server::main_loop(workspace_roots, opts, r, s) + ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s) })?; log::info!("shutting down IO..."); threads.join()?; diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index c44fc66034..f7becd8fba 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}; use gen_lsp_server::{ handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, }; -use lsp_types::NumberOrString; +use lsp_types::{ClientCapabilities, NumberOrString}; use ra_ide_api::{Canceled, FileId, LibraryData}; use ra_prof::profile; use ra_vfs::VfsTask; @@ -22,7 +22,7 @@ use crate::{ }, project_model::workspace_loader, req, - world::{WorldSnapshot, WorldState}, + world::{Options, WorldSnapshot, WorldState}, InitializationOptions, Result, }; @@ -51,6 +51,7 @@ impl Error for LspError {} pub fn main_loop( ws_roots: Vec, + client_caps: ClientCapabilities, options: InitializationOptions, msg_receiver: &Receiver, msg_sender: &Sender, @@ -77,7 +78,20 @@ pub fn main_loop( loaded_workspaces }; - let mut state = WorldState::new(ws_roots, workspaces, options.lru_capacity); + let mut state = WorldState::new( + ws_roots, + workspaces, + options.lru_capacity, + Options { + publish_decorations: options.publish_decorations, + show_workspace_loaded: options.show_workspace_loaded, + supports_location_link: client_caps + .text_document + .and_then(|it| it.definition) + .and_then(|it| it.link_support) + .unwrap_or(false), + }, + ); let pool = ThreadPool::new(THREADPOOL_SIZE); let (task_sender, task_receiver) = unbounded::(); @@ -85,7 +99,6 @@ pub fn main_loop( log::info!("server initialized, serving requests"); let main_res = main_loop_inner( - options, &pool, msg_sender, msg_receiver, @@ -159,7 +172,6 @@ impl fmt::Debug for Event { } fn main_loop_inner( - options: InitializationOptions, pool: &ThreadPool, msg_sender: &Sender, msg_receiver: &Receiver, @@ -258,7 +270,7 @@ fn main_loop_inner( && in_flight_libraries == 0 { let n_packages: usize = state.workspaces.iter().map(|it| it.count()).sum(); - if options.show_workspace_loaded { + if state.options.show_workspace_loaded { let msg = format!("workspace loaded, {} rust packages", n_packages); show_message(req::MessageType::Info, msg, msg_sender); } @@ -270,7 +282,7 @@ fn main_loop_inner( update_file_notifications_on_threadpool( pool, state.snapshot(), - options.publish_decorations, + state.options.publish_decorations, task_sender.clone(), subs.subscriptions(), ) diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index fdc577622e..9fd654305c 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs @@ -19,6 +19,13 @@ use crate::{ LspError, Result, }; +#[derive(Debug, Clone)] +pub struct Options { + pub publish_decorations: bool, + pub show_workspace_loaded: bool, + pub supports_location_link: bool, +} + /// `WorldState` is the primary mutable state of the language server /// /// The most interesting components are `vfs`, which stores a consistent @@ -26,6 +33,7 @@ use crate::{ /// incremental salsa database. #[derive(Debug)] pub struct WorldState { + pub options: Options, pub roots_to_scan: usize, pub roots: Vec, pub workspaces: Arc>, @@ -36,6 +44,7 @@ pub struct WorldState { /// An immutable snapshot of the world's state at a point in time. pub struct WorldSnapshot { + pub options: Options, pub workspaces: Arc>, pub analysis: Analysis, pub vfs: Arc>, @@ -47,6 +56,7 @@ impl WorldState { folder_roots: Vec, workspaces: Vec, lru_capacity: Option, + options: Options, ) -> WorldState { let mut change = AnalysisChange::new(); @@ -78,6 +88,7 @@ impl WorldState { let mut analysis_host = AnalysisHost::new(lru_capacity); analysis_host.apply_change(change); WorldState { + options, roots_to_scan, roots: folder_roots, workspaces: Arc::new(workspaces), @@ -140,6 +151,7 @@ impl WorldState { pub fn snapshot(&self) -> WorldSnapshot { WorldSnapshot { + options: self.options.clone(), workspaces: Arc::clone(&self.workspaces), analysis: self.analysis_host.analysis(), 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 a5e352da15..5dddbbe172 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::{ notification::DidOpenTextDocument, notification::{Notification, ShowMessage}, request::{Request, Shutdown}, - DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, + ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities, + TextDocumentIdentifier, TextDocumentItem, Url, }; use serde::Serialize; use serde_json::{to_string_pretty, Value}; @@ -92,8 +93,25 @@ impl Server { "test server", 128, move |msg_receiver, msg_sender| { - main_loop(roots, InitializationOptions::default(), &msg_receiver, &msg_sender) - .unwrap() + main_loop( + roots, + ClientCapabilities { + workspace: None, + text_document: Some(TextDocumentClientCapabilities { + definition: Some(GotoCapability { + dynamic_registration: None, + link_support: Some(true), + }), + ..Default::default() + }), + window: None, + experimental: None, + }, + InitializationOptions::default(), + &msg_receiver, + &msg_sender, + ) + .unwrap() }, ); let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };