diff options
Diffstat (limited to 'crates/ra_ide_api/src/extend_selection.rs')
-rw-r--r-- | crates/ra_ide_api/src/extend_selection.rs | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs new file mode 100644 index 000000000..c3c809c9f --- /dev/null +++ b/crates/ra_ide_api/src/extend_selection.rs | |||
@@ -0,0 +1,56 @@ | |||
1 | use ra_db::SyntaxDatabase; | ||
2 | use ra_syntax::{ | ||
3 | SyntaxNode, AstNode, SourceFile, | ||
4 | ast, algo::find_covering_node, | ||
5 | }; | ||
6 | |||
7 | use crate::{ | ||
8 | TextRange, FileRange, | ||
9 | db::RootDatabase, | ||
10 | }; | ||
11 | |||
12 | pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { | ||
13 | let source_file = db.source_file(frange.file_id); | ||
14 | if let Some(range) = extend_selection_in_macro(db, &source_file, frange) { | ||
15 | return range; | ||
16 | } | ||
17 | ra_ide_api_light::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range) | ||
18 | } | ||
19 | |||
20 | fn extend_selection_in_macro( | ||
21 | _db: &RootDatabase, | ||
22 | source_file: &SourceFile, | ||
23 | frange: FileRange, | ||
24 | ) -> Option<TextRange> { | ||
25 | let macro_call = find_macro_call(source_file.syntax(), frange.range)?; | ||
26 | let (off, exp) = hir::MacroDef::ast_expand(macro_call)?; | ||
27 | let dst_range = exp.map_range_forward(frange.range - off)?; | ||
28 | let dst_range = ra_ide_api_light::extend_selection(&exp.syntax(), dst_range)?; | ||
29 | let src_range = exp.map_range_back(dst_range)? + off; | ||
30 | Some(src_range) | ||
31 | } | ||
32 | |||
33 | fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCall> { | ||
34 | find_covering_node(node, range) | ||
35 | .ancestors() | ||
36 | .find_map(ast::MacroCall::cast) | ||
37 | } | ||
38 | |||
39 | #[cfg(test)] | ||
40 | mod tests { | ||
41 | use crate::mock_analysis::single_file_with_range; | ||
42 | use test_utils::assert_eq_dbg; | ||
43 | |||
44 | #[test] | ||
45 | fn extend_selection_inside_macros() { | ||
46 | let (analysis, frange) = single_file_with_range( | ||
47 | " | ||
48 | fn main() { | ||
49 | ctry!(foo(|x| <|>x<|>)); | ||
50 | } | ||
51 | ", | ||
52 | ); | ||
53 | let r = analysis.extend_selection(frange); | ||
54 | assert_eq_dbg("[51; 56)", &r); | ||
55 | } | ||
56 | } | ||