aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs23
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/runnables.rs18
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlight_injection.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html7
-rw-r--r--crates/ra_ide/src/snapshots/highlight_unsafe.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html1
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs22
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs1
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs4
-rw-r--r--crates/ra_ide_db/src/change.rs79
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs90
-rw-r--r--crates/ra_syntax/src/parsing/text_token_source.rs89
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs32
-rw-r--r--crates/rust-analyzer/src/global_state.rs79
-rw-r--r--crates/rust-analyzer/src/main_loop.rs68
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
22 files changed, 222 insertions, 316 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index c7bb1e69f..0b52b01ab 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -135,8 +135,8 @@ impl NavigationTarget {
135 db: &RootDatabase, 135 db: &RootDatabase,
136 node: InFile<&dyn ast::NameOwner>, 136 node: InFile<&dyn ast::NameOwner>,
137 ) -> NavigationTarget { 137 ) -> NavigationTarget {
138 //FIXME: use `_` instead of empty string 138 let name =
139 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); 139 node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
140 let focus_range = 140 let focus_range =
141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range); 141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range);
142 let frange = original_range(db, node.map(|it| it.syntax())); 142 let frange = original_range(db, node.map(|it| it.syntax()));
@@ -150,6 +150,25 @@ impl NavigationTarget {
150 ) 150 )
151 } 151 }
152 152
153 /// Allows `NavigationTarget` to be created from a `DocCommentsOwner` and a `NameOwner`
154 pub(crate) fn from_doc_commented(
155 db: &RootDatabase,
156 named: InFile<&dyn ast::NameOwner>,
157 node: InFile<&dyn ast::DocCommentsOwner>,
158 ) -> NavigationTarget {
159 let name =
160 named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
161 let frange = original_range(db, node.map(|it| it.syntax()));
162
163 NavigationTarget::from_syntax(
164 frange.file_id,
165 name,
166 None,
167 frange.range,
168 node.value.syntax().kind(),
169 )
170 }
171
153 fn from_syntax( 172 fn from_syntax(
154 file_id: FileId, 173 file_id: FileId,
155 name: SmolStr, 174 name: SmolStr,
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 375da1f45..51dc1f041 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -82,7 +82,7 @@ pub use ra_db::{
82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, 82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId,
83}; 83};
84pub use ra_ide_db::{ 84pub use ra_ide_db::{
85 change::{AnalysisChange, LibraryData}, 85 change::AnalysisChange,
86 line_index::{LineCol, LineIndex}, 86 line_index::{LineCol, LineIndex},
87 search::SearchScope, 87 search::SearchScope,
88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index fc57dc33d..8105ef373 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -171,7 +171,15 @@ fn runnable_fn(
171 let cfg_exprs = 171 let cfg_exprs =
172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); 172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
173 173
174 let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); 174 let nav = if let RunnableKind::DocTest { .. } = kind {
175 NavigationTarget::from_doc_commented(
176 sema.db,
177 InFile::new(file_id.into(), &fn_def),
178 InFile::new(file_id.into(), &fn_def),
179 )
180 } else {
181 NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def))
182 };
175 Some(Runnable { nav, kind, cfg_exprs }) 183 Some(Runnable { nav, kind, cfg_exprs })
176} 184}
177 185
@@ -419,9 +427,7 @@ mod tests {
419 full_range: 22..64, 427 full_range: 22..64,
420 name: "foo", 428 name: "foo",
421 kind: FN_DEF, 429 kind: FN_DEF,
422 focus_range: Some( 430 focus_range: None,
423 56..59,
424 ),
425 container_name: None, 431 container_name: None,
426 description: None, 432 description: None,
427 docs: None, 433 docs: None,
@@ -486,9 +492,7 @@ mod tests {
486 full_range: 51..105, 492 full_range: 51..105,
487 name: "foo", 493 name: "foo",
488 kind: FN_DEF, 494 kind: FN_DEF,
489 focus_range: Some( 495 focus_range: None,
490 97..100,
491 ),
492 container_name: None, 496 container_name: None,
493 description: None, 497 description: None,
494 docs: None, 498 docs: None,
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
index f1e007b09..f61c0daa5 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/src/snapshots/highlight_doctest.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html
index e1c9d3523..47dbd7bc8 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/src/snapshots/highlight_injection.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
index 666b48fd0..b46fa44c6 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/src/snapshots/highlight_strings.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
@@ -83,6 +84,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
83 84
84 <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); 85 <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>);
85 86
86 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>); 87 <span class="comment">// escape sequences</span>
88 <span class="macro">println!</span>(<span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span>);
89 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span>);
90
91 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>);
87 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>); 92 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>);
88}</code></pre> \ No newline at end of file 93}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html
index e1540499b..73438fbb4 100644
--- a/crates/ra_ide/src/snapshots/highlight_unsafe.html
+++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 52912dc93..0c4f0a018 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 1d7f04882..a74a70069 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; } 28.unresolved_reference { color: #FC5555; }
29.escape_sequence { color: #94BFF3; }
29 30
30.keyword { color: #F0DFAF; font-weight: bold; } 31.keyword { color: #F0DFAF; font-weight: bold; }
31.keyword.unsafe { color: #BC8383; font-weight: bold; } 32.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs
index 5b7992920..45411b357 100644
--- a/crates/ra_ide/src/status.rs
+++ b/crates/ra_ide/src/status.rs
@@ -16,6 +16,7 @@ use ra_prof::{memory_usage, Bytes};
16use ra_syntax::{ast, Parse, SyntaxNode}; 16use ra_syntax::{ast, Parse, SyntaxNode};
17 17
18use crate::FileId; 18use crate::FileId;
19use rustc_hash::FxHashMap;
19 20
20fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 21fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
21 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>() 22 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>()
@@ -123,20 +124,24 @@ struct LibrarySymbolsStats {
123 124
124impl fmt::Display for LibrarySymbolsStats { 125impl fmt::Display for LibrarySymbolsStats {
125 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 126 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
126 write!(fmt, "{} ({}) symbols", self.total, self.size,) 127 write!(fmt, "{} ({}) symbols", self.total, self.size)
127 } 128 }
128} 129}
129 130
130impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats { 131impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
132 for LibrarySymbolsStats
133{
131 fn from_iter<T>(iter: T) -> LibrarySymbolsStats 134 fn from_iter<T>(iter: T) -> LibrarySymbolsStats
132 where 135 where
133 T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>, 136 T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
134 { 137 {
135 let mut res = LibrarySymbolsStats::default(); 138 let mut res = LibrarySymbolsStats::default();
136 for entry in iter { 139 for entry in iter {
137 let value = entry.value.unwrap(); 140 let value = entry.value.unwrap();
138 res.total += value.len(); 141 for symbols in value.values() {
139 res.size += value.memory_size(); 142 res.total += symbols.len();
143 res.size += symbols.memory_size();
144 }
140 } 145 }
141 res 146 res
142 } 147 }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 6c43c5d94..f8f790e59 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -212,8 +212,8 @@ pub(crate) fn highlight(
212 if let Some(string) = 212 if let Some(string) =
213 element_to_highlight.as_token().cloned().and_then(ast::String::cast) 213 element_to_highlight.as_token().cloned().and_then(ast::String::cast)
214 { 214 {
215 stack.push();
216 if is_format_string { 215 if is_format_string {
216 stack.push();
217 string.lex_format_specifier(|piece_range, kind| { 217 string.lex_format_specifier(|piece_range, kind| {
218 if let Some(highlight) = highlight_format_specifier(kind) { 218 if let Some(highlight) = highlight_format_specifier(kind) {
219 stack.add(HighlightedRange { 219 stack.add(HighlightedRange {
@@ -223,13 +223,27 @@ pub(crate) fn highlight(
223 }); 223 });
224 } 224 }
225 }); 225 });
226 stack.pop();
227 }
228 // Highlight escape sequences
229 if let Some(char_ranges) = string.char_ranges() {
230 stack.push();
231 for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) {
232 if string.text()[piece_range.start().into()..].starts_with('\\') {
233 stack.add(HighlightedRange {
234 range: piece_range + range.start(),
235 highlight: HighlightTag::EscapeSequence.into(),
236 binding_hash: None,
237 });
238 }
239 }
240 stack.pop_and_inject(false);
226 } 241 }
227 stack.pop();
228 } else if let Some(string) = 242 } else if let Some(string) =
229 element_to_highlight.as_token().cloned().and_then(ast::RawString::cast) 243 element_to_highlight.as_token().cloned().and_then(ast::RawString::cast)
230 { 244 {
231 stack.push();
232 if is_format_string { 245 if is_format_string {
246 stack.push();
233 string.lex_format_specifier(|piece_range, kind| { 247 string.lex_format_specifier(|piece_range, kind| {
234 if let Some(highlight) = highlight_format_specifier(kind) { 248 if let Some(highlight) = highlight_format_specifier(kind) {
235 stack.add(HighlightedRange { 249 stack.add(HighlightedRange {
@@ -239,8 +253,8 @@ pub(crate) fn highlight(
239 }); 253 });
240 } 254 }
241 }); 255 });
256 stack.pop();
242 } 257 }
243 stack.pop();
244 } 258 }
245 } 259 }
246 } 260 }
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 853b4a20f..99b6b25ab 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -85,6 +85,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
85.format_specifier { color: #CC696B; } 85.format_specifier { color: #CC696B; }
86.mutable { text-decoration: underline; } 86.mutable { text-decoration: underline; }
87.unresolved_reference { color: #FC5555; } 87.unresolved_reference { color: #FC5555; }
88.escape_sequence { color: #94BFF3; }
88 89
89.keyword { color: #F0DFAF; font-weight: bold; } 90.keyword { color: #F0DFAF; font-weight: bold; }
90.keyword.unsafe { color: #BC8383; font-weight: bold; } 91.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index f593ecad8..93bbb4b4d 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -23,6 +23,7 @@ pub enum HighlightTag {
23 Constant, 23 Constant,
24 Enum, 24 Enum,
25 EnumVariant, 25 EnumVariant,
26 EscapeSequence,
26 Field, 27 Field,
27 FormatSpecifier, 28 FormatSpecifier,
28 Function, 29 Function,
@@ -72,6 +73,7 @@ impl HighlightTag {
72 HighlightTag::Constant => "constant", 73 HighlightTag::Constant => "constant",
73 HighlightTag::Enum => "enum", 74 HighlightTag::Enum => "enum",
74 HighlightTag::EnumVariant => "enum_variant", 75 HighlightTag::EnumVariant => "enum_variant",
76 HighlightTag::EscapeSequence => "escape_sequence",
75 HighlightTag::Field => "field", 77 HighlightTag::Field => "field",
76 HighlightTag::FormatSpecifier => "format_specifier", 78 HighlightTag::FormatSpecifier => "format_specifier",
77 HighlightTag::Function => "function", 79 HighlightTag::Function => "function",
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index ebf5b50ac..b4d56a7a0 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -246,6 +246,10 @@ fn main() {
246 246
247 println!(r"Hello, {}!", "world"); 247 println!(r"Hello, {}!", "world");
248 248
249 // escape sequences
250 println!("Hello\nWorld");
251 println!("\u{48}\x65\x6C\x6C\x6F World");
252
249 println!("{\x41}", A = 92); 253 println!("{\x41}", A = 92);
250 println!("{ничоси}", ничоси = 92); 254 println!("{ничоси}", ничоси = 92);
251}"# 255}"#
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index 2fc796a85..78ee6a515 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -9,22 +9,15 @@ use ra_db::{
9 SourceRootId, 9 SourceRootId,
10}; 10};
11use ra_prof::{memory_usage, profile, Bytes}; 11use ra_prof::{memory_usage, profile, Bytes};
12use ra_syntax::SourceFile;
13#[cfg(not(feature = "wasm"))]
14use rayon::prelude::*;
15use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
16 13
17use crate::{ 14use crate::{symbol_index::SymbolsDatabase, RootDatabase};
18 symbol_index::{SymbolIndex, SymbolsDatabase},
19 RootDatabase,
20};
21 15
22#[derive(Default)] 16#[derive(Default)]
23pub struct AnalysisChange { 17pub struct AnalysisChange {
24 new_roots: Vec<(SourceRootId, bool)>, 18 new_roots: Vec<(SourceRootId, bool)>,
25 roots_changed: FxHashMap<SourceRootId, RootChange>, 19 roots_changed: FxHashMap<SourceRootId, RootChange>,
26 files_changed: Vec<(FileId, Arc<String>)>, 20 files_changed: Vec<(FileId, Arc<String>)>,
27 libraries_added: Vec<LibraryData>,
28 crate_graph: Option<CrateGraph>, 21 crate_graph: Option<CrateGraph>,
29} 22}
30 23
@@ -40,9 +33,6 @@ impl fmt::Debug for AnalysisChange {
40 if !self.files_changed.is_empty() { 33 if !self.files_changed.is_empty() {
41 d.field("files_changed", &self.files_changed.len()); 34 d.field("files_changed", &self.files_changed.len());
42 } 35 }
43 if !self.libraries_added.is_empty() {
44 d.field("libraries_added", &self.libraries_added.len());
45 }
46 if self.crate_graph.is_some() { 36 if self.crate_graph.is_some() {
47 d.field("crate_graph", &self.crate_graph); 37 d.field("crate_graph", &self.crate_graph);
48 } 38 }
@@ -79,10 +69,6 @@ impl AnalysisChange {
79 self.roots_changed.entry(root_id).or_default().removed.push(file); 69 self.roots_changed.entry(root_id).or_default().removed.push(file);
80 } 70 }
81 71
82 pub fn add_library(&mut self, data: LibraryData) {
83 self.libraries_added.push(data)
84 }
85
86 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 72 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
87 self.crate_graph = Some(graph); 73 self.crate_graph = Some(graph);
88 } 74 }
@@ -116,47 +102,6 @@ impl fmt::Debug for RootChange {
116 } 102 }
117} 103}
118 104
119pub struct LibraryData {
120 root_id: SourceRootId,
121 root_change: RootChange,
122 symbol_index: SymbolIndex,
123}
124
125impl fmt::Debug for LibraryData {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 f.debug_struct("LibraryData")
128 .field("root_id", &self.root_id)
129 .field("root_change", &self.root_change)
130 .field("n_symbols", &self.symbol_index.len())
131 .finish()
132 }
133}
134
135impl LibraryData {
136 pub fn prepare(
137 root_id: SourceRootId,
138 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
139 ) -> LibraryData {
140 let _p = profile("LibraryData::prepare");
141
142 #[cfg(not(feature = "wasm"))]
143 let iter = files.par_iter();
144 #[cfg(feature = "wasm")]
145 let iter = files.iter();
146
147 let symbol_index = SymbolIndex::for_files(iter.map(|(file_id, _, text)| {
148 let parse = SourceFile::parse(text);
149 (*file_id, parse)
150 }));
151 let mut root_change = RootChange::default();
152 root_change.added = files
153 .into_iter()
154 .map(|(file_id, path, text)| AddFile { file_id, path, text })
155 .collect();
156 LibraryData { root_id, root_change, symbol_index }
157 }
158}
159
160const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); 105const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
161 106
162impl RootDatabase { 107impl RootDatabase {
@@ -171,6 +116,7 @@ impl RootDatabase {
171 log::info!("apply_change {:?}", change); 116 log::info!("apply_change {:?}", change);
172 if !change.new_roots.is_empty() { 117 if !change.new_roots.is_empty() {
173 let mut local_roots = Vec::clone(&self.local_roots()); 118 let mut local_roots = Vec::clone(&self.local_roots());
119 let mut libraries = Vec::clone(&self.library_roots());
174 for (root_id, is_local) in change.new_roots { 120 for (root_id, is_local) in change.new_roots {
175 let root = 121 let root =
176 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() }; 122 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() };
@@ -178,9 +124,12 @@ impl RootDatabase {
178 self.set_source_root_with_durability(root_id, Arc::new(root), durability); 124 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
179 if is_local { 125 if is_local {
180 local_roots.push(root_id); 126 local_roots.push(root_id);
127 } else {
128 libraries.push(root_id)
181 } 129 }
182 } 130 }
183 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 131 self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
132 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
184 } 133 }
185 134
186 for (root_id, root_change) in change.roots_changed { 135 for (root_id, root_change) in change.roots_changed {
@@ -192,24 +141,6 @@ impl RootDatabase {
192 let durability = durability(&source_root); 141 let durability = durability(&source_root);
193 self.set_file_text_with_durability(file_id, text, durability) 142 self.set_file_text_with_durability(file_id, text, durability)
194 } 143 }
195 if !change.libraries_added.is_empty() {
196 let mut libraries = Vec::clone(&self.library_roots());
197 for library in change.libraries_added {
198 libraries.push(library.root_id);
199 self.set_source_root_with_durability(
200 library.root_id,
201 Arc::new(SourceRoot::new_library()),
202 Durability::HIGH,
203 );
204 self.set_library_symbols_with_durability(
205 library.root_id,
206 Arc::new(library.symbol_index),
207 Durability::HIGH,
208 );
209 self.apply_root_change(library.root_id, library.root_change);
210 }
211 self.set_library_roots_with_durability(Arc::new(libraries), Durability::HIGH);
212 }
213 if let Some(crate_graph) = change.crate_graph { 144 if let Some(crate_graph) = change.crate_graph {
214 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) 145 self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
215 } 146 }
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index aab918973..25c99813f 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -34,14 +34,15 @@ use ra_db::{
34 salsa::{self, ParallelDatabase}, 34 salsa::{self, ParallelDatabase},
35 CrateId, FileId, SourceDatabaseExt, SourceRootId, 35 CrateId, FileId, SourceDatabaseExt, SourceRootId,
36}; 36};
37use ra_prof::profile;
37use ra_syntax::{ 38use ra_syntax::{
38 ast::{self, NameOwner}, 39 ast::{self, NameOwner},
39 match_ast, AstNode, Parse, SmolStr, SourceFile, 40 match_ast, AstNode, Parse, SmolStr, SourceFile,
40 SyntaxKind::{self, *}, 41 SyntaxKind::{self, *},
41 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, 42 SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
42}; 43};
43#[cfg(not(feature = "wasm"))]
44use rayon::prelude::*; 44use rayon::prelude::*;
45use rustc_hash::FxHashMap;
45 46
46use crate::RootDatabase; 47use crate::RootDatabase;
47 48
@@ -86,10 +87,9 @@ impl Query {
86} 87}
87 88
88#[salsa::query_group(SymbolsDatabaseStorage)] 89#[salsa::query_group(SymbolsDatabaseStorage)]
89pub trait SymbolsDatabase: hir::db::HirDatabase { 90pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDatabase {
90 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>; 91 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
91 #[salsa::input] 92 fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
92 fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
93 /// The set of "local" (that is, from the current workspace) roots. 93 /// The set of "local" (that is, from the current workspace) roots.
94 /// Files in local roots are assumed to change frequently. 94 /// Files in local roots are assumed to change frequently.
95 #[salsa::input] 95 #[salsa::input]
@@ -100,6 +100,29 @@ pub trait SymbolsDatabase: hir::db::HirDatabase {
100 fn library_roots(&self) -> Arc<Vec<SourceRootId>>; 100 fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
101} 101}
102 102
103fn library_symbols(
104 db: &(impl SymbolsDatabase + ParallelDatabase),
105) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
106 let _p = profile("library_symbols");
107
108 let roots = db.library_roots();
109 let res = roots
110 .iter()
111 .map(|&root_id| {
112 let root = db.source_root(root_id);
113 let files = root
114 .walk()
115 .map(|it| (it, SourceDatabaseExt::file_text(db, it)))
116 .collect::<Vec<_>>();
117 let symbol_index = SymbolIndex::for_files(
118 files.into_par_iter().map(|(file, text)| (file, SourceFile::parse(&text))),
119 );
120 (root_id, symbol_index)
121 })
122 .collect();
123 Arc::new(res)
124}
125
103fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 126fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
104 db.check_canceled(); 127 db.check_canceled();
105 let parse = db.parse(file_id); 128 let parse = db.parse(file_id);
@@ -112,9 +135,9 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
112} 135}
113 136
114/// Need to wrap Snapshot to provide `Clone` impl for `map_with` 137/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
115struct Snap(salsa::Snapshot<RootDatabase>); 138struct Snap<DB>(DB);
116impl Clone for Snap { 139impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
117 fn clone(&self) -> Snap { 140 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
118 Snap(self.0.snapshot()) 141 Snap(self.0.snapshot())
119 } 142 }
120} 143}
@@ -143,19 +166,11 @@ impl Clone for Snap {
143pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { 166pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
144 let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); 167 let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone());
145 168
146 let buf: Vec<Arc<SymbolIndex>> = if query.libs { 169 let tmp1;
147 let snap = Snap(db.snapshot()); 170 let tmp2;
148 #[cfg(not(feature = "wasm"))] 171 let buf: Vec<&SymbolIndex> = if query.libs {
149 let buf = db 172 tmp1 = db.library_symbols();
150 .library_roots() 173 tmp1.values().collect()
151 .par_iter()
152 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
153 .collect();
154
155 #[cfg(feature = "wasm")]
156 let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();
157
158 buf
159 } else { 174 } else {
160 let mut files = Vec::new(); 175 let mut files = Vec::new();
161 for &root in db.local_roots().iter() { 176 for &root in db.local_roots().iter() {
@@ -164,14 +179,11 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
164 } 179 }
165 180
166 let snap = Snap(db.snapshot()); 181 let snap = Snap(db.snapshot());
167 #[cfg(not(feature = "wasm"))] 182 tmp2 = files
168 let buf = 183 .par_iter()
169 files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect(); 184 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
170 185 .collect::<Vec<_>>();
171 #[cfg(feature = "wasm")] 186 tmp2.iter().map(|it| &**it).collect()
172 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect();
173
174 buf
175 }; 187 };
176 query.search(&buf) 188 query.search(&buf)
177} 189}
@@ -191,14 +203,11 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil
191 203
192 let snap = Snap(db.snapshot()); 204 let snap = Snap(db.snapshot());
193 205
194 #[cfg(not(feature = "wasm"))]
195 let buf = files 206 let buf = files
196 .par_iter() 207 .par_iter()
197 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) 208 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
198 .collect::<Vec<_>>(); 209 .collect::<Vec<_>>();
199 210 let buf = buf.iter().map(|it| &**it).collect::<Vec<_>>();
200 #[cfg(feature = "wasm")]
201 let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect::<Vec<_>>();
202 211
203 query.search(&buf) 212 query.search(&buf)
204} 213}
@@ -245,12 +254,8 @@ impl SymbolIndex {
245 lhs_chars.cmp(rhs_chars) 254 lhs_chars.cmp(rhs_chars)
246 } 255 }
247 256
248 #[cfg(not(feature = "wasm"))]
249 symbols.par_sort_by(cmp); 257 symbols.par_sort_by(cmp);
250 258
251 #[cfg(feature = "wasm")]
252 symbols.sort_by(cmp);
253
254 let mut builder = fst::MapBuilder::memory(); 259 let mut builder = fst::MapBuilder::memory();
255 260
256 let mut last_batch_start = 0; 261 let mut last_batch_start = 0;
@@ -284,7 +289,6 @@ impl SymbolIndex {
284 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>() 289 self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
285 } 290 }
286 291
287 #[cfg(not(feature = "wasm"))]
288 pub(crate) fn for_files( 292 pub(crate) fn for_files(
289 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>, 293 files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
290 ) -> SymbolIndex { 294 ) -> SymbolIndex {
@@ -294,16 +298,6 @@ impl SymbolIndex {
294 SymbolIndex::new(symbols) 298 SymbolIndex::new(symbols)
295 } 299 }
296 300
297 #[cfg(feature = "wasm")]
298 pub(crate) fn for_files(
299 files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
300 ) -> SymbolIndex {
301 let symbols = files
302 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
303 .collect::<Vec<_>>();
304 SymbolIndex::new(symbols)
305 }
306
307 fn range_to_map_value(start: usize, end: usize) -> u64 { 301 fn range_to_map_value(start: usize, end: usize) -> u64 {
308 debug_assert![start <= (std::u32::MAX as usize)]; 302 debug_assert![start <= (std::u32::MAX as usize)];
309 debug_assert![end <= (std::u32::MAX as usize)]; 303 debug_assert![end <= (std::u32::MAX as usize)];
@@ -319,7 +313,7 @@ impl SymbolIndex {
319} 313}
320 314
321impl Query { 315impl Query {
322 pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> { 316 pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> {
323 let mut op = fst::map::OpBuilder::new(); 317 let mut op = fst::map::OpBuilder::new();
324 for file_symbols in indices.iter() { 318 for file_symbols in indices.iter() {
325 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 319 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
diff --git a/crates/ra_syntax/src/parsing/text_token_source.rs b/crates/ra_syntax/src/parsing/text_token_source.rs
index 7ddc2c2c3..97aa3e795 100644
--- a/crates/ra_syntax/src/parsing/text_token_source.rs
+++ b/crates/ra_syntax/src/parsing/text_token_source.rs
@@ -1,40 +1,35 @@
1//! FIXME: write short doc here 1//! See `TextTokenSource` docs.
2 2
3use ra_parser::Token as PToken;
4use ra_parser::TokenSource; 3use ra_parser::TokenSource;
5 4
6use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize}; 5use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize};
7 6
7/// Implementation of `ra_parser::TokenSource` that takes tokens from source code text.
8pub(crate) struct TextTokenSource<'t> { 8pub(crate) struct TextTokenSource<'t> {
9 text: &'t str, 9 text: &'t str,
10 /// start position of each token(expect whitespace and comment) 10 /// token and its start position (non-whitespace/comment tokens)
11 /// ```non-rust 11 /// ```non-rust
12 /// struct Foo; 12 /// struct Foo;
13 /// ^------^--- 13 /// ^------^--^-
14 /// | | ^- 14 /// | | \________
15 /// 0 7 10 15 /// | \____ \
16 /// | \ |
17 /// (struct, 0) (Foo, 7) (;, 10)
16 /// ``` 18 /// ```
17 /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]` 19 /// `[(struct, 0), (Foo, 7), (;, 10)]`
18 start_offsets: Vec<TextSize>, 20 token_offset_pairs: Vec<(Token, TextSize)>,
19 /// non-whitespace/comment tokens
20 /// ```non-rust
21 /// struct Foo {}
22 /// ^^^^^^ ^^^ ^^
23 /// ```
24 /// tokens: `[struct, Foo, {, }]`
25 tokens: Vec<Token>,
26 21
27 /// Current token and position 22 /// Current token and position
28 curr: (PToken, usize), 23 curr: (ra_parser::Token, usize),
29} 24}
30 25
31impl<'t> TokenSource for TextTokenSource<'t> { 26impl<'t> TokenSource for TextTokenSource<'t> {
32 fn current(&self) -> PToken { 27 fn current(&self) -> ra_parser::Token {
33 self.curr.0 28 self.curr.0
34 } 29 }
35 30
36 fn lookahead_nth(&self, n: usize) -> PToken { 31 fn lookahead_nth(&self, n: usize) -> ra_parser::Token {
37 mk_token(self.curr.1 + n, &self.start_offsets, &self.tokens) 32 mk_token(self.curr.1 + n, &self.token_offset_pairs)
38 } 33 }
39 34
40 fn bump(&mut self) { 35 fn bump(&mut self) {
@@ -43,45 +38,47 @@ impl<'t> TokenSource for TextTokenSource<'t> {
43 } 38 }
44 39
45 let pos = self.curr.1 + 1; 40 let pos = self.curr.1 + 1;
46 self.curr = (mk_token(pos, &self.start_offsets, &self.tokens), pos); 41 self.curr = (mk_token(pos, &self.token_offset_pairs), pos);
47 } 42 }
48 43
49 fn is_keyword(&self, kw: &str) -> bool { 44 fn is_keyword(&self, kw: &str) -> bool {
50 let pos = self.curr.1; 45 self.token_offset_pairs
51 if pos >= self.tokens.len() { 46 .get(self.curr.1)
52 return false; 47 .map(|(token, offset)| &self.text[TextRange::at(*offset, token.len)] == kw)
53 } 48 .unwrap_or(false)
54 let range = TextRange::at(self.start_offsets[pos], self.tokens[pos].len);
55 self.text[range] == *kw
56 } 49 }
57} 50}
58 51
59fn mk_token(pos: usize, start_offsets: &[TextSize], tokens: &[Token]) -> PToken { 52fn mk_token(pos: usize, token_offset_pairs: &[(Token, TextSize)]) -> ra_parser::Token {
60 let kind = tokens.get(pos).map(|t| t.kind).unwrap_or(EOF); 53 let (kind, is_jointed_to_next) = match token_offset_pairs.get(pos) {
61 let is_jointed_to_next = if pos + 1 < start_offsets.len() { 54 Some((token, offset)) => (
62 start_offsets[pos] + tokens[pos].len == start_offsets[pos + 1] 55 token.kind,
63 } else { 56 token_offset_pairs
64 false 57 .get(pos + 1)
58 .map(|(_, next_offset)| offset + token.len == *next_offset)
59 .unwrap_or(false),
60 ),
61 None => (EOF, false),
65 }; 62 };
66 63 ra_parser::Token { kind, is_jointed_to_next }
67 PToken { kind, is_jointed_to_next }
68} 64}
69 65
70impl<'t> TextTokenSource<'t> { 66impl<'t> TextTokenSource<'t> {
71 /// Generate input from tokens(expect comment and whitespace). 67 /// Generate input from tokens(expect comment and whitespace).
72 pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> { 68 pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> {
73 let mut tokens = Vec::new(); 69 let token_offset_pairs: Vec<_> = raw_tokens
74 let mut start_offsets = Vec::new(); 70 .iter()
75 let mut len = 0.into(); 71 .filter_map({
76 for &token in raw_tokens.iter() { 72 let mut len = 0.into();
77 if !token.kind.is_trivia() { 73 move |token| {
78 tokens.push(token); 74 let pair = if token.kind.is_trivia() { None } else { Some((*token, len)) };
79 start_offsets.push(len); 75 len += token.len;
80 } 76 pair
81 len += token.len; 77 }
82 } 78 })
79 .collect();
83 80
84 let first = mk_token(0, &start_offsets, &tokens); 81 let first = mk_token(0, &token_offset_pairs);
85 TextTokenSource { text, start_offsets, tokens, curr: (first, 0) } 82 TextTokenSource { text, token_offset_pairs, curr: (first, 0) }
86 } 83 }
87} 84}
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 44f856f6b..5c22dce0d 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -2,7 +2,7 @@
2 2
3use ra_cfg::CfgExpr; 3use ra_cfg::CfgExpr;
4use ra_ide::{FileId, RunnableKind, TestId}; 4use ra_ide::{FileId, RunnableKind, TestId};
5use ra_project_model::{self, ProjectWorkspace, TargetKind}; 5use ra_project_model::{self, TargetKind};
6 6
7use crate::{global_state::GlobalStateSnapshot, Result}; 7use crate::{global_state::GlobalStateSnapshot, Result};
8 8
@@ -89,27 +89,23 @@ impl CargoTargetSpec {
89 } 89 }
90 90
91 pub(crate) fn for_file( 91 pub(crate) fn for_file(
92 world: &GlobalStateSnapshot, 92 global_state_snapshot: &GlobalStateSnapshot,
93 file_id: FileId, 93 file_id: FileId,
94 ) -> Result<Option<CargoTargetSpec>> { 94 ) -> Result<Option<CargoTargetSpec>> {
95 let &crate_id = match world.analysis().crate_for(file_id)?.first() { 95 let crate_id = match global_state_snapshot.analysis().crate_for(file_id)?.first() {
96 Some(crate_id) => crate_id, 96 Some(crate_id) => *crate_id,
97 None => return Ok(None), 97 None => return Ok(None),
98 }; 98 };
99 let file_id = world.analysis().crate_root(crate_id)?; 99 let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) {
100 let path = world.file_id_to_path(file_id); 100 Some(it) => it,
101 let res = world.workspaces.iter().find_map(|ws| match ws { 101 None => return Ok(None),
102 ProjectWorkspace::Cargo { cargo, .. } => { 102 };
103 let tgt = cargo.target_by_root(&path)?; 103 let res = CargoTargetSpec {
104 Some(CargoTargetSpec { 104 package: cargo_ws.package_flag(&cargo_ws[cargo_ws[target].package]),
105 package: cargo.package_flag(&cargo[cargo[tgt].package]), 105 target: cargo_ws[target].name.clone(),
106 target: cargo[tgt].name.clone(), 106 target_kind: cargo_ws[target].kind,
107 target_kind: cargo[tgt].kind, 107 };
108 }) 108 Ok(Some(res))
109 }
110 ProjectWorkspace::Json { .. } => None,
111 });
112 Ok(res)
113 } 109 }
114 110
115 pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) { 111 pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 73ca2a709..1527c9947 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -12,41 +12,34 @@ use crossbeam_channel::{unbounded, Receiver};
12use lsp_types::Url; 12use lsp_types::Url;
13use parking_lot::RwLock; 13use parking_lot::RwLock;
14use ra_flycheck::{Flycheck, FlycheckConfig}; 14use ra_flycheck::{Flycheck, FlycheckConfig};
15use ra_ide::{ 15use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, SourceRootId};
16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, 16use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
17};
18use ra_project_model::{ProcMacroClient, ProjectWorkspace};
19use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsTask, Watch}; 17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsTask, Watch};
20use relative_path::RelativePathBuf;
21use stdx::format_to; 18use stdx::format_to;
22 19
23use crate::{ 20use crate::{
24 config::Config, 21 config::{Config, FilesWatcher},
25 diagnostics::{CheckFixes, DiagnosticCollection}, 22 diagnostics::{CheckFixes, DiagnosticCollection},
26 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 23 main_loop::pending_requests::{CompletedRequest, LatestRequests},
27 to_proto::url_from_abs_path, 24 to_proto::url_from_abs_path,
28 vfs_glob::{Glob, RustPackageFilterBuilder}, 25 vfs_glob::{Glob, RustPackageFilterBuilder},
29 LspError, Result, 26 LspError, Result,
30}; 27};
31use ra_db::ExternSourceId; 28use ra_db::{CrateId, ExternSourceId};
32use rustc_hash::{FxHashMap, FxHashSet}; 29use rustc_hash::{FxHashMap, FxHashSet};
33 30
34fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> { 31fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> {
35 // FIXME: Figure out the multi-workspace situation 32 // FIXME: Figure out the multi-workspace situation
36 workspaces 33 workspaces.iter().find_map(|w| match w {
37 .iter() 34 ProjectWorkspace::Cargo { cargo, .. } => {
38 .find_map(|w| match w {
39 ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
40 ProjectWorkspace::Json { .. } => None,
41 })
42 .map(|cargo| {
43 let cargo_project_root = cargo.workspace_root().to_path_buf(); 35 let cargo_project_root = cargo.workspace_root().to_path_buf();
44 Some(Flycheck::new(config.clone(), cargo_project_root)) 36 Some(Flycheck::new(config.clone(), cargo_project_root))
45 }) 37 }
46 .unwrap_or_else(|| { 38 ProjectWorkspace::Json { .. } => {
47 log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); 39 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
48 None 40 None
49 }) 41 }
42 })
50} 43}
51 44
52/// `GlobalState` is the primary mutable state of the language server 45/// `GlobalState` is the primary mutable state of the language server
@@ -83,7 +76,6 @@ impl GlobalState {
83 workspaces: Vec<ProjectWorkspace>, 76 workspaces: Vec<ProjectWorkspace>,
84 lru_capacity: Option<usize>, 77 lru_capacity: Option<usize>,
85 exclude_globs: &[Glob], 78 exclude_globs: &[Glob],
86 watch: Watch,
87 config: Config, 79 config: Config,
88 ) -> GlobalState { 80 ) -> GlobalState {
89 let mut change = AnalysisChange::new(); 81 let mut change = AnalysisChange::new();
@@ -118,6 +110,7 @@ impl GlobalState {
118 110
119 let (task_sender, task_receiver) = unbounded(); 111 let (task_sender, task_receiver) = unbounded();
120 let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); 112 let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
113 let watch = Watch(matches!(config.files.watcher, FilesWatcher::Notify));
121 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); 114 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
122 115
123 let mut extern_source_roots = FxHashMap::default(); 116 let mut extern_source_roots = FxHashMap::default();
@@ -195,32 +188,18 @@ impl GlobalState {
195 188
196 /// Returns a vec of libraries 189 /// Returns a vec of libraries
197 /// FIXME: better API here 190 /// FIXME: better API here
198 pub fn process_changes( 191 pub fn process_changes(&mut self, roots_scanned: &mut usize) -> bool {
199 &mut self,
200 roots_scanned: &mut usize,
201 ) -> Option<Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>> {
202 let changes = self.vfs.write().commit_changes(); 192 let changes = self.vfs.write().commit_changes();
203 if changes.is_empty() { 193 if changes.is_empty() {
204 return None; 194 return false;
205 } 195 }
206 let mut libs = Vec::new();
207 let mut change = AnalysisChange::new(); 196 let mut change = AnalysisChange::new();
208 for c in changes { 197 for c in changes {
209 match c { 198 match c {
210 VfsChange::AddRoot { root, files } => { 199 VfsChange::AddRoot { root, files } => {
211 let root_path = self.vfs.read().root2path(root); 200 *roots_scanned += 1;
212 let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); 201 for (file, path, text) in files {
213 if is_local { 202 change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
214 *roots_scanned += 1;
215 for (file, path, text) in files {
216 change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
217 }
218 } else {
219 let files = files
220 .into_iter()
221 .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
222 .collect();
223 libs.push((SourceRootId(root.0), files));
224 } 203 }
225 } 204 }
226 VfsChange::AddFile { root, file, path, text } => { 205 VfsChange::AddFile { root, file, path, text } => {
@@ -235,13 +214,7 @@ impl GlobalState {
235 } 214 }
236 } 215 }
237 self.analysis_host.apply_change(change); 216 self.analysis_host.apply_change(change);
238 Some(libs) 217 true
239 }
240
241 pub fn add_lib(&mut self, data: LibraryData) {
242 let mut change = AnalysisChange::new();
243 change.add_library(data);
244 self.analysis_host.apply_change(change);
245 } 218 }
246 219
247 pub fn snapshot(&self) -> GlobalStateSnapshot { 220 pub fn snapshot(&self) -> GlobalStateSnapshot {
@@ -290,10 +263,6 @@ impl GlobalStateSnapshot {
290 file_id_to_url(&self.vfs.read(), id) 263 file_id_to_url(&self.vfs.read(), id)
291 } 264 }
292 265
293 pub fn file_id_to_path(&self, id: FileId) -> PathBuf {
294 self.vfs.read().file2path(VfsFile(id.0))
295 }
296
297 pub fn file_line_endings(&self, id: FileId) -> LineEndings { 266 pub fn file_line_endings(&self, id: FileId) -> LineEndings {
298 self.vfs.read().file_line_endings(VfsFile(id.0)) 267 self.vfs.read().file_line_endings(VfsFile(id.0))
299 } 268 }
@@ -305,6 +274,20 @@ impl GlobalStateSnapshot {
305 url_from_abs_path(&path) 274 url_from_abs_path(&path)
306 } 275 }
307 276
277 pub(crate) fn cargo_target_for_crate_root(
278 &self,
279 crate_id: CrateId,
280 ) -> Option<(&CargoWorkspace, Target)> {
281 let file_id = self.analysis().crate_root(crate_id).ok()?;
282 let path = self.vfs.read().file2path(VfsFile(file_id.0));
283 self.workspaces.iter().find_map(|ws| match ws {
284 ProjectWorkspace::Cargo { cargo, .. } => {
285 cargo.target_by_root(&path).map(|it| (cargo, it))
286 }
287 ProjectWorkspace::Json { .. } => None,
288 })
289 }
290
308 pub fn status(&self) -> String { 291 pub fn status(&self) -> String {
309 let mut buf = String::new(); 292 let mut buf = String::new();
310 if self.workspaces.is_empty() { 293 if self.workspaces.is_empty() {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 80cfd3c28..f0aaaa21e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -24,11 +24,10 @@ use lsp_types::{
24 WorkDoneProgressReport, 24 WorkDoneProgressReport,
25}; 25};
26use ra_flycheck::{CheckTask, Status}; 26use ra_flycheck::{CheckTask, Status};
27use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; 27use ra_ide::{Canceled, FileId, LineIndex};
28use ra_prof::profile; 28use ra_prof::profile;
29use ra_project_model::{PackageRoot, ProjectWorkspace}; 29use ra_project_model::{PackageRoot, ProjectWorkspace};
30use ra_vfs::{VfsTask, Watch}; 30use ra_vfs::VfsTask;
31use relative_path::RelativePathBuf;
32use rustc_hash::FxHashSet; 31use rustc_hash::FxHashSet;
33use serde::{de::DeserializeOwned, Serialize}; 32use serde::{de::DeserializeOwned, Serialize};
34use threadpool::ThreadPool; 33use threadpool::ThreadPool;
@@ -161,25 +160,17 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
161 connection.sender.send(request.into()).unwrap(); 160 connection.sender.send(request.into()).unwrap();
162 } 161 }
163 162
164 GlobalState::new( 163 GlobalState::new(workspaces, config.lru_capacity, &globs, config)
165 workspaces,
166 config.lru_capacity,
167 &globs,
168 Watch(matches!(config.files.watcher, FilesWatcher::Notify)),
169 config,
170 )
171 }; 164 };
172 165
173 loop_state.roots_total = global_state.vfs.read().n_roots(); 166 loop_state.roots_total = global_state.vfs.read().n_roots();
174 167
175 let pool = ThreadPool::default(); 168 let pool = ThreadPool::default();
176 let (task_sender, task_receiver) = unbounded::<Task>(); 169 let (task_sender, task_receiver) = unbounded::<Task>();
177 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
178 170
179 log::info!("server initialized, serving requests"); 171 log::info!("server initialized, serving requests");
180 { 172 {
181 let task_sender = task_sender; 173 let task_sender = task_sender;
182 let libdata_sender = libdata_sender;
183 loop { 174 loop {
184 log::trace!("selecting"); 175 log::trace!("selecting");
185 let event = select! { 176 let event = select! {
@@ -192,7 +183,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
192 Ok(task) => Event::Vfs(task), 183 Ok(task) => Event::Vfs(task),
193 Err(RecvError) => return Err("vfs died".into()), 184 Err(RecvError) => return Err("vfs died".into()),
194 }, 185 },
195 recv(libdata_receiver) -> data => Event::Lib(data.unwrap()),
196 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { 186 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
197 Ok(task) => Event::CheckWatcher(task), 187 Ok(task) => Event::CheckWatcher(task),
198 Err(RecvError) => return Err("check watcher died".into()), 188 Err(RecvError) => return Err("check watcher died".into()),
@@ -203,15 +193,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
203 break; 193 break;
204 }; 194 };
205 } 195 }
206 loop_turn( 196 loop_turn(&pool, &task_sender, &connection, &mut global_state, &mut loop_state, event)?;
207 &pool,
208 &task_sender,
209 &libdata_sender,
210 &connection,
211 &mut global_state,
212 &mut loop_state,
213 event,
214 )?;
215 } 197 }
216 } 198 }
217 global_state.analysis_host.request_cancellation(); 199 global_state.analysis_host.request_cancellation();
@@ -219,7 +201,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
219 task_receiver.into_iter().for_each(|task| { 201 task_receiver.into_iter().for_each(|task| {
220 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state) 202 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state)
221 }); 203 });
222 libdata_receiver.into_iter().for_each(drop);
223 log::info!("...tasks have finished"); 204 log::info!("...tasks have finished");
224 log::info!("joining threadpool..."); 205 log::info!("joining threadpool...");
225 pool.join(); 206 pool.join();
@@ -243,7 +224,6 @@ enum Event {
243 Msg(Message), 224 Msg(Message),
244 Task(Task), 225 Task(Task),
245 Vfs(VfsTask), 226 Vfs(VfsTask),
246 Lib(LibraryData),
247 CheckWatcher(CheckTask), 227 CheckWatcher(CheckTask),
248} 228}
249 229
@@ -279,7 +259,6 @@ impl fmt::Debug for Event {
279 Event::Msg(it) => fmt::Debug::fmt(it, f), 259 Event::Msg(it) => fmt::Debug::fmt(it, f),
280 Event::Task(it) => fmt::Debug::fmt(it, f), 260 Event::Task(it) => fmt::Debug::fmt(it, f),
281 Event::Vfs(it) => fmt::Debug::fmt(it, f), 261 Event::Vfs(it) => fmt::Debug::fmt(it, f),
282 Event::Lib(it) => fmt::Debug::fmt(it, f),
283 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f), 262 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
284 } 263 }
285 } 264 }
@@ -291,10 +270,6 @@ struct LoopState {
291 pending_responses: FxHashSet<RequestId>, 270 pending_responses: FxHashSet<RequestId>,
292 pending_requests: PendingRequests, 271 pending_requests: PendingRequests,
293 subscriptions: Subscriptions, 272 subscriptions: Subscriptions,
294 // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same
295 // time to always have a thread ready to react to input.
296 in_flight_libraries: usize,
297 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
298 workspace_loaded: bool, 273 workspace_loaded: bool,
299 roots_progress_reported: Option<usize>, 274 roots_progress_reported: Option<usize>,
300 roots_scanned: usize, 275 roots_scanned: usize,
@@ -315,7 +290,6 @@ impl LoopState {
315fn loop_turn( 290fn loop_turn(
316 pool: &ThreadPool, 291 pool: &ThreadPool,
317 task_sender: &Sender<Task>, 292 task_sender: &Sender<Task>,
318 libdata_sender: &Sender<LibraryData>,
319 connection: &Connection, 293 connection: &Connection,
320 global_state: &mut GlobalState, 294 global_state: &mut GlobalState,
321 loop_state: &mut LoopState, 295 loop_state: &mut LoopState,
@@ -339,12 +313,6 @@ fn loop_turn(
339 Event::Vfs(task) => { 313 Event::Vfs(task) => {
340 global_state.vfs.write().handle_task(task); 314 global_state.vfs.write().handle_task(task);
341 } 315 }
342 Event::Lib(lib) => {
343 global_state.add_lib(lib);
344 global_state.maybe_collect_garbage();
345 loop_state.in_flight_libraries -= 1;
346 loop_state.roots_scanned += 1;
347 }
348 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, 316 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
349 Event::Msg(msg) => match msg { 317 Event::Msg(msg) => match msg {
350 Message::Request(req) => on_request( 318 Message::Request(req) => on_request(
@@ -390,36 +358,12 @@ fn loop_turn(
390 }, 358 },
391 }; 359 };
392 360
393 let mut state_changed = false; 361 let mut state_changed = global_state.process_changes(&mut loop_state.roots_scanned);
394 if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) {
395 state_changed = true;
396 loop_state.pending_libraries.extend(changes);
397 }
398
399 let max_in_flight_libs = pool.max_count().saturating_sub(2).max(1);
400 while loop_state.in_flight_libraries < max_in_flight_libs {
401 let (root, files) = match loop_state.pending_libraries.pop() {
402 Some(it) => it,
403 None => break,
404 };
405
406 loop_state.in_flight_libraries += 1;
407 let sender = libdata_sender.clone();
408 pool.execute(move || {
409 log::info!("indexing {:?} ... ", root);
410 let data = LibraryData::prepare(root, files);
411 sender.send(data).unwrap();
412 });
413 }
414 362
415 let show_progress = 363 let show_progress =
416 !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress; 364 !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress;
417 365
418 if !loop_state.workspace_loaded 366 if !loop_state.workspace_loaded && loop_state.roots_scanned == loop_state.roots_total {
419 && loop_state.roots_scanned == loop_state.roots_total
420 && loop_state.pending_libraries.is_empty()
421 && loop_state.in_flight_libraries == 0
422 {
423 state_changed = true; 367 state_changed = true;
424 loop_state.workspace_loaded = true; 368 loop_state.workspace_loaded = true;
425 if let Some(flycheck) = &global_state.flycheck { 369 if let Some(flycheck) = &global_state.flycheck {
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 6f125c37c..2ea63d33b 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -45,6 +45,7 @@ define_semantic_token_types![
45 (UNION, "union"), 45 (UNION, "union"),
46 (UNRESOLVED_REFERENCE, "unresolvedReference"), 46 (UNRESOLVED_REFERENCE, "unresolvedReference"),
47 (FORMAT_SPECIFIER, "formatSpecifier"), 47 (FORMAT_SPECIFIER, "formatSpecifier"),
48 (ESCAPE_SEQUENCE, "escapeSequence"),
48]; 49];
49 50
50macro_rules! define_semantic_token_modifiers { 51macro_rules! define_semantic_token_modifiers {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 84d6f5155..ec153097e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -324,6 +324,7 @@ fn semantic_token_type_and_modifiers(
324 HighlightTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, 324 HighlightTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
325 HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 325 HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
326 HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 326 HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
327 HighlightTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
327 }; 328 };
328 329
329 for modifier in highlight.modifiers.iter() { 330 for modifier in highlight.modifiers.iter() {