diff options
Diffstat (limited to 'crates')
49 files changed, 1019 insertions, 1220 deletions
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs index e91b5eb8d..0c4cf2615 100644 --- a/crates/ra_assists/src/add_derive.rs +++ b/crates/ra_assists/src/add_derive.rs | |||
@@ -33,8 +33,10 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
33 | 33 | ||
34 | // Insert `derive` after doc comments. | 34 | // Insert `derive` after doc comments. |
35 | fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { | 35 | fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { |
36 | let non_ws_child = | 36 | let non_ws_child = nominal |
37 | nominal.syntax().children().find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; | 37 | .syntax() |
38 | .children_with_tokens() | ||
39 | .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; | ||
38 | Some(non_ws_child.range().start()) | 40 | Some(non_ws_child.range().start()) |
39 | } | 41 | } |
40 | 42 | ||
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs index b292f188d..fa1c85890 100644 --- a/crates/ra_assists/src/add_impl.rs +++ b/crates/ra_assists/src/add_impl.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, | 4 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, |
5 | TextUnit, | 5 | TextUnit, |
6 | }; | 6 | }; |
7 | 7 | ||
@@ -22,8 +22,10 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
22 | buf.push_str(" "); | 22 | buf.push_str(" "); |
23 | buf.push_str(name.text().as_str()); | 23 | buf.push_str(name.text().as_str()); |
24 | if let Some(type_params) = type_params { | 24 | if let Some(type_params) = type_params { |
25 | let lifetime_params = | 25 | let lifetime_params = type_params |
26 | type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); | 26 | .lifetime_params() |
27 | .filter_map(|it| it.lifetime_token()) | ||
28 | .map(|it| it.text()); | ||
27 | let type_params = | 29 | let type_params = |
28 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); | 30 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); |
29 | join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); | 31 | join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); |
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs index e13f54c4f..5b01e898e 100644 --- a/crates/ra_assists/src/add_missing_impl_members.rs +++ b/crates/ra_assists/src/add_missing_impl_members.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::fmt::Write; | ||
2 | |||
1 | use crate::{Assist, AssistId, AssistCtx}; | 3 | use crate::{Assist, AssistId, AssistCtx}; |
2 | 4 | ||
3 | use hir::Resolver; | 5 | use hir::Resolver; |
@@ -91,8 +93,9 @@ fn add_missing_impl_members_inner( | |||
91 | }; | 93 | }; |
92 | 94 | ||
93 | let changed_range = { | 95 | let changed_range = { |
94 | let children = impl_item_list.syntax().children(); | 96 | let children = impl_item_list.syntax().children_with_tokens(); |
95 | let last_whitespace = children.filter_map(ast::Whitespace::cast).last(); | 97 | let last_whitespace = |
98 | children.filter_map(|it| ast::Whitespace::cast(it.as_token()?)).last(); | ||
96 | 99 | ||
97 | last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| { | 100 | last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| { |
98 | let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}"); | 101 | let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}"); |
@@ -134,13 +137,13 @@ fn resolve_target_trait_def( | |||
134 | fn build_func_body(def: &ast::FnDef) -> String { | 137 | fn build_func_body(def: &ast::FnDef) -> String { |
135 | let mut buf = String::new(); | 138 | let mut buf = String::new(); |
136 | 139 | ||
137 | for child in def.syntax().children() { | 140 | for child in def.syntax().children_with_tokens() { |
138 | match (child.prev_sibling().map(|c| c.kind()), child.kind()) { | 141 | match (child.prev_sibling_or_token().map(|c| c.kind()), child.kind()) { |
139 | (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"), | 142 | (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"), |
140 | (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {} | 143 | (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {} |
141 | (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE) | 144 | (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE) |
142 | | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {} | 145 | | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {} |
143 | _ => child.text().push_to(&mut buf), | 146 | _ => write!(buf, "{}", child).unwrap(), |
144 | }; | 147 | }; |
145 | } | 148 | } |
146 | 149 | ||
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 4ad21c74b..bb5742bd9 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -2,8 +2,8 @@ use hir::db::HirDatabase; | |||
2 | use ra_text_edit::TextEditBuilder; | 2 | use ra_text_edit::TextEditBuilder; |
3 | use ra_db::FileRange; | 3 | use ra_db::FileRange; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, | 5 | SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, SyntaxElement, SyntaxToken, |
6 | algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, | 6 | algo::{find_token_at_offset, find_node_at_offset, find_covering_element, TokenAtOffset}, |
7 | }; | 7 | }; |
8 | use ra_fmt::{leading_indent, reindent}; | 8 | use ra_fmt::{leading_indent, reindent}; |
9 | 9 | ||
@@ -104,15 +104,15 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
104 | Some(self.assist) | 104 | Some(self.assist) |
105 | } | 105 | } |
106 | 106 | ||
107 | pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> { | 107 | pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken<'a>> { |
108 | find_leaf_at_offset(self.source_file.syntax(), self.frange.range.start()) | 108 | find_token_at_offset(self.source_file.syntax(), self.frange.range.start()) |
109 | } | 109 | } |
110 | 110 | ||
111 | pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> { | 111 | pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> { |
112 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) | 112 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) |
113 | } | 113 | } |
114 | pub(crate) fn covering_node(&self) -> &'a SyntaxNode { | 114 | pub(crate) fn covering_element(&self) -> SyntaxElement<'a> { |
115 | find_covering_node(self.source_file.syntax(), self.frange.range) | 115 | find_covering_element(self.source_file.syntax(), self.frange.range) |
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 685dbed06..3fdf6b0d9 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs | |||
@@ -21,7 +21,7 @@ fn collect_path_segments_raw<'a>( | |||
21 | ) -> Option<usize> { | 21 | ) -> Option<usize> { |
22 | let oldlen = segments.len(); | 22 | let oldlen = segments.len(); |
23 | loop { | 23 | loop { |
24 | let mut children = path.syntax().children(); | 24 | let mut children = path.syntax().children_with_tokens(); |
25 | let (first, second, third) = ( | 25 | let (first, second, third) = ( |
26 | children.next().map(|n| (n, n.kind())), | 26 | children.next().map(|n| (n, n.kind())), |
27 | children.next().map(|n| (n, n.kind())), | 27 | children.next().map(|n| (n, n.kind())), |
@@ -29,11 +29,11 @@ fn collect_path_segments_raw<'a>( | |||
29 | ); | 29 | ); |
30 | match (first, second, third) { | 30 | match (first, second, third) { |
31 | (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => { | 31 | (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => { |
32 | path = ast::Path::cast(subpath)?; | 32 | path = ast::Path::cast(subpath.as_node()?)?; |
33 | segments.push(ast::PathSegment::cast(segment)?); | 33 | segments.push(ast::PathSegment::cast(segment.as_node()?)?); |
34 | } | 34 | } |
35 | (Some((segment, PATH_SEGMENT)), _, _) => { | 35 | (Some((segment, PATH_SEGMENT)), _, _) => { |
36 | segments.push(ast::PathSegment::cast(segment)?); | 36 | segments.push(ast::PathSegment::cast(segment.as_node()?)?); |
37 | break; | 37 | break; |
38 | } | 38 | } |
39 | (_, _, _) => return None, | 39 | (_, _, _) => return None, |
@@ -514,8 +514,7 @@ fn apply_auto_import<'a>( | |||
514 | } | 514 | } |
515 | 515 | ||
516 | pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 516 | pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
517 | let node = ctx.covering_node(); | 517 | let path: &ast::Path = ctx.node_at_offset()?; |
518 | let path = node.ancestors().find_map(ast::Path::cast)?; | ||
519 | // We don't want to mess with use statements | 518 | // We don't want to mess with use statements |
520 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { | 519 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { |
521 | return None; | 520 | return None; |
@@ -537,7 +536,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
537 | ); | 536 | ); |
538 | } | 537 | } |
539 | } else { | 538 | } else { |
540 | let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; | 539 | let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; |
541 | ctx.add_action( | 540 | ctx.add_action( |
542 | AssistId("auto_import"), | 541 | AssistId("auto_import"), |
543 | format!("import {} in the current file", fmt_segments(&segments)), | 542 | format!("import {} in the current file", fmt_segments(&segments)), |
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs index 50c1be5ae..c63470726 100644 --- a/crates/ra_assists/src/change_visibility.rs +++ b/crates/ra_assists/src/change_visibility.rs | |||
@@ -15,13 +15,13 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
15 | } | 15 | } |
16 | 16 | ||
17 | fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 17 | fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
18 | let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() { | 18 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { |
19 | FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, | 19 | FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, |
20 | _ => false, | 20 | _ => false, |
21 | }); | 21 | }); |
22 | 22 | ||
23 | let (offset, target) = if let Some(keyword) = item_keyword { | 23 | let (offset, target) = if let Some(keyword) = item_keyword { |
24 | let parent = keyword.parent()?; | 24 | let parent = keyword.parent(); |
25 | let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; | 25 | let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; |
26 | // Parent is not a definition, can't add visibility | 26 | // Parent is not a definition, can't add visibility |
27 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { | 27 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { |
@@ -33,8 +33,8 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
33 | } | 33 | } |
34 | (vis_offset(parent), keyword.range()) | 34 | (vis_offset(parent), keyword.range()) |
35 | } else { | 35 | } else { |
36 | let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; | 36 | let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?; |
37 | let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; | 37 | let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?; |
38 | if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { | 38 | if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { |
39 | return None; | 39 | return None; |
40 | } | 40 | } |
@@ -51,7 +51,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
51 | } | 51 | } |
52 | 52 | ||
53 | fn vis_offset(node: &SyntaxNode) -> TextUnit { | 53 | fn vis_offset(node: &SyntaxNode) -> TextUnit { |
54 | node.children() | 54 | node.children_with_tokens() |
55 | .skip_while(|it| match it.kind() { | 55 | .skip_while(|it| match it.kind() { |
56 | WHITESPACE | COMMENT | ATTR => true, | 56 | WHITESPACE | COMMENT | ATTR => true, |
57 | _ => false, | 57 | _ => false, |
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs index ec377642e..02d27f66d 100644 --- a/crates/ra_assists/src/flip_binexpr.rs +++ b/crates/ra_assists/src/flip_binexpr.rs | |||
@@ -8,7 +8,7 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis | |||
8 | let expr = ctx.node_at_offset::<BinExpr>()?; | 8 | let expr = ctx.node_at_offset::<BinExpr>()?; |
9 | let lhs = expr.lhs()?.syntax(); | 9 | let lhs = expr.lhs()?.syntax(); |
10 | let rhs = expr.rhs()?.syntax(); | 10 | let rhs = expr.rhs()?.syntax(); |
11 | let op_range = expr.op()?.range(); | 11 | let op_range = expr.op_token()?.range(); |
12 | // The assist should be applied only if the cursor is on the operator | 12 | // The assist should be applied only if the cursor is on the operator |
13 | let cursor_in_range = ctx.frange.range.is_subrange(&op_range); | 13 | let cursor_in_range = ctx.frange.range.is_subrange(&op_range); |
14 | if !cursor_in_range { | 14 | if !cursor_in_range { |
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs index 6b98cac68..a9b108111 100644 --- a/crates/ra_assists/src/flip_comma.rs +++ b/crates/ra_assists/src/flip_comma.rs | |||
@@ -8,13 +8,13 @@ use ra_syntax::{ | |||
8 | use crate::{AssistCtx, Assist, AssistId}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; | 11 | let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == COMMA)?; |
12 | let prev = non_trivia_sibling(comma, Direction::Prev)?; | 12 | let prev = non_trivia_sibling(comma.into(), Direction::Prev)?; |
13 | let next = non_trivia_sibling(comma, Direction::Next)?; | 13 | let next = non_trivia_sibling(comma.into(), Direction::Next)?; |
14 | ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { | 14 | ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { |
15 | edit.target(comma.range()); | 15 | edit.target(comma.range()); |
16 | edit.replace(prev.range(), next.text()); | 16 | edit.replace(prev.range(), next.to_string()); |
17 | edit.replace(next.range(), prev.text()); | 17 | edit.replace(next.range(), prev.to_string()); |
18 | }); | 18 | }); |
19 | 19 | ||
20 | ctx.build() | 20 | ctx.build() |
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs index bd3cdb970..2258ca139 100644 --- a/crates/ra_assists/src/inline_local_variable.rs +++ b/crates/ra_assists/src/inline_local_variable.rs | |||
@@ -46,8 +46,10 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
46 | | ExprKind::BlockExpr(_) => false, | 46 | | ExprKind::BlockExpr(_) => false, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | let delete_range = if let Some(whitespace) = | 49 | let delete_range = if let Some(whitespace) = let_stmt |
50 | let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast) | 50 | .syntax() |
51 | .next_sibling_or_token() | ||
52 | .and_then(|it| ast::Whitespace::cast(it.as_token()?)) | ||
51 | { | 53 | { |
52 | TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) | 54 | TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) |
53 | } else { | 55 | } else { |
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs index 353bc4105..fb7333c8c 100644 --- a/crates/ra_assists/src/introduce_variable.rs +++ b/crates/ra_assists/src/introduce_variable.rs | |||
@@ -2,9 +2,8 @@ use test_utils::tested_by; | |||
2 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, AstNode}, | 4 | ast::{self, AstNode}, |
5 | SyntaxKind::{ | 5 | SyntaxNode, TextUnit, |
6 | WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT | 6 | SyntaxKind::{WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT}, |
7 | }, SyntaxNode, TextUnit, | ||
8 | }; | 7 | }; |
9 | 8 | ||
10 | use crate::{AssistCtx, Assist, AssistId}; | 9 | use crate::{AssistCtx, Assist, AssistId}; |
@@ -13,14 +12,14 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
13 | if ctx.frange.range.is_empty() { | 12 | if ctx.frange.range.is_empty() { |
14 | return None; | 13 | return None; |
15 | } | 14 | } |
16 | let node = ctx.covering_node(); | 15 | let node = ctx.covering_element(); |
17 | if node.kind() == COMMENT { | 16 | if node.kind() == COMMENT { |
18 | tested_by!(introduce_var_in_comment_is_not_applicable); | 17 | tested_by!(introduce_var_in_comment_is_not_applicable); |
19 | return None; | 18 | return None; |
20 | } | 19 | } |
21 | let expr = node.ancestors().find_map(valid_target_expr)?; | 20 | let expr = node.ancestors().find_map(valid_target_expr)?; |
22 | let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; | 21 | let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; |
23 | let indent = anchor_stmt.prev_sibling()?; | 22 | let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?; |
24 | if indent.kind() != WHITESPACE { | 23 | if indent.kind() != WHITESPACE { |
25 | return None; | 24 | return None; |
26 | } | 25 | } |
@@ -54,16 +53,15 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
54 | // We want to maintain the indent level, | 53 | // We want to maintain the indent level, |
55 | // but we do not want to duplicate possible | 54 | // but we do not want to duplicate possible |
56 | // extra newlines in the indent block | 55 | // extra newlines in the indent block |
57 | for chunk in indent.text().chunks() { | 56 | let text = indent.text(); |
58 | if chunk.starts_with("\r\n") { | 57 | if text.starts_with("\r\n") { |
59 | buf.push_str("\r\n"); | 58 | buf.push_str("\r\n"); |
60 | buf.push_str(chunk.trim_start_matches("\r\n")); | 59 | buf.push_str(text.trim_start_matches("\r\n")); |
61 | } else if chunk.starts_with("\n") { | 60 | } else if text.starts_with("\n") { |
62 | buf.push_str("\n"); | 61 | buf.push_str("\n"); |
63 | buf.push_str(chunk.trim_start_matches("\n")); | 62 | buf.push_str(text.trim_start_matches("\n")); |
64 | } else { | 63 | } else { |
65 | buf.push_str(chunk); | 64 | buf.push_str(text); |
66 | } | ||
67 | } | 65 | } |
68 | 66 | ||
69 | edit.target(expr.syntax().range()); | 67 | edit.target(expr.syntax().range()); |
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs index 6ea48d909..ae9958f11 100644 --- a/crates/ra_assists/src/remove_dbg.rs +++ b/crates/ra_assists/src/remove_dbg.rs | |||
@@ -62,15 +62,15 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b | |||
62 | let name_ref = path.segment()?.name_ref()?; | 62 | let name_ref = path.segment()?.name_ref()?; |
63 | 63 | ||
64 | // Make sure it is actually a dbg-macro call, dbg followed by ! | 64 | // Make sure it is actually a dbg-macro call, dbg followed by ! |
65 | let excl = path.syntax().next_sibling()?; | 65 | let excl = path.syntax().next_sibling_or_token()?; |
66 | 66 | ||
67 | if name_ref.text() != macro_name || excl.kind() != EXCL { | 67 | if name_ref.text() != macro_name || excl.kind() != EXCL { |
68 | return None; | 68 | return None; |
69 | } | 69 | } |
70 | 70 | ||
71 | let node = macro_call.token_tree()?.syntax(); | 71 | let node = macro_call.token_tree()?.syntax(); |
72 | let first_child = node.first_child()?; | 72 | let first_child = node.first_child_or_token()?; |
73 | let last_child = node.last_child()?; | 73 | let last_child = node.last_child_or_token()?; |
74 | 74 | ||
75 | match (first_child.kind(), last_child.kind()) { | 75 | match (first_child.kind(), last_child.kind()) { |
76 | (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), | 76 | (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), |
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs index dd5be4e91..4bf1852db 100644 --- a/crates/ra_assists/src/split_import.rs +++ b/crates/ra_assists/src/split_import.rs | |||
@@ -8,8 +8,8 @@ use ra_syntax::{ | |||
8 | use crate::{AssistCtx, Assist, AssistId}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; | 11 | let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; |
12 | let path = colon_colon.parent().and_then(ast::Path::cast)?; | 12 | let path = ast::Path::cast(colon_colon.parent())?; |
13 | let top_path = generate(Some(path), |it| it.parent_path()).last()?; | 13 | let top_path = generate(Some(path), |it| it.parent_path()).last()?; |
14 | 14 | ||
15 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); | 15 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); |
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index ee410c548..4516ed660 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::collections::HashSet; | 1 | use std::{collections::HashSet, time::Instant}; |
2 | 2 | ||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_batch::BatchDatabase; | 4 | use ra_batch::BatchDatabase; |
@@ -8,8 +8,10 @@ use ra_syntax::AstNode; | |||
8 | use crate::Result; | 8 | use crate::Result; |
9 | 9 | ||
10 | pub fn run(verbose: bool) -> Result<()> { | 10 | pub fn run(verbose: bool) -> Result<()> { |
11 | let db_load_time = Instant::now(); | ||
11 | let (db, roots) = BatchDatabase::load_cargo(".")?; | 12 | let (db, roots) = BatchDatabase::load_cargo(".")?; |
12 | println!("Database loaded, {} roots", roots.len()); | 13 | println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed()); |
14 | let analysis_time = Instant::now(); | ||
13 | let mut num_crates = 0; | 15 | let mut num_crates = 0; |
14 | let mut visited_modules = HashSet::new(); | 16 | let mut visited_modules = HashSet::new(); |
15 | let mut visit_queue = Vec::new(); | 17 | let mut visit_queue = Vec::new(); |
@@ -96,5 +98,6 @@ pub fn run(verbose: bool) -> Result<()> { | |||
96 | num_exprs_partially_unknown, | 98 | num_exprs_partially_unknown, |
97 | (num_exprs_partially_unknown * 100 / num_exprs) | 99 | (num_exprs_partially_unknown * 100 / num_exprs) |
98 | ); | 100 | ); |
101 | println!("Analysis: {:?}", analysis_time.elapsed()); | ||
99 | Ok(()) | 102 | Ok(()) |
100 | } | 103 | } |
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 11f5541eb..1f2750d89 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -3,10 +3,8 @@ mod analysis_stats; | |||
3 | use std::{fs, io::Read, path::Path, time::Instant}; | 3 | use std::{fs, io::Read, path::Path, time::Instant}; |
4 | 4 | ||
5 | use clap::{App, Arg, SubCommand}; | 5 | use clap::{App, Arg, SubCommand}; |
6 | use join_to_string::join; | ||
7 | use ra_ide_api::{Analysis, FileRange}; | ||
8 | use ra_ide_api::file_structure; | 6 | use ra_ide_api::file_structure; |
9 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; | 7 | use ra_syntax::{SourceFile, TreeArc, AstNode}; |
10 | use tools::collect_tests; | 8 | use tools::collect_tests; |
11 | use flexi_logger::Logger; | 9 | use flexi_logger::Logger; |
12 | 10 | ||
@@ -24,11 +22,6 @@ fn main() -> Result<()> { | |||
24 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) | 22 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) |
25 | .subcommand(SubCommand::with_name("symbols")) | 23 | .subcommand(SubCommand::with_name("symbols")) |
26 | .subcommand( | 24 | .subcommand( |
27 | SubCommand::with_name("extend-selection") | ||
28 | .arg(Arg::with_name("start")) | ||
29 | .arg(Arg::with_name("end")), | ||
30 | ) | ||
31 | .subcommand( | ||
32 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), | 25 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), |
33 | ) | 26 | ) |
34 | .get_matches(); | 27 | .get_matches(); |
@@ -57,13 +50,6 @@ fn main() -> Result<()> { | |||
57 | let (test, tree) = render_test(file, line)?; | 50 | let (test, tree) = render_test(file, line)?; |
58 | println!("{}\n{}", test, tree); | 51 | println!("{}\n{}", test, tree); |
59 | } | 52 | } |
60 | ("extend-selection", Some(matches)) => { | ||
61 | let start: u32 = matches.value_of("start").unwrap().parse()?; | ||
62 | let end: u32 = matches.value_of("end").unwrap().parse()?; | ||
63 | let text = read_stdin()?; | ||
64 | let sels = selections(text, start, end); | ||
65 | println!("{}", sels) | ||
66 | } | ||
67 | ("analysis-stats", Some(matches)) => { | 53 | ("analysis-stats", Some(matches)) => { |
68 | let verbose = matches.is_present("verbose"); | 54 | let verbose = matches.is_present("verbose"); |
69 | analysis_stats::run(verbose)?; | 55 | analysis_stats::run(verbose)?; |
@@ -98,22 +84,3 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> { | |||
98 | let tree = file.syntax().debug_dump(); | 84 | let tree = file.syntax().debug_dump(); |
99 | Ok((test.text, tree)) | 85 | Ok((test.text, tree)) |
100 | } | 86 | } |
101 | |||
102 | fn selections(text: String, start: u32, end: u32) -> String { | ||
103 | let (analysis, file_id) = Analysis::from_single_file(text); | ||
104 | let mut ranges = Vec::new(); | ||
105 | let mut range = TextRange::from_to((start - 1).into(), (end - 1).into()); | ||
106 | loop { | ||
107 | ranges.push(range); | ||
108 | let next = analysis.extend_selection(FileRange { file_id, range }).unwrap(); | ||
109 | if range == next { | ||
110 | break; | ||
111 | } | ||
112 | range = next; | ||
113 | } | ||
114 | let ranges = ranges | ||
115 | .iter() | ||
116 | .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end()))) | ||
117 | .map(|(s, e)| format!("({} {})", s, e)); | ||
118 | join(ranges).separator(" ").surround_with("(", ")").to_string() | ||
119 | } | ||
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index 62e6fb9c1..ea90dc2b8 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs | |||
@@ -3,8 +3,8 @@ | |||
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | AstNode, | 5 | AstNode, |
6 | SyntaxNode, SyntaxKind::*, | 6 | SyntaxNode, SyntaxKind::*, SyntaxToken, SyntaxKind, |
7 | ast::{self, AstToken}, | 7 | ast, |
8 | algo::generate, | 8 | algo::generate, |
9 | }; | 9 | }; |
10 | 10 | ||
@@ -15,26 +15,22 @@ pub fn reindent(text: &str, indent: &str) -> String { | |||
15 | 15 | ||
16 | /// If the node is on the beginning of the line, calculate indent. | 16 | /// If the node is on the beginning of the line, calculate indent. |
17 | pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { | 17 | pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { |
18 | for leaf in prev_leaves(node) { | 18 | for token in prev_tokens(node.first_token()?) { |
19 | if let Some(ws) = ast::Whitespace::cast(leaf) { | 19 | if let Some(ws) = ast::Whitespace::cast(token) { |
20 | let ws_text = ws.text(); | 20 | let ws_text = ws.text(); |
21 | if let Some(pos) = ws_text.rfind('\n') { | 21 | if let Some(pos) = ws_text.rfind('\n') { |
22 | return Some(&ws_text[pos + 1..]); | 22 | return Some(&ws_text[pos + 1..]); |
23 | } | 23 | } |
24 | } | 24 | } |
25 | if leaf.leaf_text().unwrap().contains('\n') { | 25 | if token.text().contains('\n') { |
26 | break; | 26 | break; |
27 | } | 27 | } |
28 | } | 28 | } |
29 | None | 29 | None |
30 | } | 30 | } |
31 | 31 | ||
32 | fn prev_leaves(node: &SyntaxNode) -> impl Iterator<Item = &SyntaxNode> { | 32 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { |
33 | generate(prev_leaf(node), |&node| prev_leaf(node)) | 33 | generate(token.prev_token(), |&token| token.prev_token()) |
34 | } | ||
35 | |||
36 | fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> { | ||
37 | generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| it.last_child()).last() | ||
38 | } | 34 | } |
39 | 35 | ||
40 | pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { | 36 | pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { |
@@ -52,20 +48,20 @@ pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { | |||
52 | Some(expr) | 48 | Some(expr) |
53 | } | 49 | } |
54 | 50 | ||
55 | pub fn compute_ws(left: &SyntaxNode, right: &SyntaxNode) -> &'static str { | 51 | pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { |
56 | match left.kind() { | 52 | match left { |
57 | L_PAREN | L_BRACK => return "", | 53 | L_PAREN | L_BRACK => return "", |
58 | L_CURLY => { | 54 | L_CURLY => { |
59 | if let USE_TREE = right.kind() { | 55 | if let USE_TREE = right { |
60 | return ""; | 56 | return ""; |
61 | } | 57 | } |
62 | } | 58 | } |
63 | _ => (), | 59 | _ => (), |
64 | } | 60 | } |
65 | match right.kind() { | 61 | match right { |
66 | R_PAREN | R_BRACK => return "", | 62 | R_PAREN | R_BRACK => return "", |
67 | R_CURLY => { | 63 | R_CURLY => { |
68 | if let USE_TREE = left.kind() { | 64 | if let USE_TREE = left { |
69 | return ""; | 65 | return ""; |
70 | } | 66 | } |
71 | } | 67 | } |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index a85422955..2ff4139f9 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -726,13 +726,7 @@ impl ExprCollector { | |||
726 | self.alloc_expr(Expr::Array { exprs }, syntax_ptr) | 726 | self.alloc_expr(Expr::Array { exprs }, syntax_ptr) |
727 | } | 727 | } |
728 | ast::ExprKind::Literal(e) => { | 728 | ast::ExprKind::Literal(e) => { |
729 | let child = if let Some(child) = e.literal_expr() { | 729 | let lit = match e.flavor() { |
730 | child | ||
731 | } else { | ||
732 | return self.alloc_expr(Expr::Missing, syntax_ptr); | ||
733 | }; | ||
734 | |||
735 | let lit = match child.flavor() { | ||
736 | LiteralFlavor::IntNumber { suffix } => { | 730 | LiteralFlavor::IntNumber { suffix } => { |
737 | let known_name = suffix | 731 | let known_name = suffix |
738 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); | 732 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); |
@@ -874,9 +868,7 @@ impl ExprCollector { | |||
874 | fn collect_fn_body(&mut self, node: &ast::FnDef) { | 868 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
875 | if let Some(param_list) = node.param_list() { | 869 | if let Some(param_list) = node.param_list() { |
876 | if let Some(self_param) = param_list.self_param() { | 870 | if let Some(self_param) = param_list.self_param() { |
877 | let self_param = SyntaxNodePtr::new( | 871 | let self_param = SyntaxNodePtr::new(self_param.syntax()); |
878 | self_param.self_kw().expect("self param without self keyword").syntax(), | ||
879 | ); | ||
880 | let param_pat = self.alloc_pat( | 872 | let param_pat = self.alloc_pat( |
881 | Pat::Bind { | 873 | Pat::Bind { |
882 | name: Name::self_param(), | 874 | name: Name::self_param(), |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 9dae4c3d1..54dc27399 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -9,7 +9,7 @@ use ra_db::{FileId, FilePosition}; | |||
9 | use ra_syntax::{ | 9 | use ra_syntax::{ |
10 | SyntaxNode, | 10 | SyntaxNode, |
11 | ast::{self, AstNode, NameOwner}, | 11 | ast::{self, AstNode, NameOwner}, |
12 | algo::{find_node_at_offset, find_leaf_at_offset}, | 12 | algo::{find_node_at_offset, find_token_at_offset}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
@@ -155,9 +155,9 @@ pub fn trait_from_module( | |||
155 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { | 155 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { |
156 | let file_id = position.file_id; | 156 | let file_id = position.file_id; |
157 | let file = db.parse(file_id); | 157 | let file = db.parse(file_id); |
158 | find_leaf_at_offset(file.syntax(), position.offset) | 158 | find_token_at_offset(file.syntax(), position.offset) |
159 | .find_map(|node| { | 159 | .find_map(|token| { |
160 | node.ancestors().find_map(|node| { | 160 | token.parent().ancestors().find_map(|node| { |
161 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | 161 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { |
162 | if let Some(func) = function_from_child_node(db, file_id, node) { | 162 | if let Some(func) = function_from_child_node(db, file_id, node) { |
163 | let scopes = func.scopes(db); | 163 | let scopes = func.scopes(db); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 655f3c522..943c5499b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2251,14 +2251,12 @@ fn infer(content: &str) -> String { | |||
2251 | types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); | 2251 | types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); |
2252 | for (syntax_ptr, ty) in &types { | 2252 | for (syntax_ptr, ty) in &types { |
2253 | let node = syntax_ptr.to_node(&source_file); | 2253 | let node = syntax_ptr.to_node(&source_file); |
2254 | write!( | 2254 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node) { |
2255 | acc, | 2255 | (self_param.self_kw_token().range(), "self".to_string()) |
2256 | "{} '{}': {}\n", | 2256 | } else { |
2257 | syntax_ptr.range(), | 2257 | (syntax_ptr.range(), node.text().to_string().replace("\n", " ")) |
2258 | ellipsize(node.text().to_string().replace("\n", " "), 15), | 2258 | }; |
2259 | ty.display(&db) | 2259 | write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); |
2260 | ) | ||
2261 | .unwrap(); | ||
2262 | } | 2260 | } |
2263 | } | 2261 | } |
2264 | acc.truncate(acc.trim_end().len()); | 2262 | acc.truncate(acc.trim_end().len()); |
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs index 639942f7b..a846a7a3c 100644 --- a/crates/ra_ide_api/src/completion.rs +++ b/crates/ra_ide_api/src/completion.rs | |||
@@ -13,7 +13,7 @@ mod complete_scope; | |||
13 | mod complete_postfix; | 13 | mod complete_postfix; |
14 | 14 | ||
15 | use ra_db::SourceDatabase; | 15 | use ra_db::SourceDatabase; |
16 | use ra_syntax::ast::{self, AstNode}; | 16 | use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | db, | 19 | db, |
@@ -76,11 +76,10 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> { | |||
76 | let body_range = body.syntax().range(); | 76 | let body_range = body.syntax().range(); |
77 | let label: String = node | 77 | let label: String = node |
78 | .syntax() | 78 | .syntax() |
79 | .children() | 79 | .children_with_tokens() |
80 | .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body | 80 | .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body |
81 | .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments | 81 | .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) // Filter out comments and attrs |
82 | .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes | 82 | .map(|node| node.to_string()) |
83 | .map(|node| node.text().to_string()) | ||
84 | .collect(); | 83 | .collect(); |
85 | label | 84 | label |
86 | } else { | 85 | } else { |
@@ -93,10 +92,9 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> { | |||
93 | pub fn const_label(node: &ast::ConstDef) -> String { | 92 | pub fn const_label(node: &ast::ConstDef) -> String { |
94 | let label: String = node | 93 | let label: String = node |
95 | .syntax() | 94 | .syntax() |
96 | .children() | 95 | .children_with_tokens() |
97 | .filter(|child| ast::Comment::cast(child).is_none()) | 96 | .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) |
98 | .filter(|child| ast::Attr::cast(child).is_none()) | 97 | .map(|node| node.to_string()) |
99 | .map(|node| node.text().to_string()) | ||
100 | .collect(); | 98 | .collect(); |
101 | 99 | ||
102 | label.trim().to_owned() | 100 | label.trim().to_owned() |
@@ -105,10 +103,9 @@ pub fn const_label(node: &ast::ConstDef) -> String { | |||
105 | pub fn type_label(node: &ast::TypeAliasDef) -> String { | 103 | pub fn type_label(node: &ast::TypeAliasDef) -> String { |
106 | let label: String = node | 104 | let label: String = node |
107 | .syntax() | 105 | .syntax() |
108 | .children() | 106 | .children_with_tokens() |
109 | .filter(|child| ast::Comment::cast(child).is_none()) | 107 | .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) |
110 | .filter(|child| ast::Attr::cast(child).is_none()) | 108 | .map(|node| node.to_string()) |
111 | .map(|node| node.text().to_string()) | ||
112 | .collect(); | 109 | .collect(); |
113 | 110 | ||
114 | label.trim().to_owned() | 111 | label.trim().to_owned() |
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs index ffdc744b2..f87ccdeb9 100644 --- a/crates/ra_ide_api/src/completion/complete_fn_param.rs +++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs | |||
@@ -17,7 +17,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
17 | } | 17 | } |
18 | 18 | ||
19 | let mut params = FxHashMap::default(); | 19 | let mut params = FxHashMap::default(); |
20 | for node in ctx.leaf.ancestors() { | 20 | for node in ctx.token.parent().ancestors() { |
21 | let _ = visitor_ctx(&mut params) | 21 | let _ = visitor_ctx(&mut params) |
22 | .visit::<ast::SourceFile, _>(process) | 22 | .visit::<ast::SourceFile, _>(process) |
23 | .visit::<ast::ItemList, _>(process) | 23 | .visit::<ast::ItemList, _>(process) |
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs index 841c0c554..718b83418 100644 --- a/crates/ra_ide_api/src/completion/complete_keyword.rs +++ b/crates/ra_ide_api/src/completion/complete_keyword.rs | |||
@@ -2,7 +2,7 @@ use ra_syntax::{ | |||
2 | algo::visit::{visitor, Visitor}, | 2 | algo::visit::{visitor, Visitor}, |
3 | AstNode, | 3 | AstNode, |
4 | ast::{self, LoopBodyOwner}, | 4 | ast::{self, LoopBodyOwner}, |
5 | SyntaxKind::*, SyntaxNode, | 5 | SyntaxKind::*, SyntaxToken, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind}; | 8 | use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind}; |
@@ -62,7 +62,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
62 | acc.add(keyword(ctx, "else", "else {$0}")); | 62 | acc.add(keyword(ctx, "else", "else {$0}")); |
63 | acc.add(keyword(ctx, "else if", "else if $0 {}")); | 63 | acc.add(keyword(ctx, "else if", "else if $0 {}")); |
64 | } | 64 | } |
65 | if is_in_loop_body(ctx.leaf) { | 65 | if is_in_loop_body(ctx.token) { |
66 | if ctx.can_be_stmt { | 66 | if ctx.can_be_stmt { |
67 | acc.add(keyword(ctx, "continue", "continue;")); | 67 | acc.add(keyword(ctx, "continue", "continue;")); |
68 | acc.add(keyword(ctx, "break", "break;")); | 68 | acc.add(keyword(ctx, "break", "break;")); |
@@ -74,8 +74,8 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
74 | acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt)); | 74 | acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt)); |
75 | } | 75 | } |
76 | 76 | ||
77 | fn is_in_loop_body(leaf: &SyntaxNode) -> bool { | 77 | fn is_in_loop_body(leaf: SyntaxToken) -> bool { |
78 | for node in leaf.ancestors() { | 78 | for node in leaf.parent().ancestors() { |
79 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { | 79 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { |
80 | break; | 80 | break; |
81 | } | 81 | } |
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 724d0dfbf..65dffa470 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use ra_text_edit::AtomTextEdit; | 1 | use ra_text_edit::AtomTextEdit; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, | 3 | AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, SyntaxToken, |
4 | ast, | 4 | ast, |
5 | algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, | 5 | algo::{find_token_at_offset, find_covering_element, find_node_at_offset}, |
6 | SyntaxKind::*, | 6 | SyntaxKind::*, |
7 | }; | 7 | }; |
8 | use hir::{source_binder, Resolver}; | 8 | use hir::{source_binder, Resolver}; |
@@ -15,7 +15,7 @@ use crate::{db, FilePosition}; | |||
15 | pub(crate) struct CompletionContext<'a> { | 15 | pub(crate) struct CompletionContext<'a> { |
16 | pub(super) db: &'a db::RootDatabase, | 16 | pub(super) db: &'a db::RootDatabase, |
17 | pub(super) offset: TextUnit, | 17 | pub(super) offset: TextUnit, |
18 | pub(super) leaf: &'a SyntaxNode, | 18 | pub(super) token: SyntaxToken<'a>, |
19 | pub(super) resolver: Resolver, | 19 | pub(super) resolver: Resolver, |
20 | pub(super) module: Option<hir::Module>, | 20 | pub(super) module: Option<hir::Module>, |
21 | pub(super) function: Option<hir::Function>, | 21 | pub(super) function: Option<hir::Function>, |
@@ -49,10 +49,10 @@ impl<'a> CompletionContext<'a> { | |||
49 | ) -> Option<CompletionContext<'a>> { | 49 | ) -> Option<CompletionContext<'a>> { |
50 | let resolver = source_binder::resolver_for_position(db, position); | 50 | let resolver = source_binder::resolver_for_position(db, position); |
51 | let module = source_binder::module_from_position(db, position); | 51 | let module = source_binder::module_from_position(db, position); |
52 | let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; | 52 | let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?; |
53 | let mut ctx = CompletionContext { | 53 | let mut ctx = CompletionContext { |
54 | db, | 54 | db, |
55 | leaf, | 55 | token, |
56 | offset: position.offset, | 56 | offset: position.offset, |
57 | resolver, | 57 | resolver, |
58 | module, | 58 | module, |
@@ -76,9 +76,9 @@ impl<'a> CompletionContext<'a> { | |||
76 | 76 | ||
77 | // The range of the identifier that is being completed. | 77 | // The range of the identifier that is being completed. |
78 | pub(crate) fn source_range(&self) -> TextRange { | 78 | pub(crate) fn source_range(&self) -> TextRange { |
79 | match self.leaf.kind() { | 79 | match self.token.kind() { |
80 | // workaroud when completion is triggered by trigger characters. | 80 | // workaroud when completion is triggered by trigger characters. |
81 | IDENT => self.leaf.range(), | 81 | IDENT => self.token.range(), |
82 | _ => TextRange::offset_len(self.offset, 0.into()), | 82 | _ => TextRange::offset_len(self.offset, 0.into()), |
83 | } | 83 | } |
84 | } | 84 | } |
@@ -139,10 +139,11 @@ impl<'a> CompletionContext<'a> { | |||
139 | _ => (), | 139 | _ => (), |
140 | } | 140 | } |
141 | 141 | ||
142 | self.use_item_syntax = self.leaf.ancestors().find_map(ast::UseItem::cast); | 142 | self.use_item_syntax = self.token.parent().ancestors().find_map(ast::UseItem::cast); |
143 | 143 | ||
144 | self.function_syntax = self | 144 | self.function_syntax = self |
145 | .leaf | 145 | .token |
146 | .parent() | ||
146 | .ancestors() | 147 | .ancestors() |
147 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) | 148 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) |
148 | .find_map(ast::FnDef::cast); | 149 | .find_map(ast::FnDef::cast); |
@@ -224,8 +225,7 @@ impl<'a> CompletionContext<'a> { | |||
224 | } | 225 | } |
225 | 226 | ||
226 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> { | 227 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> { |
227 | let node = find_covering_node(syntax, range); | 228 | find_covering_element(syntax, range).ancestors().find_map(N::cast) |
228 | node.ancestors().find_map(N::cast) | ||
229 | } | 229 | } |
230 | 230 | ||
231 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | 231 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { |
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs index 5a78e94d8..2dfaa0045 100644 --- a/crates/ra_ide_api/src/diagnostics.rs +++ b/crates/ra_ide_api/src/diagnostics.rs | |||
@@ -106,8 +106,10 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
106 | single_use_tree: &ast::UseTree, | 106 | single_use_tree: &ast::UseTree, |
107 | ) -> Option<TextEdit> { | 107 | ) -> Option<TextEdit> { |
108 | let use_tree_list_node = single_use_tree.syntax().parent()?; | 108 | let use_tree_list_node = single_use_tree.syntax().parent()?; |
109 | if single_use_tree.path()?.segment()?.syntax().first_child()?.kind() == SyntaxKind::SELF_KW { | 109 | if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() |
110 | let start = use_tree_list_node.prev_sibling()?.range().start(); | 110 | == SyntaxKind::SELF_KW |
111 | { | ||
112 | let start = use_tree_list_node.prev_sibling_or_token()?.range().start(); | ||
111 | let end = use_tree_list_node.range().end(); | 113 | let end = use_tree_list_node.range().end(); |
112 | let range = TextRange::from_to(start, end); | 114 | let range = TextRange::from_to(start, end); |
113 | let mut edit_builder = TextEditBuilder::default(); | 115 | let mut edit_builder = TextEditBuilder::default(); |
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs index 63879a0b5..e743bf0fe 100644 --- a/crates/ra_ide_api/src/extend_selection.rs +++ b/crates/ra_ide_api/src/extend_selection.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | Direction, SyntaxNode, TextRange, TextUnit, AstNode, | 3 | Direction, SyntaxNode, TextRange, TextUnit, AstNode, SyntaxElement, |
4 | algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, | 4 | algo::{find_covering_element, find_token_at_offset, TokenAtOffset}, |
5 | SyntaxKind::*, | 5 | SyntaxKind::*, SyntaxToken, |
6 | ast::Comment, | ||
6 | }; | 7 | }; |
7 | 8 | ||
8 | use crate::{FileRange, db::RootDatabase}; | 9 | use crate::{FileRange, db::RootDatabase}; |
@@ -32,53 +33,58 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange | |||
32 | 33 | ||
33 | if range.is_empty() { | 34 | if range.is_empty() { |
34 | let offset = range.start(); | 35 | let offset = range.start(); |
35 | let mut leaves = find_leaf_at_offset(root, offset); | 36 | let mut leaves = find_token_at_offset(root, offset); |
36 | if leaves.clone().all(|it| it.kind() == WHITESPACE) { | 37 | if leaves.clone().all(|it| it.kind() == WHITESPACE) { |
37 | return Some(extend_ws(root, leaves.next()?, offset)); | 38 | return Some(extend_ws(root, leaves.next()?, offset)); |
38 | } | 39 | } |
39 | let leaf_range = match leaves { | 40 | let leaf_range = match leaves { |
40 | LeafAtOffset::None => return None, | 41 | TokenAtOffset::None => return None, |
41 | LeafAtOffset::Single(l) => { | 42 | TokenAtOffset::Single(l) => { |
42 | if string_kinds.contains(&l.kind()) { | 43 | if string_kinds.contains(&l.kind()) { |
43 | extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range()) | 44 | extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range()) |
44 | } else { | 45 | } else { |
45 | l.range() | 46 | l.range() |
46 | } | 47 | } |
47 | } | 48 | } |
48 | LeafAtOffset::Between(l, r) => pick_best(l, r).range(), | 49 | TokenAtOffset::Between(l, r) => pick_best(l, r).range(), |
49 | }; | 50 | }; |
50 | return Some(leaf_range); | 51 | return Some(leaf_range); |
51 | }; | 52 | }; |
52 | let node = find_covering_node(root, range); | 53 | let node = match find_covering_element(root, range) { |
54 | SyntaxElement::Token(token) => { | ||
55 | if token.range() != range { | ||
56 | return Some(token.range()); | ||
57 | } | ||
58 | if let Some(comment) = Comment::cast(token) { | ||
59 | if let Some(range) = extend_comments(comment) { | ||
60 | return Some(range); | ||
61 | } | ||
62 | } | ||
63 | token.parent() | ||
64 | } | ||
65 | SyntaxElement::Node(node) => node, | ||
66 | }; | ||
67 | if node.range() != range { | ||
68 | return Some(node.range()); | ||
69 | } | ||
53 | 70 | ||
54 | // Using shallowest node with same range allows us to traverse siblings. | 71 | // Using shallowest node with same range allows us to traverse siblings. |
55 | let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap(); | 72 | let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap(); |
56 | 73 | ||
57 | if range == node.range() { | 74 | if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { |
58 | if string_kinds.contains(&node.kind()) { | 75 | if let Some(range) = extend_list_item(node) { |
59 | if let Some(range) = extend_comments(node) { | 76 | return Some(range); |
60 | return Some(range); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { | ||
65 | if let Some(range) = extend_list_item(node) { | ||
66 | return Some(range); | ||
67 | } | ||
68 | } | 77 | } |
69 | } | 78 | } |
70 | 79 | ||
71 | match node.ancestors().skip_while(|n| n.range() == range).next() { | 80 | node.parent().map(|it| it.range()) |
72 | None => None, | ||
73 | Some(parent) => Some(parent.range()), | ||
74 | } | ||
75 | } | 81 | } |
76 | 82 | ||
77 | fn extend_single_word_in_comment_or_string( | 83 | fn extend_single_word_in_comment_or_string( |
78 | leaf: &SyntaxNode, | 84 | leaf: SyntaxToken, |
79 | offset: TextUnit, | 85 | offset: TextUnit, |
80 | ) -> Option<TextRange> { | 86 | ) -> Option<TextRange> { |
81 | let text: &str = leaf.leaf_text()?; | 87 | let text: &str = leaf.text(); |
82 | let cursor_position: u32 = (offset - leaf.range().start()).into(); | 88 | let cursor_position: u32 = (offset - leaf.range().start()).into(); |
83 | 89 | ||
84 | let (before, after) = text.split_at(cursor_position as usize); | 90 | let (before, after) = text.split_at(cursor_position as usize); |
@@ -101,14 +107,14 @@ fn extend_single_word_in_comment_or_string( | |||
101 | } | 107 | } |
102 | } | 108 | } |
103 | 109 | ||
104 | fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange { | 110 | fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange { |
105 | let ws_text = ws.leaf_text().unwrap(); | 111 | let ws_text = ws.text(); |
106 | let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start(); | 112 | let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start(); |
107 | let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start(); | 113 | let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start(); |
108 | let ws_suffix = &ws_text.as_str()[suffix]; | 114 | let ws_suffix = &ws_text.as_str()[suffix]; |
109 | let ws_prefix = &ws_text.as_str()[prefix]; | 115 | let ws_prefix = &ws_text.as_str()[prefix]; |
110 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { | 116 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { |
111 | if let Some(node) = ws.next_sibling() { | 117 | if let Some(node) = ws.next_sibling_or_token() { |
112 | let start = match ws_prefix.rfind('\n') { | 118 | let start = match ws_prefix.rfind('\n') { |
113 | Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), | 119 | Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), |
114 | None => node.range().start(), | 120 | None => node.range().start(), |
@@ -124,9 +130,9 @@ fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange | |||
124 | ws.range() | 130 | ws.range() |
125 | } | 131 | } |
126 | 132 | ||
127 | fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { | 133 | fn pick_best<'a>(l: SyntaxToken<'a>, r: SyntaxToken<'a>) -> SyntaxToken<'a> { |
128 | return if priority(r) > priority(l) { r } else { l }; | 134 | return if priority(r) > priority(l) { r } else { l }; |
129 | fn priority(n: &SyntaxNode) -> usize { | 135 | fn priority(n: SyntaxToken) -> usize { |
130 | match n.kind() { | 136 | match n.kind() { |
131 | WHITESPACE => 0, | 137 | WHITESPACE => 0, |
132 | IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2, | 138 | IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2, |
@@ -137,54 +143,60 @@ fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { | |||
137 | 143 | ||
138 | /// Extend list item selection to include nearby comma and whitespace. | 144 | /// Extend list item selection to include nearby comma and whitespace. |
139 | fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> { | 145 | fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> { |
140 | fn is_single_line_ws(node: &SyntaxNode) -> bool { | 146 | fn is_single_line_ws(node: &SyntaxToken) -> bool { |
141 | node.kind() == WHITESPACE && !node.leaf_text().unwrap().contains('\n') | 147 | node.kind() == WHITESPACE && !node.text().contains('\n') |
142 | } | 148 | } |
143 | 149 | ||
144 | fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<&SyntaxNode> { | 150 | fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<SyntaxToken> { |
145 | node.siblings(dir) | 151 | node.siblings_with_tokens(dir) |
146 | .skip(1) | 152 | .skip(1) |
147 | .skip_while(|node| is_single_line_ws(node)) | 153 | .skip_while(|node| match node { |
154 | SyntaxElement::Node(_) => false, | ||
155 | SyntaxElement::Token(it) => is_single_line_ws(it), | ||
156 | }) | ||
148 | .next() | 157 | .next() |
158 | .and_then(|it| it.as_token()) | ||
149 | .filter(|node| node.kind() == COMMA) | 159 | .filter(|node| node.kind() == COMMA) |
150 | } | 160 | } |
151 | 161 | ||
152 | if let Some(comma_node) = nearby_comma(node, Direction::Prev) { | 162 | if let Some(comma_node) = nearby_comma(node, Direction::Prev) { |
153 | return Some(TextRange::from_to(comma_node.range().start(), node.range().end())); | 163 | return Some(TextRange::from_to(comma_node.range().start(), node.range().end())); |
154 | } | 164 | } |
155 | |||
156 | if let Some(comma_node) = nearby_comma(node, Direction::Next) { | 165 | if let Some(comma_node) = nearby_comma(node, Direction::Next) { |
157 | // Include any following whitespace when comma if after list item. | 166 | // Include any following whitespace when comma if after list item. |
158 | let final_node = comma_node | 167 | let final_node = comma_node |
159 | .siblings(Direction::Next) | 168 | .next_sibling_or_token() |
160 | .skip(1) | 169 | .and_then(|it| it.as_token()) |
161 | .next() | ||
162 | .filter(|node| is_single_line_ws(node)) | 170 | .filter(|node| is_single_line_ws(node)) |
163 | .unwrap_or(comma_node); | 171 | .unwrap_or(comma_node); |
164 | 172 | ||
165 | return Some(TextRange::from_to(node.range().start(), final_node.range().end())); | 173 | return Some(TextRange::from_to(node.range().start(), final_node.range().end())); |
166 | } | 174 | } |
167 | 175 | ||
168 | return None; | 176 | None |
169 | } | 177 | } |
170 | 178 | ||
171 | fn extend_comments(node: &SyntaxNode) -> Option<TextRange> { | 179 | fn extend_comments(comment: Comment) -> Option<TextRange> { |
172 | let prev = adj_comments(node, Direction::Prev); | 180 | let prev = adj_comments(comment, Direction::Prev); |
173 | let next = adj_comments(node, Direction::Next); | 181 | let next = adj_comments(comment, Direction::Next); |
174 | if prev != next { | 182 | if prev != next { |
175 | Some(TextRange::from_to(prev.range().start(), next.range().end())) | 183 | Some(TextRange::from_to(prev.syntax().range().start(), next.syntax().range().end())) |
176 | } else { | 184 | } else { |
177 | None | 185 | None |
178 | } | 186 | } |
179 | } | 187 | } |
180 | 188 | ||
181 | fn adj_comments(node: &SyntaxNode, dir: Direction) -> &SyntaxNode { | 189 | fn adj_comments(comment: Comment, dir: Direction) -> Comment { |
182 | let mut res = node; | 190 | let mut res = comment; |
183 | for node in node.siblings(dir) { | 191 | for element in comment.syntax().siblings_with_tokens(dir) { |
184 | match node.kind() { | 192 | let token = match element.as_token() { |
185 | COMMENT => res = node, | 193 | None => break, |
186 | WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | 194 | Some(token) => token, |
187 | _ => break, | 195 | }; |
196 | if let Some(c) = Comment::cast(token) { | ||
197 | res = c | ||
198 | } else if token.kind() != WHITESPACE || token.text().contains("\n\n") { | ||
199 | break; | ||
188 | } | 200 | } |
189 | } | 201 | } |
190 | res | 202 | res |
@@ -308,23 +320,13 @@ fn bar(){} | |||
308 | /* | 320 | /* |
309 | foo | 321 | foo |
310 | _bar1<|>*/ | 322 | _bar1<|>*/ |
311 | "#, | 323 | "#, |
312 | &["_bar1", "/*\nfoo\n_bar1*/"], | 324 | &["_bar1", "/*\nfoo\n_bar1*/"], |
313 | ); | 325 | ); |
314 | 326 | ||
315 | do_check( | 327 | do_check(r#"//!<|>foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); |
316 | r#" | ||
317 | //!<|>foo_2 bar | ||
318 | "#, | ||
319 | &["foo_2", "//!foo_2 bar"], | ||
320 | ); | ||
321 | 328 | ||
322 | do_check( | 329 | do_check(r#"/<|>/foo bar"#, &["//foo bar"]); |
323 | r#" | ||
324 | /<|>/foo bar | ||
325 | "#, | ||
326 | &["//foo bar"], | ||
327 | ); | ||
328 | } | 330 | } |
329 | 331 | ||
330 | #[test] | 332 | #[test] |
@@ -332,13 +334,13 @@ _bar1<|>*/ | |||
332 | do_check( | 334 | do_check( |
333 | r#" | 335 | r#" |
334 | fn main() { foo<|>+bar;} | 336 | fn main() { foo<|>+bar;} |
335 | "#, | 337 | "#, |
336 | &["foo", "foo+bar"], | 338 | &["foo", "foo+bar"], |
337 | ); | 339 | ); |
338 | do_check( | 340 | do_check( |
339 | r#" | 341 | r#" |
340 | fn main() { foo+<|>bar;} | 342 | fn main() { foo+<|>bar;} |
341 | "#, | 343 | "#, |
342 | &["bar", "foo+bar"], | 344 | &["bar", "foo+bar"], |
343 | ); | 345 | ); |
344 | } | 346 | } |
@@ -355,11 +357,11 @@ fn main() { foo+<|>bar;} | |||
355 | do_check( | 357 | do_check( |
356 | r#" | 358 | r#" |
357 | impl S { | 359 | impl S { |
358 | fn foo() { | 360 | fn foo() { |
359 | // hel<|>lo world | 361 | // hel<|>lo world |
360 | } | ||
361 | } | 362 | } |
362 | "#, | 363 | } |
364 | "#, | ||
363 | &["hello", "// hello world"], | 365 | &["hello", "// hello world"], |
364 | ); | 366 | ); |
365 | } | 367 | } |
@@ -371,7 +373,7 @@ impl S { | |||
371 | fn bar(){} | 373 | fn bar(){} |
372 | 374 | ||
373 | " fn f<|>oo() {" | 375 | " fn f<|>oo() {" |
374 | "#, | 376 | "#, |
375 | &["foo", "\" fn foo() {\""], | 377 | &["foo", "\" fn foo() {\""], |
376 | ); | 378 | ); |
377 | } | 379 | } |
diff --git a/crates/ra_ide_api/src/folding_ranges.rs b/crates/ra_ide_api/src/folding_ranges.rs index b96145f05..a6fe8a5d5 100644 --- a/crates/ra_ide_api/src/folding_ranges.rs +++ b/crates/ra_ide_api/src/folding_ranges.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | AstNode, Direction, SourceFile, SyntaxNode, TextRange, | 4 | AstNode, SourceFile, SyntaxNode, TextRange, Direction, SyntaxElement, |
5 | SyntaxKind::{self, *}, | 5 | SyntaxKind::{self, *}, |
6 | ast::{self, VisibilityOwner}, | 6 | ast::{self, VisibilityOwner, Comment}, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | #[derive(Debug, PartialEq, Eq)] | 9 | #[derive(Debug, PartialEq, Eq)] |
@@ -26,34 +26,49 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
26 | let mut visited_imports = FxHashSet::default(); | 26 | let mut visited_imports = FxHashSet::default(); |
27 | let mut visited_mods = FxHashSet::default(); | 27 | let mut visited_mods = FxHashSet::default(); |
28 | 28 | ||
29 | for node in file.syntax().descendants() { | 29 | for element in file.syntax().descendants_with_tokens() { |
30 | // Fold items that span multiple lines | 30 | // Fold items that span multiple lines |
31 | if let Some(kind) = fold_kind(node.kind()) { | 31 | if let Some(kind) = fold_kind(element.kind()) { |
32 | if node.text().contains('\n') { | 32 | let is_multiline = match element { |
33 | res.push(Fold { range: node.range(), kind }); | 33 | SyntaxElement::Node(node) => node.text().contains('\n'), |
34 | SyntaxElement::Token(token) => token.text().contains('\n'), | ||
35 | }; | ||
36 | if is_multiline { | ||
37 | res.push(Fold { range: element.range(), kind }); | ||
38 | continue; | ||
34 | } | 39 | } |
35 | } | 40 | } |
36 | 41 | ||
37 | // Fold groups of comments | 42 | match element { |
38 | if node.kind() == COMMENT && !visited_comments.contains(&node) { | 43 | SyntaxElement::Token(token) => { |
39 | if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) { | 44 | // Fold groups of comments |
40 | res.push(Fold { range, kind: FoldKind::Comment }) | 45 | if let Some(comment) = ast::Comment::cast(token) { |
46 | if !visited_comments.contains(&comment) { | ||
47 | if let Some(range) = | ||
48 | contiguous_range_for_comment(comment, &mut visited_comments) | ||
49 | { | ||
50 | res.push(Fold { range, kind: FoldKind::Comment }) | ||
51 | } | ||
52 | } | ||
53 | } | ||
41 | } | 54 | } |
42 | } | 55 | SyntaxElement::Node(node) => { |
43 | 56 | // Fold groups of imports | |
44 | // Fold groups of imports | 57 | if node.kind() == USE_ITEM && !visited_imports.contains(&node) { |
45 | if node.kind() == USE_ITEM && !visited_imports.contains(&node) { | 58 | if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) { |
46 | if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) { | 59 | res.push(Fold { range, kind: FoldKind::Imports }) |
47 | res.push(Fold { range, kind: FoldKind::Imports }) | 60 | } |
48 | } | 61 | } |
49 | } | 62 | |
50 | 63 | // Fold groups of mods | |
51 | // Fold groups of mods | 64 | if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) |
52 | if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) { | 65 | { |
53 | if let Some(range) = | 66 | if let Some(range) = |
54 | contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods) | 67 | contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods) |
55 | { | 68 | { |
56 | res.push(Fold { range, kind: FoldKind::Mods }) | 69 | res.push(Fold { range, kind: FoldKind::Mods }) |
70 | } | ||
71 | } | ||
57 | } | 72 | } |
58 | } | 73 | } |
59 | } | 74 | } |
@@ -90,16 +105,21 @@ fn contiguous_range_for_group_unless<'a>( | |||
90 | visited.insert(first); | 105 | visited.insert(first); |
91 | 106 | ||
92 | let mut last = first; | 107 | let mut last = first; |
93 | for node in first.siblings(Direction::Next) { | 108 | for element in first.siblings_with_tokens(Direction::Next) { |
94 | if let Some(ws) = ast::Whitespace::cast(node) { | 109 | let node = match element { |
95 | // There is a blank line, which means that the group ends here | 110 | SyntaxElement::Token(token) => { |
96 | if ws.count_newlines_lazy().take(2).count() == 2 { | 111 | if let Some(ws) = ast::Whitespace::cast(token) { |
112 | if !ws.spans_multiple_lines() { | ||
113 | // Ignore whitespace without blank lines | ||
114 | continue; | ||
115 | } | ||
116 | } | ||
117 | // There is a blank line or another token, which means that the | ||
118 | // group ends here | ||
97 | break; | 119 | break; |
98 | } | 120 | } |
99 | 121 | SyntaxElement::Node(node) => node, | |
100 | // Ignore whitespace without blank lines | 122 | }; |
101 | continue; | ||
102 | } | ||
103 | 123 | ||
104 | // Stop if we find a node that doesn't belong to the group | 124 | // Stop if we find a node that doesn't belong to the group |
105 | if node.kind() != first.kind() || unless(node) { | 125 | if node.kind() != first.kind() || unless(node) { |
@@ -119,40 +139,42 @@ fn contiguous_range_for_group_unless<'a>( | |||
119 | } | 139 | } |
120 | 140 | ||
121 | fn contiguous_range_for_comment<'a>( | 141 | fn contiguous_range_for_comment<'a>( |
122 | first: &'a SyntaxNode, | 142 | first: Comment<'a>, |
123 | visited: &mut FxHashSet<&'a SyntaxNode>, | 143 | visited: &mut FxHashSet<Comment<'a>>, |
124 | ) -> Option<TextRange> { | 144 | ) -> Option<TextRange> { |
125 | visited.insert(first); | 145 | visited.insert(first); |
126 | 146 | ||
127 | // Only fold comments of the same flavor | 147 | // Only fold comments of the same flavor |
128 | let group_flavor = ast::Comment::cast(first)?.flavor(); | 148 | let group_flavor = first.flavor(); |
129 | 149 | ||
130 | let mut last = first; | 150 | let mut last = first; |
131 | for node in first.siblings(Direction::Next) { | 151 | for element in first.syntax().siblings_with_tokens(Direction::Next) { |
132 | if let Some(ws) = ast::Whitespace::cast(node) { | 152 | match element { |
133 | // There is a blank line, which means the group ends here | 153 | SyntaxElement::Token(token) => { |
134 | if ws.count_newlines_lazy().take(2).count() == 2 { | 154 | if let Some(ws) = ast::Whitespace::cast(token) { |
155 | if !ws.spans_multiple_lines() { | ||
156 | // Ignore whitespace without blank lines | ||
157 | continue; | ||
158 | } | ||
159 | } | ||
160 | if let Some(c) = Comment::cast(token) { | ||
161 | if c.flavor() == group_flavor { | ||
162 | visited.insert(c); | ||
163 | last = c; | ||
164 | continue; | ||
165 | } | ||
166 | } | ||
167 | // The comment group ends because either: | ||
168 | // * An element of a different kind was reached | ||
169 | // * A comment of a different flavor was reached | ||
135 | break; | 170 | break; |
136 | } | 171 | } |
137 | 172 | SyntaxElement::Node(_) => break, | |
138 | // Ignore whitespace without blank lines | 173 | }; |
139 | continue; | ||
140 | } | ||
141 | |||
142 | match ast::Comment::cast(node) { | ||
143 | Some(next_comment) if next_comment.flavor() == group_flavor => { | ||
144 | visited.insert(node); | ||
145 | last = node; | ||
146 | } | ||
147 | // The comment group ends because either: | ||
148 | // * An element of a different kind was reached | ||
149 | // * A comment of a different flavor was reached | ||
150 | _ => break, | ||
151 | } | ||
152 | } | 174 | } |
153 | 175 | ||
154 | if first != last { | 176 | if first != last { |
155 | Some(TextRange::from_to(first.range().start(), last.range().end())) | 177 | Some(TextRange::from_to(first.syntax().range().start(), last.syntax().range().end())) |
156 | } else { | 178 | } else { |
157 | // The group consists of only one element, therefore it cannot be folded | 179 | // The group consists of only one element, therefore it cannot be folded |
158 | None | 180 | None |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 3206e68b9..bfa7cd67a 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, | 3 | AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, |
4 | algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, | 4 | algo::{find_covering_element, find_node_at_offset, find_token_at_offset, visit::{visitor, Visitor}}, |
5 | }; | 5 | }; |
6 | use hir::HirDisplay; | 6 | use hir::HirDisplay; |
7 | 7 | ||
@@ -104,8 +104,11 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
104 | } | 104 | } |
105 | 105 | ||
106 | if range.is_none() { | 106 | if range.is_none() { |
107 | let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| { | 107 | let node = find_token_at_offset(file.syntax(), position.offset).find_map(|token| { |
108 | leaf.ancestors().find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) | 108 | token |
109 | .parent() | ||
110 | .ancestors() | ||
111 | .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) | ||
109 | })?; | 112 | })?; |
110 | let frange = FileRange { file_id: position.file_id, range: node.range() }; | 113 | let frange = FileRange { file_id: position.file_id, range: node.range() }; |
111 | res.extend(type_of(db, frange).map(rust_code_markup)); | 114 | res.extend(type_of(db, frange).map(rust_code_markup)); |
@@ -123,13 +126,12 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
123 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { | 126 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { |
124 | let file = db.parse(frange.file_id); | 127 | let file = db.parse(frange.file_id); |
125 | let syntax = file.syntax(); | 128 | let syntax = file.syntax(); |
126 | let leaf_node = find_covering_node(syntax, frange.range); | 129 | let leaf_node = find_covering_element(syntax, frange.range); |
127 | // if we picked identifier, expand to pattern/expression | 130 | // if we picked identifier, expand to pattern/expression |
128 | let node = leaf_node | 131 | let node = leaf_node |
129 | .ancestors() | 132 | .ancestors() |
130 | .take_while(|it| it.range() == leaf_node.range()) | 133 | .take_while(|it| it.range() == leaf_node.range()) |
131 | .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some()) | 134 | .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())?; |
132 | .unwrap_or(leaf_node); | ||
133 | let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?; | 135 | let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?; |
134 | let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?; | 136 | let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?; |
135 | let infer = function.infer(db); | 137 | let infer = function.infer(db); |
diff --git a/crates/ra_ide_api/src/join_lines.rs b/crates/ra_ide_api/src/join_lines.rs index 8fb3eaa06..57b6f8384 100644 --- a/crates/ra_ide_api/src/join_lines.rs +++ b/crates/ra_ide_api/src/join_lines.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use itertools::Itertools; | 1 | use itertools::Itertools; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | SourceFile, TextRange, TextUnit, AstNode, SyntaxNode, | 3 | SourceFile, TextRange, TextUnit, AstNode, SyntaxNode, SyntaxElement, SyntaxToken, |
4 | SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK}, | 4 | SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK}, |
5 | algo::{find_covering_node, non_trivia_sibling}, | 5 | algo::{find_covering_element, non_trivia_sibling}, |
6 | ast, | 6 | ast, |
7 | Direction, | 7 | Direction, |
8 | }; | 8 | }; |
@@ -24,22 +24,22 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | |||
24 | range | 24 | range |
25 | }; | 25 | }; |
26 | 26 | ||
27 | let node = find_covering_node(file.syntax(), range); | 27 | let node = match find_covering_element(file.syntax(), range) { |
28 | SyntaxElement::Node(node) => node, | ||
29 | SyntaxElement::Token(token) => token.parent(), | ||
30 | }; | ||
28 | let mut edit = TextEditBuilder::default(); | 31 | let mut edit = TextEditBuilder::default(); |
29 | for node in node.descendants() { | 32 | for token in node.descendants_with_tokens().filter_map(|it| it.as_token()) { |
30 | let text = match node.leaf_text() { | 33 | let range = match range.intersection(&token.range()) { |
31 | Some(text) => text, | ||
32 | None => continue, | ||
33 | }; | ||
34 | let range = match range.intersection(&node.range()) { | ||
35 | Some(range) => range, | 34 | Some(range) => range, |
36 | None => continue, | 35 | None => continue, |
37 | } - node.range().start(); | 36 | } - token.range().start(); |
37 | let text = token.text(); | ||
38 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { | 38 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { |
39 | let pos: TextUnit = (pos as u32).into(); | 39 | let pos: TextUnit = (pos as u32).into(); |
40 | let off = node.range().start() + range.start() + pos; | 40 | let off = token.range().start() + range.start() + pos; |
41 | if !edit.invalidates_offset(off) { | 41 | if !edit.invalidates_offset(off) { |
42 | remove_newline(&mut edit, node, text.as_str(), off); | 42 | remove_newline(&mut edit, token, off); |
43 | } | 43 | } |
44 | } | 44 | } |
45 | } | 45 | } |
@@ -47,17 +47,12 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | |||
47 | edit.finish() | 47 | edit.finish() |
48 | } | 48 | } |
49 | 49 | ||
50 | fn remove_newline( | 50 | fn remove_newline(edit: &mut TextEditBuilder, token: SyntaxToken, offset: TextUnit) { |
51 | edit: &mut TextEditBuilder, | 51 | if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { |
52 | node: &SyntaxNode, | ||
53 | node_text: &str, | ||
54 | offset: TextUnit, | ||
55 | ) { | ||
56 | if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 { | ||
57 | // The node is either the first or the last in the file | 52 | // The node is either the first or the last in the file |
58 | let suff = &node_text[TextRange::from_to( | 53 | let suff = &token.text()[TextRange::from_to( |
59 | offset - node.range().start() + TextUnit::of_char('\n'), | 54 | offset - token.range().start() + TextUnit::of_char('\n'), |
60 | TextUnit::of_str(node_text), | 55 | TextUnit::of_str(token.text()), |
61 | )]; | 56 | )]; |
62 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); | 57 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); |
63 | 58 | ||
@@ -74,7 +69,7 @@ fn remove_newline( | |||
74 | // ``` | 69 | // ``` |
75 | // | 70 | // |
76 | // into `my_function(<some-expr>)` | 71 | // into `my_function(<some-expr>)` |
77 | if join_single_expr_block(edit, node).is_some() { | 72 | if join_single_expr_block(edit, token).is_some() { |
78 | return; | 73 | return; |
79 | } | 74 | } |
80 | // ditto for | 75 | // ditto for |
@@ -84,44 +79,50 @@ fn remove_newline( | |||
84 | // bar | 79 | // bar |
85 | // }; | 80 | // }; |
86 | // ``` | 81 | // ``` |
87 | if join_single_use_tree(edit, node).is_some() { | 82 | if join_single_use_tree(edit, token).is_some() { |
88 | return; | 83 | return; |
89 | } | 84 | } |
90 | 85 | ||
91 | // The node is between two other nodes | 86 | // The node is between two other nodes |
92 | let prev = node.prev_sibling().unwrap(); | 87 | let prev = token.prev_sibling_or_token().unwrap(); |
93 | let next = node.next_sibling().unwrap(); | 88 | let next = token.next_sibling_or_token().unwrap(); |
94 | if is_trailing_comma(prev.kind(), next.kind()) { | 89 | if is_trailing_comma(prev.kind(), next.kind()) { |
95 | // Removes: trailing comma, newline (incl. surrounding whitespace) | 90 | // Removes: trailing comma, newline (incl. surrounding whitespace) |
96 | edit.delete(TextRange::from_to(prev.range().start(), node.range().end())); | 91 | edit.delete(TextRange::from_to(prev.range().start(), token.range().end())); |
97 | } else if prev.kind() == COMMA && next.kind() == R_CURLY { | 92 | } else if prev.kind() == COMMA && next.kind() == R_CURLY { |
98 | // Removes: comma, newline (incl. surrounding whitespace) | 93 | // Removes: comma, newline (incl. surrounding whitespace) |
99 | let space = if let Some(left) = prev.prev_sibling() { compute_ws(left, next) } else { " " }; | 94 | let space = if let Some(left) = prev.prev_sibling_or_token() { |
95 | compute_ws(left.kind(), next.kind()) | ||
96 | } else { | ||
97 | " " | ||
98 | }; | ||
100 | edit.replace( | 99 | edit.replace( |
101 | TextRange::from_to(prev.range().start(), node.range().end()), | 100 | TextRange::from_to(prev.range().start(), token.range().end()), |
102 | space.to_string(), | 101 | space.to_string(), |
103 | ); | 102 | ); |
104 | } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { | 103 | } else if let (Some(_), Some(next)) = |
104 | (prev.as_token().and_then(ast::Comment::cast), next.as_token().and_then(ast::Comment::cast)) | ||
105 | { | ||
105 | // Removes: newline (incl. surrounding whitespace), start of the next comment | 106 | // Removes: newline (incl. surrounding whitespace), start of the next comment |
106 | edit.delete(TextRange::from_to( | 107 | edit.delete(TextRange::from_to( |
107 | node.range().start(), | 108 | token.range().start(), |
108 | next.syntax().range().start() + TextUnit::of_str(next.prefix()), | 109 | next.syntax().range().start() + TextUnit::of_str(next.prefix()), |
109 | )); | 110 | )); |
110 | } else { | 111 | } else { |
111 | // Remove newline but add a computed amount of whitespace characters | 112 | // Remove newline but add a computed amount of whitespace characters |
112 | edit.replace(node.range(), compute_ws(prev, next).to_string()); | 113 | edit.replace(token.range(), compute_ws(prev.kind(), next.kind()).to_string()); |
113 | } | 114 | } |
114 | } | 115 | } |
115 | 116 | ||
116 | fn has_comma_after(node: &SyntaxNode) -> bool { | 117 | fn has_comma_after(node: &SyntaxNode) -> bool { |
117 | match non_trivia_sibling(node, Direction::Next) { | 118 | match non_trivia_sibling(node.into(), Direction::Next) { |
118 | Some(n) => n.kind() == COMMA, | 119 | Some(n) => n.kind() == COMMA, |
119 | _ => false, | 120 | _ => false, |
120 | } | 121 | } |
121 | } | 122 | } |
122 | 123 | ||
123 | fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { | 124 | fn join_single_expr_block(edit: &mut TextEditBuilder, token: SyntaxToken) -> Option<()> { |
124 | let block = ast::Block::cast(node.parent()?)?; | 125 | let block = ast::Block::cast(token.parent())?; |
125 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; | 126 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; |
126 | let expr = extract_trivial_expression(block)?; | 127 | let expr = extract_trivial_expression(block)?; |
127 | 128 | ||
@@ -140,8 +141,8 @@ fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Opti | |||
140 | Some(()) | 141 | Some(()) |
141 | } | 142 | } |
142 | 143 | ||
143 | fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { | 144 | fn join_single_use_tree(edit: &mut TextEditBuilder, token: SyntaxToken) -> Option<()> { |
144 | let use_tree_list = ast::UseTreeList::cast(node.parent()?)?; | 145 | let use_tree_list = ast::UseTreeList::cast(token.parent())?; |
145 | let (tree,) = use_tree_list.use_trees().collect_tuple()?; | 146 | let (tree,) = use_tree_list.use_trees().collect_tuple()?; |
146 | edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string()); | 147 | edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string()); |
147 | Some(()) | 148 | Some(()) |
@@ -401,13 +402,13 @@ use ra_syntax::{ | |||
401 | r" | 402 | r" |
402 | use ra_syntax::{ | 403 | use ra_syntax::{ |
403 | algo::<|>{ | 404 | algo::<|>{ |
404 | find_leaf_at_offset, | 405 | find_token_at_offset, |
405 | }, | 406 | }, |
406 | ast, | 407 | ast, |
407 | };", | 408 | };", |
408 | r" | 409 | r" |
409 | use ra_syntax::{ | 410 | use ra_syntax::{ |
410 | algo::<|>find_leaf_at_offset, | 411 | algo::<|>find_token_at_offset, |
411 | ast, | 412 | ast, |
412 | };", | 413 | };", |
413 | ); | 414 | ); |
diff --git a/crates/ra_ide_api/src/matching_brace.rs b/crates/ra_ide_api/src/matching_brace.rs index d1405f14f..bebd16a69 100644 --- a/crates/ra_ide_api/src/matching_brace.rs +++ b/crates/ra_ide_api/src/matching_brace.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | SourceFile, TextUnit, | 2 | SourceFile, TextUnit, |
3 | algo::find_leaf_at_offset, | 3 | algo::find_token_at_offset, |
4 | SyntaxKind::{self, *}, | 4 | SyntaxKind::{self, *}, |
5 | ast::AstNode, | 5 | ast::AstNode, |
6 | }; | 6 | }; |
@@ -8,15 +8,15 @@ use ra_syntax::{ | |||
8 | pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> { | 8 | pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> { |
9 | const BRACES: &[SyntaxKind] = | 9 | const BRACES: &[SyntaxKind] = |
10 | &[L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE]; | 10 | &[L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE]; |
11 | let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) | 11 | let (brace_node, brace_idx) = find_token_at_offset(file.syntax(), offset) |
12 | .filter_map(|node| { | 12 | .filter_map(|node| { |
13 | let idx = BRACES.iter().position(|&brace| brace == node.kind())?; | 13 | let idx = BRACES.iter().position(|&brace| brace == node.kind())?; |
14 | Some((node, idx)) | 14 | Some((node, idx)) |
15 | }) | 15 | }) |
16 | .next()?; | 16 | .next()?; |
17 | let parent = brace_node.parent()?; | 17 | let parent = brace_node.parent(); |
18 | let matching_kind = BRACES[brace_idx ^ 1]; | 18 | let matching_kind = BRACES[brace_idx ^ 1]; |
19 | let matching_node = parent.children().find(|node| node.kind() == matching_kind)?; | 19 | let matching_node = parent.children_with_tokens().find(|node| node.kind() == matching_kind)?; |
20 | Some(matching_node.range().start()) | 20 | Some(matching_node.range().start()) |
21 | } | 21 | } |
22 | 22 | ||
@@ -41,5 +41,4 @@ mod tests { | |||
41 | 41 | ||
42 | do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); | 42 | do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); |
43 | } | 43 | } |
44 | |||
45 | } | 44 | } |
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index a0c5e78ad..d9a28d2b5 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | 2 | ||
3 | use ra_syntax::{ast, AstNode, TextRange, Direction, SyntaxKind::*}; | 3 | use ra_syntax::{ast, AstNode, TextRange, Direction, SyntaxKind::*, SyntaxElement}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | 5 | ||
6 | use crate::{FileId, db::RootDatabase}; | 6 | use crate::{FileId, db::RootDatabase}; |
@@ -15,9 +15,9 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
15 | let source_file = db.parse(file_id); | 15 | let source_file = db.parse(file_id); |
16 | 16 | ||
17 | // Visited nodes to handle highlighting priorities | 17 | // Visited nodes to handle highlighting priorities |
18 | let mut highlighted = FxHashSet::default(); | 18 | let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); |
19 | let mut res = Vec::new(); | 19 | let mut res = Vec::new(); |
20 | for node in source_file.syntax().descendants() { | 20 | for node in source_file.syntax().descendants_with_tokens() { |
21 | if highlighted.contains(&node) { | 21 | if highlighted.contains(&node) { |
22 | continue; | 22 | continue; |
23 | } | 23 | } |
@@ -31,14 +31,14 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
31 | LIFETIME => "parameter", | 31 | LIFETIME => "parameter", |
32 | k if k.is_keyword() => "keyword", | 32 | k if k.is_keyword() => "keyword", |
33 | _ => { | 33 | _ => { |
34 | if let Some(macro_call) = ast::MacroCall::cast(node) { | 34 | if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) { |
35 | if let Some(path) = macro_call.path() { | 35 | if let Some(path) = macro_call.path() { |
36 | if let Some(segment) = path.segment() { | 36 | if let Some(segment) = path.segment() { |
37 | if let Some(name_ref) = segment.name_ref() { | 37 | if let Some(name_ref) = segment.name_ref() { |
38 | highlighted.insert(name_ref.syntax()); | 38 | highlighted.insert(name_ref.syntax().into()); |
39 | let range_start = name_ref.syntax().range().start(); | 39 | let range_start = name_ref.syntax().range().start(); |
40 | let mut range_end = name_ref.syntax().range().end(); | 40 | let mut range_end = name_ref.syntax().range().end(); |
41 | for sibling in path.syntax().siblings(Direction::Next) { | 41 | for sibling in path.syntax().siblings_with_tokens(Direction::Next) { |
42 | match sibling.kind() { | 42 | match sibling.kind() { |
43 | EXCL | IDENT => range_end = sibling.range().end(), | 43 | EXCL | IDENT => range_end = sibling.range().end(), |
44 | _ => (), | 44 | _ => (), |
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs index 276f8a8c8..a4e4c3dbe 100644 --- a/crates/ra_ide_api/src/syntax_tree.rs +++ b/crates/ra_ide_api/src/syntax_tree.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use crate::db::RootDatabase; | 2 | use crate::db::RootDatabase; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | SourceFile, SyntaxNode, TextRange, AstNode, | 4 | SourceFile, TextRange, AstNode, SyntaxToken, SyntaxElement, |
5 | algo::{self, visit::{visitor, Visitor}}, ast::{self, AstToken} | 5 | algo, |
6 | SyntaxKind::{STRING, RAW_STRING}, | ||
6 | }; | 7 | }; |
7 | 8 | ||
8 | pub use ra_db::FileId; | 9 | pub use ra_db::FileId; |
@@ -14,11 +15,15 @@ pub(crate) fn syntax_tree( | |||
14 | ) -> String { | 15 | ) -> String { |
15 | if let Some(text_range) = text_range { | 16 | if let Some(text_range) = text_range { |
16 | let file = db.parse(file_id); | 17 | let file = db.parse(file_id); |
17 | let node = algo::find_covering_node(file.syntax(), text_range); | 18 | let node = match algo::find_covering_element(file.syntax(), text_range) { |
18 | 19 | SyntaxElement::Node(node) => node, | |
19 | if let Some(tree) = syntax_tree_for_string(node, text_range) { | 20 | SyntaxElement::Token(token) => { |
20 | return tree; | 21 | if let Some(tree) = syntax_tree_for_string(token, text_range) { |
21 | } | 22 | return tree; |
23 | } | ||
24 | token.parent() | ||
25 | } | ||
26 | }; | ||
22 | 27 | ||
23 | node.debug_dump() | 28 | node.debug_dump() |
24 | } else { | 29 | } else { |
@@ -28,19 +33,19 @@ pub(crate) fn syntax_tree( | |||
28 | 33 | ||
29 | /// Attempts parsing the selected contents of a string literal | 34 | /// Attempts parsing the selected contents of a string literal |
30 | /// as rust syntax and returns its syntax tree | 35 | /// as rust syntax and returns its syntax tree |
31 | fn syntax_tree_for_string(node: &SyntaxNode, text_range: TextRange) -> Option<String> { | 36 | fn syntax_tree_for_string(token: SyntaxToken, text_range: TextRange) -> Option<String> { |
32 | // When the range is inside a string | 37 | // When the range is inside a string |
33 | // we'll attempt parsing it as rust syntax | 38 | // we'll attempt parsing it as rust syntax |
34 | // to provide the syntax tree of the contents of the string | 39 | // to provide the syntax tree of the contents of the string |
35 | visitor() | 40 | match token.kind() { |
36 | .visit(|node: &ast::String| syntax_tree_for_token(node, text_range)) | 41 | STRING | RAW_STRING => syntax_tree_for_token(token, text_range), |
37 | .visit(|node: &ast::RawString| syntax_tree_for_token(node, text_range)) | 42 | _ => None, |
38 | .accept(node)? | 43 | } |
39 | } | 44 | } |
40 | 45 | ||
41 | fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option<String> { | 46 | fn syntax_tree_for_token(node: SyntaxToken, text_range: TextRange) -> Option<String> { |
42 | // Range of the full node | 47 | // Range of the full node |
43 | let node_range = node.syntax().range(); | 48 | let node_range = node.range(); |
44 | let text = node.text().to_string(); | 49 | let text = node.text().to_string(); |
45 | 50 | ||
46 | // We start at some point inside the node | 51 | // We start at some point inside the node |
diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 501d44dbb..4510d663d 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | AstNode, SourceFile, SyntaxKind::*, | 2 | AstNode, SourceFile, SyntaxKind::*, |
3 | SyntaxNode, TextUnit, TextRange, | 3 | TextUnit, TextRange, SyntaxToken, |
4 | algo::{find_node_at_offset, find_leaf_at_offset, LeafAtOffset}, | 4 | algo::{find_node_at_offset, find_token_at_offset, TokenAtOffset}, |
5 | ast::{self, AstToken}, | 5 | ast::{self}, |
6 | }; | 6 | }; |
7 | use ra_fmt::leading_indent; | 7 | use ra_fmt::leading_indent; |
8 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 8 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
@@ -11,11 +11,11 @@ use crate::{db::RootDatabase, SourceChange, SourceFileEdit}; | |||
11 | 11 | ||
12 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { | 12 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { |
13 | let file = db.parse(position.file_id); | 13 | let file = db.parse(position.file_id); |
14 | let comment = find_leaf_at_offset(file.syntax(), position.offset) | 14 | let comment = find_token_at_offset(file.syntax(), position.offset) |
15 | .left_biased() | 15 | .left_biased() |
16 | .and_then(ast::Comment::cast)?; | 16 | .and_then(ast::Comment::cast)?; |
17 | 17 | ||
18 | if let ast::CommentFlavor::Multiline = comment.flavor() { | 18 | if comment.flavor() == ast::CommentFlavor::Multiline { |
19 | return None; | 19 | return None; |
20 | } | 20 | } |
21 | 21 | ||
@@ -41,23 +41,23 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour | |||
41 | ) | 41 | ) |
42 | } | 42 | } |
43 | 43 | ||
44 | fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> { | 44 | fn node_indent<'a>(file: &'a SourceFile, token: SyntaxToken) -> Option<&'a str> { |
45 | let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) { | 45 | let ws = match find_token_at_offset(file.syntax(), token.range().start()) { |
46 | LeafAtOffset::Between(l, r) => { | 46 | TokenAtOffset::Between(l, r) => { |
47 | assert!(r == node); | 47 | assert!(r == token); |
48 | l | 48 | l |
49 | } | 49 | } |
50 | LeafAtOffset::Single(n) => { | 50 | TokenAtOffset::Single(n) => { |
51 | assert!(n == node); | 51 | assert!(n == token); |
52 | return Some(""); | 52 | return Some(""); |
53 | } | 53 | } |
54 | LeafAtOffset::None => unreachable!(), | 54 | TokenAtOffset::None => unreachable!(), |
55 | }; | 55 | }; |
56 | if ws.kind() != WHITESPACE { | 56 | if ws.kind() != WHITESPACE { |
57 | return None; | 57 | return None; |
58 | } | 58 | } |
59 | let text = ws.leaf_text().unwrap(); | 59 | let text = ws.text(); |
60 | let pos = text.as_str().rfind('\n').map(|it| it + 1).unwrap_or(0); | 60 | let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0); |
61 | Some(&text[pos..]) | 61 | Some(&text[pos..]) |
62 | } | 62 | } |
63 | 63 | ||
@@ -88,7 +88,7 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option< | |||
88 | let file = db.parse(position.file_id); | 88 | let file = db.parse(position.file_id); |
89 | assert_eq!(file.syntax().text().char_at(position.offset), Some('.')); | 89 | assert_eq!(file.syntax().text().char_at(position.offset), Some('.')); |
90 | 90 | ||
91 | let whitespace = find_leaf_at_offset(file.syntax(), position.offset) | 91 | let whitespace = find_token_at_offset(file.syntax(), position.offset) |
92 | .left_biased() | 92 | .left_biased() |
93 | .and_then(ast::Whitespace::cast)?; | 93 | .and_then(ast::Whitespace::cast)?; |
94 | 94 | ||
@@ -100,7 +100,7 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option< | |||
100 | let current_indent_len = TextUnit::of_str(current_indent); | 100 | let current_indent_len = TextUnit::of_str(current_indent); |
101 | 101 | ||
102 | // Make sure dot is a part of call chain | 102 | // Make sure dot is a part of call chain |
103 | let field_expr = whitespace.syntax().parent().and_then(ast::FieldExpr::cast)?; | 103 | let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?; |
104 | let prev_indent = leading_indent(field_expr.syntax())?; | 104 | let prev_indent = leading_indent(field_expr.syntax())?; |
105 | let target_indent = format!(" {}", prev_indent); | 105 | let target_indent = format!(" {}", prev_indent); |
106 | let target_indent_len = TextUnit::of_str(&target_indent); | 106 | let target_indent_len = TextUnit::of_str(&target_indent); |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 4b1d1d3ca..05f9817da 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_parser::{TokenSource, TreeSink, ParseError}; | 1 | use ra_parser::{TokenSource, TreeSink, ParseError}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc, | 3 | AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc, SyntaxElement, |
4 | ast, SyntaxKind::*, TextUnit | 4 | ast, SyntaxKind::*, TextUnit |
5 | }; | 5 | }; |
6 | 6 | ||
@@ -47,8 +47,8 @@ fn convert_tt( | |||
47 | global_offset: TextUnit, | 47 | global_offset: TextUnit, |
48 | tt: &SyntaxNode, | 48 | tt: &SyntaxNode, |
49 | ) -> Option<tt::Subtree> { | 49 | ) -> Option<tt::Subtree> { |
50 | let first_child = tt.first_child()?; | 50 | let first_child = tt.first_child_or_token()?; |
51 | let last_child = tt.last_child()?; | 51 | let last_child = tt.last_child_or_token()?; |
52 | let delimiter = match (first_child.kind(), last_child.kind()) { | 52 | let delimiter = match (first_child.kind(), last_child.kind()) { |
53 | (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis, | 53 | (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis, |
54 | (L_CURLY, R_CURLY) => tt::Delimiter::Brace, | 54 | (L_CURLY, R_CURLY) => tt::Delimiter::Brace, |
@@ -56,39 +56,47 @@ fn convert_tt( | |||
56 | _ => return None, | 56 | _ => return None, |
57 | }; | 57 | }; |
58 | let mut token_trees = Vec::new(); | 58 | let mut token_trees = Vec::new(); |
59 | for child in tt.children().skip(1) { | 59 | for child in tt.children_with_tokens().skip(1) { |
60 | if child == first_child || child == last_child || child.kind().is_trivia() { | 60 | if child == first_child || child == last_child || child.kind().is_trivia() { |
61 | continue; | 61 | continue; |
62 | } | 62 | } |
63 | if child.kind().is_punct() { | 63 | match child { |
64 | let mut prev = None; | 64 | SyntaxElement::Token(token) => { |
65 | for char in child.leaf_text().unwrap().chars() { | 65 | if token.kind().is_punct() { |
66 | if let Some(char) = prev { | 66 | let mut prev = None; |
67 | token_trees.push( | 67 | for char in token.text().chars() { |
68 | tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Joint }).into(), | 68 | if let Some(char) = prev { |
69 | ); | 69 | token_trees.push( |
70 | tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Joint }) | ||
71 | .into(), | ||
72 | ); | ||
73 | } | ||
74 | prev = Some(char) | ||
75 | } | ||
76 | if let Some(char) = prev { | ||
77 | token_trees.push( | ||
78 | tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Alone }).into(), | ||
79 | ); | ||
80 | } | ||
81 | } else { | ||
82 | let child = if token.kind().is_keyword() || token.kind() == IDENT { | ||
83 | let relative_range = token.range() - global_offset; | ||
84 | let id = token_map.alloc(relative_range); | ||
85 | let text = token.text().clone(); | ||
86 | tt::Leaf::from(tt::Ident { text, id }).into() | ||
87 | } else if token.kind().is_literal() { | ||
88 | tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() | ||
89 | } else { | ||
90 | return None; | ||
91 | }; | ||
92 | token_trees.push(child); | ||
70 | } | 93 | } |
71 | prev = Some(char) | ||
72 | } | 94 | } |
73 | if let Some(char) = prev { | 95 | SyntaxElement::Node(node) => { |
74 | token_trees | 96 | let child = convert_tt(token_map, global_offset, node)?.into(); |
75 | .push(tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Alone }).into()); | 97 | token_trees.push(child); |
76 | } | 98 | } |
77 | } else { | 99 | }; |
78 | let child: tt::TokenTree = if child.kind() == TOKEN_TREE { | ||
79 | convert_tt(token_map, global_offset, child)?.into() | ||
80 | } else if child.kind().is_keyword() || child.kind() == IDENT { | ||
81 | let relative_range = child.range() - global_offset; | ||
82 | let id = token_map.alloc(relative_range); | ||
83 | let text = child.leaf_text().unwrap().clone(); | ||
84 | tt::Leaf::from(tt::Ident { text, id }).into() | ||
85 | } else if child.kind().is_literal() { | ||
86 | tt::Leaf::from(tt::Literal { text: child.leaf_text().unwrap().clone() }).into() | ||
87 | } else { | ||
88 | return None; | ||
89 | }; | ||
90 | token_trees.push(child) | ||
91 | } | ||
92 | } | 100 | } |
93 | 101 | ||
94 | let res = tt::Subtree { delimiter, token_trees }; | 102 | let res = tt::Subtree { delimiter, token_trees }; |
@@ -118,12 +126,12 @@ impl TtTokenSource { | |||
118 | } | 126 | } |
119 | fn convert_tt(&mut self, tt: &tt::TokenTree) { | 127 | fn convert_tt(&mut self, tt: &tt::TokenTree) { |
120 | match tt { | 128 | match tt { |
121 | tt::TokenTree::Leaf(leaf) => self.convert_leaf(leaf), | 129 | tt::TokenTree::Leaf(token) => self.convert_token(token), |
122 | tt::TokenTree::Subtree(sub) => self.convert_subtree(sub), | 130 | tt::TokenTree::Subtree(sub) => self.convert_subtree(sub), |
123 | } | 131 | } |
124 | } | 132 | } |
125 | fn convert_leaf(&mut self, leaf: &tt::Leaf) { | 133 | fn convert_token(&mut self, token: &tt::Leaf) { |
126 | let tok = match leaf { | 134 | let tok = match token { |
127 | tt::Leaf::Literal(l) => TtToken { | 135 | tt::Leaf::Literal(l) => TtToken { |
128 | kind: SyntaxKind::INT_NUMBER, // FIXME | 136 | kind: SyntaxKind::INT_NUMBER, // FIXME |
129 | is_joint_to_next: false, | 137 | is_joint_to_next: false, |
@@ -206,7 +214,7 @@ impl<'a> TtTreeSink<'a> { | |||
206 | } | 214 | } |
207 | 215 | ||
208 | impl<'a> TreeSink for TtTreeSink<'a> { | 216 | impl<'a> TreeSink for TtTreeSink<'a> { |
209 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { | 217 | fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { |
210 | for _ in 0..n_tokens { | 218 | for _ in 0..n_tokens { |
211 | self.buf += self.tokens[self.token_pos].text.as_str(); | 219 | self.buf += self.tokens[self.token_pos].text.as_str(); |
212 | self.token_pos += 1; | 220 | self.token_pos += 1; |
@@ -214,15 +222,15 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
214 | self.text_pos += TextUnit::of_str(&self.buf); | 222 | self.text_pos += TextUnit::of_str(&self.buf); |
215 | let text = SmolStr::new(self.buf.as_str()); | 223 | let text = SmolStr::new(self.buf.as_str()); |
216 | self.buf.clear(); | 224 | self.buf.clear(); |
217 | self.inner.leaf(kind, text) | 225 | self.inner.token(kind, text) |
218 | } | 226 | } |
219 | 227 | ||
220 | fn start_branch(&mut self, kind: SyntaxKind) { | 228 | fn start_node(&mut self, kind: SyntaxKind) { |
221 | self.inner.start_branch(kind); | 229 | self.inner.start_node(kind); |
222 | } | 230 | } |
223 | 231 | ||
224 | fn finish_branch(&mut self) { | 232 | fn finish_node(&mut self) { |
225 | self.inner.finish_branch(); | 233 | self.inner.finish_node(); |
226 | } | 234 | } |
227 | 235 | ||
228 | fn error(&mut self, error: ParseError) { | 236 | fn error(&mut self, error: ParseError) { |
diff --git a/crates/ra_parser/src/event.rs b/crates/ra_parser/src/event.rs index c1773e8e0..87cf4eca0 100644 --- a/crates/ra_parser/src/event.rs +++ b/crates/ra_parser/src/event.rs | |||
@@ -116,12 +116,12 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) { | |||
116 | } | 116 | } |
117 | 117 | ||
118 | for kind in forward_parents.drain(..).rev() { | 118 | for kind in forward_parents.drain(..).rev() { |
119 | sink.start_branch(kind); | 119 | sink.start_node(kind); |
120 | } | 120 | } |
121 | } | 121 | } |
122 | Event::Finish => sink.finish_branch(), | 122 | Event::Finish => sink.finish_node(), |
123 | Event::Token { kind, n_raw_tokens } => { | 123 | Event::Token { kind, n_raw_tokens } => { |
124 | sink.leaf(kind, n_raw_tokens); | 124 | sink.token(kind, n_raw_tokens); |
125 | } | 125 | } |
126 | Event::Error { msg } => sink.error(msg), | 126 | Event::Error { msg } => sink.error(msg), |
127 | } | 127 | } |
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs index ddc08e462..30ba06aac 100644 --- a/crates/ra_parser/src/lib.rs +++ b/crates/ra_parser/src/lib.rs | |||
@@ -40,15 +40,15 @@ pub trait TokenSource { | |||
40 | 40 | ||
41 | /// `TreeSink` abstracts details of a particular syntax tree implementation. | 41 | /// `TreeSink` abstracts details of a particular syntax tree implementation. |
42 | pub trait TreeSink { | 42 | pub trait TreeSink { |
43 | /// Adds new leaf to the current branch. | 43 | /// Adds new token to the current branch. |
44 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8); | 44 | fn token(&mut self, kind: SyntaxKind, n_tokens: u8); |
45 | 45 | ||
46 | /// Start new branch and make it current. | 46 | /// Start new branch and make it current. |
47 | fn start_branch(&mut self, kind: SyntaxKind); | 47 | fn start_node(&mut self, kind: SyntaxKind); |
48 | 48 | ||
49 | /// Finish current branch and restore previous | 49 | /// Finish current branch and restore previous |
50 | /// branch as current. | 50 | /// branch as current. |
51 | fn finish_branch(&mut self); | 51 | fn finish_node(&mut self); |
52 | 52 | ||
53 | fn error(&mut self, error: ParseError); | 53 | fn error(&mut self, error: ParseError); |
54 | } | 54 | } |
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 7e70dad3f..1a763fb47 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ unicode-xid = "0.1.0" | |||
13 | itertools = "0.8.0" | 13 | itertools = "0.8.0" |
14 | drop_bomb = "0.1.4" | 14 | drop_bomb = "0.1.4" |
15 | parking_lot = "0.7.0" | 15 | parking_lot = "0.7.0" |
16 | rowan = "0.3.3" | 16 | rowan = "0.4.0" |
17 | 17 | ||
18 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here | 18 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here |
19 | # to reduce number of compilations | 19 | # to reduce number of compilations |
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index e2b4f0388..06b45135c 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs | |||
@@ -1,18 +1,14 @@ | |||
1 | pub mod visit; | 1 | pub mod visit; |
2 | 2 | ||
3 | use rowan::TransparentNewType; | 3 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; |
4 | 4 | ||
5 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction}; | 5 | pub use rowan::TokenAtOffset; |
6 | 6 | ||
7 | pub use rowan::LeafAtOffset; | 7 | pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset<SyntaxToken> { |
8 | 8 | match node.0.token_at_offset(offset) { | |
9 | pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<&SyntaxNode> { | 9 | TokenAtOffset::None => TokenAtOffset::None, |
10 | match node.0.leaf_at_offset(offset) { | 10 | TokenAtOffset::Single(n) => TokenAtOffset::Single(n.into()), |
11 | LeafAtOffset::None => LeafAtOffset::None, | 11 | TokenAtOffset::Between(l, r) => TokenAtOffset::Between(l.into(), r.into()), |
12 | LeafAtOffset::Single(n) => LeafAtOffset::Single(SyntaxNode::from_repr(n)), | ||
13 | LeafAtOffset::Between(l, r) => { | ||
14 | LeafAtOffset::Between(SyntaxNode::from_repr(l), SyntaxNode::from_repr(r)) | ||
15 | } | ||
16 | } | 12 | } |
17 | } | 13 | } |
18 | 14 | ||
@@ -26,16 +22,29 @@ pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset< | |||
26 | /// | 22 | /// |
27 | /// then the left node will be silently preferred. | 23 | /// then the left node will be silently preferred. |
28 | pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { | 24 | pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { |
29 | find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) | 25 | find_token_at_offset(syntax, offset) |
26 | .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast)) | ||
30 | } | 27 | } |
31 | 28 | ||
32 | /// Finds the first sibling in the given direction which is not `trivia` | 29 | /// Finds the first sibling in the given direction which is not `trivia` |
33 | pub fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> { | 30 | pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { |
34 | node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia()) | 31 | return match element { |
32 | SyntaxElement::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), | ||
33 | SyntaxElement::Token(token) => { | ||
34 | token.siblings_with_tokens(direction).skip(1).find(not_trivia) | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | fn not_trivia(element: &SyntaxElement) -> bool { | ||
39 | match element { | ||
40 | SyntaxElement::Node(_) => true, | ||
41 | SyntaxElement::Token(token) => !token.kind().is_trivia(), | ||
42 | } | ||
43 | } | ||
35 | } | 44 | } |
36 | 45 | ||
37 | pub fn find_covering_node(root: &SyntaxNode, range: TextRange) -> &SyntaxNode { | 46 | pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { |
38 | SyntaxNode::from_repr(root.0.covering_node(range)) | 47 | root.0.covering_node(range).into() |
39 | } | 48 | } |
40 | 49 | ||
41 | // Replace with `std::iter::successors` in `1.34.0` | 50 | // Replace with `std::iter::successors` in `1.34.0` |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index fd7e63f84..9a44afc67 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -7,7 +7,7 @@ use itertools::Itertools; | |||
7 | 7 | ||
8 | pub use self::generated::*; | 8 | pub use self::generated::*; |
9 | use crate::{ | 9 | use crate::{ |
10 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, | 10 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren}, |
11 | SmolStr, | 11 | SmolStr, |
12 | SyntaxKind::*, | 12 | SyntaxKind::*, |
13 | }; | 13 | }; |
@@ -27,7 +27,8 @@ pub trait AstNode: | |||
27 | 27 | ||
28 | pub trait AstToken: AstNode { | 28 | pub trait AstToken: AstNode { |
29 | fn text(&self) -> &SmolStr { | 29 | fn text(&self) -> &SmolStr { |
30 | self.syntax().leaf_text().unwrap() | 30 | // self.syntax().leaf_text().unwrap() |
31 | unimplemented!() | ||
31 | } | 32 | } |
32 | } | 33 | } |
33 | 34 | ||
@@ -126,8 +127,8 @@ pub trait AttrsOwner: AstNode { | |||
126 | } | 127 | } |
127 | 128 | ||
128 | pub trait DocCommentsOwner: AstNode { | 129 | pub trait DocCommentsOwner: AstNode { |
129 | fn doc_comments(&self) -> AstChildren<Comment> { | 130 | fn doc_comments(&self) -> CommentIter { |
130 | children(self) | 131 | CommentIter { iter: self.syntax().children_with_tokens() } |
131 | } | 132 | } |
132 | 133 | ||
133 | /// Returns the textual content of a doc comment block as a single string. | 134 | /// Returns the textual content of a doc comment block as a single string. |
@@ -179,9 +180,9 @@ impl Attr { | |||
179 | 180 | ||
180 | pub fn as_atom(&self) -> Option<SmolStr> { | 181 | pub fn as_atom(&self) -> Option<SmolStr> { |
181 | let tt = self.value()?; | 182 | let tt = self.value()?; |
182 | let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; | 183 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; |
183 | if attr.kind() == IDENT { | 184 | if attr.kind() == IDENT { |
184 | Some(attr.leaf_text().unwrap().clone()) | 185 | Some(attr.as_token()?.text().clone()) |
185 | } else { | 186 | } else { |
186 | None | 187 | None |
187 | } | 188 | } |
@@ -189,10 +190,10 @@ impl Attr { | |||
189 | 190 | ||
190 | pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { | 191 | pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { |
191 | let tt = self.value()?; | 192 | let tt = self.value()?; |
192 | let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; | 193 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; |
193 | let args = TokenTree::cast(args)?; | 194 | let args = TokenTree::cast(args.as_node()?)?; |
194 | if attr.kind() == IDENT { | 195 | if attr.kind() == IDENT { |
195 | Some((attr.leaf_text().unwrap().clone(), args)) | 196 | Some((attr.as_token()?.text().clone(), args)) |
196 | } else { | 197 | } else { |
197 | None | 198 | None |
198 | } | 199 | } |
@@ -200,16 +201,35 @@ impl Attr { | |||
200 | 201 | ||
201 | pub fn as_named(&self) -> Option<SmolStr> { | 202 | pub fn as_named(&self) -> Option<SmolStr> { |
202 | let tt = self.value()?; | 203 | let tt = self.value()?; |
203 | let attr = tt.syntax().children().nth(1)?; | 204 | let attr = tt.syntax().children_with_tokens().nth(1)?; |
204 | if attr.kind() == IDENT { | 205 | if attr.kind() == IDENT { |
205 | Some(attr.leaf_text().unwrap().clone()) | 206 | Some(attr.as_token()?.text().clone()) |
206 | } else { | 207 | } else { |
207 | None | 208 | None |
208 | } | 209 | } |
209 | } | 210 | } |
210 | } | 211 | } |
211 | 212 | ||
212 | impl Comment { | 213 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
214 | pub struct Comment<'a>(SyntaxToken<'a>); | ||
215 | |||
216 | impl<'a> Comment<'a> { | ||
217 | pub fn cast(token: SyntaxToken<'a>) -> Option<Self> { | ||
218 | if token.kind() == COMMENT { | ||
219 | Some(Comment(token)) | ||
220 | } else { | ||
221 | None | ||
222 | } | ||
223 | } | ||
224 | |||
225 | pub fn syntax(&self) -> SyntaxToken<'a> { | ||
226 | self.0 | ||
227 | } | ||
228 | |||
229 | pub fn text(&self) -> &'a SmolStr { | ||
230 | self.0.text() | ||
231 | } | ||
232 | |||
213 | pub fn flavor(&self) -> CommentFlavor { | 233 | pub fn flavor(&self) -> CommentFlavor { |
214 | let text = self.text(); | 234 | let text = self.text(); |
215 | if text.starts_with("///") { | 235 | if text.starts_with("///") { |
@@ -230,13 +250,16 @@ impl Comment { | |||
230 | pub fn prefix(&self) -> &'static str { | 250 | pub fn prefix(&self) -> &'static str { |
231 | self.flavor().prefix() | 251 | self.flavor().prefix() |
232 | } | 252 | } |
253 | } | ||
233 | 254 | ||
234 | pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { | 255 | pub struct CommentIter<'a> { |
235 | self.text().chars().filter(|&c| c == '\n').map(|_| &()) | 256 | iter: SyntaxElementChildren<'a>, |
236 | } | 257 | } |
237 | 258 | ||
238 | pub fn has_newlines(&self) -> bool { | 259 | impl<'a> Iterator for CommentIter<'a> { |
239 | self.count_newlines_lazy().count() > 0 | 260 | type Item = Comment<'a>; |
261 | fn next(&mut self) -> Option<Comment<'a>> { | ||
262 | self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast)) | ||
240 | } | 263 | } |
241 | } | 264 | } |
242 | 265 | ||
@@ -267,27 +290,42 @@ impl CommentFlavor { | |||
267 | } | 290 | } |
268 | } | 291 | } |
269 | 292 | ||
270 | impl Whitespace { | 293 | pub struct Whitespace<'a>(SyntaxToken<'a>); |
271 | pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { | 294 | |
272 | self.text().chars().filter(|&c| c == '\n').map(|_| &()) | 295 | impl<'a> Whitespace<'a> { |
296 | pub fn cast(token: SyntaxToken<'a>) -> Option<Self> { | ||
297 | if token.kind() == WHITESPACE { | ||
298 | Some(Whitespace(token)) | ||
299 | } else { | ||
300 | None | ||
301 | } | ||
302 | } | ||
303 | |||
304 | pub fn syntax(&self) -> SyntaxToken<'a> { | ||
305 | self.0 | ||
273 | } | 306 | } |
274 | 307 | ||
275 | pub fn has_newlines(&self) -> bool { | 308 | pub fn text(&self) -> &'a SmolStr { |
276 | self.text().contains('\n') | 309 | self.0.text() |
310 | } | ||
311 | |||
312 | pub fn spans_multiple_lines(&self) -> bool { | ||
313 | let text = self.text(); | ||
314 | text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) | ||
277 | } | 315 | } |
278 | } | 316 | } |
279 | 317 | ||
280 | impl Name { | 318 | impl Name { |
281 | pub fn text(&self) -> &SmolStr { | 319 | pub fn text(&self) -> &SmolStr { |
282 | let ident = self.syntax().first_child().unwrap(); | 320 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); |
283 | ident.leaf_text().unwrap() | 321 | ident.text() |
284 | } | 322 | } |
285 | } | 323 | } |
286 | 324 | ||
287 | impl NameRef { | 325 | impl NameRef { |
288 | pub fn text(&self) -> &SmolStr { | 326 | pub fn text(&self) -> &SmolStr { |
289 | let ident = self.syntax().first_child().unwrap(); | 327 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); |
290 | ident.leaf_text().unwrap() | 328 | ident.text() |
291 | } | 329 | } |
292 | } | 330 | } |
293 | 331 | ||
@@ -316,7 +354,7 @@ impl ImplBlock { | |||
316 | 354 | ||
317 | impl Module { | 355 | impl Module { |
318 | pub fn has_semi(&self) -> bool { | 356 | pub fn has_semi(&self) -> bool { |
319 | match self.syntax().last_child() { | 357 | match self.syntax().last_child_or_token() { |
320 | None => false, | 358 | None => false, |
321 | Some(node) => node.kind() == SEMI, | 359 | Some(node) => node.kind() == SEMI, |
322 | } | 360 | } |
@@ -325,7 +363,7 @@ impl Module { | |||
325 | 363 | ||
326 | impl LetStmt { | 364 | impl LetStmt { |
327 | pub fn has_semi(&self) -> bool { | 365 | pub fn has_semi(&self) -> bool { |
328 | match self.syntax().last_child() { | 366 | match self.syntax().last_child_or_token() { |
329 | None => false, | 367 | None => false, |
330 | Some(node) => node.kind() == SEMI, | 368 | Some(node) => node.kind() == SEMI, |
331 | } | 369 | } |
@@ -360,7 +398,7 @@ impl IfExpr { | |||
360 | 398 | ||
361 | impl ExprStmt { | 399 | impl ExprStmt { |
362 | pub fn has_semi(&self) -> bool { | 400 | pub fn has_semi(&self) -> bool { |
363 | match self.syntax().last_child() { | 401 | match self.syntax().last_child_or_token() { |
364 | None => false, | 402 | None => false, |
365 | Some(node) => node.kind() == SEMI, | 403 | Some(node) => node.kind() == SEMI, |
366 | } | 404 | } |
@@ -384,7 +422,7 @@ impl PathSegment { | |||
384 | let res = if let Some(name_ref) = self.name_ref() { | 422 | let res = if let Some(name_ref) = self.name_ref() { |
385 | PathSegmentKind::Name(name_ref) | 423 | PathSegmentKind::Name(name_ref) |
386 | } else { | 424 | } else { |
387 | match self.syntax().first_child()?.kind() { | 425 | match self.syntax().first_child_or_token()?.kind() { |
388 | SELF_KW => PathSegmentKind::SelfKw, | 426 | SELF_KW => PathSegmentKind::SelfKw, |
389 | SUPER_KW => PathSegmentKind::SuperKw, | 427 | SUPER_KW => PathSegmentKind::SuperKw, |
390 | CRATE_KW => PathSegmentKind::CrateKw, | 428 | CRATE_KW => PathSegmentKind::CrateKw, |
@@ -395,7 +433,7 @@ impl PathSegment { | |||
395 | } | 433 | } |
396 | 434 | ||
397 | pub fn has_colon_colon(&self) -> bool { | 435 | pub fn has_colon_colon(&self) -> bool { |
398 | match self.syntax.first_child().map(|s| s.kind()) { | 436 | match self.syntax.first_child_or_token().map(|s| s.kind()) { |
399 | Some(COLONCOLON) => true, | 437 | Some(COLONCOLON) => true, |
400 | _ => false, | 438 | _ => false, |
401 | } | 439 | } |
@@ -410,7 +448,7 @@ impl Path { | |||
410 | 448 | ||
411 | impl UseTree { | 449 | impl UseTree { |
412 | pub fn has_star(&self) -> bool { | 450 | pub fn has_star(&self) -> bool { |
413 | self.syntax().children().any(|it| it.kind() == STAR) | 451 | self.syntax().children_with_tokens().any(|it| it.kind() == STAR) |
414 | } | 452 | } |
415 | } | 453 | } |
416 | 454 | ||
@@ -425,7 +463,7 @@ impl UseTreeList { | |||
425 | 463 | ||
426 | impl RefPat { | 464 | impl RefPat { |
427 | pub fn is_mut(&self) -> bool { | 465 | pub fn is_mut(&self) -> bool { |
428 | self.syntax().children().any(|n| n.kind() == MUT_KW) | 466 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
429 | } | 467 | } |
430 | } | 468 | } |
431 | 469 | ||
@@ -500,19 +538,19 @@ impl EnumVariant { | |||
500 | 538 | ||
501 | impl PointerType { | 539 | impl PointerType { |
502 | pub fn is_mut(&self) -> bool { | 540 | pub fn is_mut(&self) -> bool { |
503 | self.syntax().children().any(|n| n.kind() == MUT_KW) | 541 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
504 | } | 542 | } |
505 | } | 543 | } |
506 | 544 | ||
507 | impl ReferenceType { | 545 | impl ReferenceType { |
508 | pub fn is_mut(&self) -> bool { | 546 | pub fn is_mut(&self) -> bool { |
509 | self.syntax().children().any(|n| n.kind() == MUT_KW) | 547 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
510 | } | 548 | } |
511 | } | 549 | } |
512 | 550 | ||
513 | impl RefExpr { | 551 | impl RefExpr { |
514 | pub fn is_mut(&self) -> bool { | 552 | pub fn is_mut(&self) -> bool { |
515 | self.syntax().children().any(|n| n.kind() == MUT_KW) | 553 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
516 | } | 554 | } |
517 | } | 555 | } |
518 | 556 | ||
@@ -528,7 +566,7 @@ pub enum PrefixOp { | |||
528 | 566 | ||
529 | impl PrefixExpr { | 567 | impl PrefixExpr { |
530 | pub fn op_kind(&self) -> Option<PrefixOp> { | 568 | pub fn op_kind(&self) -> Option<PrefixOp> { |
531 | match self.syntax().first_child()?.kind() { | 569 | match self.op_token()?.kind() { |
532 | STAR => Some(PrefixOp::Deref), | 570 | STAR => Some(PrefixOp::Deref), |
533 | EXCL => Some(PrefixOp::Not), | 571 | EXCL => Some(PrefixOp::Not), |
534 | MINUS => Some(PrefixOp::Neg), | 572 | MINUS => Some(PrefixOp::Neg), |
@@ -536,8 +574,8 @@ impl PrefixExpr { | |||
536 | } | 574 | } |
537 | } | 575 | } |
538 | 576 | ||
539 | pub fn op(&self) -> Option<&SyntaxNode> { | 577 | pub fn op_token(&self) -> Option<SyntaxToken> { |
540 | self.syntax().first_child() | 578 | self.syntax().first_child_or_token()?.as_token() |
541 | } | 579 | } |
542 | } | 580 | } |
543 | 581 | ||
@@ -608,40 +646,42 @@ pub enum BinOp { | |||
608 | } | 646 | } |
609 | 647 | ||
610 | impl BinExpr { | 648 | impl BinExpr { |
611 | fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> { | 649 | fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { |
612 | self.syntax().children().find_map(|c| match c.kind() { | 650 | self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { |
613 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | 651 | match c.kind() { |
614 | AMPAMP => Some((c, BinOp::BooleanAnd)), | 652 | PIPEPIPE => Some((c, BinOp::BooleanOr)), |
615 | EQEQ => Some((c, BinOp::EqualityTest)), | 653 | AMPAMP => Some((c, BinOp::BooleanAnd)), |
616 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | 654 | EQEQ => Some((c, BinOp::EqualityTest)), |
617 | LTEQ => Some((c, BinOp::LesserEqualTest)), | 655 | NEQ => Some((c, BinOp::NegatedEqualityTest)), |
618 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | 656 | LTEQ => Some((c, BinOp::LesserEqualTest)), |
619 | L_ANGLE => Some((c, BinOp::LesserTest)), | 657 | GTEQ => Some((c, BinOp::GreaterEqualTest)), |
620 | R_ANGLE => Some((c, BinOp::GreaterTest)), | 658 | L_ANGLE => Some((c, BinOp::LesserTest)), |
621 | PLUS => Some((c, BinOp::Addition)), | 659 | R_ANGLE => Some((c, BinOp::GreaterTest)), |
622 | STAR => Some((c, BinOp::Multiplication)), | 660 | PLUS => Some((c, BinOp::Addition)), |
623 | MINUS => Some((c, BinOp::Subtraction)), | 661 | STAR => Some((c, BinOp::Multiplication)), |
624 | SLASH => Some((c, BinOp::Division)), | 662 | MINUS => Some((c, BinOp::Subtraction)), |
625 | PERCENT => Some((c, BinOp::Remainder)), | 663 | SLASH => Some((c, BinOp::Division)), |
626 | SHL => Some((c, BinOp::LeftShift)), | 664 | PERCENT => Some((c, BinOp::Remainder)), |
627 | SHR => Some((c, BinOp::RightShift)), | 665 | SHL => Some((c, BinOp::LeftShift)), |
628 | CARET => Some((c, BinOp::BitwiseXor)), | 666 | SHR => Some((c, BinOp::RightShift)), |
629 | PIPE => Some((c, BinOp::BitwiseOr)), | 667 | CARET => Some((c, BinOp::BitwiseXor)), |
630 | AMP => Some((c, BinOp::BitwiseAnd)), | 668 | PIPE => Some((c, BinOp::BitwiseOr)), |
631 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | 669 | AMP => Some((c, BinOp::BitwiseAnd)), |
632 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | 670 | DOTDOT => Some((c, BinOp::RangeRightOpen)), |
633 | EQ => Some((c, BinOp::Assignment)), | 671 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), |
634 | PLUSEQ => Some((c, BinOp::AddAssign)), | 672 | EQ => Some((c, BinOp::Assignment)), |
635 | SLASHEQ => Some((c, BinOp::DivAssign)), | 673 | PLUSEQ => Some((c, BinOp::AddAssign)), |
636 | STAREQ => Some((c, BinOp::MulAssign)), | 674 | SLASHEQ => Some((c, BinOp::DivAssign)), |
637 | PERCENTEQ => Some((c, BinOp::RemAssign)), | 675 | STAREQ => Some((c, BinOp::MulAssign)), |
638 | SHREQ => Some((c, BinOp::ShrAssign)), | 676 | PERCENTEQ => Some((c, BinOp::RemAssign)), |
639 | SHLEQ => Some((c, BinOp::ShlAssign)), | 677 | SHREQ => Some((c, BinOp::ShrAssign)), |
640 | MINUSEQ => Some((c, BinOp::SubAssign)), | 678 | SHLEQ => Some((c, BinOp::ShlAssign)), |
641 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | 679 | MINUSEQ => Some((c, BinOp::SubAssign)), |
642 | AMPEQ => Some((c, BinOp::BitAndAssign)), | 680 | PIPEEQ => Some((c, BinOp::BitOrAssign)), |
643 | CARETEQ => Some((c, BinOp::BitXorAssign)), | 681 | AMPEQ => Some((c, BinOp::BitAndAssign)), |
644 | _ => None, | 682 | CARETEQ => Some((c, BinOp::BitXorAssign)), |
683 | _ => None, | ||
684 | } | ||
645 | }) | 685 | }) |
646 | } | 686 | } |
647 | 687 | ||
@@ -649,7 +689,7 @@ impl BinExpr { | |||
649 | self.op_details().map(|t| t.1) | 689 | self.op_details().map(|t| t.1) |
650 | } | 690 | } |
651 | 691 | ||
652 | pub fn op(&self) -> Option<&SyntaxNode> { | 692 | pub fn op_token(&self) -> Option<SyntaxToken> { |
653 | self.op_details().map(|t| t.0) | 693 | self.op_details().map(|t| t.0) |
654 | } | 694 | } |
655 | 695 | ||
@@ -680,11 +720,23 @@ pub enum SelfParamFlavor { | |||
680 | } | 720 | } |
681 | 721 | ||
682 | impl SelfParam { | 722 | impl SelfParam { |
723 | pub fn self_kw_token(&self) -> SyntaxToken { | ||
724 | self.syntax() | ||
725 | .children_with_tokens() | ||
726 | .filter_map(|it| it.as_token()) | ||
727 | .find(|it| it.kind() == SELF_KW) | ||
728 | .expect("invalid tree: self param must have self") | ||
729 | } | ||
730 | |||
683 | pub fn flavor(&self) -> SelfParamFlavor { | 731 | pub fn flavor(&self) -> SelfParamFlavor { |
684 | let borrowed = self.syntax().children().any(|n| n.kind() == AMP); | 732 | let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP); |
685 | if borrowed { | 733 | if borrowed { |
686 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | 734 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` |
687 | if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW) | 735 | if self |
736 | .syntax() | ||
737 | .children_with_tokens() | ||
738 | .skip_while(|n| n.kind() != AMP) | ||
739 | .any(|n| n.kind() == MUT_KW) | ||
688 | { | 740 | { |
689 | SelfParamFlavor::MutRef | 741 | SelfParamFlavor::MutRef |
690 | } else { | 742 | } else { |
@@ -707,25 +759,31 @@ pub enum LiteralFlavor { | |||
707 | Bool, | 759 | Bool, |
708 | } | 760 | } |
709 | 761 | ||
710 | impl LiteralExpr { | 762 | impl Literal { |
763 | pub fn token(&self) -> SyntaxToken { | ||
764 | match self.syntax().first_child_or_token().unwrap() { | ||
765 | SyntaxElement::Token(token) => token, | ||
766 | _ => unreachable!(), | ||
767 | } | ||
768 | } | ||
769 | |||
711 | pub fn flavor(&self) -> LiteralFlavor { | 770 | pub fn flavor(&self) -> LiteralFlavor { |
712 | let syntax = self.syntax(); | 771 | match self.token().kind() { |
713 | match syntax.kind() { | ||
714 | INT_NUMBER => { | 772 | INT_NUMBER => { |
715 | let allowed_suffix_list = [ | 773 | let allowed_suffix_list = [ |
716 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | 774 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", |
717 | "u16", "u8", | 775 | "u16", "u8", |
718 | ]; | 776 | ]; |
719 | let text = syntax.text().to_string(); | 777 | let text = self.token().text().to_string(); |
720 | let suffix = allowed_suffix_list | 778 | let suffix = allowed_suffix_list |
721 | .iter() | 779 | .iter() |
722 | .find(|&s| text.ends_with(s)) | 780 | .find(|&s| text.ends_with(s)) |
723 | .map(|&suf| SmolStr::new(suf)); | 781 | .map(|&suf| SmolStr::new(suf)); |
724 | LiteralFlavor::IntNumber { suffix: suffix } | 782 | LiteralFlavor::IntNumber { suffix } |
725 | } | 783 | } |
726 | FLOAT_NUMBER => { | 784 | FLOAT_NUMBER => { |
727 | let allowed_suffix_list = ["f64", "f32"]; | 785 | let allowed_suffix_list = ["f64", "f32"]; |
728 | let text = syntax.text().to_string(); | 786 | let text = self.token().text().to_string(); |
729 | let suffix = allowed_suffix_list | 787 | let suffix = allowed_suffix_list |
730 | .iter() | 788 | .iter() |
731 | .find(|&s| text.ends_with(s)) | 789 | .find(|&s| text.ends_with(s)) |
@@ -750,11 +808,29 @@ impl NamedField { | |||
750 | 808 | ||
751 | impl BindPat { | 809 | impl BindPat { |
752 | pub fn is_mutable(&self) -> bool { | 810 | pub fn is_mutable(&self) -> bool { |
753 | self.syntax().children().any(|n| n.kind() == MUT_KW) | 811 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
754 | } | 812 | } |
755 | 813 | ||
756 | pub fn is_ref(&self) -> bool { | 814 | pub fn is_ref(&self) -> bool { |
757 | self.syntax().children().any(|n| n.kind() == REF_KW) | 815 | self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW) |
816 | } | ||
817 | } | ||
818 | |||
819 | impl LifetimeParam { | ||
820 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
821 | self.syntax() | ||
822 | .children_with_tokens() | ||
823 | .filter_map(|it| it.as_token()) | ||
824 | .find(|it| it.kind() == LIFETIME) | ||
825 | } | ||
826 | } | ||
827 | |||
828 | impl WherePred { | ||
829 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
830 | self.syntax() | ||
831 | .children_with_tokens() | ||
832 | .filter_map(|it| it.as_token()) | ||
833 | .find(|it| it.kind() == LIFETIME) | ||
758 | } | 834 | } |
759 | } | 835 | } |
760 | 836 | ||
@@ -835,7 +911,7 @@ where | |||
835 | let pred = predicates.next().unwrap(); | 911 | let pred = predicates.next().unwrap(); |
836 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | 912 | let mut bounds = pred.type_bound_list().unwrap().bounds(); |
837 | 913 | ||
838 | assert_eq!("'a", pred.lifetime().unwrap().syntax().text().to_string()); | 914 | assert_eq!("'a", pred.lifetime_token().unwrap().text()); |
839 | 915 | ||
840 | assert_bound("'b", bounds.next()); | 916 | assert_bound("'b", bounds.next()); |
841 | assert_bound("'c", bounds.next()); | 917 | assert_bound("'c", bounds.next()); |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index c51b4caa4..4afe1a146 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -376,64 +376,6 @@ impl BreakExpr { | |||
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | // Byte | ||
380 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
381 | #[repr(transparent)] | ||
382 | pub struct Byte { | ||
383 | pub(crate) syntax: SyntaxNode, | ||
384 | } | ||
385 | unsafe impl TransparentNewType for Byte { | ||
386 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
387 | } | ||
388 | |||
389 | impl AstNode for Byte { | ||
390 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
391 | match syntax.kind() { | ||
392 | BYTE => Some(Byte::from_repr(syntax.into_repr())), | ||
393 | _ => None, | ||
394 | } | ||
395 | } | ||
396 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
397 | } | ||
398 | |||
399 | impl ToOwned for Byte { | ||
400 | type Owned = TreeArc<Byte>; | ||
401 | fn to_owned(&self) -> TreeArc<Byte> { TreeArc::cast(self.syntax.to_owned()) } | ||
402 | } | ||
403 | |||
404 | |||
405 | impl ast::AstToken for Byte {} | ||
406 | impl Byte {} | ||
407 | |||
408 | // ByteString | ||
409 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
410 | #[repr(transparent)] | ||
411 | pub struct ByteString { | ||
412 | pub(crate) syntax: SyntaxNode, | ||
413 | } | ||
414 | unsafe impl TransparentNewType for ByteString { | ||
415 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
416 | } | ||
417 | |||
418 | impl AstNode for ByteString { | ||
419 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
420 | match syntax.kind() { | ||
421 | BYTE_STRING => Some(ByteString::from_repr(syntax.into_repr())), | ||
422 | _ => None, | ||
423 | } | ||
424 | } | ||
425 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
426 | } | ||
427 | |||
428 | impl ToOwned for ByteString { | ||
429 | type Owned = TreeArc<ByteString>; | ||
430 | fn to_owned(&self) -> TreeArc<ByteString> { TreeArc::cast(self.syntax.to_owned()) } | ||
431 | } | ||
432 | |||
433 | |||
434 | impl ast::AstToken for ByteString {} | ||
435 | impl ByteString {} | ||
436 | |||
437 | // CallExpr | 379 | // CallExpr |
438 | #[derive(Debug, PartialEq, Eq, Hash)] | 380 | #[derive(Debug, PartialEq, Eq, Hash)] |
439 | #[repr(transparent)] | 381 | #[repr(transparent)] |
@@ -503,64 +445,6 @@ impl CastExpr { | |||
503 | } | 445 | } |
504 | } | 446 | } |
505 | 447 | ||
506 | // Char | ||
507 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
508 | #[repr(transparent)] | ||
509 | pub struct Char { | ||
510 | pub(crate) syntax: SyntaxNode, | ||
511 | } | ||
512 | unsafe impl TransparentNewType for Char { | ||
513 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
514 | } | ||
515 | |||
516 | impl AstNode for Char { | ||
517 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
518 | match syntax.kind() { | ||
519 | CHAR => Some(Char::from_repr(syntax.into_repr())), | ||
520 | _ => None, | ||
521 | } | ||
522 | } | ||
523 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
524 | } | ||
525 | |||
526 | impl ToOwned for Char { | ||
527 | type Owned = TreeArc<Char>; | ||
528 | fn to_owned(&self) -> TreeArc<Char> { TreeArc::cast(self.syntax.to_owned()) } | ||
529 | } | ||
530 | |||
531 | |||
532 | impl ast::AstToken for Char {} | ||
533 | impl Char {} | ||
534 | |||
535 | // Comment | ||
536 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
537 | #[repr(transparent)] | ||
538 | pub struct Comment { | ||
539 | pub(crate) syntax: SyntaxNode, | ||
540 | } | ||
541 | unsafe impl TransparentNewType for Comment { | ||
542 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
543 | } | ||
544 | |||
545 | impl AstNode for Comment { | ||
546 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
547 | match syntax.kind() { | ||
548 | COMMENT => Some(Comment::from_repr(syntax.into_repr())), | ||
549 | _ => None, | ||
550 | } | ||
551 | } | ||
552 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
553 | } | ||
554 | |||
555 | impl ToOwned for Comment { | ||
556 | type Owned = TreeArc<Comment>; | ||
557 | fn to_owned(&self) -> TreeArc<Comment> { TreeArc::cast(self.syntax.to_owned()) } | ||
558 | } | ||
559 | |||
560 | |||
561 | impl ast::AstToken for Comment {} | ||
562 | impl Comment {} | ||
563 | |||
564 | // Condition | 448 | // Condition |
565 | #[derive(Debug, PartialEq, Eq, Hash)] | 449 | #[derive(Debug, PartialEq, Eq, Hash)] |
566 | #[repr(transparent)] | 450 | #[repr(transparent)] |
@@ -1115,35 +999,6 @@ impl ExternCrateItem { | |||
1115 | } | 999 | } |
1116 | } | 1000 | } |
1117 | 1001 | ||
1118 | // FalseKw | ||
1119 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1120 | #[repr(transparent)] | ||
1121 | pub struct FalseKw { | ||
1122 | pub(crate) syntax: SyntaxNode, | ||
1123 | } | ||
1124 | unsafe impl TransparentNewType for FalseKw { | ||
1125 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1126 | } | ||
1127 | |||
1128 | impl AstNode for FalseKw { | ||
1129 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1130 | match syntax.kind() { | ||
1131 | FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())), | ||
1132 | _ => None, | ||
1133 | } | ||
1134 | } | ||
1135 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1136 | } | ||
1137 | |||
1138 | impl ToOwned for FalseKw { | ||
1139 | type Owned = TreeArc<FalseKw>; | ||
1140 | fn to_owned(&self) -> TreeArc<FalseKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | impl ast::AstToken for FalseKw {} | ||
1145 | impl FalseKw {} | ||
1146 | |||
1147 | // FieldExpr | 1002 | // FieldExpr |
1148 | #[derive(Debug, PartialEq, Eq, Hash)] | 1003 | #[derive(Debug, PartialEq, Eq, Hash)] |
1149 | #[repr(transparent)] | 1004 | #[repr(transparent)] |
@@ -1249,35 +1104,6 @@ impl FieldPatList { | |||
1249 | } | 1104 | } |
1250 | } | 1105 | } |
1251 | 1106 | ||
1252 | // FloatNumber | ||
1253 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1254 | #[repr(transparent)] | ||
1255 | pub struct FloatNumber { | ||
1256 | pub(crate) syntax: SyntaxNode, | ||
1257 | } | ||
1258 | unsafe impl TransparentNewType for FloatNumber { | ||
1259 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1260 | } | ||
1261 | |||
1262 | impl AstNode for FloatNumber { | ||
1263 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1264 | match syntax.kind() { | ||
1265 | FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())), | ||
1266 | _ => None, | ||
1267 | } | ||
1268 | } | ||
1269 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1270 | } | ||
1271 | |||
1272 | impl ToOwned for FloatNumber { | ||
1273 | type Owned = TreeArc<FloatNumber>; | ||
1274 | fn to_owned(&self) -> TreeArc<FloatNumber> { TreeArc::cast(self.syntax.to_owned()) } | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | impl ast::AstToken for FloatNumber {} | ||
1279 | impl FloatNumber {} | ||
1280 | |||
1281 | // FnDef | 1107 | // FnDef |
1282 | #[derive(Debug, PartialEq, Eq, Hash)] | 1108 | #[derive(Debug, PartialEq, Eq, Hash)] |
1283 | #[repr(transparent)] | 1109 | #[repr(transparent)] |
@@ -1613,35 +1439,6 @@ impl ToOwned for IndexExpr { | |||
1613 | 1439 | ||
1614 | impl IndexExpr {} | 1440 | impl IndexExpr {} |
1615 | 1441 | ||
1616 | // IntNumber | ||
1617 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1618 | #[repr(transparent)] | ||
1619 | pub struct IntNumber { | ||
1620 | pub(crate) syntax: SyntaxNode, | ||
1621 | } | ||
1622 | unsafe impl TransparentNewType for IntNumber { | ||
1623 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1624 | } | ||
1625 | |||
1626 | impl AstNode for IntNumber { | ||
1627 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1628 | match syntax.kind() { | ||
1629 | INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())), | ||
1630 | _ => None, | ||
1631 | } | ||
1632 | } | ||
1633 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1634 | } | ||
1635 | |||
1636 | impl ToOwned for IntNumber { | ||
1637 | type Owned = TreeArc<IntNumber>; | ||
1638 | fn to_owned(&self) -> TreeArc<IntNumber> { TreeArc::cast(self.syntax.to_owned()) } | ||
1639 | } | ||
1640 | |||
1641 | |||
1642 | impl ast::AstToken for IntNumber {} | ||
1643 | impl IntNumber {} | ||
1644 | |||
1645 | // ItemList | 1442 | // ItemList |
1646 | #[derive(Debug, PartialEq, Eq, Hash)] | 1443 | #[derive(Debug, PartialEq, Eq, Hash)] |
1647 | #[repr(transparent)] | 1444 | #[repr(transparent)] |
@@ -1777,35 +1574,6 @@ impl LetStmt { | |||
1777 | } | 1574 | } |
1778 | } | 1575 | } |
1779 | 1576 | ||
1780 | // Lifetime | ||
1781 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1782 | #[repr(transparent)] | ||
1783 | pub struct Lifetime { | ||
1784 | pub(crate) syntax: SyntaxNode, | ||
1785 | } | ||
1786 | unsafe impl TransparentNewType for Lifetime { | ||
1787 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1788 | } | ||
1789 | |||
1790 | impl AstNode for Lifetime { | ||
1791 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1792 | match syntax.kind() { | ||
1793 | LIFETIME => Some(Lifetime::from_repr(syntax.into_repr())), | ||
1794 | _ => None, | ||
1795 | } | ||
1796 | } | ||
1797 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1798 | } | ||
1799 | |||
1800 | impl ToOwned for Lifetime { | ||
1801 | type Owned = TreeArc<Lifetime>; | ||
1802 | fn to_owned(&self) -> TreeArc<Lifetime> { TreeArc::cast(self.syntax.to_owned()) } | ||
1803 | } | ||
1804 | |||
1805 | |||
1806 | impl ast::AstToken for Lifetime {} | ||
1807 | impl Lifetime {} | ||
1808 | |||
1809 | // LifetimeArg | 1577 | // LifetimeArg |
1810 | #[derive(Debug, PartialEq, Eq, Hash)] | 1578 | #[derive(Debug, PartialEq, Eq, Hash)] |
1811 | #[repr(transparent)] | 1579 | #[repr(transparent)] |
@@ -1832,11 +1600,7 @@ impl ToOwned for LifetimeArg { | |||
1832 | } | 1600 | } |
1833 | 1601 | ||
1834 | 1602 | ||
1835 | impl LifetimeArg { | 1603 | impl LifetimeArg {} |
1836 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1837 | super::child_opt(self) | ||
1838 | } | ||
1839 | } | ||
1840 | 1604 | ||
1841 | // LifetimeParam | 1605 | // LifetimeParam |
1842 | #[derive(Debug, PartialEq, Eq, Hash)] | 1606 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -1865,11 +1629,7 @@ impl ToOwned for LifetimeParam { | |||
1865 | 1629 | ||
1866 | 1630 | ||
1867 | impl ast::AttrsOwner for LifetimeParam {} | 1631 | impl ast::AttrsOwner for LifetimeParam {} |
1868 | impl LifetimeParam { | 1632 | impl LifetimeParam {} |
1869 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1870 | super::child_opt(self) | ||
1871 | } | ||
1872 | } | ||
1873 | 1633 | ||
1874 | // Literal | 1634 | // Literal |
1875 | #[derive(Debug, PartialEq, Eq, Hash)] | 1635 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -1897,130 +1657,7 @@ impl ToOwned for Literal { | |||
1897 | } | 1657 | } |
1898 | 1658 | ||
1899 | 1659 | ||
1900 | impl Literal { | 1660 | impl Literal {} |
1901 | pub fn literal_expr(&self) -> Option<&LiteralExpr> { | ||
1902 | super::child_opt(self) | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | // LiteralExpr | ||
1907 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1908 | #[repr(transparent)] | ||
1909 | pub struct LiteralExpr { | ||
1910 | pub(crate) syntax: SyntaxNode, | ||
1911 | } | ||
1912 | unsafe impl TransparentNewType for LiteralExpr { | ||
1913 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1914 | } | ||
1915 | |||
1916 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
1917 | pub enum LiteralExprKind<'a> { | ||
1918 | String(&'a String), | ||
1919 | ByteString(&'a ByteString), | ||
1920 | RawString(&'a RawString), | ||
1921 | RawByteString(&'a RawByteString), | ||
1922 | Char(&'a Char), | ||
1923 | Byte(&'a Byte), | ||
1924 | IntNumber(&'a IntNumber), | ||
1925 | FloatNumber(&'a FloatNumber), | ||
1926 | TrueKw(&'a TrueKw), | ||
1927 | FalseKw(&'a FalseKw), | ||
1928 | } | ||
1929 | impl<'a> From<&'a String> for &'a LiteralExpr { | ||
1930 | fn from(n: &'a String) -> &'a LiteralExpr { | ||
1931 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1932 | } | ||
1933 | } | ||
1934 | impl<'a> From<&'a ByteString> for &'a LiteralExpr { | ||
1935 | fn from(n: &'a ByteString) -> &'a LiteralExpr { | ||
1936 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1937 | } | ||
1938 | } | ||
1939 | impl<'a> From<&'a RawString> for &'a LiteralExpr { | ||
1940 | fn from(n: &'a RawString) -> &'a LiteralExpr { | ||
1941 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1942 | } | ||
1943 | } | ||
1944 | impl<'a> From<&'a RawByteString> for &'a LiteralExpr { | ||
1945 | fn from(n: &'a RawByteString) -> &'a LiteralExpr { | ||
1946 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1947 | } | ||
1948 | } | ||
1949 | impl<'a> From<&'a Char> for &'a LiteralExpr { | ||
1950 | fn from(n: &'a Char) -> &'a LiteralExpr { | ||
1951 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1952 | } | ||
1953 | } | ||
1954 | impl<'a> From<&'a Byte> for &'a LiteralExpr { | ||
1955 | fn from(n: &'a Byte) -> &'a LiteralExpr { | ||
1956 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1957 | } | ||
1958 | } | ||
1959 | impl<'a> From<&'a IntNumber> for &'a LiteralExpr { | ||
1960 | fn from(n: &'a IntNumber) -> &'a LiteralExpr { | ||
1961 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1962 | } | ||
1963 | } | ||
1964 | impl<'a> From<&'a FloatNumber> for &'a LiteralExpr { | ||
1965 | fn from(n: &'a FloatNumber) -> &'a LiteralExpr { | ||
1966 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1967 | } | ||
1968 | } | ||
1969 | impl<'a> From<&'a TrueKw> for &'a LiteralExpr { | ||
1970 | fn from(n: &'a TrueKw) -> &'a LiteralExpr { | ||
1971 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1972 | } | ||
1973 | } | ||
1974 | impl<'a> From<&'a FalseKw> for &'a LiteralExpr { | ||
1975 | fn from(n: &'a FalseKw) -> &'a LiteralExpr { | ||
1976 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1977 | } | ||
1978 | } | ||
1979 | |||
1980 | |||
1981 | impl AstNode for LiteralExpr { | ||
1982 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1983 | match syntax.kind() { | ||
1984 | | STRING | ||
1985 | | BYTE_STRING | ||
1986 | | RAW_STRING | ||
1987 | | RAW_BYTE_STRING | ||
1988 | | CHAR | ||
1989 | | BYTE | ||
1990 | | INT_NUMBER | ||
1991 | | FLOAT_NUMBER | ||
1992 | | TRUE_KW | ||
1993 | | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())), | ||
1994 | _ => None, | ||
1995 | } | ||
1996 | } | ||
1997 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1998 | } | ||
1999 | |||
2000 | impl ToOwned for LiteralExpr { | ||
2001 | type Owned = TreeArc<LiteralExpr>; | ||
2002 | fn to_owned(&self) -> TreeArc<LiteralExpr> { TreeArc::cast(self.syntax.to_owned()) } | ||
2003 | } | ||
2004 | |||
2005 | impl LiteralExpr { | ||
2006 | pub fn kind(&self) -> LiteralExprKind { | ||
2007 | match self.syntax.kind() { | ||
2008 | STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()), | ||
2009 | BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()), | ||
2010 | RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()), | ||
2011 | RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()), | ||
2012 | CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()), | ||
2013 | BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()), | ||
2014 | INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), | ||
2015 | FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), | ||
2016 | TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()), | ||
2017 | FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()), | ||
2018 | _ => unreachable!(), | ||
2019 | } | ||
2020 | } | ||
2021 | } | ||
2022 | |||
2023 | impl LiteralExpr {} | ||
2024 | 1661 | ||
2025 | // LiteralPat | 1662 | // LiteralPat |
2026 | #[derive(Debug, PartialEq, Eq, Hash)] | 1663 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3404,64 +3041,6 @@ impl ToOwned for RangePat { | |||
3404 | 3041 | ||
3405 | impl RangePat {} | 3042 | impl RangePat {} |
3406 | 3043 | ||
3407 | // RawByteString | ||
3408 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3409 | #[repr(transparent)] | ||
3410 | pub struct RawByteString { | ||
3411 | pub(crate) syntax: SyntaxNode, | ||
3412 | } | ||
3413 | unsafe impl TransparentNewType for RawByteString { | ||
3414 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3415 | } | ||
3416 | |||
3417 | impl AstNode for RawByteString { | ||
3418 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3419 | match syntax.kind() { | ||
3420 | RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())), | ||
3421 | _ => None, | ||
3422 | } | ||
3423 | } | ||
3424 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3425 | } | ||
3426 | |||
3427 | impl ToOwned for RawByteString { | ||
3428 | type Owned = TreeArc<RawByteString>; | ||
3429 | fn to_owned(&self) -> TreeArc<RawByteString> { TreeArc::cast(self.syntax.to_owned()) } | ||
3430 | } | ||
3431 | |||
3432 | |||
3433 | impl ast::AstToken for RawByteString {} | ||
3434 | impl RawByteString {} | ||
3435 | |||
3436 | // RawString | ||
3437 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3438 | #[repr(transparent)] | ||
3439 | pub struct RawString { | ||
3440 | pub(crate) syntax: SyntaxNode, | ||
3441 | } | ||
3442 | unsafe impl TransparentNewType for RawString { | ||
3443 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3444 | } | ||
3445 | |||
3446 | impl AstNode for RawString { | ||
3447 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3448 | match syntax.kind() { | ||
3449 | RAW_STRING => Some(RawString::from_repr(syntax.into_repr())), | ||
3450 | _ => None, | ||
3451 | } | ||
3452 | } | ||
3453 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3454 | } | ||
3455 | |||
3456 | impl ToOwned for RawString { | ||
3457 | type Owned = TreeArc<RawString>; | ||
3458 | fn to_owned(&self) -> TreeArc<RawString> { TreeArc::cast(self.syntax.to_owned()) } | ||
3459 | } | ||
3460 | |||
3461 | |||
3462 | impl ast::AstToken for RawString {} | ||
3463 | impl RawString {} | ||
3464 | |||
3465 | // RefExpr | 3044 | // RefExpr |
3466 | #[derive(Debug, PartialEq, Eq, Hash)] | 3045 | #[derive(Debug, PartialEq, Eq, Hash)] |
3467 | #[repr(transparent)] | 3046 | #[repr(transparent)] |
@@ -3622,34 +3201,6 @@ impl ReturnExpr { | |||
3622 | } | 3201 | } |
3623 | } | 3202 | } |
3624 | 3203 | ||
3625 | // SelfKw | ||
3626 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3627 | #[repr(transparent)] | ||
3628 | pub struct SelfKw { | ||
3629 | pub(crate) syntax: SyntaxNode, | ||
3630 | } | ||
3631 | unsafe impl TransparentNewType for SelfKw { | ||
3632 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3633 | } | ||
3634 | |||
3635 | impl AstNode for SelfKw { | ||
3636 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3637 | match syntax.kind() { | ||
3638 | SELF_KW => Some(SelfKw::from_repr(syntax.into_repr())), | ||
3639 | _ => None, | ||
3640 | } | ||
3641 | } | ||
3642 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3643 | } | ||
3644 | |||
3645 | impl ToOwned for SelfKw { | ||
3646 | type Owned = TreeArc<SelfKw>; | ||
3647 | fn to_owned(&self) -> TreeArc<SelfKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
3648 | } | ||
3649 | |||
3650 | |||
3651 | impl SelfKw {} | ||
3652 | |||
3653 | // SelfParam | 3204 | // SelfParam |
3654 | #[derive(Debug, PartialEq, Eq, Hash)] | 3205 | #[derive(Debug, PartialEq, Eq, Hash)] |
3655 | #[repr(transparent)] | 3206 | #[repr(transparent)] |
@@ -3677,11 +3228,7 @@ impl ToOwned for SelfParam { | |||
3677 | 3228 | ||
3678 | 3229 | ||
3679 | impl ast::TypeAscriptionOwner for SelfParam {} | 3230 | impl ast::TypeAscriptionOwner for SelfParam {} |
3680 | impl SelfParam { | 3231 | impl SelfParam {} |
3681 | pub fn self_kw(&self) -> Option<&SelfKw> { | ||
3682 | super::child_opt(self) | ||
3683 | } | ||
3684 | } | ||
3685 | 3232 | ||
3686 | // SlicePat | 3233 | // SlicePat |
3687 | #[derive(Debug, PartialEq, Eq, Hash)] | 3234 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3866,35 +3413,6 @@ impl Stmt { | |||
3866 | 3413 | ||
3867 | impl Stmt {} | 3414 | impl Stmt {} |
3868 | 3415 | ||
3869 | // String | ||
3870 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3871 | #[repr(transparent)] | ||
3872 | pub struct String { | ||
3873 | pub(crate) syntax: SyntaxNode, | ||
3874 | } | ||
3875 | unsafe impl TransparentNewType for String { | ||
3876 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3877 | } | ||
3878 | |||
3879 | impl AstNode for String { | ||
3880 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3881 | match syntax.kind() { | ||
3882 | STRING => Some(String::from_repr(syntax.into_repr())), | ||
3883 | _ => None, | ||
3884 | } | ||
3885 | } | ||
3886 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3887 | } | ||
3888 | |||
3889 | impl ToOwned for String { | ||
3890 | type Owned = TreeArc<String>; | ||
3891 | fn to_owned(&self) -> TreeArc<String> { TreeArc::cast(self.syntax.to_owned()) } | ||
3892 | } | ||
3893 | |||
3894 | |||
3895 | impl ast::AstToken for String {} | ||
3896 | impl String {} | ||
3897 | |||
3898 | // StructDef | 3416 | // StructDef |
3899 | #[derive(Debug, PartialEq, Eq, Hash)] | 3417 | #[derive(Debug, PartialEq, Eq, Hash)] |
3900 | #[repr(transparent)] | 3418 | #[repr(transparent)] |
@@ -4070,35 +3588,6 @@ impl TraitDef { | |||
4070 | } | 3588 | } |
4071 | } | 3589 | } |
4072 | 3590 | ||
4073 | // TrueKw | ||
4074 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
4075 | #[repr(transparent)] | ||
4076 | pub struct TrueKw { | ||
4077 | pub(crate) syntax: SyntaxNode, | ||
4078 | } | ||
4079 | unsafe impl TransparentNewType for TrueKw { | ||
4080 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
4081 | } | ||
4082 | |||
4083 | impl AstNode for TrueKw { | ||
4084 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
4085 | match syntax.kind() { | ||
4086 | TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())), | ||
4087 | _ => None, | ||
4088 | } | ||
4089 | } | ||
4090 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
4091 | } | ||
4092 | |||
4093 | impl ToOwned for TrueKw { | ||
4094 | type Owned = TreeArc<TrueKw>; | ||
4095 | fn to_owned(&self) -> TreeArc<TrueKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
4096 | } | ||
4097 | |||
4098 | |||
4099 | impl ast::AstToken for TrueKw {} | ||
4100 | impl TrueKw {} | ||
4101 | |||
4102 | // TryExpr | 3591 | // TryExpr |
4103 | #[derive(Debug, PartialEq, Eq, Hash)] | 3592 | #[derive(Debug, PartialEq, Eq, Hash)] |
4104 | #[repr(transparent)] | 3593 | #[repr(transparent)] |
@@ -4403,10 +3892,6 @@ impl TypeBound { | |||
4403 | pub fn type_ref(&self) -> Option<&TypeRef> { | 3892 | pub fn type_ref(&self) -> Option<&TypeRef> { |
4404 | super::child_opt(self) | 3893 | super::child_opt(self) |
4405 | } | 3894 | } |
4406 | |||
4407 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
4408 | super::child_opt(self) | ||
4409 | } | ||
4410 | } | 3895 | } |
4411 | 3896 | ||
4412 | // TypeBoundList | 3897 | // TypeBoundList |
@@ -4847,10 +4332,6 @@ impl WherePred { | |||
4847 | pub fn type_ref(&self) -> Option<&TypeRef> { | 4332 | pub fn type_ref(&self) -> Option<&TypeRef> { |
4848 | super::child_opt(self) | 4333 | super::child_opt(self) |
4849 | } | 4334 | } |
4850 | |||
4851 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
4852 | super::child_opt(self) | ||
4853 | } | ||
4854 | } | 4335 | } |
4855 | 4336 | ||
4856 | // WhileExpr | 4337 | // WhileExpr |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 1123c2e95..6d7a5a1cb 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -463,31 +463,7 @@ Grammar( | |||
463 | "RangeExpr": (), | 463 | "RangeExpr": (), |
464 | "BinExpr": (), | 464 | "BinExpr": (), |
465 | 465 | ||
466 | "IntNumber": ( traits: ["AstToken"] ), | 466 | "Literal": (), |
467 | "FloatNumber": ( traits: ["AstToken"] ), | ||
468 | "String": ( traits: ["AstToken"] ), | ||
469 | "RawString": ( traits: ["AstToken"] ), | ||
470 | "Byte": ( traits: ["AstToken"] ), | ||
471 | "RawByteString": ( traits: ["AstToken"] ), | ||
472 | "ByteString": ( traits: ["AstToken"] ), | ||
473 | "Char": ( traits: ["AstToken"] ), | ||
474 | "TrueKw": ( traits: ["AstToken"] ), | ||
475 | "FalseKw": ( traits: ["AstToken"] ), | ||
476 | "LiteralExpr": ( | ||
477 | enum: [ | ||
478 | "String", | ||
479 | "ByteString", | ||
480 | "RawString", | ||
481 | "RawByteString", | ||
482 | "Char", | ||
483 | "Byte", | ||
484 | "IntNumber", | ||
485 | "FloatNumber", | ||
486 | "TrueKw", | ||
487 | "FalseKw", | ||
488 | ] | ||
489 | ), | ||
490 | "Literal": (options: ["LiteralExpr"]), | ||
491 | 467 | ||
492 | "Expr": ( | 468 | "Expr": ( |
493 | enum: [ | 469 | enum: [ |
@@ -580,14 +556,11 @@ Grammar( | |||
580 | ), | 556 | ), |
581 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ), | 557 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ), |
582 | "LifetimeParam": ( | 558 | "LifetimeParam": ( |
583 | options: [ "Lifetime"], | ||
584 | traits: ["AttrsOwner"], | 559 | traits: ["AttrsOwner"], |
585 | ), | 560 | ), |
586 | "Lifetime": ( traits: ["AstToken"] ), | ||
587 | "TypeBound": ( | 561 | "TypeBound": ( |
588 | options: [ | 562 | options: [ |
589 | "TypeRef", | 563 | "TypeRef", |
590 | "Lifetime", | ||
591 | ] | 564 | ] |
592 | ), | 565 | ), |
593 | "TypeBoundList": ( | 566 | "TypeBoundList": ( |
@@ -598,7 +571,6 @@ Grammar( | |||
598 | "WherePred": ( | 571 | "WherePred": ( |
599 | options: [ | 572 | options: [ |
600 | "TypeRef", | 573 | "TypeRef", |
601 | "Lifetime", | ||
602 | ], | 574 | ], |
603 | traits: [ | 575 | traits: [ |
604 | "TypeBoundsOwner", | 576 | "TypeBoundsOwner", |
@@ -643,12 +615,10 @@ Grammar( | |||
643 | ] | 615 | ] |
644 | ), | 616 | ), |
645 | "SelfParam": ( | 617 | "SelfParam": ( |
646 | options: ["SelfKw"], | ||
647 | traits: [ | 618 | traits: [ |
648 | "TypeAscriptionOwner", | 619 | "TypeAscriptionOwner", |
649 | ] | 620 | ] |
650 | ), | 621 | ), |
651 | "SelfKw": (), | ||
652 | "Param": ( | 622 | "Param": ( |
653 | options: [ "Pat" ], | 623 | options: [ "Pat" ], |
654 | traits: [ | 624 | traits: [ |
@@ -692,8 +662,7 @@ Grammar( | |||
692 | ]), | 662 | ]), |
693 | "TypeArg": (options: ["TypeRef"]), | 663 | "TypeArg": (options: ["TypeRef"]), |
694 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), | 664 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), |
695 | "LifetimeArg": (options: ["Lifetime"]), | 665 | "LifetimeArg": (), |
696 | "Comment": ( traits: ["AstToken"] ), | ||
697 | "Whitespace": ( traits: ["AstToken"] ), | 666 | "Whitespace": ( traits: ["AstToken"] ), |
698 | }, | 667 | }, |
699 | ) | 668 | ) |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 4f3020440..e1088e296 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -38,7 +38,7 @@ pub use crate::{ | |||
38 | ast::AstNode, | 38 | ast::AstNode, |
39 | syntax_error::{SyntaxError, SyntaxErrorKind, Location}, | 39 | syntax_error::{SyntaxError, SyntaxErrorKind, Location}, |
40 | syntax_text::SyntaxText, | 40 | syntax_text::SyntaxText, |
41 | syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder}, | 41 | syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken}, |
42 | ptr::{SyntaxNodePtr, AstPtr}, | 42 | ptr::{SyntaxNodePtr, AstPtr}, |
43 | parsing::{tokenize, Token}, | 43 | parsing::{tokenize, Token}, |
44 | }; | 44 | }; |
@@ -70,7 +70,7 @@ impl SourceFile { | |||
70 | 70 | ||
71 | pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { | 71 | pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { |
72 | parsing::incremental_reparse(self.syntax(), edit, self.errors()) | 72 | parsing::incremental_reparse(self.syntax(), edit, self.errors()) |
73 | .map(|(green_node, errors)| SourceFile::new(green_node, errors)) | 73 | .map(|(green_node, errors, _reparsed_range)| SourceFile::new(green_node, errors)) |
74 | } | 74 | } |
75 | 75 | ||
76 | fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { | 76 | fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { |
@@ -179,15 +179,23 @@ fn api_walkthrough() { | |||
179 | 179 | ||
180 | // There's a bunch of traversal methods on `SyntaxNode`: | 180 | // There's a bunch of traversal methods on `SyntaxNode`: |
181 | assert_eq!(expr_syntax.parent(), Some(block.syntax())); | 181 | assert_eq!(expr_syntax.parent(), Some(block.syntax())); |
182 | assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY)); | 182 | assert_eq!( |
183 | assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE)); | 183 | block.syntax().first_child_or_token().map(|it| it.kind()), |
184 | Some(SyntaxKind::L_CURLY) | ||
185 | ); | ||
186 | assert_eq!( | ||
187 | expr_syntax.next_sibling_or_token().map(|it| it.kind()), | ||
188 | Some(SyntaxKind::WHITESPACE) | ||
189 | ); | ||
184 | 190 | ||
185 | // As well as some iterator helpers: | 191 | // As well as some iterator helpers: |
186 | let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); | 192 | let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); |
187 | assert_eq!(f, Some(&*func)); | 193 | assert_eq!(f, Some(&*func)); |
188 | assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY)); | 194 | assert!(expr_syntax |
195 | .siblings_with_tokens(Direction::Next) | ||
196 | .any(|it| it.kind() == SyntaxKind::R_CURLY)); | ||
189 | assert_eq!( | 197 | assert_eq!( |
190 | expr_syntax.descendants().count(), | 198 | expr_syntax.descendants_with_tokens().count(), |
191 | 8, // 5 tokens `1`, ` `, `+`, ` `, `!` | 199 | 8, // 5 tokens `1`, ` `, `+`, ` `, `!` |
192 | // 2 child literal expressions: `1`, `1` | 200 | // 2 child literal expressions: `1`, `1` |
193 | // 1 the node itself: `1 + 1` | 201 | // 1 the node itself: `1 + 1` |
@@ -196,16 +204,14 @@ fn api_walkthrough() { | |||
196 | // There's also a `preorder` method with a more fine-grained iteration control: | 204 | // There's also a `preorder` method with a more fine-grained iteration control: |
197 | let mut buf = String::new(); | 205 | let mut buf = String::new(); |
198 | let mut indent = 0; | 206 | let mut indent = 0; |
199 | for event in expr_syntax.preorder() { | 207 | for event in expr_syntax.preorder_with_tokens() { |
200 | match event { | 208 | match event { |
201 | WalkEvent::Enter(node) => { | 209 | WalkEvent::Enter(node) => { |
202 | buf += &format!( | 210 | let text = match node { |
203 | "{:indent$}{:?} {:?}\n", | 211 | SyntaxElement::Node(it) => it.text().to_string(), |
204 | " ", | 212 | SyntaxElement::Token(it) => it.text().to_string(), |
205 | node.text(), | 213 | }; |
206 | node.kind(), | 214 | buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent); |
207 | indent = indent | ||
208 | ); | ||
209 | indent += 2; | 215 | indent += 2; |
210 | } | 216 | } |
211 | WalkEvent::Leave(_) => indent -= 2, | 217 | WalkEvent::Leave(_) => indent -= 2, |
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index 7e7f914f5..69887f500 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs | |||
@@ -12,7 +12,7 @@ use ra_parser::Reparser; | |||
12 | use crate::{ | 12 | use crate::{ |
13 | SyntaxKind::*, TextRange, TextUnit, SyntaxError, | 13 | SyntaxKind::*, TextRange, TextUnit, SyntaxError, |
14 | algo, | 14 | algo, |
15 | syntax_node::{GreenNode, SyntaxNode}, | 15 | syntax_node::{GreenNode, SyntaxNode, GreenToken, SyntaxElement}, |
16 | parsing::{ | 16 | parsing::{ |
17 | text_token_source::TextTokenSource, | 17 | text_token_source::TextTokenSource, |
18 | text_tree_sink::TextTreeSink, | 18 | text_tree_sink::TextTreeSink, |
@@ -24,60 +24,62 @@ pub(crate) fn incremental_reparse( | |||
24 | node: &SyntaxNode, | 24 | node: &SyntaxNode, |
25 | edit: &AtomTextEdit, | 25 | edit: &AtomTextEdit, |
26 | errors: Vec<SyntaxError>, | 26 | errors: Vec<SyntaxError>, |
27 | ) -> Option<(GreenNode, Vec<SyntaxError>)> { | 27 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
28 | let (node, green, new_errors) = | 28 | if let Some((green, old_range)) = reparse_token(node, &edit) { |
29 | reparse_leaf(node, &edit).or_else(|| reparse_block(node, &edit))?; | 29 | return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range)); |
30 | let green_root = node.replace_with(green); | 30 | } |
31 | let errors = merge_errors(errors, new_errors, node, edit); | 31 | |
32 | Some((green_root, errors)) | 32 | if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) { |
33 | return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); | ||
34 | } | ||
35 | None | ||
33 | } | 36 | } |
34 | 37 | ||
35 | fn reparse_leaf<'node>( | 38 | fn reparse_token<'node>( |
36 | root: &'node SyntaxNode, | 39 | root: &'node SyntaxNode, |
37 | edit: &AtomTextEdit, | 40 | edit: &AtomTextEdit, |
38 | ) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { | 41 | ) -> Option<(GreenNode, TextRange)> { |
39 | let node = algo::find_covering_node(root, edit.delete); | 42 | let token = algo::find_covering_element(root, edit.delete).as_token()?; |
40 | match node.kind() { | 43 | match token.kind() { |
41 | WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { | 44 | WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { |
42 | if node.kind() == WHITESPACE || node.kind() == COMMENT { | 45 | if token.kind() == WHITESPACE || token.kind() == COMMENT { |
43 | // removing a new line may extends previous token | 46 | // removing a new line may extends previous token |
44 | if node.text().to_string()[edit.delete - node.range().start()].contains('\n') { | 47 | if token.text().to_string()[edit.delete - token.range().start()].contains('\n') { |
45 | return None; | 48 | return None; |
46 | } | 49 | } |
47 | } | 50 | } |
48 | 51 | ||
49 | let text = get_text_after_edit(node, &edit); | 52 | let text = get_text_after_edit(token.into(), &edit); |
50 | let tokens = tokenize(&text); | 53 | let lex_tokens = tokenize(&text); |
51 | let token = match tokens[..] { | 54 | let lex_token = match lex_tokens[..] { |
52 | [token] if token.kind == node.kind() => token, | 55 | [lex_token] if lex_token.kind == token.kind() => lex_token, |
53 | _ => return None, | 56 | _ => return None, |
54 | }; | 57 | }; |
55 | 58 | ||
56 | if token.kind == IDENT && is_contextual_kw(&text) { | 59 | if lex_token.kind == IDENT && is_contextual_kw(&text) { |
57 | return None; | 60 | return None; |
58 | } | 61 | } |
59 | 62 | ||
60 | if let Some(next_char) = root.text().char_at(node.range().end()) { | 63 | if let Some(next_char) = root.text().char_at(token.range().end()) { |
61 | let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); | 64 | let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); |
62 | if tokens_with_next_char.len() == 1 { | 65 | if tokens_with_next_char.len() == 1 { |
63 | return None; | 66 | return None; |
64 | } | 67 | } |
65 | } | 68 | } |
66 | 69 | ||
67 | let green = GreenNode::new_leaf(node.kind(), text.into()); | 70 | let new_token = GreenToken::new(token.kind(), text.into()); |
68 | let new_errors = vec![]; | 71 | Some((token.replace_with(new_token), token.range())) |
69 | Some((node, green, new_errors)) | ||
70 | } | 72 | } |
71 | _ => None, | 73 | _ => None, |
72 | } | 74 | } |
73 | } | 75 | } |
74 | 76 | ||
75 | fn reparse_block<'node>( | 77 | fn reparse_block<'node>( |
76 | node: &'node SyntaxNode, | 78 | root: &'node SyntaxNode, |
77 | edit: &AtomTextEdit, | 79 | edit: &AtomTextEdit, |
78 | ) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { | 80 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
79 | let (node, reparser) = find_reparsable_node(node, edit.delete)?; | 81 | let (node, reparser) = find_reparsable_node(root, edit.delete)?; |
80 | let text = get_text_after_edit(node, &edit); | 82 | let text = get_text_after_edit(node.into(), &edit); |
81 | let tokens = tokenize(&text); | 83 | let tokens = tokenize(&text); |
82 | if !is_balanced(&tokens) { | 84 | if !is_balanced(&tokens) { |
83 | return None; | 85 | return None; |
@@ -86,12 +88,16 @@ fn reparse_block<'node>( | |||
86 | let mut tree_sink = TextTreeSink::new(&text, &tokens); | 88 | let mut tree_sink = TextTreeSink::new(&text, &tokens); |
87 | reparser.parse(&token_source, &mut tree_sink); | 89 | reparser.parse(&token_source, &mut tree_sink); |
88 | let (green, new_errors) = tree_sink.finish(); | 90 | let (green, new_errors) = tree_sink.finish(); |
89 | Some((node, green, new_errors)) | 91 | Some((node.replace_with(green), new_errors, node.range())) |
90 | } | 92 | } |
91 | 93 | ||
92 | fn get_text_after_edit(node: &SyntaxNode, edit: &AtomTextEdit) -> String { | 94 | fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { |
93 | let edit = AtomTextEdit::replace(edit.delete - node.range().start(), edit.insert.clone()); | 95 | let edit = AtomTextEdit::replace(edit.delete - element.range().start(), edit.insert.clone()); |
94 | edit.apply(node.text().to_string()) | 96 | let text = match element { |
97 | SyntaxElement::Token(token) => token.text().to_string(), | ||
98 | SyntaxElement::Node(node) => node.text().to_string(), | ||
99 | }; | ||
100 | edit.apply(text) | ||
95 | } | 101 | } |
96 | 102 | ||
97 | fn is_contextual_kw(text: &str) -> bool { | 103 | fn is_contextual_kw(text: &str) -> bool { |
@@ -102,9 +108,13 @@ fn is_contextual_kw(text: &str) -> bool { | |||
102 | } | 108 | } |
103 | 109 | ||
104 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { | 110 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { |
105 | let node = algo::find_covering_node(node, range); | 111 | let node = algo::find_covering_element(node, range); |
106 | node.ancestors().find_map(|node| { | 112 | let mut ancestors = match node { |
107 | let first_child = node.first_child().map(|it| it.kind()); | 113 | SyntaxElement::Token(it) => it.parent().ancestors(), |
114 | SyntaxElement::Node(it) => it.ancestors(), | ||
115 | }; | ||
116 | ancestors.find_map(|node| { | ||
117 | let first_child = node.first_child_or_token().map(|it| it.kind()); | ||
108 | let parent = node.parent().map(|it| it.kind()); | 118 | let parent = node.parent().map(|it| it.kind()); |
109 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) | 119 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) |
110 | }) | 120 | }) |
@@ -136,19 +146,19 @@ fn is_balanced(tokens: &[Token]) -> bool { | |||
136 | fn merge_errors( | 146 | fn merge_errors( |
137 | old_errors: Vec<SyntaxError>, | 147 | old_errors: Vec<SyntaxError>, |
138 | new_errors: Vec<SyntaxError>, | 148 | new_errors: Vec<SyntaxError>, |
139 | old_node: &SyntaxNode, | 149 | old_range: TextRange, |
140 | edit: &AtomTextEdit, | 150 | edit: &AtomTextEdit, |
141 | ) -> Vec<SyntaxError> { | 151 | ) -> Vec<SyntaxError> { |
142 | let mut res = Vec::new(); | 152 | let mut res = Vec::new(); |
143 | for e in old_errors { | 153 | for e in old_errors { |
144 | if e.offset() <= old_node.range().start() { | 154 | if e.offset() <= old_range.start() { |
145 | res.push(e) | 155 | res.push(e) |
146 | } else if e.offset() >= old_node.range().end() { | 156 | } else if e.offset() >= old_range.end() { |
147 | res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); | 157 | res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); |
148 | } | 158 | } |
149 | } | 159 | } |
150 | for e in new_errors { | 160 | for e in new_errors { |
151 | res.push(e.add_offset(old_node.range().start(), 0.into())); | 161 | res.push(e.add_offset(old_range.start(), 0.into())); |
152 | } | 162 | } |
153 | res | 163 | res |
154 | } | 164 | } |
@@ -160,13 +170,7 @@ mod tests { | |||
160 | use crate::{SourceFile, AstNode}; | 170 | use crate::{SourceFile, AstNode}; |
161 | use super::*; | 171 | use super::*; |
162 | 172 | ||
163 | fn do_check<F>(before: &str, replace_with: &str, reparser: F) | 173 | fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { |
164 | where | ||
165 | for<'a> F: Fn( | ||
166 | &'a SyntaxNode, | ||
167 | &AtomTextEdit, | ||
168 | ) -> Option<(&'a SyntaxNode, GreenNode, Vec<SyntaxError>)>, | ||
169 | { | ||
170 | let (range, before) = extract_range(before); | 174 | let (range, before) = extract_range(before); |
171 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); | 175 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); |
172 | let after = edit.apply(before.clone()); | 176 | let after = edit.apply(before.clone()); |
@@ -175,23 +179,20 @@ mod tests { | |||
175 | let incrementally_reparsed = { | 179 | let incrementally_reparsed = { |
176 | let f = SourceFile::parse(&before); | 180 | let f = SourceFile::parse(&before); |
177 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; | 181 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; |
178 | let (node, green, new_errors) = | 182 | let (green, new_errors, range) = |
179 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); | 183 | incremental_reparse(f.syntax(), &edit, f.errors()).unwrap(); |
180 | let green_root = node.replace_with(green); | 184 | assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); |
181 | let errors = super::merge_errors(f.errors(), new_errors, node, &edit); | 185 | SourceFile::new(green, new_errors) |
182 | SourceFile::new(green_root, errors) | ||
183 | }; | 186 | }; |
184 | 187 | ||
185 | assert_eq_text!( | 188 | assert_eq_text!( |
186 | &fully_reparsed.syntax().debug_dump(), | 189 | &fully_reparsed.syntax().debug_dump(), |
187 | &incrementally_reparsed.syntax().debug_dump(), | 190 | &incrementally_reparsed.syntax().debug_dump(), |
188 | ) | 191 | ); |
189 | } | 192 | } |
190 | 193 | ||
191 | #[test] | 194 | #[test] // FIXME: some test here actually test token reparsing |
192 | fn reparse_block_tests() { | 195 | fn reparse_block_tests() { |
193 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_block); | ||
194 | |||
195 | do_check( | 196 | do_check( |
196 | r" | 197 | r" |
197 | fn foo() { | 198 | fn foo() { |
@@ -199,6 +200,7 @@ fn foo() { | |||
199 | } | 200 | } |
200 | ", | 201 | ", |
201 | "baz", | 202 | "baz", |
203 | 3, | ||
202 | ); | 204 | ); |
203 | do_check( | 205 | do_check( |
204 | r" | 206 | r" |
@@ -207,6 +209,7 @@ fn foo() { | |||
207 | } | 209 | } |
208 | ", | 210 | ", |
209 | "baz", | 211 | "baz", |
212 | 25, | ||
210 | ); | 213 | ); |
211 | do_check( | 214 | do_check( |
212 | r" | 215 | r" |
@@ -215,6 +218,7 @@ struct Foo { | |||
215 | } | 218 | } |
216 | ", | 219 | ", |
217 | ",\n g: (),", | 220 | ",\n g: (),", |
221 | 14, | ||
218 | ); | 222 | ); |
219 | do_check( | 223 | do_check( |
220 | r" | 224 | r" |
@@ -225,6 +229,7 @@ fn foo { | |||
225 | } | 229 | } |
226 | ", | 230 | ", |
227 | "62", | 231 | "62", |
232 | 31, // FIXME: reparse only int literal here | ||
228 | ); | 233 | ); |
229 | do_check( | 234 | do_check( |
230 | r" | 235 | r" |
@@ -233,7 +238,9 @@ mod foo { | |||
233 | } | 238 | } |
234 | ", | 239 | ", |
235 | "bar", | 240 | "bar", |
241 | 11, | ||
236 | ); | 242 | ); |
243 | |||
237 | do_check( | 244 | do_check( |
238 | r" | 245 | r" |
239 | trait Foo { | 246 | trait Foo { |
@@ -241,6 +248,7 @@ trait Foo { | |||
241 | } | 248 | } |
242 | ", | 249 | ", |
243 | "Output", | 250 | "Output", |
251 | 3, | ||
244 | ); | 252 | ); |
245 | do_check( | 253 | do_check( |
246 | r" | 254 | r" |
@@ -249,13 +257,9 @@ impl IntoIterator<Item=i32> for Foo { | |||
249 | } | 257 | } |
250 | ", | 258 | ", |
251 | "n next(", | 259 | "n next(", |
260 | 9, | ||
252 | ); | 261 | ); |
253 | do_check( | 262 | do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10); |
254 | r" | ||
255 | use a::b::{foo,<|>,bar<|>}; | ||
256 | ", | ||
257 | "baz", | ||
258 | ); | ||
259 | do_check( | 263 | do_check( |
260 | r" | 264 | r" |
261 | pub enum A { | 265 | pub enum A { |
@@ -263,12 +267,14 @@ pub enum A { | |||
263 | } | 267 | } |
264 | ", | 268 | ", |
265 | "\nBar;\n", | 269 | "\nBar;\n", |
270 | 11, | ||
266 | ); | 271 | ); |
267 | do_check( | 272 | do_check( |
268 | r" | 273 | r" |
269 | foo!{a, b<|><|> d} | 274 | foo!{a, b<|><|> d} |
270 | ", | 275 | ", |
271 | ", c[3]", | 276 | ", c[3]", |
277 | 8, | ||
272 | ); | 278 | ); |
273 | do_check( | 279 | do_check( |
274 | r" | 280 | r" |
@@ -277,6 +283,7 @@ fn foo() { | |||
277 | } | 283 | } |
278 | ", | 284 | ", |
279 | "123", | 285 | "123", |
286 | 14, | ||
280 | ); | 287 | ); |
281 | do_check( | 288 | do_check( |
282 | r" | 289 | r" |
@@ -285,54 +292,60 @@ extern { | |||
285 | } | 292 | } |
286 | ", | 293 | ", |
287 | " exit(code: c_int)", | 294 | " exit(code: c_int)", |
295 | 11, | ||
288 | ); | 296 | ); |
289 | } | 297 | } |
290 | 298 | ||
291 | #[test] | 299 | #[test] |
292 | fn reparse_leaf_tests() { | 300 | fn reparse_token_tests() { |
293 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf); | ||
294 | |||
295 | do_check( | 301 | do_check( |
296 | r"<|><|> | 302 | r"<|><|> |
297 | fn foo() -> i32 { 1 } | 303 | fn foo() -> i32 { 1 } |
298 | ", | 304 | ", |
299 | "\n\n\n \n", | 305 | "\n\n\n \n", |
306 | 1, | ||
300 | ); | 307 | ); |
301 | do_check( | 308 | do_check( |
302 | r" | 309 | r" |
303 | fn foo() -> <|><|> {} | 310 | fn foo() -> <|><|> {} |
304 | ", | 311 | ", |
305 | " \n", | 312 | " \n", |
313 | 2, | ||
306 | ); | 314 | ); |
307 | do_check( | 315 | do_check( |
308 | r" | 316 | r" |
309 | fn <|>foo<|>() -> i32 { 1 } | 317 | fn <|>foo<|>() -> i32 { 1 } |
310 | ", | 318 | ", |
311 | "bar", | 319 | "bar", |
320 | 3, | ||
312 | ); | 321 | ); |
313 | do_check( | 322 | do_check( |
314 | r" | 323 | r" |
315 | fn foo<|><|>foo() { } | 324 | fn foo<|><|>foo() { } |
316 | ", | 325 | ", |
317 | "bar", | 326 | "bar", |
327 | 6, | ||
318 | ); | 328 | ); |
319 | do_check( | 329 | do_check( |
320 | r" | 330 | r" |
321 | fn foo /* <|><|> */ () {} | 331 | fn foo /* <|><|> */ () {} |
322 | ", | 332 | ", |
323 | "some comment", | 333 | "some comment", |
334 | 6, | ||
324 | ); | 335 | ); |
325 | do_check( | 336 | do_check( |
326 | r" | 337 | r" |
327 | fn baz <|><|> () {} | 338 | fn baz <|><|> () {} |
328 | ", | 339 | ", |
329 | " \t\t\n\n", | 340 | " \t\t\n\n", |
341 | 2, | ||
330 | ); | 342 | ); |
331 | do_check( | 343 | do_check( |
332 | r" | 344 | r" |
333 | fn baz <|><|> () {} | 345 | fn baz <|><|> () {} |
334 | ", | 346 | ", |
335 | " \t\t\n\n", | 347 | " \t\t\n\n", |
348 | 2, | ||
336 | ); | 349 | ); |
337 | do_check( | 350 | do_check( |
338 | r" | 351 | r" |
@@ -340,24 +353,28 @@ fn baz <|><|> () {} | |||
340 | mod { } | 353 | mod { } |
341 | ", | 354 | ", |
342 | "c", | 355 | "c", |
356 | 14, | ||
343 | ); | 357 | ); |
344 | do_check( | 358 | do_check( |
345 | r#" | 359 | r#" |
346 | fn -> &str { "Hello<|><|>" } | 360 | fn -> &str { "Hello<|><|>" } |
347 | "#, | 361 | "#, |
348 | ", world", | 362 | ", world", |
363 | 7, | ||
349 | ); | 364 | ); |
350 | do_check( | 365 | do_check( |
351 | r#" | 366 | r#" |
352 | fn -> &str { // "Hello<|><|>" | 367 | fn -> &str { // "Hello<|><|>" |
353 | "#, | 368 | "#, |
354 | ", world", | 369 | ", world", |
370 | 10, | ||
355 | ); | 371 | ); |
356 | do_check( | 372 | do_check( |
357 | r##" | 373 | r##" |
358 | fn -> &str { r#"Hello<|><|>"# | 374 | fn -> &str { r#"Hello<|><|>"# |
359 | "##, | 375 | "##, |
360 | ", world", | 376 | ", world", |
377 | 10, | ||
361 | ); | 378 | ); |
362 | do_check( | 379 | do_check( |
363 | r" | 380 | r" |
@@ -367,6 +384,7 @@ enum Foo { | |||
367 | } | 384 | } |
368 | ", | 385 | ", |
369 | "Clone", | 386 | "Clone", |
387 | 4, | ||
370 | ); | 388 | ); |
371 | } | 389 | } |
372 | } | 390 | } |
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs index b17d06c61..71fc515f2 100644 --- a/crates/ra_syntax/src/parsing/text_tree_sink.rs +++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs | |||
@@ -28,10 +28,10 @@ enum State { | |||
28 | } | 28 | } |
29 | 29 | ||
30 | impl<'a> TreeSink for TextTreeSink<'a> { | 30 | impl<'a> TreeSink for TextTreeSink<'a> { |
31 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { | 31 | fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { |
32 | match mem::replace(&mut self.state, State::Normal) { | 32 | match mem::replace(&mut self.state, State::Normal) { |
33 | State::PendingStart => unreachable!(), | 33 | State::PendingStart => unreachable!(), |
34 | State::PendingFinish => self.inner.finish_branch(), | 34 | State::PendingFinish => self.inner.finish_node(), |
35 | State::Normal => (), | 35 | State::Normal => (), |
36 | } | 36 | } |
37 | self.eat_trivias(); | 37 | self.eat_trivias(); |
@@ -40,18 +40,18 @@ impl<'a> TreeSink for TextTreeSink<'a> { | |||
40 | .iter() | 40 | .iter() |
41 | .map(|it| it.len) | 41 | .map(|it| it.len) |
42 | .sum::<TextUnit>(); | 42 | .sum::<TextUnit>(); |
43 | self.do_leaf(kind, len, n_tokens); | 43 | self.do_token(kind, len, n_tokens); |
44 | } | 44 | } |
45 | 45 | ||
46 | fn start_branch(&mut self, kind: SyntaxKind) { | 46 | fn start_node(&mut self, kind: SyntaxKind) { |
47 | match mem::replace(&mut self.state, State::Normal) { | 47 | match mem::replace(&mut self.state, State::Normal) { |
48 | State::PendingStart => { | 48 | State::PendingStart => { |
49 | self.inner.start_branch(kind); | 49 | self.inner.start_node(kind); |
50 | // No need to attach trivias to previous node: there is no | 50 | // No need to attach trivias to previous node: there is no |
51 | // previous node. | 51 | // previous node. |
52 | return; | 52 | return; |
53 | } | 53 | } |
54 | State::PendingFinish => self.inner.finish_branch(), | 54 | State::PendingFinish => self.inner.finish_node(), |
55 | State::Normal => (), | 55 | State::Normal => (), |
56 | } | 56 | } |
57 | 57 | ||
@@ -71,14 +71,14 @@ impl<'a> TreeSink for TextTreeSink<'a> { | |||
71 | n_attached_trivias(kind, leading_trivias) | 71 | n_attached_trivias(kind, leading_trivias) |
72 | }; | 72 | }; |
73 | self.eat_n_trivias(n_trivias - n_attached_trivias); | 73 | self.eat_n_trivias(n_trivias - n_attached_trivias); |
74 | self.inner.start_branch(kind); | 74 | self.inner.start_node(kind); |
75 | self.eat_n_trivias(n_attached_trivias); | 75 | self.eat_n_trivias(n_attached_trivias); |
76 | } | 76 | } |
77 | 77 | ||
78 | fn finish_branch(&mut self) { | 78 | fn finish_node(&mut self) { |
79 | match mem::replace(&mut self.state, State::PendingFinish) { | 79 | match mem::replace(&mut self.state, State::PendingFinish) { |
80 | State::PendingStart => unreachable!(), | 80 | State::PendingStart => unreachable!(), |
81 | State::PendingFinish => self.inner.finish_branch(), | 81 | State::PendingFinish => self.inner.finish_node(), |
82 | State::Normal => (), | 82 | State::Normal => (), |
83 | } | 83 | } |
84 | } | 84 | } |
@@ -104,7 +104,7 @@ impl<'a> TextTreeSink<'a> { | |||
104 | match mem::replace(&mut self.state, State::Normal) { | 104 | match mem::replace(&mut self.state, State::Normal) { |
105 | State::PendingFinish => { | 105 | State::PendingFinish => { |
106 | self.eat_trivias(); | 106 | self.eat_trivias(); |
107 | self.inner.finish_branch() | 107 | self.inner.finish_node() |
108 | } | 108 | } |
109 | State::PendingStart | State::Normal => unreachable!(), | 109 | State::PendingStart | State::Normal => unreachable!(), |
110 | } | 110 | } |
@@ -117,7 +117,7 @@ impl<'a> TextTreeSink<'a> { | |||
117 | if !token.kind.is_trivia() { | 117 | if !token.kind.is_trivia() { |
118 | break; | 118 | break; |
119 | } | 119 | } |
120 | self.do_leaf(token.kind, token.len, 1); | 120 | self.do_token(token.kind, token.len, 1); |
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
@@ -125,16 +125,16 @@ impl<'a> TextTreeSink<'a> { | |||
125 | for _ in 0..n { | 125 | for _ in 0..n { |
126 | let token = self.tokens[self.token_pos]; | 126 | let token = self.tokens[self.token_pos]; |
127 | assert!(token.kind.is_trivia()); | 127 | assert!(token.kind.is_trivia()); |
128 | self.do_leaf(token.kind, token.len, 1); | 128 | self.do_token(token.kind, token.len, 1); |
129 | } | 129 | } |
130 | } | 130 | } |
131 | 131 | ||
132 | fn do_leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { | 132 | fn do_token(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { |
133 | let range = TextRange::offset_len(self.text_pos, len); | 133 | let range = TextRange::offset_len(self.text_pos, len); |
134 | let text: SmolStr = self.text[range].into(); | 134 | let text: SmolStr = self.text[range].into(); |
135 | self.text_pos += len; | 135 | self.text_pos += len; |
136 | self.token_pos += n_tokens; | 136 | self.token_pos += n_tokens; |
137 | self.inner.leaf(kind, text); | 137 | self.inner.token(kind, text); |
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index e5b4cdb11..be181d0ae 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs | |||
@@ -29,6 +29,9 @@ impl Types for RaTypes { | |||
29 | } | 29 | } |
30 | 30 | ||
31 | pub(crate) type GreenNode = rowan::GreenNode<RaTypes>; | 31 | pub(crate) type GreenNode = rowan::GreenNode<RaTypes>; |
32 | pub(crate) type GreenToken = rowan::GreenToken<RaTypes>; | ||
33 | #[allow(unused)] | ||
34 | pub(crate) type GreenElement = rowan::GreenElement<RaTypes>; | ||
32 | 35 | ||
33 | /// Marker trait for CST and AST nodes | 36 | /// Marker trait for CST and AST nodes |
34 | pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {} | 37 | pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {} |
@@ -113,11 +116,13 @@ impl ToOwned for SyntaxNode { | |||
113 | 116 | ||
114 | impl fmt::Debug for SyntaxNode { | 117 | impl fmt::Debug for SyntaxNode { |
115 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | 118 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
116 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | 119 | write!(fmt, "{:?}@{:?}", self.kind(), self.range()) |
117 | if has_short_text(self.kind()) { | 120 | } |
118 | write!(fmt, " \"{}\"", self.text())?; | 121 | } |
119 | } | 122 | |
120 | Ok(()) | 123 | impl fmt::Display for SyntaxNode { |
124 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
125 | fmt::Display::fmt(&self.text(), fmt) | ||
121 | } | 126 | } |
122 | } | 127 | } |
123 | 128 | ||
@@ -145,14 +150,6 @@ impl SyntaxNode { | |||
145 | SyntaxText::new(self) | 150 | SyntaxText::new(self) |
146 | } | 151 | } |
147 | 152 | ||
148 | pub fn is_leaf(&self) -> bool { | ||
149 | self.0.is_leaf() | ||
150 | } | ||
151 | |||
152 | pub fn leaf_text(&self) -> Option<&SmolStr> { | ||
153 | self.0.leaf_text() | ||
154 | } | ||
155 | |||
156 | pub fn parent(&self) -> Option<&SyntaxNode> { | 153 | pub fn parent(&self) -> Option<&SyntaxNode> { |
157 | self.0.parent().map(SyntaxNode::from_repr) | 154 | self.0.parent().map(SyntaxNode::from_repr) |
158 | } | 155 | } |
@@ -161,22 +158,50 @@ impl SyntaxNode { | |||
161 | self.0.first_child().map(SyntaxNode::from_repr) | 158 | self.0.first_child().map(SyntaxNode::from_repr) |
162 | } | 159 | } |
163 | 160 | ||
161 | pub fn first_child_or_token(&self) -> Option<SyntaxElement> { | ||
162 | self.0.first_child_or_token().map(SyntaxElement::from) | ||
163 | } | ||
164 | |||
164 | pub fn last_child(&self) -> Option<&SyntaxNode> { | 165 | pub fn last_child(&self) -> Option<&SyntaxNode> { |
165 | self.0.last_child().map(SyntaxNode::from_repr) | 166 | self.0.last_child().map(SyntaxNode::from_repr) |
166 | } | 167 | } |
167 | 168 | ||
169 | pub fn last_child_or_token(&self) -> Option<SyntaxElement> { | ||
170 | self.0.last_child_or_token().map(SyntaxElement::from) | ||
171 | } | ||
172 | |||
168 | pub fn next_sibling(&self) -> Option<&SyntaxNode> { | 173 | pub fn next_sibling(&self) -> Option<&SyntaxNode> { |
169 | self.0.next_sibling().map(SyntaxNode::from_repr) | 174 | self.0.next_sibling().map(SyntaxNode::from_repr) |
170 | } | 175 | } |
171 | 176 | ||
177 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> { | ||
178 | self.0.next_sibling_or_token().map(SyntaxElement::from) | ||
179 | } | ||
180 | |||
172 | pub fn prev_sibling(&self) -> Option<&SyntaxNode> { | 181 | pub fn prev_sibling(&self) -> Option<&SyntaxNode> { |
173 | self.0.prev_sibling().map(SyntaxNode::from_repr) | 182 | self.0.prev_sibling().map(SyntaxNode::from_repr) |
174 | } | 183 | } |
175 | 184 | ||
185 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { | ||
186 | self.0.prev_sibling_or_token().map(SyntaxElement::from) | ||
187 | } | ||
188 | |||
176 | pub fn children(&self) -> SyntaxNodeChildren { | 189 | pub fn children(&self) -> SyntaxNodeChildren { |
177 | SyntaxNodeChildren(self.0.children()) | 190 | SyntaxNodeChildren(self.0.children()) |
178 | } | 191 | } |
179 | 192 | ||
193 | pub fn children_with_tokens(&self) -> SyntaxElementChildren { | ||
194 | SyntaxElementChildren(self.0.children_with_tokens()) | ||
195 | } | ||
196 | |||
197 | pub fn first_token(&self) -> Option<SyntaxToken> { | ||
198 | self.0.first_token().map(SyntaxToken::from) | ||
199 | } | ||
200 | |||
201 | pub fn last_token(&self) -> Option<SyntaxToken> { | ||
202 | self.0.last_token().map(SyntaxToken::from) | ||
203 | } | ||
204 | |||
180 | pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> { | 205 | pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> { |
181 | crate::algo::generate(Some(self), |&node| node.parent()) | 206 | crate::algo::generate(Some(self), |&node| node.parent()) |
182 | } | 207 | } |
@@ -188,6 +213,13 @@ impl SyntaxNode { | |||
188 | }) | 213 | }) |
189 | } | 214 | } |
190 | 215 | ||
216 | pub fn descendants_with_tokens(&self) -> impl Iterator<Item = SyntaxElement> { | ||
217 | self.preorder_with_tokens().filter_map(|event| match event { | ||
218 | WalkEvent::Enter(it) => Some(it), | ||
219 | WalkEvent::Leave(_) => None, | ||
220 | }) | ||
221 | } | ||
222 | |||
191 | pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> { | 223 | pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> { |
192 | crate::algo::generate(Some(self), move |&node| match direction { | 224 | crate::algo::generate(Some(self), move |&node| match direction { |
193 | Direction::Next => node.next_sibling(), | 225 | Direction::Next => node.next_sibling(), |
@@ -195,6 +227,17 @@ impl SyntaxNode { | |||
195 | }) | 227 | }) |
196 | } | 228 | } |
197 | 229 | ||
230 | pub fn siblings_with_tokens( | ||
231 | &self, | ||
232 | direction: Direction, | ||
233 | ) -> impl Iterator<Item = SyntaxElement> { | ||
234 | let me: SyntaxElement = self.into(); | ||
235 | crate::algo::generate(Some(me), move |el| match direction { | ||
236 | Direction::Next => el.next_sibling_or_token(), | ||
237 | Direction::Prev => el.prev_sibling_or_token(), | ||
238 | }) | ||
239 | } | ||
240 | |||
198 | pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> { | 241 | pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> { |
199 | self.0.preorder().map(|event| match event { | 242 | self.0.preorder().map(|event| match event { |
200 | WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), | 243 | WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), |
@@ -202,6 +245,13 @@ impl SyntaxNode { | |||
202 | }) | 245 | }) |
203 | } | 246 | } |
204 | 247 | ||
248 | pub fn preorder_with_tokens(&self) -> impl Iterator<Item = WalkEvent<SyntaxElement>> { | ||
249 | self.0.preorder_with_tokens().map(|event| match event { | ||
250 | WalkEvent::Enter(n) => WalkEvent::Enter(n.into()), | ||
251 | WalkEvent::Leave(n) => WalkEvent::Leave(n.into()), | ||
252 | }) | ||
253 | } | ||
254 | |||
205 | pub fn memory_size_of_subtree(&self) -> usize { | 255 | pub fn memory_size_of_subtree(&self) -> usize { |
206 | self.0.memory_size_of_subtree() | 256 | self.0.memory_size_of_subtree() |
207 | } | 257 | } |
@@ -223,17 +273,20 @@ impl SyntaxNode { | |||
223 | }; | 273 | }; |
224 | } | 274 | } |
225 | 275 | ||
226 | for event in self.preorder() { | 276 | for event in self.preorder_with_tokens() { |
227 | match event { | 277 | match event { |
228 | WalkEvent::Enter(node) => { | 278 | WalkEvent::Enter(element) => { |
229 | indent!(); | 279 | indent!(); |
230 | writeln!(buf, "{:?}", node).unwrap(); | 280 | match element { |
231 | if node.first_child().is_none() { | 281 | SyntaxElement::Node(node) => writeln!(buf, "{:?}", node).unwrap(), |
232 | let off = node.range().end(); | 282 | SyntaxElement::Token(token) => { |
233 | while err_pos < errors.len() && errors[err_pos].offset() <= off { | 283 | writeln!(buf, "{:?}", token).unwrap(); |
234 | indent!(); | 284 | let off = token.range().end(); |
235 | writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); | 285 | while err_pos < errors.len() && errors[err_pos].offset() <= off { |
236 | err_pos += 1; | 286 | indent!(); |
287 | writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); | ||
288 | err_pos += 1; | ||
289 | } | ||
237 | } | 290 | } |
238 | } | 291 | } |
239 | level += 1; | 292 | level += 1; |
@@ -255,7 +308,172 @@ impl SyntaxNode { | |||
255 | } | 308 | } |
256 | 309 | ||
257 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { | 310 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { |
258 | self.0.replace_self(replacement) | 311 | self.0.replace_with(replacement) |
312 | } | ||
313 | } | ||
314 | |||
315 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | ||
316 | pub struct SyntaxToken<'a>(pub(crate) rowan::SyntaxToken<'a, RaTypes>); | ||
317 | |||
318 | //FIXME: always output text | ||
319 | impl<'a> fmt::Debug for SyntaxToken<'a> { | ||
320 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
321 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
322 | if has_short_text(self.kind()) { | ||
323 | write!(fmt, " \"{}\"", self.text())?; | ||
324 | } | ||
325 | Ok(()) | ||
326 | } | ||
327 | } | ||
328 | |||
329 | impl<'a> fmt::Display for SyntaxToken<'a> { | ||
330 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
331 | fmt::Display::fmt(self.text(), fmt) | ||
332 | } | ||
333 | } | ||
334 | |||
335 | impl<'a> From<rowan::SyntaxToken<'a, RaTypes>> for SyntaxToken<'a> { | ||
336 | fn from(t: rowan::SyntaxToken<'a, RaTypes>) -> Self { | ||
337 | SyntaxToken(t) | ||
338 | } | ||
339 | } | ||
340 | |||
341 | impl<'a> SyntaxToken<'a> { | ||
342 | pub fn kind(&self) -> SyntaxKind { | ||
343 | self.0.kind() | ||
344 | } | ||
345 | |||
346 | pub fn text(&self) -> &'a SmolStr { | ||
347 | self.0.text() | ||
348 | } | ||
349 | |||
350 | pub fn range(&self) -> TextRange { | ||
351 | self.0.range() | ||
352 | } | ||
353 | |||
354 | pub fn parent(&self) -> &'a SyntaxNode { | ||
355 | SyntaxNode::from_repr(self.0.parent()) | ||
356 | } | ||
357 | |||
358 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
359 | self.0.next_sibling_or_token().map(SyntaxElement::from) | ||
360 | } | ||
361 | |||
362 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
363 | self.0.prev_sibling_or_token().map(SyntaxElement::from) | ||
364 | } | ||
365 | |||
366 | pub fn siblings_with_tokens( | ||
367 | &self, | ||
368 | direction: Direction, | ||
369 | ) -> impl Iterator<Item = SyntaxElement<'a>> { | ||
370 | let me: SyntaxElement = (*self).into(); | ||
371 | crate::algo::generate(Some(me), move |el| match direction { | ||
372 | Direction::Next => el.next_sibling_or_token(), | ||
373 | Direction::Prev => el.prev_sibling_or_token(), | ||
374 | }) | ||
375 | } | ||
376 | |||
377 | pub fn next_token(&self) -> Option<SyntaxToken<'a>> { | ||
378 | self.0.next_token().map(SyntaxToken::from) | ||
379 | } | ||
380 | |||
381 | pub fn prev_token(&self) -> Option<SyntaxToken<'a>> { | ||
382 | self.0.prev_token().map(SyntaxToken::from) | ||
383 | } | ||
384 | |||
385 | pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode { | ||
386 | self.0.replace_with(new_token) | ||
387 | } | ||
388 | } | ||
389 | |||
390 | #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] | ||
391 | pub enum SyntaxElement<'a> { | ||
392 | Node(&'a SyntaxNode), | ||
393 | Token(SyntaxToken<'a>), | ||
394 | } | ||
395 | |||
396 | impl<'a> fmt::Display for SyntaxElement<'a> { | ||
397 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
398 | match self { | ||
399 | SyntaxElement::Node(it) => fmt::Display::fmt(it, fmt), | ||
400 | SyntaxElement::Token(it) => fmt::Display::fmt(it, fmt), | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | |||
405 | impl<'a> SyntaxElement<'a> { | ||
406 | pub fn kind(&self) -> SyntaxKind { | ||
407 | match self { | ||
408 | SyntaxElement::Node(it) => it.kind(), | ||
409 | SyntaxElement::Token(it) => it.kind(), | ||
410 | } | ||
411 | } | ||
412 | |||
413 | pub fn as_node(&self) -> Option<&'a SyntaxNode> { | ||
414 | match self { | ||
415 | SyntaxElement::Node(node) => Some(*node), | ||
416 | SyntaxElement::Token(_) => None, | ||
417 | } | ||
418 | } | ||
419 | |||
420 | pub fn as_token(&self) -> Option<SyntaxToken<'a>> { | ||
421 | match self { | ||
422 | SyntaxElement::Node(_) => None, | ||
423 | SyntaxElement::Token(token) => Some(*token), | ||
424 | } | ||
425 | } | ||
426 | |||
427 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
428 | match self { | ||
429 | SyntaxElement::Node(it) => it.next_sibling_or_token(), | ||
430 | SyntaxElement::Token(it) => it.next_sibling_or_token(), | ||
431 | } | ||
432 | } | ||
433 | |||
434 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
435 | match self { | ||
436 | SyntaxElement::Node(it) => it.prev_sibling_or_token(), | ||
437 | SyntaxElement::Token(it) => it.prev_sibling_or_token(), | ||
438 | } | ||
439 | } | ||
440 | |||
441 | pub fn ancestors(&self) -> impl Iterator<Item = &'a SyntaxNode> { | ||
442 | match self { | ||
443 | SyntaxElement::Node(it) => it, | ||
444 | SyntaxElement::Token(it) => it.parent(), | ||
445 | } | ||
446 | .ancestors() | ||
447 | } | ||
448 | } | ||
449 | |||
450 | impl<'a> From<rowan::SyntaxElement<'a, RaTypes>> for SyntaxElement<'a> { | ||
451 | fn from(el: rowan::SyntaxElement<'a, RaTypes>) -> Self { | ||
452 | match el { | ||
453 | rowan::SyntaxElement::Node(n) => SyntaxElement::Node(SyntaxNode::from_repr(n)), | ||
454 | rowan::SyntaxElement::Token(t) => SyntaxElement::Token(t.into()), | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | |||
459 | impl<'a> From<&'a SyntaxNode> for SyntaxElement<'a> { | ||
460 | fn from(node: &'a SyntaxNode) -> SyntaxElement<'a> { | ||
461 | SyntaxElement::Node(node) | ||
462 | } | ||
463 | } | ||
464 | |||
465 | impl<'a> From<SyntaxToken<'a>> for SyntaxElement<'a> { | ||
466 | fn from(token: SyntaxToken<'a>) -> SyntaxElement<'a> { | ||
467 | SyntaxElement::Token(token) | ||
468 | } | ||
469 | } | ||
470 | |||
471 | impl<'a> SyntaxElement<'a> { | ||
472 | pub fn range(&self) -> TextRange { | ||
473 | match self { | ||
474 | SyntaxElement::Node(it) => it.range(), | ||
475 | SyntaxElement::Token(it) => it.range(), | ||
476 | } | ||
259 | } | 477 | } |
260 | } | 478 | } |
261 | 479 | ||
@@ -270,6 +488,17 @@ impl<'a> Iterator for SyntaxNodeChildren<'a> { | |||
270 | } | 488 | } |
271 | } | 489 | } |
272 | 490 | ||
491 | #[derive(Debug)] | ||
492 | pub struct SyntaxElementChildren<'a>(rowan::SyntaxElementChildren<'a, RaTypes>); | ||
493 | |||
494 | impl<'a> Iterator for SyntaxElementChildren<'a> { | ||
495 | type Item = SyntaxElement<'a>; | ||
496 | |||
497 | fn next(&mut self) -> Option<SyntaxElement<'a>> { | ||
498 | self.0.next().map(SyntaxElement::from) | ||
499 | } | ||
500 | } | ||
501 | |||
273 | fn has_short_text(kind: SyntaxKind) -> bool { | 502 | fn has_short_text(kind: SyntaxKind) -> bool { |
274 | use crate::SyntaxKind::*; | 503 | use crate::SyntaxKind::*; |
275 | match kind { | 504 | match kind { |
@@ -304,16 +533,16 @@ impl SyntaxTreeBuilder { | |||
304 | node | 533 | node |
305 | } | 534 | } |
306 | 535 | ||
307 | pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) { | 536 | pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { |
308 | self.inner.leaf(kind, text) | 537 | self.inner.token(kind, text) |
309 | } | 538 | } |
310 | 539 | ||
311 | pub fn start_branch(&mut self, kind: SyntaxKind) { | 540 | pub fn start_node(&mut self, kind: SyntaxKind) { |
312 | self.inner.start_internal(kind) | 541 | self.inner.start_node(kind) |
313 | } | 542 | } |
314 | 543 | ||
315 | pub fn finish_branch(&mut self) { | 544 | pub fn finish_node(&mut self) { |
316 | self.inner.finish_internal() | 545 | self.inner.finish_node() |
317 | } | 546 | } |
318 | 547 | ||
319 | pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { | 548 | pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { |
diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs index 84e5b231a..6bb2ff461 100644 --- a/crates/ra_syntax/src/syntax_text.rs +++ b/crates/ra_syntax/src/syntax_text.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::{fmt, ops}; | 1 | use std::{fmt, ops}; |
2 | 2 | ||
3 | use crate::{SyntaxNode, TextRange, TextUnit}; | 3 | use crate::{SyntaxNode, TextRange, TextUnit, SyntaxElement}; |
4 | 4 | ||
5 | #[derive(Clone)] | 5 | #[derive(Clone)] |
6 | pub struct SyntaxText<'a> { | 6 | pub struct SyntaxText<'a> { |
@@ -15,11 +15,14 @@ impl<'a> SyntaxText<'a> { | |||
15 | 15 | ||
16 | pub fn chunks(&self) -> impl Iterator<Item = &'a str> { | 16 | pub fn chunks(&self) -> impl Iterator<Item = &'a str> { |
17 | let range = self.range; | 17 | let range = self.range; |
18 | self.node.descendants().filter_map(move |node| { | 18 | self.node.descendants_with_tokens().filter_map(move |el| match el { |
19 | let text = node.leaf_text()?; | 19 | SyntaxElement::Token(t) => { |
20 | let range = range.intersection(&node.range())?; | 20 | let text = t.text(); |
21 | let range = range - node.range().start(); | 21 | let range = range.intersection(&t.range())?; |
22 | Some(&text[range]) | 22 | let range = range - t.range().start(); |
23 | Some(&text[range]) | ||
24 | } | ||
25 | SyntaxElement::Node(_) => None, | ||
23 | }) | 26 | }) |
24 | } | 27 | } |
25 | 28 | ||
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 69f344d65..fc534df83 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -6,7 +6,7 @@ mod block; | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | SourceFile, SyntaxError, AstNode, SyntaxNode, | 8 | SourceFile, SyntaxError, AstNode, SyntaxNode, |
9 | SyntaxKind::{L_CURLY, R_CURLY}, | 9 | SyntaxKind::{L_CURLY, R_CURLY, BYTE, BYTE_STRING, STRING, CHAR}, |
10 | ast, | 10 | ast, |
11 | algo::visit::{visitor_ctx, VisitorCtx}, | 11 | algo::visit::{visitor_ctx, VisitorCtx}, |
12 | }; | 12 | }; |
@@ -15,16 +15,24 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> { | |||
15 | let mut errors = Vec::new(); | 15 | let mut errors = Vec::new(); |
16 | for node in file.syntax().descendants() { | 16 | for node in file.syntax().descendants() { |
17 | let _ = visitor_ctx(&mut errors) | 17 | let _ = visitor_ctx(&mut errors) |
18 | .visit::<ast::Byte, _>(byte::validate_byte_node) | 18 | .visit::<ast::Literal, _>(validate_literal) |
19 | .visit::<ast::ByteString, _>(byte_string::validate_byte_string_node) | ||
20 | .visit::<ast::Char, _>(char::validate_char_node) | ||
21 | .visit::<ast::String, _>(string::validate_string_node) | ||
22 | .visit::<ast::Block, _>(block::validate_block_node) | 19 | .visit::<ast::Block, _>(block::validate_block_node) |
23 | .accept(node); | 20 | .accept(node); |
24 | } | 21 | } |
25 | errors | 22 | errors |
26 | } | 23 | } |
27 | 24 | ||
25 | // FIXME: kill duplication | ||
26 | fn validate_literal(literal: &ast::Literal, acc: &mut Vec<SyntaxError>) { | ||
27 | match literal.token().kind() { | ||
28 | BYTE => byte::validate_byte_node(literal.token(), acc), | ||
29 | BYTE_STRING => byte_string::validate_byte_string_node(literal.token(), acc), | ||
30 | STRING => string::validate_string_node(literal.token(), acc), | ||
31 | CHAR => char::validate_char_node(literal.token(), acc), | ||
32 | _ => (), | ||
33 | } | ||
34 | } | ||
35 | |||
28 | pub(crate) fn validate_block_structure(root: &SyntaxNode) { | 36 | pub(crate) fn validate_block_structure(root: &SyntaxNode) { |
29 | let mut stack = Vec::new(); | 37 | let mut stack = Vec::new(); |
30 | for node in root.descendants() { | 38 | for node in root.descendants() { |
diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs index 838e7a65f..290f80fc6 100644 --- a/crates/ra_syntax/src/validation/byte.rs +++ b/crates/ra_syntax/src/validation/byte.rs | |||
@@ -1,17 +1,17 @@ | |||
1 | //! Validation of byte literals | 1 | //! Validation of byte literals |
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | ast::{self, AstNode, AstToken}, | ||
5 | string_lexing::{self, StringComponentKind}, | 4 | string_lexing::{self, StringComponentKind}, |
6 | TextRange, | 5 | TextRange, |
7 | validation::char, | 6 | validation::char, |
8 | SyntaxError, | 7 | SyntaxError, |
9 | SyntaxErrorKind::*, | 8 | SyntaxErrorKind::*, |
9 | SyntaxToken, | ||
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(super) fn validate_byte_node(node: &ast::Byte, errors: &mut Vec<SyntaxError>) { | 12 | pub(super) fn validate_byte_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
13 | let literal_text = node.text(); | 13 | let literal_text = node.text(); |
14 | let literal_range = node.syntax().range(); | 14 | let literal_range = node.range(); |
15 | let mut components = string_lexing::parse_byte_literal(literal_text); | 15 | let mut components = string_lexing::parse_byte_literal(literal_text); |
16 | let mut len = 0; | 16 | let mut len = 0; |
17 | for component in &mut components { | 17 | for component in &mut components { |
diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs index 64c7054a1..eae395e9d 100644 --- a/crates/ra_syntax/src/validation/byte_string.rs +++ b/crates/ra_syntax/src/validation/byte_string.rs | |||
@@ -1,15 +1,15 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | ast::{self, AstNode, AstToken}, | ||
3 | string_lexing::{self, StringComponentKind}, | 2 | string_lexing::{self, StringComponentKind}, |
4 | SyntaxError, | 3 | SyntaxError, |
5 | SyntaxErrorKind::*, | 4 | SyntaxErrorKind::*, |
5 | SyntaxToken, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use super::byte; | 8 | use super::byte; |
9 | 9 | ||
10 | pub(crate) fn validate_byte_string_node(node: &ast::ByteString, errors: &mut Vec<SyntaxError>) { | 10 | pub(crate) fn validate_byte_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
11 | let literal_text = node.text(); | 11 | let literal_text = node.text(); |
12 | let literal_range = node.syntax().range(); | 12 | let literal_range = node.range(); |
13 | let mut components = string_lexing::parse_byte_string_literal(literal_text); | 13 | let mut components = string_lexing::parse_byte_string_literal(literal_text); |
14 | for component in &mut components { | 14 | for component in &mut components { |
15 | let range = component.range + literal_range.start(); | 15 | let range = component.range + literal_range.start(); |
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs index c874e5d08..a385accdd 100644 --- a/crates/ra_syntax/src/validation/char.rs +++ b/crates/ra_syntax/src/validation/char.rs | |||
@@ -5,16 +5,16 @@ use std::u32; | |||
5 | use arrayvec::ArrayString; | 5 | use arrayvec::ArrayString; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ast::{self, AstNode, AstToken}, | ||
9 | string_lexing::{self, StringComponentKind}, | 8 | string_lexing::{self, StringComponentKind}, |
10 | TextRange, | 9 | TextRange, |
11 | SyntaxError, | 10 | SyntaxError, |
12 | SyntaxErrorKind::*, | 11 | SyntaxErrorKind::*, |
12 | SyntaxToken, | ||
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(super) fn validate_char_node(node: &ast::Char, errors: &mut Vec<SyntaxError>) { | 15 | pub(super) fn validate_char_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
16 | let literal_text = node.text(); | 16 | let literal_text = node.text(); |
17 | let literal_range = node.syntax().range(); | 17 | let literal_range = node.range(); |
18 | let mut components = string_lexing::parse_char_literal(literal_text); | 18 | let mut components = string_lexing::parse_char_literal(literal_text); |
19 | let mut len = 0; | 19 | let mut len = 0; |
20 | for component in &mut components { | 20 | for component in &mut components { |
diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs index d857d088c..f7f5c02c0 100644 --- a/crates/ra_syntax/src/validation/string.rs +++ b/crates/ra_syntax/src/validation/string.rs | |||
@@ -1,15 +1,15 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | ast::{self, AstNode, AstToken}, | ||
3 | string_lexing, | 2 | string_lexing, |
4 | SyntaxError, | 3 | SyntaxError, |
5 | SyntaxErrorKind::*, | 4 | SyntaxErrorKind::*, |
5 | SyntaxToken, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use super::char; | 8 | use super::char; |
9 | 9 | ||
10 | pub(crate) fn validate_string_node(node: &ast::String, errors: &mut Vec<SyntaxError>) { | 10 | pub(crate) fn validate_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
11 | let literal_text = node.text(); | 11 | let literal_text = node.text(); |
12 | let literal_range = node.syntax().range(); | 12 | let literal_range = node.range(); |
13 | let mut components = string_lexing::parse_string_literal(literal_text); | 13 | let mut components = string_lexing::parse_string_literal(literal_text); |
14 | for component in &mut components { | 14 | for component in &mut components { |
15 | let range = component.range + literal_range.start(); | 15 | let range = component.range + literal_range.start(); |