diff options
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 24 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model.rs | 36 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 39 |
3 files changed, 75 insertions, 24 deletions
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 0e1878906..41f70f263 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -9,7 +9,8 @@ use gen_lsp_server::{ | |||
9 | }; | 9 | }; |
10 | use languageserver_types::NumberOrString; | 10 | use languageserver_types::NumberOrString; |
11 | use ra_analysis::{Canceled, FileId, LibraryData}; | 11 | use ra_analysis::{Canceled, FileId, LibraryData}; |
12 | use rayon::{self, ThreadPool}; | 12 | use rayon; |
13 | use threadpool::ThreadPool; | ||
13 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
14 | use serde::{de::DeserializeOwned, Serialize}; | 15 | use serde::{de::DeserializeOwned, Serialize}; |
15 | use failure::{format_err, bail}; | 16 | use failure::{format_err, bail}; |
@@ -54,11 +55,7 @@ pub fn main_loop( | |||
54 | msg_receiver: &Receiver<RawMessage>, | 55 | msg_receiver: &Receiver<RawMessage>, |
55 | msg_sender: &Sender<RawMessage>, | 56 | msg_sender: &Sender<RawMessage>, |
56 | ) -> Result<()> { | 57 | ) -> Result<()> { |
57 | let pool = rayon::ThreadPoolBuilder::new() | 58 | let pool = ThreadPool::new(8); |
58 | .num_threads(4) | ||
59 | .panic_handler(|_| log::error!("thread panicked :(")) | ||
60 | .build() | ||
61 | .unwrap(); | ||
62 | let (task_sender, task_receiver) = unbounded::<Task>(); | 59 | let (task_sender, task_receiver) = unbounded::<Task>(); |
63 | let (fs_worker, fs_watcher) = vfs::roots_loader(); | 60 | let (fs_worker, fs_watcher) = vfs::roots_loader(); |
64 | let (ws_worker, ws_watcher) = workspace_loader(); | 61 | let (ws_worker, ws_watcher) = workspace_loader(); |
@@ -155,7 +152,7 @@ fn main_loop_inner( | |||
155 | } else { | 152 | } else { |
156 | let (files, resolver) = state.events_to_files(events); | 153 | let (files, resolver) = state.events_to_files(events); |
157 | let sender = libdata_sender.clone(); | 154 | let sender = libdata_sender.clone(); |
158 | pool.spawn(move || { | 155 | pool.execute(move || { |
159 | let start = ::std::time::Instant::now(); | 156 | let start = ::std::time::Instant::now(); |
160 | log::info!("indexing {} ... ", root.display()); | 157 | log::info!("indexing {} ... ", root.display()); |
161 | let data = LibraryData::prepare(files, resolver); | 158 | let data = LibraryData::prepare(files, resolver); |
@@ -321,7 +318,14 @@ fn on_notification( | |||
321 | panic!("string id's not supported: {:?}", id); | 318 | panic!("string id's not supported: {:?}", id); |
322 | } | 319 | } |
323 | }; | 320 | }; |
324 | pending_requests.remove(&id); | 321 | if pending_requests.remove(&id) { |
322 | let response = RawResponse::err( | ||
323 | id, | ||
324 | ErrorCode::RequestCancelled as i32, | ||
325 | "canceled by client".to_string(), | ||
326 | ); | ||
327 | msg_sender.send(RawMessage::Response(response)) | ||
328 | } | ||
325 | return Ok(()); | 329 | return Ok(()); |
326 | } | 330 | } |
327 | Err(not) => not, | 331 | Err(not) => not, |
@@ -402,7 +406,7 @@ impl<'a> PoolDispatcher<'a> { | |||
402 | Ok((id, params)) => { | 406 | Ok((id, params)) => { |
403 | let world = self.world.snapshot(); | 407 | let world = self.world.snapshot(); |
404 | let sender = self.sender.clone(); | 408 | let sender = self.sender.clone(); |
405 | self.pool.spawn(move || { | 409 | self.pool.execute(move || { |
406 | let resp = match f(world, params) { | 410 | let resp = match f(world, params) { |
407 | Ok(resp) => RawResponse::ok::<R>(id, &resp), | 411 | Ok(resp) => RawResponse::ok::<R>(id, &resp), |
408 | Err(e) => match e.downcast::<LspError>() { | 412 | Err(e) => match e.downcast::<LspError>() { |
@@ -452,7 +456,7 @@ fn update_file_notifications_on_threadpool( | |||
452 | sender: Sender<Task>, | 456 | sender: Sender<Task>, |
453 | subscriptions: Vec<FileId>, | 457 | subscriptions: Vec<FileId>, |
454 | ) { | 458 | ) { |
455 | pool.spawn(move || { | 459 | pool.execute(move || { |
456 | for file_id in subscriptions { | 460 | for file_id in subscriptions { |
457 | match handlers::publish_diagnostics(&world, file_id) { | 461 | match handlers::publish_diagnostics(&world, file_id) { |
458 | Err(e) => { | 462 | Err(e) => { |
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index 3305d468a..cb91ada90 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::path::{Path, PathBuf}; | 1 | use std::path::{Path, PathBuf}; |
2 | 2 | ||
3 | use serde_derive::Serialize; | ||
4 | use cargo_metadata::{metadata_run, CargoOpt}; | 3 | use cargo_metadata::{metadata_run, CargoOpt}; |
5 | use ra_syntax::SmolStr; | 4 | use ra_syntax::SmolStr; |
6 | use rustc_hash::{FxHashMap, FxHashSet}; | 5 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -11,15 +10,22 @@ use crate::{ | |||
11 | thread_watcher::{ThreadWatcher, Worker}, | 10 | thread_watcher::{ThreadWatcher, Worker}, |
12 | }; | 11 | }; |
13 | 12 | ||
13 | /// `CargoWorksapce` represents the logical structure of, well, a Cargo | ||
14 | /// workspace. It pretty closely mirrors `cargo metadata` output. | ||
15 | /// | ||
16 | /// Note that internally, rust analyzer uses a differnet structure: | ||
17 | /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, | ||
18 | /// while this knows about `Pacakges` & `Targets`: purely cargo-related | ||
19 | /// concepts. | ||
14 | #[derive(Debug, Clone)] | 20 | #[derive(Debug, Clone)] |
15 | pub struct CargoWorkspace { | 21 | pub struct CargoWorkspace { |
16 | packages: Vec<PackageData>, | 22 | packages: Vec<PackageData>, |
17 | targets: Vec<TargetData>, | 23 | targets: Vec<TargetData>, |
18 | } | 24 | } |
19 | 25 | ||
20 | #[derive(Clone, Copy, Debug, Serialize)] | 26 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
21 | pub struct Package(usize); | 27 | pub struct Package(usize); |
22 | #[derive(Clone, Copy, Debug, Serialize)] | 28 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
23 | pub struct Target(usize); | 29 | pub struct Target(usize); |
24 | 30 | ||
25 | #[derive(Debug, Clone)] | 31 | #[derive(Debug, Clone)] |
@@ -28,6 +34,13 @@ struct PackageData { | |||
28 | manifest: PathBuf, | 34 | manifest: PathBuf, |
29 | targets: Vec<Target>, | 35 | targets: Vec<Target>, |
30 | is_member: bool, | 36 | is_member: bool, |
37 | dependencies: Vec<PackageDependency>, | ||
38 | } | ||
39 | |||
40 | #[derive(Debug, Clone)] | ||
41 | pub struct PackageDependency { | ||
42 | pub pkg: Package, | ||
43 | pub name: SmolStr, | ||
31 | } | 44 | } |
32 | 45 | ||
33 | #[derive(Debug, Clone)] | 46 | #[derive(Debug, Clone)] |
@@ -61,6 +74,12 @@ impl Package { | |||
61 | pub fn is_member(self, ws: &CargoWorkspace) -> bool { | 74 | pub fn is_member(self, ws: &CargoWorkspace) -> bool { |
62 | ws.pkg(self).is_member | 75 | ws.pkg(self).is_member |
63 | } | 76 | } |
77 | pub fn dependencies<'a>( | ||
78 | self, | ||
79 | ws: &'a CargoWorkspace, | ||
80 | ) -> impl Iterator<Item = &'a PackageDependency> + 'a { | ||
81 | ws.pkg(self).dependencies.iter() | ||
82 | } | ||
64 | } | 83 | } |
65 | 84 | ||
66 | impl Target { | 85 | impl Target { |
@@ -106,6 +125,7 @@ impl CargoWorkspace { | |||
106 | manifest: PathBuf::from(meta_pkg.manifest_path), | 125 | manifest: PathBuf::from(meta_pkg.manifest_path), |
107 | targets: Vec::new(), | 126 | targets: Vec::new(), |
108 | is_member, | 127 | is_member, |
128 | dependencies: Vec::new(), | ||
109 | }; | 129 | }; |
110 | for meta_tgt in meta_pkg.targets { | 130 | for meta_tgt in meta_pkg.targets { |
111 | let tgt = Target(targets.len()); | 131 | let tgt = Target(targets.len()); |
@@ -119,6 +139,16 @@ impl CargoWorkspace { | |||
119 | } | 139 | } |
120 | packages.push(pkg_data) | 140 | packages.push(pkg_data) |
121 | } | 141 | } |
142 | let resolve = meta.resolve.expect("metadata executed with deps"); | ||
143 | for node in resolve.nodes { | ||
144 | let source = pkg_by_id[&node.id]; | ||
145 | for id in node.dependencies { | ||
146 | let target = pkg_by_id[&id]; | ||
147 | let name: SmolStr = packages[target.0].name.replace('-', "_").into(); | ||
148 | let dep = PackageDependency { name, pkg: target }; | ||
149 | packages[source.0].dependencies.push(dep); | ||
150 | } | ||
151 | } | ||
122 | 152 | ||
123 | Ok(CargoWorkspace { packages, targets }) | 153 | Ok(CargoWorkspace { packages, targets }) |
124 | } | 154 | } |
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index c3f89ad5f..ab4c2c8aa 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -13,7 +13,7 @@ use failure::{bail, format_err}; | |||
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | path_map::{PathMap, Root}, | 15 | path_map::{PathMap, Root}, |
16 | project_model::CargoWorkspace, | 16 | project_model::{CargoWorkspace, TargetKind}, |
17 | vfs::{FileEvent, FileEventKind}, | 17 | vfs::{FileEvent, FileEventKind}, |
18 | Result, | 18 | Result, |
19 | }; | 19 | }; |
@@ -142,17 +142,34 @@ impl ServerWorldState { | |||
142 | } | 142 | } |
143 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { | 143 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { |
144 | let mut crate_graph = CrateGraph::default(); | 144 | let mut crate_graph = CrateGraph::default(); |
145 | ws.iter() | 145 | let mut pkg_to_lib_crate = FxHashMap::default(); |
146 | .flat_map(|ws| { | 146 | let mut pkg_crates = FxHashMap::default(); |
147 | ws.packages() | 147 | for ws in ws.iter() { |
148 | .flat_map(move |pkg| pkg.targets(ws)) | 148 | for pkg in ws.packages() { |
149 | .map(move |tgt| tgt.root(ws)) | 149 | for tgt in pkg.targets(ws) { |
150 | }) | 150 | let root = tgt.root(ws); |
151 | .for_each(|root| { | 151 | if let Some(file_id) = self.path_map.get_id(root) { |
152 | if let Some(file_id) = self.path_map.get_id(root) { | 152 | let crate_id = crate_graph.add_crate_root(file_id); |
153 | crate_graph.add_crate_root(file_id); | 153 | if tgt.kind(ws) == TargetKind::Lib { |
154 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
155 | } | ||
156 | pkg_crates | ||
157 | .entry(pkg) | ||
158 | .or_insert_with(Vec::new) | ||
159 | .push(crate_id); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | for pkg in ws.packages() { | ||
164 | for dep in pkg.dependencies(ws) { | ||
165 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
166 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
167 | crate_graph.add_dep(from, dep.name.clone(), to); | ||
168 | } | ||
169 | } | ||
154 | } | 170 | } |
155 | }); | 171 | } |
172 | } | ||
156 | self.workspaces = Arc::new(ws); | 173 | self.workspaces = Arc::new(ws); |
157 | let mut change = AnalysisChange::new(); | 174 | let mut change = AnalysisChange::new(); |
158 | change.set_crate_graph(crate_graph); | 175 | change.set_crate_graph(crate_graph); |