diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/src/macros.rs | 64 | ||||
-rw-r--r-- | crates/ra_analysis/src/syntax_highlighting.rs | 62 |
3 files changed, 67 insertions, 60 deletions
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 98abe8523..67b1c1482 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -18,6 +18,7 @@ pub mod mock_analysis; | |||
18 | 18 | ||
19 | mod extend_selection; | 19 | mod extend_selection; |
20 | mod syntax_highlighting; | 20 | mod syntax_highlighting; |
21 | mod macros; | ||
21 | 22 | ||
22 | use std::{fmt, sync::Arc}; | 23 | use std::{fmt, sync::Arc}; |
23 | 24 | ||
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 index 98551df8f..38219da71 100644 --- a/crates/ra_analysis/src/syntax_highlighting.rs +++ b/crates/ra_analysis/src/syntax_highlighting.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use ra_syntax::{ast, AstNode, SourceFileNode, TextRange}; | 1 | use ra_syntax::{ast, AstNode,}; |
2 | use ra_editor::HighlightedRange; | 2 | use ra_editor::HighlightedRange; |
3 | use ra_db::SyntaxDatabase; | 3 | use ra_db::SyntaxDatabase; |
4 | 4 | ||
@@ -15,7 +15,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi | |||
15 | .descendants() | 15 | .descendants() |
16 | .filter_map(ast::MacroCall::cast) | 16 | .filter_map(ast::MacroCall::cast) |
17 | { | 17 | { |
18 | if let Some(exp) = expand(db, file_id, macro_call) { | 18 | if let Some(exp) = crate::macros::expand(db, file_id, macro_call) { |
19 | let mapped_ranges = ra_editor::highlight(exp.source_file()) | 19 | let mapped_ranges = ra_editor::highlight(exp.source_file()) |
20 | .into_iter() | 20 | .into_iter() |
21 | .filter_map(|r| { | 21 | .filter_map(|r| { |
@@ -32,64 +32,6 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi | |||
32 | Ok(res) | 32 | Ok(res) |
33 | } | 33 | } |
34 | 34 | ||
35 | fn expand( | ||
36 | _db: &RootDatabase, | ||
37 | _file_id: FileId, | ||
38 | macro_call: ast::MacroCall, | ||
39 | ) -> Option<MacroExpansion> { | ||
40 | let path = macro_call.path()?; | ||
41 | if path.qualifier().is_some() { | ||
42 | return None; | ||
43 | } | ||
44 | let name_ref = path.segment()?.name_ref()?; | ||
45 | if name_ref.text() != "ctry" { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | let arg = macro_call.token_tree()?; | ||
50 | let text = format!( | ||
51 | r" | ||
52 | fn dummy() {{ | ||
53 | match {} {{ | ||
54 | None => return Ok(None), | ||
55 | Some(it) => it, | ||
56 | }} | ||
57 | }}", | ||
58 | arg.syntax().text() | ||
59 | ); | ||
60 | let file = SourceFileNode::parse(&text); | ||
61 | let match_expr = file.syntax().descendants().find_map(ast::MatchExpr::cast)?; | ||
62 | let match_arg = match_expr.expr()?; | ||
63 | let ranges_map = vec![(arg.syntax().range(), match_arg.syntax().range())]; | ||
64 | let res = MacroExpansion { | ||
65 | source_file: file, | ||
66 | ranges_map, | ||
67 | }; | ||
68 | Some(res) | ||
69 | } | ||
70 | |||
71 | struct MacroExpansion { | ||
72 | source_file: SourceFileNode, | ||
73 | ranges_map: Vec<(TextRange, TextRange)>, | ||
74 | } | ||
75 | |||
76 | impl MacroExpansion { | ||
77 | fn source_file(&self) -> &SourceFileNode { | ||
78 | &self.source_file | ||
79 | } | ||
80 | fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> { | ||
81 | for (s_range, t_range) in self.ranges_map.iter() { | ||
82 | if tgt_range.is_subrange(&t_range) { | ||
83 | let tgt_at_zero_range = tgt_range - tgt_range.start(); | ||
84 | let tgt_range_offset = tgt_range.start() - t_range.start(); | ||
85 | let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start(); | ||
86 | return Some(src_range); | ||
87 | } | ||
88 | } | ||
89 | None | ||
90 | } | ||
91 | } | ||
92 | |||
93 | #[cfg(test)] | 35 | #[cfg(test)] |
94 | mod tests { | 36 | mod tests { |
95 | use crate::mock_analysis::single_file; | 37 | use crate::mock_analysis::single_file; |