aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-10 17:13:08 +0000
committerAleksey Kladov <[email protected]>2019-01-10 21:51:34 +0000
commite8923713c51bc3484bd98085ad620713959bbc0d (patch)
treed7146aa1dac0e3d056daacf47770a239cf1f62c6 /crates/ra_lsp_server
parentb6bc55f542c88b1b0789435219f9dbf38c110f47 (diff)
add sysroot boilerplate
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs8
-rw-r--r--crates/ra_lsp_server/src/project_model.rs116
-rw-r--r--crates/ra_lsp_server/src/project_model/cargo_workspace.rs0
-rw-r--r--crates/ra_lsp_server/src/project_model/sysroot.rs0
-rw-r--r--crates/ra_lsp_server/src/server_world.rs24
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs41
6 files changed, 157 insertions, 32 deletions
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 069e7f932..0dda9548a 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -347,11 +347,11 @@ pub fn handle_runnables(
347 .read() 347 .read()
348 .file2path(ra_vfs::VfsFile(file_id.0.into())); 348 .file2path(ra_vfs::VfsFile(file_id.0.into()));
349 let res = world.workspaces.iter().find_map(|ws| { 349 let res = world.workspaces.iter().find_map(|ws| {
350 let tgt = ws.target_by_root(&path)?; 350 let tgt = ws.cargo.target_by_root(&path)?;
351 let res = CargoTargetSpec { 351 let res = CargoTargetSpec {
352 package: tgt.package(ws).name(ws).to_string(), 352 package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(),
353 target: tgt.name(ws).to_string(), 353 target: tgt.name(&ws.cargo).to_string(),
354 target_kind: tgt.kind(ws), 354 target_kind: tgt.kind(&ws.cargo),
355 }; 355 };
356 Some(res) 356 Some(res)
357 }); 357 });
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index 9f429c9a1..6fbaba7d9 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,4 +1,7 @@
1use std::path::{Path, PathBuf}; 1use std::{
2 path::{Path, PathBuf},
3 process::Command,
4};
2 5
3use cargo_metadata::{metadata_run, CargoOpt}; 6use cargo_metadata::{metadata_run, CargoOpt};
4use ra_syntax::SmolStr; 7use ra_syntax::SmolStr;
@@ -9,6 +12,36 @@ use thread_worker::{WorkerHandle, Worker};
9 12
10use crate::Result; 13use crate::Result;
11 14
15#[derive(Debug, Clone)]
16pub struct ProjectWorkspace {
17 pub(crate) cargo: CargoWorkspace,
18 pub(crate) sysroot: Sysroot,
19}
20
21impl ProjectWorkspace {
22 pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
23 let cargo_toml = find_cargo_toml(path)?;
24 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
25 let sysroot = sysroot_info(&cargo_toml)?;
26 let res = ProjectWorkspace { cargo, sysroot };
27 Ok(res)
28 }
29}
30
31pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) {
32 thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>(
33 "workspace loader",
34 1,
35 |input_receiver, output_sender| {
36 input_receiver
37 .into_iter()
38 .map(|path| ProjectWorkspace::discover(path.as_path()))
39 .try_for_each(|it| output_sender.send(it))
40 .unwrap()
41 },
42 )
43}
44
12/// `CargoWorksapce` represents the logical structure of, well, a Cargo 45/// `CargoWorksapce` represents the logical structure of, well, a Cargo
13/// workspace. It pretty closely mirrors `cargo metadata` output. 46/// workspace. It pretty closely mirrors `cargo metadata` output.
14/// 47///
@@ -63,6 +96,11 @@ pub enum TargetKind {
63 Other, 96 Other,
64} 97}
65 98
99#[derive(Debug, Clone)]
100pub(crate) struct Sysroot {
101 crates: FxHashMap<SmolStr, PathBuf>,
102}
103
66impl Package { 104impl Package {
67 pub fn name(self, ws: &CargoWorkspace) -> &str { 105 pub fn name(self, ws: &CargoWorkspace) -> &str {
68 ws.packages[self].name.as_str() 106 ws.packages[self].name.as_str()
@@ -160,6 +198,68 @@ impl CargoWorkspace {
160 } 198 }
161} 199}
162 200
201fn sysroot_info(cargo_toml: &Path) -> Result<Sysroot> {
202 let rustc_output = Command::new("rustc")
203 .current_dir(cargo_toml.parent().unwrap())
204 .args(&["--print", "sysroot"])
205 .output()?;
206 if !rustc_output.status.success() {
207 failure::bail!("failed to locate sysroot")
208 }
209 let stdout = String::from_utf8(rustc_output.stdout)?;
210 let sysroot_path = Path::new(stdout.trim());
211 let src = sysroot_path.join("lib/rustlib/src/rust/src");
212
213 let crates: &[(&str, &[&str])] = &[
214 (
215 "std",
216 &[
217 "alloc_jemalloc",
218 "alloc_system",
219 "panic_abort",
220 "rand",
221 "compiler_builtins",
222 "unwind",
223 "rustc_asan",
224 "rustc_lsan",
225 "rustc_msan",
226 "rustc_tsan",
227 "build_helper",
228 ],
229 ),
230 ("core", &[]),
231 ("alloc", &[]),
232 ("collections", &[]),
233 ("libc", &[]),
234 ("panic_unwind", &[]),
235 ("proc_macro", &[]),
236 ("rustc_unicode", &[]),
237 ("std_unicode", &[]),
238 ("test", &[]),
239 // Feature gated
240 ("alloc_jemalloc", &[]),
241 ("alloc_system", &[]),
242 ("compiler_builtins", &[]),
243 ("getopts", &[]),
244 ("panic_unwind", &[]),
245 ("panic_abort", &[]),
246 ("rand", &[]),
247 ("term", &[]),
248 ("unwind", &[]),
249 // Dependencies
250 ("build_helper", &[]),
251 ("rustc_asan", &[]),
252 ("rustc_lsan", &[]),
253 ("rustc_msan", &[]),
254 ("rustc_tsan", &[]),
255 ("syntax", &[]),
256 ];
257
258 Ok(Sysroot {
259 crates: FxHashMap::default(),
260 })
261}
262
163fn find_cargo_toml(path: &Path) -> Result<PathBuf> { 263fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
164 if path.ends_with("Cargo.toml") { 264 if path.ends_with("Cargo.toml") {
165 return Ok(path.to_path_buf()); 265 return Ok(path.to_path_buf());
@@ -190,17 +290,3 @@ impl TargetKind {
190 TargetKind::Other 290 TargetKind::Other
191 } 291 }
192} 292}
193
194pub fn workspace_loader() -> (Worker<PathBuf, Result<CargoWorkspace>>, WorkerHandle) {
195 thread_worker::spawn::<PathBuf, Result<CargoWorkspace>, _>(
196 "workspace loader",
197 1,
198 |input_receiver, output_sender| {
199 input_receiver
200 .into_iter()
201 .map(|path| CargoWorkspace::from_cargo_metadata(path.as_path()))
202 .try_for_each(|it| output_sender.send(it))
203 .unwrap()
204 },
205 )
206}
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/ra_lsp_server/src/project_model/sysroot.rs
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 76c76766d..2debbe557 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -15,7 +15,7 @@ use parking_lot::RwLock;
15use failure::format_err; 15use failure::format_err;
16 16
17use crate::{ 17use crate::{
18 project_model::{CargoWorkspace, TargetKind}, 18 project_model::{ProjectWorkspace, TargetKind},
19 Result, 19 Result,
20}; 20};
21 21
@@ -23,26 +23,26 @@ use crate::{
23pub struct ServerWorldState { 23pub struct ServerWorldState {
24 pub roots_to_scan: usize, 24 pub roots_to_scan: usize,
25 pub root: PathBuf, 25 pub root: PathBuf,
26 pub workspaces: Arc<Vec<CargoWorkspace>>, 26 pub workspaces: Arc<Vec<ProjectWorkspace>>,
27 pub analysis_host: AnalysisHost, 27 pub analysis_host: AnalysisHost,
28 pub vfs: Arc<RwLock<Vfs>>, 28 pub vfs: Arc<RwLock<Vfs>>,
29} 29}
30 30
31pub struct ServerWorld { 31pub struct ServerWorld {
32 pub workspaces: Arc<Vec<CargoWorkspace>>, 32 pub workspaces: Arc<Vec<ProjectWorkspace>>,
33 pub analysis: Analysis, 33 pub analysis: Analysis,
34 pub vfs: Arc<RwLock<Vfs>>, 34 pub vfs: Arc<RwLock<Vfs>>,
35} 35}
36 36
37impl ServerWorldState { 37impl ServerWorldState {
38 pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState { 38 pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
39 let mut change = AnalysisChange::new(); 39 let mut change = AnalysisChange::new();
40 40
41 let mut roots = Vec::new(); 41 let mut roots = Vec::new();
42 roots.push(root.clone()); 42 roots.push(root.clone());
43 for ws in workspaces.iter() { 43 for ws in workspaces.iter() {
44 for pkg in ws.packages() { 44 for pkg in ws.cargo.packages() {
45 roots.push(pkg.root(&ws).to_path_buf()); 45 roots.push(pkg.root(&ws.cargo).to_path_buf());
46 } 46 }
47 } 47 }
48 let roots_to_scan = roots.len(); 48 let roots_to_scan = roots.len();
@@ -56,13 +56,13 @@ impl ServerWorldState {
56 let mut pkg_to_lib_crate = FxHashMap::default(); 56 let mut pkg_to_lib_crate = FxHashMap::default();
57 let mut pkg_crates = FxHashMap::default(); 57 let mut pkg_crates = FxHashMap::default();
58 for ws in workspaces.iter() { 58 for ws in workspaces.iter() {
59 for pkg in ws.packages() { 59 for pkg in ws.cargo.packages() {
60 for tgt in pkg.targets(ws) { 60 for tgt in pkg.targets(&ws.cargo) {
61 let root = tgt.root(ws); 61 let root = tgt.root(&ws.cargo);
62 if let Some(file_id) = vfs.load(root) { 62 if let Some(file_id) = vfs.load(root) {
63 let file_id = FileId(file_id.0.into()); 63 let file_id = FileId(file_id.0.into());
64 let crate_id = crate_graph.add_crate_root(file_id); 64 let crate_id = crate_graph.add_crate_root(file_id);
65 if tgt.kind(ws) == TargetKind::Lib { 65 if tgt.kind(&ws.cargo) == TargetKind::Lib {
66 pkg_to_lib_crate.insert(pkg, crate_id); 66 pkg_to_lib_crate.insert(pkg, crate_id);
67 } 67 }
68 pkg_crates 68 pkg_crates
@@ -72,8 +72,8 @@ impl ServerWorldState {
72 } 72 }
73 } 73 }
74 } 74 }
75 for pkg in ws.packages() { 75 for pkg in ws.cargo.packages() {
76 for dep in pkg.dependencies(ws) { 76 for dep in pkg.dependencies(&ws.cargo) {
77 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 77 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
78 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 78 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
79 crate_graph.add_dep(from, dep.name.clone(), to); 79 crate_graph.add_dep(from, dep.name.clone(), to);
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 9eaf46ac8..927664ffb 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -4,7 +4,7 @@ use languageserver_types::{
4 CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, 4 CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
5}; 5};
6use ra_lsp_server::req::{ 6use ra_lsp_server::req::{
7 CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, 7 CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
8}; 8};
9use serde_json::json; 9use serde_json::json;
10 10
@@ -13,6 +13,45 @@ use crate::support::project;
13const LOG: &'static str = ""; 13const LOG: &'static str = "";
14 14
15#[test] 15#[test]
16fn completes_items_from_standard_library() {
17 let server = project(
18 r#"
19//- Cargo.toml
20[package]
21name = "foo"
22version = "0.0.0"
23
24//- src/lib.rs
25use std::collections::;
26"#,
27 );
28 server.wait_for_feedback("workspace loaded");
29 server.request::<Completion>(
30 CompletionParams {
31 text_document: server.doc_id("src/lib.rs"),
32 context: None,
33 position: Position::new(0, 22),
34 },
35 json!([
36 {
37 "filterText": "self",
38 "insertText": "self",
39 "insertTextFormat": 1,
40 "kind": 14,
41 "label": "self"
42 },
43 {
44 "filterText": "super",
45 "insertText": "super",
46 "insertTextFormat": 1,
47 "kind": 14,
48 "label": "super"
49 }
50 ]),
51 );
52}
53
54#[test]
16fn test_runnables_no_project() { 55fn test_runnables_no_project() {
17 let server = project( 56 let server = project(
18 r" 57 r"