diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/extend_selection.rs | 11 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 24 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 27 | ||||
-rw-r--r-- | crates/ra_analysis/src/macros.rs | 64 | ||||
-rw-r--r-- | crates/ra_analysis/src/syntax_highlighting.rs | 63 |
5 files changed, 167 insertions, 22 deletions
diff --git a/crates/ra_analysis/src/extend_selection.rs b/crates/ra_analysis/src/extend_selection.rs new file mode 100644 index 000000000..5e1fbee18 --- /dev/null +++ b/crates/ra_analysis/src/extend_selection.rs | |||
@@ -0,0 +1,11 @@ | |||
1 | use ra_db::SyntaxDatabase; | ||
2 | |||
3 | use crate::{ | ||
4 | TextRange, FileRange, | ||
5 | db::RootDatabase, | ||
6 | }; | ||
7 | |||
8 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { | ||
9 | let file = db.source_file(frange.file_id); | ||
10 | ra_editor::extend_selection(&file, frange.range).unwrap_or(frange.range) | ||
11 | } | ||
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index e6663810d..fcb4cd957 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -23,7 +23,7 @@ use crate::{ | |||
23 | AnalysisChange, | 23 | AnalysisChange, |
24 | Cancelable, | 24 | Cancelable, |
25 | completion::{CompletionItem, completions}, | 25 | completion::{CompletionItem, completions}, |
26 | CrateId, db, Diagnostic, FileId, FilePosition, FileSystemEdit, | 26 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, |
27 | Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, | 27 | Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, |
28 | symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase}, | 28 | symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase}, |
29 | }; | 29 | }; |
@@ -404,19 +404,21 @@ impl AnalysisImpl { | |||
404 | Ok(res) | 404 | Ok(res) |
405 | } | 405 | } |
406 | 406 | ||
407 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { | 407 | pub fn assists(&self, frange: FileRange) -> Vec<SourceChange> { |
408 | let file = self.file_syntax(file_id); | 408 | let file = self.file_syntax(frange.file_id); |
409 | let offset = range.start(); | 409 | let offset = frange.range.start(); |
410 | let actions = vec![ | 410 | let actions = vec![ |
411 | ra_editor::flip_comma(&file, offset).map(|f| f()), | 411 | ra_editor::flip_comma(&file, offset).map(|f| f()), |
412 | ra_editor::add_derive(&file, offset).map(|f| f()), | 412 | ra_editor::add_derive(&file, offset).map(|f| f()), |
413 | ra_editor::add_impl(&file, offset).map(|f| f()), | 413 | ra_editor::add_impl(&file, offset).map(|f| f()), |
414 | ra_editor::make_pub_crate(&file, offset).map(|f| f()), | 414 | ra_editor::make_pub_crate(&file, offset).map(|f| f()), |
415 | ra_editor::introduce_variable(&file, range).map(|f| f()), | 415 | ra_editor::introduce_variable(&file, frange.range).map(|f| f()), |
416 | ]; | 416 | ]; |
417 | actions | 417 | actions |
418 | .into_iter() | 418 | .into_iter() |
419 | .filter_map(|local_edit| Some(SourceChange::from_local_edit(file_id, local_edit?))) | 419 | .filter_map(|local_edit| { |
420 | Some(SourceChange::from_local_edit(frange.file_id, local_edit?)) | ||
421 | }) | ||
420 | .collect() | 422 | .collect() |
421 | } | 423 | } |
422 | 424 | ||
@@ -487,13 +489,15 @@ impl AnalysisImpl { | |||
487 | Ok(None) | 489 | Ok(None) |
488 | } | 490 | } |
489 | 491 | ||
490 | pub fn type_of(&self, file_id: FileId, range: TextRange) -> Cancelable<Option<String>> { | 492 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
491 | let file = self.db.source_file(file_id); | 493 | let file = self.db.source_file(frange.file_id); |
492 | let syntax = file.syntax(); | 494 | let syntax = file.syntax(); |
493 | let node = find_covering_node(syntax, range); | 495 | let node = find_covering_node(syntax, frange.range); |
494 | let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast)); | 496 | let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast)); |
495 | let function = ctry!(source_binder::function_from_source( | 497 | let function = ctry!(source_binder::function_from_source( |
496 | &*self.db, file_id, parent_fn | 498 | &*self.db, |
499 | frange.file_id, | ||
500 | parent_fn | ||
497 | )?); | 501 | )?); |
498 | let infer = function.infer(&*self.db)?; | 502 | let infer = function.infer(&*self.db)?; |
499 | Ok(infer.type_of_node(node).map(|t| t.to_string())) | 503 | Ok(infer.type_of_node(node).map(|t| t.to_string())) |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 65c3eb3ec..67b1c1482 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -16,6 +16,10 @@ mod completion; | |||
16 | mod symbol_index; | 16 | mod symbol_index; |
17 | pub mod mock_analysis; | 17 | pub mod mock_analysis; |
18 | 18 | ||
19 | mod extend_selection; | ||
20 | mod syntax_highlighting; | ||
21 | mod macros; | ||
22 | |||
19 | use std::{fmt, sync::Arc}; | 23 | use std::{fmt, sync::Arc}; |
20 | 24 | ||
21 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
@@ -37,7 +41,7 @@ pub use ra_editor::{ | |||
37 | pub use hir::FnSignatureInfo; | 41 | pub use hir::FnSignatureInfo; |
38 | 42 | ||
39 | pub use ra_db::{ | 43 | pub use ra_db::{ |
40 | Canceled, Cancelable, FilePosition, | 44 | Canceled, Cancelable, FilePosition, FileRange, |
41 | CrateGraph, CrateId, SourceRootId, FileId | 45 | CrateGraph, CrateId, SourceRootId, FileId |
42 | }; | 46 | }; |
43 | 47 | ||
@@ -276,8 +280,8 @@ impl Analysis { | |||
276 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 280 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
277 | self.imp.file_line_index(file_id) | 281 | self.imp.file_line_index(file_id) |
278 | } | 282 | } |
279 | pub fn extend_selection(&self, file: &SourceFileNode, range: TextRange) -> TextRange { | 283 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { |
280 | ra_editor::extend_selection(file, range).unwrap_or(range) | 284 | extend_selection::extend_selection(&self.imp.db, frange) |
281 | } | 285 | } |
282 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { | 286 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { |
283 | ra_editor::matching_brace(file, offset) | 287 | ra_editor::matching_brace(file, offset) |
@@ -286,9 +290,9 @@ impl Analysis { | |||
286 | let file = self.imp.file_syntax(file_id); | 290 | let file = self.imp.file_syntax(file_id); |
287 | ra_editor::syntax_tree(&file) | 291 | ra_editor::syntax_tree(&file) |
288 | } | 292 | } |
289 | pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange { | 293 | pub fn join_lines(&self, frange: FileRange) -> SourceChange { |
290 | let file = self.imp.file_syntax(file_id); | 294 | let file = self.imp.file_syntax(frange.file_id); |
291 | SourceChange::from_local_edit(file_id, ra_editor::join_lines(&file, range)) | 295 | SourceChange::from_local_edit(frange.file_id, ra_editor::join_lines(&file, frange.range)) |
292 | } | 296 | } |
293 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { | 297 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { |
294 | let file = self.imp.file_syntax(position.file_id); | 298 | let file = self.imp.file_syntax(position.file_id); |
@@ -340,14 +344,13 @@ impl Analysis { | |||
340 | Ok(ra_editor::runnables(&file)) | 344 | Ok(ra_editor::runnables(&file)) |
341 | } | 345 | } |
342 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 346 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
343 | let file = self.imp.file_syntax(file_id); | 347 | syntax_highlighting::highlight(&*self.imp.db, file_id) |
344 | Ok(ra_editor::highlight(&file)) | ||
345 | } | 348 | } |
346 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 349 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
347 | self.imp.completions(position) | 350 | self.imp.completions(position) |
348 | } | 351 | } |
349 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> { | 352 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { |
350 | Ok(self.imp.assists(file_id, range)) | 353 | Ok(self.imp.assists(frange)) |
351 | } | 354 | } |
352 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 355 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
353 | self.imp.diagnostics(file_id) | 356 | self.imp.diagnostics(file_id) |
@@ -358,8 +361,8 @@ impl Analysis { | |||
358 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { | 361 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
359 | self.imp.resolve_callable(position) | 362 | self.imp.resolve_callable(position) |
360 | } | 363 | } |
361 | pub fn type_of(&self, file_id: FileId, range: TextRange) -> Cancelable<Option<String>> { | 364 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
362 | self.imp.type_of(file_id, range) | 365 | self.imp.type_of(frange) |
363 | } | 366 | } |
364 | } | 367 | } |
365 | 368 | ||
diff --git a/crates/ra_analysis/src/macros.rs b/crates/ra_analysis/src/macros.rs new file mode 100644 index 000000000..c0dd49dc8 --- /dev/null +++ b/crates/ra_analysis/src/macros.rs | |||
@@ -0,0 +1,64 @@ | |||
1 | /// Begining of macro expansion. | ||
2 | /// | ||
3 | /// This code should be moved out of ra_analysis into hir (?) ideally. | ||
4 | use ra_syntax::{ast, AstNode, SourceFileNode, TextRange}; | ||
5 | |||
6 | use crate::{db::RootDatabase, FileId}; | ||
7 | |||
8 | pub(crate) fn expand( | ||
9 | _db: &RootDatabase, | ||
10 | _file_id: FileId, | ||
11 | macro_call: ast::MacroCall, | ||
12 | ) -> Option<MacroExpansion> { | ||
13 | let path = macro_call.path()?; | ||
14 | if path.qualifier().is_some() { | ||
15 | return None; | ||
16 | } | ||
17 | let name_ref = path.segment()?.name_ref()?; | ||
18 | if name_ref.text() != "ctry" { | ||
19 | return None; | ||
20 | } | ||
21 | |||
22 | let arg = macro_call.token_tree()?; | ||
23 | let text = format!( | ||
24 | r" | ||
25 | fn dummy() {{ | ||
26 | match {} {{ | ||
27 | None => return Ok(None), | ||
28 | Some(it) => it, | ||
29 | }} | ||
30 | }}", | ||
31 | arg.syntax().text() | ||
32 | ); | ||
33 | let file = SourceFileNode::parse(&text); | ||
34 | let match_expr = file.syntax().descendants().find_map(ast::MatchExpr::cast)?; | ||
35 | let match_arg = match_expr.expr()?; | ||
36 | let ranges_map = vec![(arg.syntax().range(), match_arg.syntax().range())]; | ||
37 | let res = MacroExpansion { | ||
38 | source_file: file, | ||
39 | ranges_map, | ||
40 | }; | ||
41 | Some(res) | ||
42 | } | ||
43 | |||
44 | pub(crate) struct MacroExpansion { | ||
45 | pub(crate) source_file: SourceFileNode, | ||
46 | pub(crate) ranges_map: Vec<(TextRange, TextRange)>, | ||
47 | } | ||
48 | |||
49 | impl MacroExpansion { | ||
50 | pub(crate) fn source_file(&self) -> &SourceFileNode { | ||
51 | &self.source_file | ||
52 | } | ||
53 | pub(crate) fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> { | ||
54 | for (s_range, t_range) in self.ranges_map.iter() { | ||
55 | if tgt_range.is_subrange(&t_range) { | ||
56 | let tgt_at_zero_range = tgt_range - tgt_range.start(); | ||
57 | let tgt_range_offset = tgt_range.start() - t_range.start(); | ||
58 | let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start(); | ||
59 | return Some(src_range); | ||
60 | } | ||
61 | } | ||
62 | None | ||
63 | } | ||
64 | } | ||
diff --git a/crates/ra_analysis/src/syntax_highlighting.rs b/crates/ra_analysis/src/syntax_highlighting.rs new file mode 100644 index 000000000..38219da71 --- /dev/null +++ b/crates/ra_analysis/src/syntax_highlighting.rs | |||
@@ -0,0 +1,63 @@ | |||
1 | use ra_syntax::{ast, AstNode,}; | ||
2 | use ra_editor::HighlightedRange; | ||
3 | use ra_db::SyntaxDatabase; | ||
4 | |||
5 | use crate::{ | ||
6 | db::RootDatabase, | ||
7 | FileId, Cancelable, | ||
8 | }; | ||
9 | |||
10 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | ||
11 | let source_file = db.source_file(file_id); | ||
12 | let mut res = ra_editor::highlight(&source_file); | ||
13 | for macro_call in source_file | ||
14 | .syntax() | ||
15 | .descendants() | ||
16 | .filter_map(ast::MacroCall::cast) | ||
17 | { | ||
18 | if let Some(exp) = crate::macros::expand(db, file_id, macro_call) { | ||
19 | let mapped_ranges = ra_editor::highlight(exp.source_file()) | ||
20 | .into_iter() | ||
21 | .filter_map(|r| { | ||
22 | let mapped_range = exp.map_range_back(r.range)?; | ||
23 | let res = HighlightedRange { | ||
24 | range: mapped_range, | ||
25 | tag: r.tag, | ||
26 | }; | ||
27 | Some(res) | ||
28 | }); | ||
29 | res.extend(mapped_ranges); | ||
30 | } | ||
31 | } | ||
32 | Ok(res) | ||
33 | } | ||
34 | |||
35 | #[cfg(test)] | ||
36 | mod tests { | ||
37 | use crate::mock_analysis::single_file; | ||
38 | use test_utils::assert_eq_dbg; | ||
39 | |||
40 | #[test] | ||
41 | fn highlights_code_inside_macros() { | ||
42 | let (analysis, file_id) = single_file( | ||
43 | " | ||
44 | fn main() { | ||
45 | ctry!({ let x = 92; x}); | ||
46 | } | ||
47 | ", | ||
48 | ); | ||
49 | let highlights = analysis.highlight(file_id).unwrap(); | ||
50 | assert_eq_dbg( | ||
51 | r#"[HighlightedRange { range: [13; 15), tag: "keyword" }, | ||
52 | HighlightedRange { range: [16; 20), tag: "function" }, | ||
53 | HighlightedRange { range: [41; 46), tag: "macro" }, | ||
54 | HighlightedRange { range: [49; 52), tag: "keyword" }, | ||
55 | HighlightedRange { range: [57; 59), tag: "literal" }, | ||
56 | HighlightedRange { range: [49; 52), tag: "keyword" }, | ||
57 | HighlightedRange { range: [53; 54), tag: "function" }, | ||
58 | HighlightedRange { range: [57; 59), tag: "literal" }, | ||
59 | HighlightedRange { range: [61; 62), tag: "text" }]"#, | ||
60 | &highlights, | ||
61 | ) | ||
62 | } | ||
63 | } | ||