aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs24
-rw-r--r--crates/ra_lsp_server/src/project_model.rs36
-rw-r--r--crates/ra_lsp_server/src/server_world.rs39
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};
10use languageserver_types::NumberOrString; 10use languageserver_types::NumberOrString;
11use ra_analysis::{Canceled, FileId, LibraryData}; 11use ra_analysis::{Canceled, FileId, LibraryData};
12use rayon::{self, ThreadPool}; 12use rayon;
13use threadpool::ThreadPool;
13use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
14use serde::{de::DeserializeOwned, Serialize}; 15use serde::{de::DeserializeOwned, Serialize};
15use failure::{format_err, bail}; 16use 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 @@
1use std::path::{Path, PathBuf}; 1use std::path::{Path, PathBuf};
2 2
3use serde_derive::Serialize;
4use cargo_metadata::{metadata_run, CargoOpt}; 3use cargo_metadata::{metadata_run, CargoOpt};
5use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
6use rustc_hash::{FxHashMap, FxHashSet}; 5use 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)]
15pub struct CargoWorkspace { 21pub 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)]
21pub struct Package(usize); 27pub struct Package(usize);
22#[derive(Clone, Copy, Debug, Serialize)] 28#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
23pub struct Target(usize); 29pub 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)]
41pub 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
66impl Target { 85impl 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
14use crate::{ 14use 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);