diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-28 16:17:19 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-28 16:17:19 +0000 |
commit | 7a268b9b9635425176f93d3c893fb5345e84e9ce (patch) | |
tree | 6ea69024cb22d3fc48a3b392a0185163fa452014 /crates | |
parent | 9d6740a9c9ad2ca47c4885bd994f849e90bbef86 (diff) | |
parent | b911ee542b2f4d1cd62a655f24197856cd9b9097 (diff) |
Merge #350
350: Super simple macro support r=matklad a=matklad
Super simple support for macros, mostly for figuring out how to fit them into the current architecture. Expansion is hard-coded and string based (mid-term, we should try to copy-paste macro-by-example expander from rustc).
Ideally, we should handle
* highlighting inside the macro (done)
* extend selection inside the macro
* completion inside the macro
* indexing structs, produced by the macro
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-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 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_editor/src/lib.rs | 35 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 13 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 20 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 45 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 1 |
11 files changed, 273 insertions, 38 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 | } | ||
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 3028db17c..7181f2950 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -8,7 +8,7 @@ pub mod mock; | |||
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use ra_editor::LineIndex; | 10 | use ra_editor::LineIndex; |
11 | use ra_syntax::{TextUnit, SourceFileNode}; | 11 | use ra_syntax::{TextUnit, TextRange, SourceFileNode}; |
12 | 12 | ||
13 | pub use crate::{ | 13 | pub use crate::{ |
14 | cancelation::{Canceled, Cancelable}, | 14 | cancelation::{Canceled, Cancelable}, |
@@ -70,3 +70,9 @@ pub struct FilePosition { | |||
70 | pub file_id: FileId, | 70 | pub file_id: FileId, |
71 | pub offset: TextUnit, | 71 | pub offset: TextUnit, |
72 | } | 72 | } |
73 | |||
74 | #[derive(Clone, Copy, Debug)] | ||
75 | pub struct FileRange { | ||
76 | pub file_id: FileId, | ||
77 | pub range: TextRange, | ||
78 | } | ||
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index d9b89155b..9043026c1 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -24,9 +24,10 @@ use ra_syntax::{ | |||
24 | SourceFileNode, | 24 | SourceFileNode, |
25 | Location, | 25 | Location, |
26 | SyntaxKind::{self, *}, | 26 | SyntaxKind::{self, *}, |
27 | SyntaxNodeRef, TextRange, TextUnit, | 27 | SyntaxNodeRef, TextRange, TextUnit, Direction, |
28 | }; | 28 | }; |
29 | use itertools::Itertools; | 29 | use itertools::Itertools; |
30 | use rustc_hash::FxHashSet; | ||
30 | 31 | ||
31 | #[derive(Debug)] | 32 | #[derive(Debug)] |
32 | pub struct HighlightedRange { | 33 | pub struct HighlightedRange { |
@@ -79,8 +80,13 @@ pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUni | |||
79 | } | 80 | } |
80 | 81 | ||
81 | pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> { | 82 | pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> { |
83 | // Visited nodes to handle highlighting priorities | ||
84 | let mut highlighted = FxHashSet::default(); | ||
82 | let mut res = Vec::new(); | 85 | let mut res = Vec::new(); |
83 | for node in file.syntax().descendants() { | 86 | for node in file.syntax().descendants() { |
87 | if highlighted.contains(&node) { | ||
88 | continue; | ||
89 | } | ||
84 | let tag = match node.kind() { | 90 | let tag = match node.kind() { |
85 | COMMENT => "comment", | 91 | COMMENT => "comment", |
86 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", | 92 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", |
@@ -90,7 +96,30 @@ pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> { | |||
90 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", | 96 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", |
91 | LIFETIME => "parameter", | 97 | LIFETIME => "parameter", |
92 | k if k.is_keyword() => "keyword", | 98 | k if k.is_keyword() => "keyword", |
93 | _ => continue, | 99 | _ => { |
100 | if let Some(macro_call) = ast::MacroCall::cast(node) { | ||
101 | if let Some(path) = macro_call.path() { | ||
102 | if let Some(segment) = path.segment() { | ||
103 | if let Some(name_ref) = segment.name_ref() { | ||
104 | highlighted.insert(name_ref.syntax()); | ||
105 | let range_start = name_ref.syntax().range().start(); | ||
106 | let mut range_end = name_ref.syntax().range().end(); | ||
107 | for sibling in path.syntax().siblings(Direction::Next) { | ||
108 | match sibling.kind() { | ||
109 | EXCL | IDENT => range_end = sibling.range().end(), | ||
110 | _ => (), | ||
111 | } | ||
112 | } | ||
113 | res.push(HighlightedRange { | ||
114 | range: TextRange::from_to(range_start, range_end), | ||
115 | tag: "macro", | ||
116 | }) | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | continue; | ||
122 | } | ||
94 | }; | 123 | }; |
95 | res.push(HighlightedRange { | 124 | res.push(HighlightedRange { |
96 | range: node.range(), | 125 | range: node.range(), |
@@ -235,7 +264,7 @@ fn main() {} | |||
235 | r#"[HighlightedRange { range: [1; 11), tag: "comment" }, | 264 | r#"[HighlightedRange { range: [1; 11), tag: "comment" }, |
236 | HighlightedRange { range: [12; 14), tag: "keyword" }, | 265 | HighlightedRange { range: [12; 14), tag: "keyword" }, |
237 | HighlightedRange { range: [15; 19), tag: "function" }, | 266 | HighlightedRange { range: [15; 19), tag: "function" }, |
238 | HighlightedRange { range: [29; 36), tag: "text" }, | 267 | HighlightedRange { range: [29; 37), tag: "macro" }, |
239 | HighlightedRange { range: [38; 50), tag: "string" }, | 268 | HighlightedRange { range: [38; 50), tag: "string" }, |
240 | HighlightedRange { range: [52; 54), tag: "literal" }]"#, | 269 | HighlightedRange { range: [52; 54), tag: "literal" }]"#, |
241 | &hls, | 270 | &hls, |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index d3670104e..3d56ccd97 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -2,7 +2,7 @@ use languageserver_types::{ | |||
2 | self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, | 2 | self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, |
3 | TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat, | 3 | TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat, |
4 | }; | 4 | }; |
5 | use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition, CompletionItem, CompletionItemKind, InsertText}; | 5 | use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition,FileRange, CompletionItem, CompletionItemKind, InsertText}; |
6 | use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; | 6 | use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; |
7 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 7 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
8 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 8 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
@@ -218,6 +218,17 @@ impl<'a> TryConvWith for &'a TextDocumentPositionParams { | |||
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | impl<'a> TryConvWith for (&'a TextDocumentIdentifier, Range) { | ||
222 | type Ctx = ServerWorld; | ||
223 | type Output = FileRange; | ||
224 | fn try_conv_with(self, world: &ServerWorld) -> Result<FileRange> { | ||
225 | let file_id = self.0.try_conv_with(world)?; | ||
226 | let line_index = world.analysis().file_line_index(file_id); | ||
227 | let range = self.1.conv_with(&line_index); | ||
228 | Ok(FileRange { file_id, range }) | ||
229 | } | ||
230 | } | ||
231 | |||
221 | impl<T: TryConvWith> TryConvWith for Vec<T> { | 232 | impl<T: TryConvWith> TryConvWith for Vec<T> { |
222 | type Ctx = <T as TryConvWith>::Ctx; | 233 | type Ctx = <T as TryConvWith>::Ctx; |
223 | type Output = Vec<<T as TryConvWith>::Output>; | 234 | type Output = Vec<<T as TryConvWith>::Output>; |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 0e9a66a8a..d6f3dbe28 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -8,7 +8,7 @@ use languageserver_types::{ | |||
8 | PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, | 8 | PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, |
9 | WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, | 9 | WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, |
10 | }; | 10 | }; |
11 | use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition, Severity}; | 11 | use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; |
12 | use ra_syntax::{TextUnit, text_utils::intersect}; | 12 | use ra_syntax::{TextUnit, text_utils::intersect}; |
13 | use ra_text_edit::text_utils::contains_offset_nonstrict; | 13 | use ra_text_edit::text_utils::contains_offset_nonstrict; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -33,13 +33,13 @@ pub fn handle_extend_selection( | |||
33 | params: req::ExtendSelectionParams, | 33 | params: req::ExtendSelectionParams, |
34 | ) -> Result<req::ExtendSelectionResult> { | 34 | ) -> Result<req::ExtendSelectionResult> { |
35 | let file_id = params.text_document.try_conv_with(&world)?; | 35 | let file_id = params.text_document.try_conv_with(&world)?; |
36 | let file = world.analysis().file_syntax(file_id); | ||
37 | let line_index = world.analysis().file_line_index(file_id); | 36 | let line_index = world.analysis().file_line_index(file_id); |
38 | let selections = params | 37 | let selections = params |
39 | .selections | 38 | .selections |
40 | .into_iter() | 39 | .into_iter() |
41 | .map_conv_with(&line_index) | 40 | .map_conv_with(&line_index) |
42 | .map(|r| world.analysis().extend_selection(&file, r)) | 41 | .map(|range| FileRange { file_id, range }) |
42 | .map(|frange| world.analysis().extend_selection(frange)) | ||
43 | .map_conv_with(&line_index) | 43 | .map_conv_with(&line_index) |
44 | .collect(); | 44 | .collect(); |
45 | Ok(req::ExtendSelectionResult { selections }) | 45 | Ok(req::ExtendSelectionResult { selections }) |
@@ -71,13 +71,8 @@ pub fn handle_join_lines( | |||
71 | world: ServerWorld, | 71 | world: ServerWorld, |
72 | params: req::JoinLinesParams, | 72 | params: req::JoinLinesParams, |
73 | ) -> Result<req::SourceChange> { | 73 | ) -> Result<req::SourceChange> { |
74 | let file_id = params.text_document.try_conv_with(&world)?; | 74 | let frange = (¶ms.text_document, params.range).try_conv_with(&world)?; |
75 | let line_index = world.analysis().file_line_index(file_id); | 75 | world.analysis().join_lines(frange).try_conv_with(&world) |
76 | let range = params.range.conv_with(&line_index); | ||
77 | world | ||
78 | .analysis() | ||
79 | .join_lines(file_id, range) | ||
80 | .try_conv_with(&world) | ||
81 | } | 76 | } |
82 | 77 | ||
83 | pub fn handle_on_enter( | 78 | pub fn handle_on_enter( |
@@ -614,7 +609,10 @@ pub fn handle_code_action( | |||
614 | let line_index = world.analysis().file_line_index(file_id); | 609 | let line_index = world.analysis().file_line_index(file_id); |
615 | let range = params.range.conv_with(&line_index); | 610 | let range = params.range.conv_with(&line_index); |
616 | 611 | ||
617 | let assists = world.analysis().assists(file_id, range)?.into_iter(); | 612 | let assists = world |
613 | .analysis() | ||
614 | .assists(FileRange { file_id, range })? | ||
615 | .into_iter(); | ||
618 | let fixes = world | 616 | let fixes = world |
619 | .analysis() | 617 | .analysis() |
620 | .diagnostics(file_id)? | 618 | .diagnostics(file_id)? |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index c22e026cf..c5ac90a62 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1838,6 +1838,51 @@ impl<R: TreeRoot<RaTypes>> LoopExprNode<R> { | |||
1838 | impl<'a> ast::LoopBodyOwner<'a> for LoopExpr<'a> {} | 1838 | impl<'a> ast::LoopBodyOwner<'a> for LoopExpr<'a> {} |
1839 | impl<'a> LoopExpr<'a> {} | 1839 | impl<'a> LoopExpr<'a> {} |
1840 | 1840 | ||
1841 | // MacroCall | ||
1842 | #[derive(Debug, Clone, Copy,)] | ||
1843 | pub struct MacroCallNode<R: TreeRoot<RaTypes> = OwnedRoot> { | ||
1844 | pub(crate) syntax: SyntaxNode<R>, | ||
1845 | } | ||
1846 | pub type MacroCall<'a> = MacroCallNode<RefRoot<'a>>; | ||
1847 | |||
1848 | impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<MacroCallNode<R1>> for MacroCallNode<R2> { | ||
1849 | fn eq(&self, other: &MacroCallNode<R1>) -> bool { self.syntax == other.syntax } | ||
1850 | } | ||
1851 | impl<R: TreeRoot<RaTypes>> Eq for MacroCallNode<R> {} | ||
1852 | impl<R: TreeRoot<RaTypes>> Hash for MacroCallNode<R> { | ||
1853 | fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) } | ||
1854 | } | ||
1855 | |||
1856 | impl<'a> AstNode<'a> for MacroCall<'a> { | ||
1857 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { | ||
1858 | match syntax.kind() { | ||
1859 | MACRO_CALL => Some(MacroCall { syntax }), | ||
1860 | _ => None, | ||
1861 | } | ||
1862 | } | ||
1863 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | ||
1864 | } | ||
1865 | |||
1866 | impl<R: TreeRoot<RaTypes>> MacroCallNode<R> { | ||
1867 | pub fn borrowed(&self) -> MacroCall { | ||
1868 | MacroCallNode { syntax: self.syntax.borrowed() } | ||
1869 | } | ||
1870 | pub fn owned(&self) -> MacroCallNode { | ||
1871 | MacroCallNode { syntax: self.syntax.owned() } | ||
1872 | } | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | impl<'a> MacroCall<'a> { | ||
1877 | pub fn token_tree(self) -> Option<TokenTree<'a>> { | ||
1878 | super::child_opt(self) | ||
1879 | } | ||
1880 | |||
1881 | pub fn path(self) -> Option<Path<'a>> { | ||
1882 | super::child_opt(self) | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1841 | // MatchArm | 1886 | // MatchArm |
1842 | #[derive(Debug, Clone, Copy,)] | 1887 | #[derive(Debug, Clone, Copy,)] |
1843 | pub struct MatchArmNode<R: TreeRoot<RaTypes> = OwnedRoot> { | 1888 | pub struct MatchArmNode<R: TreeRoot<RaTypes> = OwnedRoot> { |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 4bcff4e14..aab4839a9 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -484,6 +484,7 @@ Grammar( | |||
484 | 484 | ||
485 | "Name": (), | 485 | "Name": (), |
486 | "NameRef": (), | 486 | "NameRef": (), |
487 | "MacroCall": ( options: [ "TokenTree", "Path" ] ), | ||
487 | "Attr": ( options: [ ["value", "TokenTree"] ] ), | 488 | "Attr": ( options: [ ["value", "TokenTree"] ] ), |
488 | "TokenTree": (), | 489 | "TokenTree": (), |
489 | "TypeParamList": ( | 490 | "TypeParamList": ( |