diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-14 18:26:07 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-14 18:26:07 +0100 |
commit | 88be6f32172813f53dae60d73c9f5deb0c3fb29f (patch) | |
tree | 0b5f8f793929f651dfe332e0f5545b938ff5189f /crates/ra_lsp_server/tests/heavy_tests | |
parent | 5d35f284f5ac70cde5d758e7c63a38eae0fb0b55 (diff) | |
parent | c2dfc8a229c0a18dff08d5ce7e6836c91648eee5 (diff) |
Merge #1137
1137: Adds support for multiple editor workspaces on initialization r=matklad a=jrvidal
OK, so this "simple hack" turned out to be way more contrived than I expected :joy:
### What works
This patch only handles multi-folder editor workspaces _on initialization_.
* I've found that modifying the layout of a workspace in VSCode just reloads the extension, so this hack should be enough for now.
* Not sure about how emacs-lsp behaves, but we fallback gracefully to the mono-folder workspace, so it should be fine.
### What doesn't work
* [x] `cargo watch` can only watch a single root folder with a `Cargo.toml`. I've left this part untouched but we could either warn that it's not supported or launch _multiple_ `cargo-watch` processes.
* [x] The `rust-analyzer/runnables` command is not functional, since we don't send the correct `cwd`.
* [x] Should we add some happy path test to `heavy_tests`?
* [ ] Going from a single `root` to multiple `roots` leaves us with a couple of `n * m` loops that smell a bit. The number of folders in the editor workspace is probably low though.
Co-authored-by: Roberto Vidal <[email protected]>
Diffstat (limited to 'crates/ra_lsp_server/tests/heavy_tests')
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 37 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/support.rs | 68 |
2 files changed, 76 insertions, 29 deletions
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 407719080..6f37a980d 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs | |||
@@ -14,7 +14,7 @@ use ra_lsp_server::req::{ | |||
14 | use serde_json::json; | 14 | use serde_json::json; |
15 | use tempfile::TempDir; | 15 | use tempfile::TempDir; |
16 | 16 | ||
17 | use crate::support::{project, project_with_tmpdir}; | 17 | use crate::support::{project, Project}; |
18 | 18 | ||
19 | const LOG: &'static str = ""; | 19 | const LOG: &'static str = ""; |
20 | 20 | ||
@@ -62,6 +62,7 @@ fn foo() { | |||
62 | "args": [ "test", "--", "foo", "--nocapture" ], | 62 | "args": [ "test", "--", "foo", "--nocapture" ], |
63 | "bin": "cargo", | 63 | "bin": "cargo", |
64 | "env": { "RUST_BACKTRACE": "short" }, | 64 | "env": { "RUST_BACKTRACE": "short" }, |
65 | "cwd": null, | ||
65 | "label": "test foo", | 66 | "label": "test foo", |
66 | "range": { | 67 | "range": { |
67 | "end": { "character": 1, "line": 2 }, | 68 | "end": { "character": 1, "line": 2 }, |
@@ -75,6 +76,7 @@ fn foo() { | |||
75 | ], | 76 | ], |
76 | "bin": "cargo", | 77 | "bin": "cargo", |
77 | "env": {}, | 78 | "env": {}, |
79 | "cwd": null, | ||
78 | "label": "cargo check --all", | 80 | "label": "cargo check --all", |
79 | "range": { | 81 | "range": { |
80 | "end": { | 82 | "end": { |
@@ -93,25 +95,34 @@ fn foo() { | |||
93 | 95 | ||
94 | #[test] | 96 | #[test] |
95 | fn test_runnables_project() { | 97 | fn test_runnables_project() { |
96 | let server = project( | 98 | let code = r#" |
97 | r#" | 99 | //- foo/Cargo.toml |
98 | //- Cargo.toml | ||
99 | [package] | 100 | [package] |
100 | name = "foo" | 101 | name = "foo" |
101 | version = "0.0.0" | 102 | version = "0.0.0" |
102 | 103 | ||
103 | //- src/lib.rs | 104 | //- foo/src/lib.rs |
104 | pub fn foo() {} | 105 | pub fn foo() {} |
105 | 106 | ||
106 | //- tests/spam.rs | 107 | //- foo/tests/spam.rs |
107 | #[test] | 108 | #[test] |
108 | fn test_eggs() {} | 109 | fn test_eggs() {} |
109 | "#, | 110 | |
110 | ); | 111 | //- bar/Cargo.toml |
112 | [package] | ||
113 | name = "bar" | ||
114 | version = "0.0.0" | ||
115 | |||
116 | //- bar/src/main.rs | ||
117 | fn main() {} | ||
118 | "#; | ||
119 | |||
120 | let server = Project::with_fixture(code).root("foo").root("bar").server(); | ||
121 | |||
111 | server.wait_until_workspace_is_loaded(); | 122 | server.wait_until_workspace_is_loaded(); |
112 | server.request::<Runnables>( | 123 | server.request::<Runnables>( |
113 | RunnablesParams { | 124 | RunnablesParams { |
114 | text_document: server.doc_id("tests/spam.rs"), | 125 | text_document: server.doc_id("foo/tests/spam.rs"), |
115 | position: None, | 126 | position: None, |
116 | }, | 127 | }, |
117 | json!([ | 128 | json!([ |
@@ -123,7 +134,8 @@ fn test_eggs() {} | |||
123 | "range": { | 134 | "range": { |
124 | "end": { "character": 17, "line": 1 }, | 135 | "end": { "character": 17, "line": 1 }, |
125 | "start": { "character": 0, "line": 0 } | 136 | "start": { "character": 0, "line": 0 } |
126 | } | 137 | }, |
138 | "cwd": server.path().join("foo") | ||
127 | }, | 139 | }, |
128 | { | 140 | { |
129 | "args": [ | 141 | "args": [ |
@@ -135,6 +147,7 @@ fn test_eggs() {} | |||
135 | ], | 147 | ], |
136 | "bin": "cargo", | 148 | "bin": "cargo", |
137 | "env": {}, | 149 | "env": {}, |
150 | "cwd": server.path().join("foo"), | ||
138 | "label": "cargo check -p foo", | 151 | "label": "cargo check -p foo", |
139 | "range": { | 152 | "range": { |
140 | "end": { | 153 | "end": { |
@@ -283,7 +296,9 @@ fn main() {{}} | |||
283 | "#, | 296 | "#, |
284 | PROJECT = project.to_string(), | 297 | PROJECT = project.to_string(), |
285 | ); | 298 | ); |
286 | let server = project_with_tmpdir(tmp_dir, &code); | 299 | |
300 | let server = Project::with_fixture(&code).tmp_dir(tmp_dir).server(); | ||
301 | |||
287 | server.wait_until_workspace_is_loaded(); | 302 | server.wait_until_workspace_is_loaded(); |
288 | let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None }; | 303 | let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None }; |
289 | server.request::<CodeActionRequest>( | 304 | server.request::<CodeActionRequest>( |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index ab9db3dd4..b07882700 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | cell::{Cell, RefCell}, | 2 | cell::{Cell, RefCell}, |
3 | fs, | 3 | fs, |
4 | path::PathBuf, | 4 | path::{Path, PathBuf}, |
5 | sync::Once, | 5 | sync::Once, |
6 | time::Duration, | 6 | time::Duration, |
7 | }; | 7 | }; |
@@ -26,26 +26,51 @@ use ra_lsp_server::{ | |||
26 | InitializationOptions, | 26 | InitializationOptions, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | pub fn project(fixture: &str) -> Server { | 29 | pub struct Project<'a> { |
30 | let tmp_dir = TempDir::new().unwrap(); | 30 | fixture: &'a str, |
31 | project_with_tmpdir(tmp_dir, fixture) | 31 | tmp_dir: Option<TempDir>, |
32 | roots: Vec<PathBuf>, | ||
32 | } | 33 | } |
33 | 34 | ||
34 | pub fn project_with_tmpdir(tmp_dir: TempDir, fixture: &str) -> Server { | 35 | impl<'a> Project<'a> { |
35 | static INIT: Once = Once::new(); | 36 | pub fn with_fixture(fixture: &str) -> Project { |
36 | INIT.call_once(|| { | 37 | Project { fixture, tmp_dir: None, roots: vec![] } |
37 | let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); | 38 | } |
38 | }); | ||
39 | 39 | ||
40 | let mut paths = vec![]; | 40 | pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> { |
41 | self.tmp_dir = Some(tmp_dir); | ||
42 | self | ||
43 | } | ||
41 | 44 | ||
42 | for entry in parse_fixture(fixture) { | 45 | pub fn root(mut self, path: &str) -> Project<'a> { |
43 | let path = tmp_dir.path().join(entry.meta); | 46 | self.roots.push(path.into()); |
44 | fs::create_dir_all(path.parent().unwrap()).unwrap(); | 47 | self |
45 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | ||
46 | paths.push((path, entry.text)); | ||
47 | } | 48 | } |
48 | Server::new(tmp_dir, paths) | 49 | |
50 | pub fn server(self) -> Server { | ||
51 | let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap()); | ||
52 | static INIT: Once = Once::new(); | ||
53 | INIT.call_once(|| { | ||
54 | let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); | ||
55 | }); | ||
56 | |||
57 | let mut paths = vec![]; | ||
58 | |||
59 | for entry in parse_fixture(self.fixture) { | ||
60 | let path = tmp_dir.path().join(entry.meta); | ||
61 | fs::create_dir_all(path.parent().unwrap()).unwrap(); | ||
62 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | ||
63 | paths.push((path, entry.text)); | ||
64 | } | ||
65 | |||
66 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); | ||
67 | |||
68 | Server::new(tmp_dir, roots, paths) | ||
69 | } | ||
70 | } | ||
71 | |||
72 | pub fn project(fixture: &str) -> Server { | ||
73 | Project::with_fixture(fixture).server() | ||
49 | } | 74 | } |
50 | 75 | ||
51 | pub struct Server { | 76 | pub struct Server { |
@@ -56,14 +81,17 @@ pub struct Server { | |||
56 | } | 81 | } |
57 | 82 | ||
58 | impl Server { | 83 | impl Server { |
59 | fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server { | 84 | fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server { |
60 | let path = dir.path().to_path_buf(); | 85 | let path = dir.path().to_path_buf(); |
86 | |||
87 | let roots = if roots.is_empty() { vec![path] } else { roots }; | ||
88 | |||
61 | let worker = Worker::<RawMessage, RawMessage>::spawn( | 89 | let worker = Worker::<RawMessage, RawMessage>::spawn( |
62 | "test server", | 90 | "test server", |
63 | 128, | 91 | 128, |
64 | move |mut msg_receiver, mut msg_sender| { | 92 | move |mut msg_receiver, mut msg_sender| { |
65 | main_loop( | 93 | main_loop( |
66 | path, | 94 | roots, |
67 | InitializationOptions::default(), | 95 | InitializationOptions::default(), |
68 | &mut msg_receiver, | 96 | &mut msg_receiver, |
69 | &mut msg_sender, | 97 | &mut msg_sender, |
@@ -177,6 +205,10 @@ impl Server { | |||
177 | fn send_notification(&self, not: RawNotification) { | 205 | fn send_notification(&self, not: RawNotification) { |
178 | self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap(); | 206 | self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap(); |
179 | } | 207 | } |
208 | |||
209 | pub fn path(&self) -> &Path { | ||
210 | self.dir.path() | ||
211 | } | ||
180 | } | 212 | } |
181 | 213 | ||
182 | impl Drop for Server { | 214 | impl Drop for Server { |