diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/flip_comma.rs | 6 | ||||
-rw-r--r-- | crates/base_db/src/fixture.rs | 16 | ||||
-rw-r--r-- | crates/flycheck/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/flycheck/src/lib.rs | 23 | ||||
-rw-r--r-- | crates/ide/src/join_lines.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/injection.rs | 56 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/test_data/injection.html | 48 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/tests.rs | 19 | ||||
-rw-r--r-- | crates/project_model/src/cargo_workspace.rs | 26 | ||||
-rw-r--r-- | crates/project_model/src/workspace.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 12 | ||||
-rw-r--r-- | crates/rust-analyzer/src/reload.rs | 34 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 23 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/vfs/src/lib.rs | 51 |
16 files changed, 268 insertions, 83 deletions
diff --git a/crates/assists/src/handlers/flip_comma.rs b/crates/assists/src/handlers/flip_comma.rs index a48b0e450..18cf64a34 100644 --- a/crates/assists/src/handlers/flip_comma.rs +++ b/crates/assists/src/handlers/flip_comma.rs | |||
@@ -49,14 +49,14 @@ mod tests { | |||
49 | fn flip_comma_works_for_function_parameters() { | 49 | fn flip_comma_works_for_function_parameters() { |
50 | check_assist( | 50 | check_assist( |
51 | flip_comma, | 51 | flip_comma, |
52 | "fn foo(x: i32,$0 y: Result<(), ()>) {}", | 52 | r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, |
53 | "fn foo(y: Result<(), ()>, x: i32) {}", | 53 | r#"fn foo(y: Result<(), ()>, x: i32) {}"#, |
54 | ) | 54 | ) |
55 | } | 55 | } |
56 | 56 | ||
57 | #[test] | 57 | #[test] |
58 | fn flip_comma_target() { | 58 | fn flip_comma_target() { |
59 | check_assist_target(flip_comma, "fn foo(x: i32,$0 y: Result<(), ()>) {}", ",") | 59 | check_assist_target(flip_comma, r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, ",") |
60 | } | 60 | } |
61 | 61 | ||
62 | #[test] | 62 | #[test] |
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 66e6443cb..98acd61b1 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -61,7 +61,9 @@ use std::{str::FromStr, sync::Arc}; | |||
61 | 61 | ||
62 | use cfg::CfgOptions; | 62 | use cfg::CfgOptions; |
63 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
64 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; | 64 | use test_utils::{ |
65 | extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, | ||
66 | }; | ||
65 | use vfs::{file_set::FileSet, VfsPath}; | 67 | use vfs::{file_set::FileSet, VfsPath}; |
66 | 68 | ||
67 | use crate::{ | 69 | use crate::{ |
@@ -142,10 +144,14 @@ impl ChangeFixture { | |||
142 | 144 | ||
143 | for entry in fixture { | 145 | for entry in fixture { |
144 | let text = if entry.text.contains(CURSOR_MARKER) { | 146 | let text = if entry.text.contains(CURSOR_MARKER) { |
145 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); | 147 | if entry.text.contains(ESCAPED_CURSOR_MARKER) { |
146 | assert!(file_position.is_none()); | 148 | entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER) |
147 | file_position = Some((file_id, range_or_offset)); | 149 | } else { |
148 | text.to_string() | 150 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
151 | assert!(file_position.is_none()); | ||
152 | file_position = Some((file_id, range_or_offset)); | ||
153 | text.to_string() | ||
154 | } | ||
149 | } else { | 155 | } else { |
150 | entry.text.clone() | 156 | entry.text.clone() |
151 | }; | 157 | }; |
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 3d9436d69..1bad64a1b 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml | |||
@@ -17,3 +17,4 @@ serde_json = "1.0.48" | |||
17 | jod-thread = "0.1.1" | 17 | jod-thread = "0.1.1" |
18 | 18 | ||
19 | toolchain = { path = "../toolchain", version = "0.0.0" } | 19 | toolchain = { path = "../toolchain", version = "0.0.0" } |
20 | stdx = { path = "../stdx", version = "0.0.0" } | ||
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index d982c5f29..4388e8c67 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs | |||
@@ -5,13 +5,13 @@ | |||
5 | use std::{ | 5 | use std::{ |
6 | fmt, | 6 | fmt, |
7 | io::{self, BufReader}, | 7 | io::{self, BufReader}, |
8 | ops, | ||
9 | path::PathBuf, | 8 | path::PathBuf, |
10 | process::{self, Command, Stdio}, | 9 | process::{self, Command, Stdio}, |
11 | time::Duration, | 10 | time::Duration, |
12 | }; | 11 | }; |
13 | 12 | ||
14 | use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; | 13 | use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; |
14 | use stdx::JodChild; | ||
15 | 15 | ||
16 | pub use cargo_metadata::diagnostic::{ | 16 | pub use cargo_metadata::diagnostic::{ |
17 | Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, | 17 | Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, |
@@ -323,24 +323,3 @@ impl CargoActor { | |||
323 | Ok(read_at_least_one_message) | 323 | Ok(read_at_least_one_message) |
324 | } | 324 | } |
325 | } | 325 | } |
326 | |||
327 | struct JodChild(process::Child); | ||
328 | |||
329 | impl ops::Deref for JodChild { | ||
330 | type Target = process::Child; | ||
331 | fn deref(&self) -> &process::Child { | ||
332 | &self.0 | ||
333 | } | ||
334 | } | ||
335 | |||
336 | impl ops::DerefMut for JodChild { | ||
337 | fn deref_mut(&mut self) -> &mut process::Child { | ||
338 | &mut self.0 | ||
339 | } | ||
340 | } | ||
341 | |||
342 | impl Drop for JodChild { | ||
343 | fn drop(&mut self) { | ||
344 | let _ = self.0.kill(); | ||
345 | } | ||
346 | } | ||
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 296893d2f..05380f2a1 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -198,8 +198,8 @@ mod tests { | |||
198 | 198 | ||
199 | use super::*; | 199 | use super::*; |
200 | 200 | ||
201 | fn check_join_lines(before: &str, after: &str) { | 201 | fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { |
202 | let (before_cursor_pos, before) = extract_offset(before); | 202 | let (before_cursor_pos, before) = extract_offset(ra_fixture_before); |
203 | let file = SourceFile::parse(&before).ok().unwrap(); | 203 | let file = SourceFile::parse(&before).ok().unwrap(); |
204 | 204 | ||
205 | let range = TextRange::empty(before_cursor_pos); | 205 | let range = TextRange::empty(before_cursor_pos); |
@@ -214,7 +214,7 @@ mod tests { | |||
214 | .apply_to_offset(before_cursor_pos) | 214 | .apply_to_offset(before_cursor_pos) |
215 | .expect("cursor position is affected by the edit"); | 215 | .expect("cursor position is affected by the edit"); |
216 | let actual = add_cursor(&actual, actual_cursor_pos); | 216 | let actual = add_cursor(&actual, actual_cursor_pos); |
217 | assert_eq_text!(after, &actual); | 217 | assert_eq_text!(ra_fixture_after, &actual); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
@@ -604,8 +604,8 @@ fn foo() { | |||
604 | ); | 604 | ); |
605 | } | 605 | } |
606 | 606 | ||
607 | fn check_join_lines_sel(before: &str, after: &str) { | 607 | fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { |
608 | let (sel, before) = extract_range(before); | 608 | let (sel, before) = extract_range(ra_fixture_before); |
609 | let parse = SourceFile::parse(&before); | 609 | let parse = SourceFile::parse(&before); |
610 | let result = join_lines(&parse.tree(), sel); | 610 | let result = join_lines(&parse.tree(), sel); |
611 | let actual = { | 611 | let actual = { |
@@ -613,7 +613,7 @@ fn foo() { | |||
613 | result.apply(&mut actual); | 613 | result.apply(&mut actual); |
614 | actual | 614 | actual |
615 | }; | 615 | }; |
616 | assert_eq_text!(after, &actual); | 616 | assert_eq_text!(ra_fixture_after, &actual); |
617 | } | 617 | } |
618 | 618 | ||
619 | #[test] | 619 | #[test] |
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs index 6cbd683c6..d6be9708d 100644 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ b/crates/ide/src/syntax_highlighting/injection.rs | |||
@@ -22,7 +22,8 @@ pub(super) fn highlight_injection( | |||
22 | return None; | 22 | return None; |
23 | } | 23 | } |
24 | let value = literal.value()?; | 24 | let value = literal.value()?; |
25 | let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned()); | 25 | let marker_info = MarkerInfo::new(&*value); |
26 | let (analysis, tmp_file_id) = Analysis::from_single_file(marker_info.cleaned_text.clone()); | ||
26 | 27 | ||
27 | if let Some(range) = literal.open_quote_text_range() { | 28 | if let Some(range) = literal.open_quote_text_range() { |
28 | acc.add(HighlightedRange { | 29 | acc.add(HighlightedRange { |
@@ -33,9 +34,10 @@ pub(super) fn highlight_injection( | |||
33 | } | 34 | } |
34 | 35 | ||
35 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | 36 | for mut h in analysis.highlight(tmp_file_id).unwrap() { |
36 | if let Some(r) = literal.map_range_up(h.range) { | 37 | let range = marker_info.map_range_up(h.range); |
37 | h.range = r; | 38 | if let Some(range) = literal.map_range_up(range) { |
38 | acc.add(h) | 39 | h.range = range; |
40 | acc.add(h); | ||
39 | } | 41 | } |
40 | } | 42 | } |
41 | 43 | ||
@@ -50,6 +52,52 @@ pub(super) fn highlight_injection( | |||
50 | Some(()) | 52 | Some(()) |
51 | } | 53 | } |
52 | 54 | ||
55 | /// Data to remove `$0` from string and map ranges | ||
56 | #[derive(Default, Debug)] | ||
57 | struct MarkerInfo { | ||
58 | cleaned_text: String, | ||
59 | markers: Vec<TextRange>, | ||
60 | } | ||
61 | |||
62 | impl MarkerInfo { | ||
63 | fn new(mut text: &str) -> Self { | ||
64 | let marker = "$0"; | ||
65 | |||
66 | let mut res = MarkerInfo::default(); | ||
67 | let mut offset: TextSize = 0.into(); | ||
68 | while !text.is_empty() { | ||
69 | let idx = text.find(marker).unwrap_or(text.len()); | ||
70 | let (chunk, next) = text.split_at(idx); | ||
71 | text = next; | ||
72 | res.cleaned_text.push_str(chunk); | ||
73 | offset += TextSize::of(chunk); | ||
74 | |||
75 | if let Some(next) = text.strip_prefix(marker) { | ||
76 | text = next; | ||
77 | |||
78 | let marker_len = TextSize::of(marker); | ||
79 | res.markers.push(TextRange::at(offset, marker_len)); | ||
80 | offset += marker_len; | ||
81 | } | ||
82 | } | ||
83 | res | ||
84 | } | ||
85 | fn map_range_up(&self, range: TextRange) -> TextRange { | ||
86 | TextRange::new( | ||
87 | self.map_offset_up(range.start(), true), | ||
88 | self.map_offset_up(range.end(), false), | ||
89 | ) | ||
90 | } | ||
91 | fn map_offset_up(&self, mut offset: TextSize, start: bool) -> TextSize { | ||
92 | for r in &self.markers { | ||
93 | if r.start() < offset || (start && r.start() == offset) { | ||
94 | offset += r.len() | ||
95 | } | ||
96 | } | ||
97 | offset | ||
98 | } | ||
99 | } | ||
100 | |||
53 | /// Mapping from extracted documentation code to original code | 101 | /// Mapping from extracted documentation code to original code |
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | 102 | type RangesMap = BTreeMap<TextSize, TextSize>; |
55 | 103 | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html new file mode 100644 index 000000000..a54d303b4 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .label { color: #DFAF8F; font-style: italic; } | ||
8 | .comment { color: #7F9F7F; } | ||
9 | .documentation { color: #629755; } | ||
10 | .injected { opacity: 0.65 ; } | ||
11 | .struct, .enum { color: #7CB8BB; } | ||
12 | .enum_variant { color: #BDE0F3; } | ||
13 | .string_literal { color: #CC9393; } | ||
14 | .field { color: #94BFF3; } | ||
15 | .function { color: #93E0E3; } | ||
16 | .function.unsafe { color: #BC8383; } | ||
17 | .operator.unsafe { color: #BC8383; } | ||
18 | .parameter { color: #94BFF3; } | ||
19 | .text { color: #DCDCCC; } | ||
20 | .type { color: #7CB8BB; } | ||
21 | .builtin_type { color: #8CD0D3; } | ||
22 | .type_param { color: #DFAF8F; } | ||
23 | .attribute { color: #94BFF3; } | ||
24 | .numeric_literal { color: #BFEBBF; } | ||
25 | .bool_literal { color: #BFE6EB; } | ||
26 | .macro { color: #94BFF3; } | ||
27 | .module { color: #AFD8AF; } | ||
28 | .value_param { color: #DCDCCC; } | ||
29 | .variable { color: #DCDCCC; } | ||
30 | .format_specifier { color: #CC696B; } | ||
31 | .mutable { text-decoration: underline; } | ||
32 | .escape_sequence { color: #94BFF3; } | ||
33 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
34 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
35 | .control { font-style: italic; } | ||
36 | |||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | ||
38 | </style> | ||
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
40 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | ||
41 | <span class="function">f</span><span class="punctuation">(</span><span class="string_literal">r"</span> | ||
42 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | ||
43 | <span class="function">foo</span><span class="punctuation">(</span>$0<span class="punctuation">{</span> | ||
44 | <span class="numeric_literal">92</span> | ||
45 | <span class="punctuation">}</span>$0<span class="punctuation">)</span> | ||
46 | <span class="punctuation">}</span><span class="string_literal">"</span><span class="punctuation">)</span><span class="punctuation">;</span> | ||
47 | <span class="punctuation">}</span> | ||
48 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 30b5b648e..9e1a3974c 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -555,6 +555,25 @@ impl t for foo { | |||
555 | ) | 555 | ) |
556 | } | 556 | } |
557 | 557 | ||
558 | #[test] | ||
559 | fn test_injection() { | ||
560 | check_highlighting( | ||
561 | r##" | ||
562 | fn f(ra_fixture: &str) {} | ||
563 | fn main() { | ||
564 | f(r" | ||
565 | fn foo() { | ||
566 | foo(\$0{ | ||
567 | 92 | ||
568 | }\$0) | ||
569 | }"); | ||
570 | } | ||
571 | "##, | ||
572 | expect_file!["./test_data/injection.html"], | ||
573 | false, | ||
574 | ); | ||
575 | } | ||
576 | |||
558 | /// Highlights the code given by the `ra_fixture` argument, renders the | 577 | /// Highlights the code given by the `ra_fixture` argument, renders the |
559 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | 578 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
560 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | 579 | /// Note that the `snapshot` file is overwritten by the rendered HTML. |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index 0e6679542..2ee4e88b2 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -3,9 +3,10 @@ | |||
3 | use std::{ | 3 | use std::{ |
4 | convert::TryInto, | 4 | convert::TryInto, |
5 | ffi::OsStr, | 5 | ffi::OsStr, |
6 | io::BufReader, | ||
6 | ops, | 7 | ops, |
7 | path::{Path, PathBuf}, | 8 | path::{Path, PathBuf}, |
8 | process::Command, | 9 | process::{Command, Stdio}, |
9 | }; | 10 | }; |
10 | 11 | ||
11 | use anyhow::{Context, Result}; | 12 | use anyhow::{Context, Result}; |
@@ -15,6 +16,7 @@ use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId} | |||
15 | use itertools::Itertools; | 16 | use itertools::Itertools; |
16 | use paths::{AbsPath, AbsPathBuf}; | 17 | use paths::{AbsPath, AbsPathBuf}; |
17 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
19 | use stdx::JodChild; | ||
18 | 20 | ||
19 | use crate::cfg_flag::CfgFlag; | 21 | use crate::cfg_flag::CfgFlag; |
20 | use crate::utf8_stdout; | 22 | use crate::utf8_stdout; |
@@ -171,6 +173,7 @@ impl CargoWorkspace { | |||
171 | pub fn from_cargo_metadata( | 173 | pub fn from_cargo_metadata( |
172 | cargo_toml: &AbsPath, | 174 | cargo_toml: &AbsPath, |
173 | config: &CargoConfig, | 175 | config: &CargoConfig, |
176 | progress: &dyn Fn(String), | ||
174 | ) -> Result<CargoWorkspace> { | 177 | ) -> Result<CargoWorkspace> { |
175 | let mut meta = MetadataCommand::new(); | 178 | let mut meta = MetadataCommand::new(); |
176 | meta.cargo_path(toolchain::cargo()); | 179 | meta.cargo_path(toolchain::cargo()); |
@@ -220,6 +223,9 @@ impl CargoWorkspace { | |||
220 | meta.other_options(vec![String::from("--filter-platform"), target]); | 223 | meta.other_options(vec![String::from("--filter-platform"), target]); |
221 | } | 224 | } |
222 | 225 | ||
226 | // FIXME: Currently MetadataCommand is not based on parse_stream, | ||
227 | // So we just report it as a whole | ||
228 | progress("metadata".to_string()); | ||
223 | let mut meta = meta.exec().with_context(|| { | 229 | let mut meta = meta.exec().with_context(|| { |
224 | let cwd: Option<AbsPathBuf> = | 230 | let cwd: Option<AbsPathBuf> = |
225 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); | 231 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); |
@@ -243,7 +249,7 @@ impl CargoWorkspace { | |||
243 | let mut envs = FxHashMap::default(); | 249 | let mut envs = FxHashMap::default(); |
244 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 250 | let mut proc_macro_dylib_paths = FxHashMap::default(); |
245 | if config.load_out_dirs_from_check { | 251 | if config.load_out_dirs_from_check { |
246 | let resources = load_extern_resources(cargo_toml, config)?; | 252 | let resources = load_extern_resources(cargo_toml, config, progress)?; |
247 | out_dir_by_id = resources.out_dirs; | 253 | out_dir_by_id = resources.out_dirs; |
248 | cfgs = resources.cfgs; | 254 | cfgs = resources.cfgs; |
249 | envs = resources.env; | 255 | envs = resources.env; |
@@ -368,6 +374,7 @@ pub(crate) struct ExternResources { | |||
368 | pub(crate) fn load_extern_resources( | 374 | pub(crate) fn load_extern_resources( |
369 | cargo_toml: &Path, | 375 | cargo_toml: &Path, |
370 | cargo_features: &CargoConfig, | 376 | cargo_features: &CargoConfig, |
377 | progress: &dyn Fn(String), | ||
371 | ) -> Result<ExternResources> { | 378 | ) -> Result<ExternResources> { |
372 | let mut cmd = Command::new(toolchain::cargo()); | 379 | let mut cmd = Command::new(toolchain::cargo()); |
373 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | 380 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
@@ -395,11 +402,14 @@ pub(crate) fn load_extern_resources( | |||
395 | } | 402 | } |
396 | } | 403 | } |
397 | 404 | ||
398 | let output = cmd.output()?; | 405 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); |
399 | 406 | ||
400 | let mut res = ExternResources::default(); | 407 | let mut child = cmd.spawn().map(JodChild)?; |
408 | let child_stdout = child.stdout.take().unwrap(); | ||
409 | let stdout = BufReader::new(child_stdout); | ||
401 | 410 | ||
402 | for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) { | 411 | let mut res = ExternResources::default(); |
412 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
403 | if let Ok(message) = message { | 413 | if let Ok(message) = message { |
404 | match message { | 414 | match message { |
405 | Message::BuildScriptExecuted(BuildScript { | 415 | Message::BuildScriptExecuted(BuildScript { |
@@ -432,6 +442,8 @@ pub(crate) fn load_extern_resources( | |||
432 | res.env.insert(package_id, env); | 442 | res.env.insert(package_id, env); |
433 | } | 443 | } |
434 | Message::CompilerArtifact(message) => { | 444 | Message::CompilerArtifact(message) => { |
445 | progress(format!("metadata {}", message.target.name)); | ||
446 | |||
435 | if message.target.kind.contains(&"proc-macro".to_string()) { | 447 | if message.target.kind.contains(&"proc-macro".to_string()) { |
436 | let package_id = message.package_id; | 448 | let package_id = message.package_id; |
437 | // Skip rmeta file | 449 | // Skip rmeta file |
@@ -442,7 +454,9 @@ pub(crate) fn load_extern_resources( | |||
442 | } | 454 | } |
443 | } | 455 | } |
444 | } | 456 | } |
445 | Message::CompilerMessage(_) => (), | 457 | Message::CompilerMessage(message) => { |
458 | progress(message.target.name.clone()); | ||
459 | } | ||
446 | Message::Unknown => (), | 460 | Message::Unknown => (), |
447 | Message::BuildFinished(_) => {} | 461 | Message::BuildFinished(_) => {} |
448 | Message::TextLine(_) => {} | 462 | Message::TextLine(_) => {} |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 68a235ce3..06a0be284 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -64,7 +64,11 @@ impl fmt::Debug for ProjectWorkspace { | |||
64 | } | 64 | } |
65 | 65 | ||
66 | impl ProjectWorkspace { | 66 | impl ProjectWorkspace { |
67 | pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result<ProjectWorkspace> { | 67 | pub fn load( |
68 | manifest: ProjectManifest, | ||
69 | config: &CargoConfig, | ||
70 | progress: &dyn Fn(String), | ||
71 | ) -> Result<ProjectWorkspace> { | ||
68 | let res = match manifest { | 72 | let res = match manifest { |
69 | ProjectManifest::ProjectJson(project_json) => { | 73 | ProjectManifest::ProjectJson(project_json) => { |
70 | let file = fs::read_to_string(&project_json).with_context(|| { | 74 | let file = fs::read_to_string(&project_json).with_context(|| { |
@@ -84,15 +88,14 @@ impl ProjectWorkspace { | |||
84 | cmd | 88 | cmd |
85 | })?; | 89 | })?; |
86 | 90 | ||
87 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config).with_context( | 91 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress) |
88 | || { | 92 | .with_context(|| { |
89 | format!( | 93 | format!( |
90 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", | 94 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", |
91 | cargo_toml.display(), | 95 | cargo_toml.display(), |
92 | cargo_version | 96 | cargo_version |
93 | ) | 97 | ) |
94 | }, | 98 | })?; |
95 | )?; | ||
96 | let sysroot = if config.no_sysroot { | 99 | let sysroot = if config.no_sysroot { |
97 | Sysroot::default() | 100 | Sysroot::default() |
98 | } else { | 101 | } else { |
@@ -105,9 +108,12 @@ impl ProjectWorkspace { | |||
105 | }; | 108 | }; |
106 | 109 | ||
107 | let rustc = if let Some(rustc_dir) = &config.rustc_source { | 110 | let rustc = if let Some(rustc_dir) = &config.rustc_source { |
108 | Some(CargoWorkspace::from_cargo_metadata(&rustc_dir, config).with_context( | 111 | Some( |
109 | || format!("Failed to read Cargo metadata for Rust sources"), | 112 | CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) |
110 | )?) | 113 | .with_context(|| { |
114 | format!("Failed to read Cargo metadata for Rust sources") | ||
115 | })?, | ||
116 | ) | ||
111 | } else { | 117 | } else { |
112 | None | 118 | None |
113 | }; | 119 | }; |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index e5ab6c73b..31a16ca46 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -21,6 +21,7 @@ pub fn load_cargo( | |||
21 | let ws = ProjectWorkspace::load( | 21 | let ws = ProjectWorkspace::load( |
22 | root, | 22 | root, |
23 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, | 23 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, |
24 | &|_| {}, | ||
24 | )?; | 25 | )?; |
25 | 26 | ||
26 | let (sender, receiver) = unbounded(); | 27 | let (sender, receiver) = unbounded(); |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 7ac6acf70..22ee96775 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -22,6 +22,7 @@ use crate::{ | |||
22 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, | 22 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, |
23 | handlers, lsp_ext, | 23 | handlers, lsp_ext, |
24 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, | 24 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, |
25 | reload::ProjectWorkspaceProgress, | ||
25 | Result, | 26 | Result, |
26 | }; | 27 | }; |
27 | 28 | ||
@@ -63,6 +64,7 @@ pub(crate) enum Task { | |||
63 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), | 64 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), |
64 | Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), | 65 | Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), |
65 | PrimeCaches(PrimeCachesProgress), | 66 | PrimeCaches(PrimeCachesProgress), |
67 | FetchWorkspace(ProjectWorkspaceProgress), | ||
66 | } | 68 | } |
67 | 69 | ||
68 | impl fmt::Debug for Event { | 70 | impl fmt::Debug for Event { |
@@ -216,6 +218,16 @@ impl GlobalState { | |||
216 | } | 218 | } |
217 | PrimeCachesProgress::Finished => prime_caches_progress.push(progress), | 219 | PrimeCachesProgress::Finished => prime_caches_progress.push(progress), |
218 | }, | 220 | }, |
221 | Task::FetchWorkspace(progress) => { | ||
222 | let (state, msg) = match progress { | ||
223 | ProjectWorkspaceProgress::Begin => (Progress::Begin, None), | ||
224 | ProjectWorkspaceProgress::Report(msg) => { | ||
225 | (Progress::Report, Some(msg)) | ||
226 | } | ||
227 | ProjectWorkspaceProgress::End => (Progress::End, None), | ||
228 | }; | ||
229 | self.report_progress("fetching", state, msg, None); | ||
230 | } | ||
219 | } | 231 | } |
220 | // Coalesce multiple task events into one loop turn | 232 | // Coalesce multiple task events into one loop turn |
221 | task = match self.task_pool.receiver.try_recv() { | 233 | task = match self.task_pool.receiver.try_recv() { |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 76b50931a..f4e084741 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -15,6 +15,13 @@ use crate::{ | |||
15 | }; | 15 | }; |
16 | use lsp_ext::StatusParams; | 16 | use lsp_ext::StatusParams; |
17 | 17 | ||
18 | #[derive(Debug)] | ||
19 | pub(crate) enum ProjectWorkspaceProgress { | ||
20 | Begin, | ||
21 | Report(String), | ||
22 | End, | ||
23 | } | ||
24 | |||
18 | impl GlobalState { | 25 | impl GlobalState { |
19 | pub(crate) fn update_configuration(&mut self, config: Config) { | 26 | pub(crate) fn update_configuration(&mut self, config: Config) { |
20 | let _p = profile::span("GlobalState::update_configuration"); | 27 | let _p = profile::span("GlobalState::update_configuration"); |
@@ -93,23 +100,42 @@ impl GlobalState { | |||
93 | } | 100 | } |
94 | pub(crate) fn fetch_workspaces(&mut self) { | 101 | pub(crate) fn fetch_workspaces(&mut self) { |
95 | log::info!("will fetch workspaces"); | 102 | log::info!("will fetch workspaces"); |
96 | self.task_pool.handle.spawn({ | 103 | |
104 | self.task_pool.handle.spawn_with_sender({ | ||
97 | let linked_projects = self.config.linked_projects(); | 105 | let linked_projects = self.config.linked_projects(); |
98 | let cargo_config = self.config.cargo(); | 106 | let cargo_config = self.config.cargo(); |
99 | move || { | 107 | |
108 | move |sender| { | ||
109 | let progress = { | ||
110 | let sender = sender.clone(); | ||
111 | move |msg| { | ||
112 | sender | ||
113 | .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg))) | ||
114 | .unwrap() | ||
115 | } | ||
116 | }; | ||
117 | |||
118 | sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); | ||
119 | |||
100 | let workspaces = linked_projects | 120 | let workspaces = linked_projects |
101 | .iter() | 121 | .iter() |
102 | .map(|project| match project { | 122 | .map(|project| match project { |
103 | LinkedProject::ProjectManifest(manifest) => { | 123 | LinkedProject::ProjectManifest(manifest) => { |
104 | project_model::ProjectWorkspace::load(manifest.clone(), &cargo_config) | 124 | project_model::ProjectWorkspace::load( |
125 | manifest.clone(), | ||
126 | &cargo_config, | ||
127 | &progress, | ||
128 | ) | ||
105 | } | 129 | } |
106 | LinkedProject::InlineJsonProject(it) => { | 130 | LinkedProject::InlineJsonProject(it) => { |
107 | project_model::ProjectWorkspace::load_inline(it.clone()) | 131 | project_model::ProjectWorkspace::load_inline(it.clone()) |
108 | } | 132 | } |
109 | }) | 133 | }) |
110 | .collect::<Vec<_>>(); | 134 | .collect::<Vec<_>>(); |
135 | |||
136 | sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End)).unwrap(); | ||
111 | log::info!("did fetch workspaces {:?}", workspaces); | 137 | log::info!("did fetch workspaces {:?}", workspaces); |
112 | Task::Workspaces(workspaces) | 138 | sender.send(Task::Workspaces(workspaces)).unwrap() |
113 | } | 139 | } |
114 | }); | 140 | }); |
115 | } | 141 | } |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 374ed5910..5332edb09 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! Missing batteries for standard libraries. | 1 | //! Missing batteries for standard libraries. |
2 | use std::time::Instant; | 2 | use std::{ops, process, time::Instant}; |
3 | 3 | ||
4 | mod macros; | 4 | mod macros; |
5 | pub mod panic_context; | 5 | pub mod panic_context; |
@@ -147,6 +147,27 @@ where | |||
147 | left | 147 | left |
148 | } | 148 | } |
149 | 149 | ||
150 | pub struct JodChild(pub process::Child); | ||
151 | |||
152 | impl ops::Deref for JodChild { | ||
153 | type Target = process::Child; | ||
154 | fn deref(&self) -> &process::Child { | ||
155 | &self.0 | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl ops::DerefMut for JodChild { | ||
160 | fn deref_mut(&mut self) -> &mut process::Child { | ||
161 | &mut self.0 | ||
162 | } | ||
163 | } | ||
164 | |||
165 | impl Drop for JodChild { | ||
166 | fn drop(&mut self) { | ||
167 | let _ = self.0.kill(); | ||
168 | } | ||
169 | } | ||
170 | |||
150 | #[cfg(test)] | 171 | #[cfg(test)] |
151 | mod tests { | 172 | mod tests { |
152 | use super::*; | 173 | use super::*; |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 05d6e8c9e..84c1d7ebb 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -26,6 +26,7 @@ pub use rustc_hash::FxHashMap; | |||
26 | pub use crate::fixture::Fixture; | 26 | pub use crate::fixture::Fixture; |
27 | 27 | ||
28 | pub const CURSOR_MARKER: &str = "$0"; | 28 | pub const CURSOR_MARKER: &str = "$0"; |
29 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; | ||
29 | 30 | ||
30 | /// Asserts that two strings are equal, otherwise displays a rich diff between them. | 31 | /// Asserts that two strings are equal, otherwise displays a rich diff between them. |
31 | /// | 32 | /// |
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 9cf2afd33..2b7b14524 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs | |||
@@ -2,43 +2,46 @@ | |||
2 | //! | 2 | //! |
3 | //! VFS stores all files read by rust-analyzer. Reading file contents from VFS | 3 | //! VFS stores all files read by rust-analyzer. Reading file contents from VFS |
4 | //! always returns the same contents, unless VFS was explicitly modified with | 4 | //! always returns the same contents, unless VFS was explicitly modified with |
5 | //! `set_file_contents`. All changes to VFS are logged, and can be retrieved via | 5 | //! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via |
6 | //! `take_changes` method. The pack of changes is then pushed to `salsa` and | 6 | //! [`take_changes`] method. The pack of changes is then pushed to `salsa` and |
7 | //! triggers incremental recomputation. | 7 | //! triggers incremental recomputation. |
8 | //! | 8 | //! |
9 | //! Files in VFS are identified with `FileId`s -- interned paths. The notion of | 9 | //! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of |
10 | //! the path, `VfsPath` is somewhat abstract: at the moment, it is represented | 10 | //! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented |
11 | //! as an `std::path::PathBuf` internally, but this is an implementation detail. | 11 | //! as an [`std::path::PathBuf`] internally, but this is an implementation detail. |
12 | //! | 12 | //! |
13 | //! VFS doesn't do IO or file watching itself. For that, see the `loader` | 13 | //! VFS doesn't do IO or file watching itself. For that, see the [`loader`] |
14 | //! module. `loader::Handle` is an object-safe trait which abstracts both file | 14 | //! module. [`loader::Handle`] is an object-safe trait which abstracts both file |
15 | //! loading and file watching. `Handle` is dynamically configured with a set of | 15 | //! loading and file watching. [`Handle`] is dynamically configured with a set of |
16 | //! directory entries which should be scanned and watched. `Handle` then | 16 | //! directory entries which should be scanned and watched. [`Handle`] then |
17 | //! asynchronously pushes file changes. Directory entries are configured in | 17 | //! asynchronously pushes file changes. Directory entries are configured in |
18 | //! free-form via list of globs, it's up to the `Handle` to interpret the globs | 18 | //! free-form via list of globs, it's up to the [`Handle`] to interpret the globs |
19 | //! in any specific way. | 19 | //! in any specific way. |
20 | //! | 20 | //! |
21 | //! A simple `WalkdirLoaderHandle` is provided, which doesn't implement watching | 21 | //! VFS stores a flat list of files. [`file_set::FileSet`] can partition this list |
22 | //! and just scans the directory using walkdir. | 22 | //! of files into disjoint sets of files. Traversal-like operations (including |
23 | //! | 23 | //! getting the neighbor file by the relative path) are handled by the [`FileSet`]. |
24 | //! VFS stores a flat list of files. `FileSet` can partition this list of files | 24 | //! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;` |
25 | //! into disjoint sets of files. Traversal-like operations (including getting | ||
26 | //! the neighbor file by the relative path) are handled by the `FileSet`. | ||
27 | //! `FileSet`s are also pushed to salsa and cause it to re-check `mod foo;` | ||
28 | //! declarations when files are created or deleted. | 25 | //! declarations when files are created or deleted. |
29 | //! | 26 | //! |
30 | //! `file_set::FileSet` and `loader::Entry` play similar, but different roles. | 27 | //! [`FileSet`] and [`loader::Entry`] play similar, but different roles. |
31 | //! Both specify the "set of paths/files", one is geared towards file watching, | 28 | //! Both specify the "set of paths/files", one is geared towards file watching, |
32 | //! the other towards salsa changes. In particular, single `file_set::FileSet` | 29 | //! the other towards salsa changes. In particular, single [`FileSet`] |
33 | //! may correspond to several `loader::Entry`. For example, a crate from | 30 | //! may correspond to several [`loader::Entry`]. For example, a crate from |
34 | //! crates.io which uses code generation would have two `Entries` -- for sources | 31 | //! crates.io which uses code generation would have two [`Entries`] -- for sources |
35 | //! in `~/.cargo`, and for generated code in `./target/debug/build`. It will | 32 | //! in `~/.cargo`, and for generated code in `./target/debug/build`. It will |
36 | //! have a single `FileSet` which unions the two sources. | 33 | //! have a single [`FileSet`] which unions the two sources. |
37 | mod vfs_path; | 34 | //! |
38 | mod path_interner; | 35 | //! [`set_file_contents`]: Vfs::set_file_contents |
36 | //! [`take_changes`]: Vfs::take_changes | ||
37 | //! [`FileSet`]: file_set::FileSet | ||
38 | //! [`Handle`]: loader::Handle | ||
39 | //! [`Entries`]: loader::Entry | ||
39 | mod anchored_path; | 40 | mod anchored_path; |
40 | pub mod file_set; | 41 | pub mod file_set; |
41 | pub mod loader; | 42 | pub mod loader; |
43 | mod path_interner; | ||
44 | mod vfs_path; | ||
42 | 45 | ||
43 | use std::{fmt, mem}; | 46 | use std::{fmt, mem}; |
44 | 47 | ||