aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-12-28 16:17:19 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-12-28 16:17:19 +0000
commit7a268b9b9635425176f93d3c893fb5345e84e9ce (patch)
tree6ea69024cb22d3fc48a3b392a0185163fa452014 /crates
parent9d6740a9c9ad2ca47c4885bd994f849e90bbef86 (diff)
parentb911ee542b2f4d1cd62a655f24197856cd9b9097 (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.rs11
-rw-r--r--crates/ra_analysis/src/imp.rs24
-rw-r--r--crates/ra_analysis/src/lib.rs27
-rw-r--r--crates/ra_analysis/src/macros.rs64
-rw-r--r--crates/ra_analysis/src/syntax_highlighting.rs63
-rw-r--r--crates/ra_db/src/lib.rs8
-rw-r--r--crates/ra_editor/src/lib.rs35
-rw-r--r--crates/ra_lsp_server/src/conv.rs13
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs20
-rw-r--r--crates/ra_syntax/src/ast/generated.rs45
-rw-r--r--crates/ra_syntax/src/grammar.ron1
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 @@
1use ra_db::SyntaxDatabase;
2
3use crate::{
4 TextRange, FileRange,
5 db::RootDatabase,
6};
7
8pub(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;
16mod symbol_index; 16mod symbol_index;
17pub mod mock_analysis; 17pub mod mock_analysis;
18 18
19mod extend_selection;
20mod syntax_highlighting;
21mod macros;
22
19use std::{fmt, sync::Arc}; 23use std::{fmt, sync::Arc};
20 24
21use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
@@ -37,7 +41,7 @@ pub use ra_editor::{
37pub use hir::FnSignatureInfo; 41pub use hir::FnSignatureInfo;
38 42
39pub use ra_db::{ 43pub 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.
4use ra_syntax::{ast, AstNode, SourceFileNode, TextRange};
5
6use crate::{db::RootDatabase, FileId};
7
8pub(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
44pub(crate) struct MacroExpansion {
45 pub(crate) source_file: SourceFileNode,
46 pub(crate) ranges_map: Vec<(TextRange, TextRange)>,
47}
48
49impl 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 @@
1use ra_syntax::{ast, AstNode,};
2use ra_editor::HighlightedRange;
3use ra_db::SyntaxDatabase;
4
5use crate::{
6 db::RootDatabase,
7 FileId, Cancelable,
8};
9
10pub(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)]
36mod 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;
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_editor::LineIndex; 10use ra_editor::LineIndex;
11use ra_syntax::{TextUnit, SourceFileNode}; 11use ra_syntax::{TextUnit, TextRange, SourceFileNode};
12 12
13pub use crate::{ 13pub 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)]
75pub 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};
29use itertools::Itertools; 29use itertools::Itertools;
30use rustc_hash::FxHashSet;
30 31
31#[derive(Debug)] 32#[derive(Debug)]
32pub struct HighlightedRange { 33pub struct HighlightedRange {
@@ -79,8 +80,13 @@ pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUni
79} 80}
80 81
81pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> { 82pub 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};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition, CompletionItem, CompletionItemKind, InsertText}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition,FileRange, CompletionItem, CompletionItemKind, InsertText};
6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; 6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit};
7use ra_text_edit::{AtomTextEdit, TextEdit}; 7use ra_text_edit::{AtomTextEdit, TextEdit};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 8use ra_syntax::{SyntaxKind, TextRange, TextUnit};
@@ -218,6 +218,17 @@ impl<'a> TryConvWith for &'a TextDocumentPositionParams {
218 } 218 }
219} 219}
220 220
221impl<'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
221impl<T: TryConvWith> TryConvWith for Vec<T> { 232impl<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};
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition, Severity}; 11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity};
12use ra_syntax::{TextUnit, text_utils::intersect}; 12use ra_syntax::{TextUnit, text_utils::intersect};
13use ra_text_edit::text_utils::contains_offset_nonstrict; 13use ra_text_edit::text_utils::contains_offset_nonstrict;
14use rustc_hash::FxHashMap; 14use 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 = (&params.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
83pub fn handle_on_enter( 78pub 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> {
1838impl<'a> ast::LoopBodyOwner<'a> for LoopExpr<'a> {} 1838impl<'a> ast::LoopBodyOwner<'a> for LoopExpr<'a> {}
1839impl<'a> LoopExpr<'a> {} 1839impl<'a> LoopExpr<'a> {}
1840 1840
1841// MacroCall
1842#[derive(Debug, Clone, Copy,)]
1843pub struct MacroCallNode<R: TreeRoot<RaTypes> = OwnedRoot> {
1844 pub(crate) syntax: SyntaxNode<R>,
1845}
1846pub type MacroCall<'a> = MacroCallNode<RefRoot<'a>>;
1847
1848impl<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}
1851impl<R: TreeRoot<RaTypes>> Eq for MacroCallNode<R> {}
1852impl<R: TreeRoot<RaTypes>> Hash for MacroCallNode<R> {
1853 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
1854}
1855
1856impl<'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
1866impl<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
1876impl<'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,)]
1843pub struct MatchArmNode<R: TreeRoot<RaTypes> = OwnedRoot> { 1888pub 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": (