diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 8 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model.rs | 116 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model/cargo_workspace.rs | 0 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model/sysroot.rs | 0 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 24 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 41 |
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 @@ | |||
1 | use std::path::{Path, PathBuf}; | 1 | use std::{ |
2 | path::{Path, PathBuf}, | ||
3 | process::Command, | ||
4 | }; | ||
2 | 5 | ||
3 | use cargo_metadata::{metadata_run, CargoOpt}; | 6 | use cargo_metadata::{metadata_run, CargoOpt}; |
4 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
@@ -9,6 +12,36 @@ use thread_worker::{WorkerHandle, Worker}; | |||
9 | 12 | ||
10 | use crate::Result; | 13 | use crate::Result; |
11 | 14 | ||
15 | #[derive(Debug, Clone)] | ||
16 | pub struct ProjectWorkspace { | ||
17 | pub(crate) cargo: CargoWorkspace, | ||
18 | pub(crate) sysroot: Sysroot, | ||
19 | } | ||
20 | |||
21 | impl 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 | |||
31 | pub 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)] | ||
100 | pub(crate) struct Sysroot { | ||
101 | crates: FxHashMap<SmolStr, PathBuf>, | ||
102 | } | ||
103 | |||
66 | impl Package { | 104 | impl 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 | ||
201 | fn 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 | |||
163 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | 263 | fn 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 | |||
194 | pub 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; | |||
15 | use failure::format_err; | 15 | use failure::format_err; |
16 | 16 | ||
17 | use crate::{ | 17 | use 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::{ | |||
23 | pub struct ServerWorldState { | 23 | pub 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 | ||
31 | pub struct ServerWorld { | 31 | pub 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 | ||
37 | impl ServerWorldState { | 37 | impl 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 | }; |
6 | use ra_lsp_server::req::{ | 6 | use ra_lsp_server::req::{ |
7 | CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, | 7 | CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion, |
8 | }; | 8 | }; |
9 | use serde_json::json; | 9 | use serde_json::json; |
10 | 10 | ||
@@ -13,6 +13,45 @@ use crate::support::project; | |||
13 | const LOG: &'static str = ""; | 13 | const LOG: &'static str = ""; |
14 | 14 | ||
15 | #[test] | 15 | #[test] |
16 | fn completes_items_from_standard_library() { | ||
17 | let server = project( | ||
18 | r#" | ||
19 | //- Cargo.toml | ||
20 | [package] | ||
21 | name = "foo" | ||
22 | version = "0.0.0" | ||
23 | |||
24 | //- src/lib.rs | ||
25 | use 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] | ||
16 | fn test_runnables_no_project() { | 55 | fn test_runnables_no_project() { |
17 | let server = project( | 56 | let server = project( |
18 | r" | 57 | r" |