aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_editor/src/code_actions.rs18
-rw-r--r--crates/ra_editor/src/completion.rs13
-rw-r--r--crates/ra_editor/src/extend_selection.rs18
-rw-r--r--crates/ra_editor/src/folding_ranges.rs10
-rw-r--r--crates/ra_editor/src/lib.rs10
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs6
-rw-r--r--crates/ra_editor/src/symbols.rs4
-rw-r--r--crates/ra_editor/src/typing.rs3
-rw-r--r--crates/ra_syntax/src/algo/mod.rs24
-rw-r--r--crates/ra_syntax/src/algo/walk.rs6
-rw-r--r--crates/ra_syntax/src/lib.rs2
-rw-r--r--crates/ra_syntax/src/reparsing.rs2
-rw-r--r--crates/ra_syntax/src/utils.rs4
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs26
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs4
15 files changed, 70 insertions, 80 deletions
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index 83f7956d2..216d592ff 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -1,15 +1,13 @@
1use join_to_string::join; 1use join_to_string::join;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 File, TextUnit, TextRange, 4 File, TextUnit, TextRange, Direction,
5 ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, 5 ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
6 SyntaxKind::{COMMA, WHITESPACE}, 6 SyntaxKind::{COMMA, WHITESPACE},
7 SyntaxNodeRef, 7 SyntaxNodeRef,
8 algo::{ 8 algo::{
9 Direction, siblings,
10 find_leaf_at_offset, 9 find_leaf_at_offset,
11 find_covering_node, 10 find_covering_node,
12 ancestors,
13 }, 11 },
14}; 12};
15 13
@@ -25,12 +23,12 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
25 let syntax = file.syntax(); 23 let syntax = file.syntax();
26 24
27 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?; 25 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?;
28 let left = non_trivia_sibling(comma, Direction::Backward)?; 26 let prev = non_trivia_sibling(comma, Direction::Prev)?;
29 let right = non_trivia_sibling(comma, Direction::Forward)?; 27 let next = non_trivia_sibling(comma, Direction::Next)?;
30 Some(move || { 28 Some(move || {
31 let mut edit = EditBuilder::new(); 29 let mut edit = EditBuilder::new();
32 edit.replace(left.range(), right.text().to_string()); 30 edit.replace(prev.range(), next.text().to_string());
33 edit.replace(right.range(), left.text().to_string()); 31 edit.replace(next.range(), prev.text().to_string());
34 LocalEdit { 32 LocalEdit {
35 edit: edit.finish(), 33 edit: edit.finish(),
36 cursor_position: None, 34 cursor_position: None,
@@ -101,8 +99,8 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() ->
101 99
102pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { 100pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> {
103 let node = find_covering_node(file.syntax(), range); 101 let node = find_covering_node(file.syntax(), range);
104 let expr = ancestors(node).filter_map(ast::Expr::cast).next()?; 102 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
105 let anchor_stmt = ancestors(expr.syntax()).filter_map(ast::Stmt::cast).next()?; 103 let anchor_stmt = expr.syntax().ancestors().filter_map(ast::Stmt::cast).next()?;
106 let indent = anchor_stmt.syntax().prev_sibling()?; 104 let indent = anchor_stmt.syntax().prev_sibling()?;
107 if indent.kind() != WHITESPACE { 105 if indent.kind() != WHITESPACE {
108 return None; 106 return None;
@@ -130,7 +128,7 @@ pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl F
130} 128}
131 129
132fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { 130fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> {
133 siblings(node, direction) 131 node.siblings(direction)
134 .skip(1) 132 .skip(1)
135 .find(|node| !node.kind().is_trivia()) 133 .find(|node| !node.kind().is_trivia())
136} 134}
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs
index ff9de20d3..62a63fb04 100644
--- a/crates/ra_editor/src/completion.rs
+++ b/crates/ra_editor/src/completion.rs
@@ -4,7 +4,6 @@ use ra_syntax::{
4 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, 4 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*,
5 ast::{self, LoopBodyOwner, ModuleItemOwner}, 5 ast::{self, LoopBodyOwner, ModuleItemOwner},
6 algo::{ 6 algo::{
7 ancestors,
8 visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, 7 visit::{visitor, Visitor, visitor_ctx, VisitorCtx},
9 }, 8 },
10 text_utils::is_subrange, 9 text_utils::is_subrange,
@@ -59,7 +58,7 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi
59 return; 58 return;
60 } 59 }
61 let mut visited_fn = false; 60 let mut visited_fn = false;
62 for node in ancestors(name_ref.syntax()) { 61 for node in name_ref.syntax().ancestors() {
63 if let Some(items) = visitor() 62 if let Some(items) = visitor()
64 .visit::<ast::Root, _>(|it| Some(it.items())) 63 .visit::<ast::Root, _>(|it| Some(it.items()))
65 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) 64 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items()))
@@ -92,7 +91,7 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi
92 91
93fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { 92fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
94 let mut params = HashMap::new(); 93 let mut params = HashMap::new();
95 for node in ancestors(ctx) { 94 for node in ctx.ancestors() {
96 let _ = visitor_ctx(&mut params) 95 let _ = visitor_ctx(&mut params)
97 .visit::<ast::Root, _>(process) 96 .visit::<ast::Root, _>(process)
98 .visit::<ast::ItemList, _>(process) 97 .visit::<ast::ItemList, _>(process)
@@ -123,7 +122,7 @@ fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
123} 122}
124 123
125fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { 124fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
126 match ancestors(node).filter_map(N::cast).next() { 125 match node.ancestors().filter_map(N::cast).next() {
127 None => false, 126 None => false,
128 Some(n) => n.syntax().range() == node.range(), 127 Some(n) => n.syntax().range() == node.range(),
129 } 128 }
@@ -152,7 +151,7 @@ fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRe
152} 151}
153 152
154fn is_in_loop_body(name_ref: ast::NameRef) -> bool { 153fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
155 for node in ancestors(name_ref.syntax()) { 154 for node in name_ref.syntax().ancestors() {
156 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { 155 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
157 break; 156 break;
158 } 157 }
@@ -171,7 +170,7 @@ fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
171} 170}
172 171
173fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> { 172fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> {
174 // let is_last_in_block = ancestors(name_ref.syntax()).filter_map(ast::Expr::cast) 173 // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast)
175 // .next() 174 // .next()
176 // .and_then(|it| it.syntax().parent()) 175 // .and_then(|it| it.syntax().parent())
177 // .and_then(ast::Block::cast) 176 // .and_then(ast::Block::cast)
@@ -181,7 +180,7 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<Complet
181 // return None; 180 // return None;
182 // } 181 // }
183 182
184 let is_stmt = match ancestors(name_ref.syntax()).filter_map(ast::ExprStmt::cast).next() { 183 let is_stmt = match name_ref.syntax().ancestors().filter_map(ast::ExprStmt::cast).next() {
185 None => false, 184 None => false,
186 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range() 185 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range()
187 }; 186 };
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index dc914a26a..b00a457b9 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -1,7 +1,7 @@
1use ra_syntax::{ 1use ra_syntax::{
2 File, TextRange, SyntaxNodeRef, TextUnit, 2 File, TextRange, SyntaxNodeRef, TextUnit, Direction,
3 SyntaxKind::*, 3 SyntaxKind::*,
4 algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node, ancestors, Direction, siblings}, 4 algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node},
5}; 5};
6 6
7pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { 7pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> {
@@ -30,7 +30,7 @@ pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange>
30 } 30 }
31 } 31 }
32 32
33 match ancestors(node).skip_while(|n| n.range() == range).next() { 33 match node.ancestors().skip_while(|n| n.range() == range).next() {
34 None => None, 34 None => None,
35 Some(parent) => Some(parent.range()), 35 Some(parent) => Some(parent.range()),
36 } 36 }
@@ -71,12 +71,12 @@ fn pick_best<'a>(l: SyntaxNodeRef<'a>, r: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a
71} 71}
72 72
73fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> { 73fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> {
74 let left = adj_comments(node, Direction::Backward); 74 let prev = adj_comments(node, Direction::Prev);
75 let right = adj_comments(node, Direction::Forward); 75 let next = adj_comments(node, Direction::Next);
76 if left != right { 76 if prev != next {
77 Some(TextRange::from_to( 77 Some(TextRange::from_to(
78 left.range().start(), 78 prev.range().start(),
79 right.range().end(), 79 next.range().end(),
80 )) 80 ))
81 } else { 81 } else {
82 None 82 None
@@ -85,7 +85,7 @@ fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> {
85 85
86fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef { 86fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef {
87 let mut res = node; 87 let mut res = node;
88 for node in siblings(node, dir) { 88 for node in node.siblings(dir) {
89 match node.kind() { 89 match node.kind() {
90 COMMENT => res = node, 90 COMMENT => res = node,
91 WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), 91 WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index 817da28d1..733512368 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -3,7 +3,7 @@ use std::collections::HashSet;
3use ra_syntax::{ 3use ra_syntax::{
4 File, TextRange, SyntaxNodeRef, 4 File, TextRange, SyntaxNodeRef,
5 SyntaxKind, 5 SyntaxKind,
6 algo::{walk, Direction, siblings}, 6 Direction,
7}; 7};
8 8
9#[derive(Debug, PartialEq, Eq)] 9#[derive(Debug, PartialEq, Eq)]
@@ -19,12 +19,10 @@ pub struct Fold {
19} 19}
20 20
21pub fn folding_ranges(file: &File) -> Vec<Fold> { 21pub fn folding_ranges(file: &File) -> Vec<Fold> {
22 let syntax = file.syntax();
23
24 let mut res = vec![]; 22 let mut res = vec![];
25 let mut visited = HashSet::new(); 23 let mut visited = HashSet::new();
26 24
27 for node in walk::preorder(syntax) { 25 for node in file.syntax().descendants() {
28 if visited.contains(&node) { 26 if visited.contains(&node) {
29 continue; 27 continue;
30 } 28 }
@@ -64,7 +62,7 @@ fn contiguous_range_for<'a>(
64 62
65 let left = node; 63 let left = node;
66 let mut right = node; 64 let mut right = node;
67 for node in siblings(node, Direction::Forward) { 65 for node in node.siblings(Direction::Next) {
68 visited.insert(node); 66 visited.insert(node);
69 match node.kind() { 67 match node.kind() {
70 SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), 68 SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
@@ -139,4 +137,4 @@ fn main() {
139 } 137 }
140 138
141 139
142} \ No newline at end of file 140}
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index de929d73a..a93924e00 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -21,7 +21,7 @@ mod test_utils;
21use ra_syntax::{ 21use ra_syntax::{
22 File, TextUnit, TextRange, SyntaxNodeRef, 22 File, TextUnit, TextRange, SyntaxNodeRef,
23 ast::{self, AstNode, NameOwner}, 23 ast::{self, AstNode, NameOwner},
24 algo::{walk, find_leaf_at_offset, ancestors}, 24 algo::find_leaf_at_offset,
25 SyntaxKind::{self, *}, 25 SyntaxKind::{self, *},
26}; 26};
27pub use ra_syntax::AtomEdit; 27pub use ra_syntax::AtomEdit;
@@ -86,7 +86,7 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> {
86 86
87pub fn highlight(file: &File) -> Vec<HighlightedRange> { 87pub fn highlight(file: &File) -> Vec<HighlightedRange> {
88 let mut res = Vec::new(); 88 let mut res = Vec::new();
89 for node in walk::preorder(file.syntax()) { 89 for node in file.syntax().descendants() {
90 let tag = match node.kind() { 90 let tag = match node.kind() {
91 ERROR => "error", 91 ERROR => "error",
92 COMMENT | DOC_COMMENT => "comment", 92 COMMENT | DOC_COMMENT => "comment",
@@ -110,7 +110,7 @@ pub fn highlight(file: &File) -> Vec<HighlightedRange> {
110pub fn diagnostics(file: &File) -> Vec<Diagnostic> { 110pub fn diagnostics(file: &File) -> Vec<Diagnostic> {
111 let mut res = Vec::new(); 111 let mut res = Vec::new();
112 112
113 for node in walk::preorder(file.syntax()) { 113 for node in file.syntax().descendants() {
114 if node.kind() == ERROR { 114 if node.kind() == ERROR {
115 res.push(Diagnostic { 115 res.push(Diagnostic {
116 range: node.range(), 116 range: node.range(),
@@ -130,7 +130,7 @@ pub fn syntax_tree(file: &File) -> String {
130} 130}
131 131
132pub fn runnables(file: &File) -> Vec<Runnable> { 132pub fn runnables(file: &File) -> Vec<Runnable> {
133 walk::preorder(file.syntax()) 133 file.syntax().descendants()
134 .filter_map(ast::FnDef::cast) 134 .filter_map(ast::FnDef::cast)
135 .filter_map(|f| { 135 .filter_map(|f| {
136 let name = f.name()?.text(); 136 let name = f.name()?.text();
@@ -159,7 +159,7 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
159 let leaf = leaves.clone() 159 let leaf = leaves.clone()
160 .find(|leaf| !leaf.kind().is_trivia()) 160 .find(|leaf| !leaf.kind().is_trivia())
161 .or_else(|| leaves.right_biased())?; 161 .or_else(|| leaves.right_biased())?;
162 ancestors(leaf) 162 leaf.ancestors()
163 .filter_map(N::cast) 163 .filter_map(N::cast)
164 .next() 164 .next()
165} 165}
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 3ae5276a2..eddd87495 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -6,7 +6,7 @@ use std::{
6use ra_syntax::{ 6use ra_syntax::{
7 SyntaxNodeRef, SyntaxNode, SmolStr, AstNode, 7 SyntaxNodeRef, SyntaxNode, SmolStr, AstNode,
8 ast::{self, NameOwner, LoopBodyOwner, ArgListOwner}, 8 ast::{self, NameOwner, LoopBodyOwner, ArgListOwner},
9 algo::{ancestors, generate, walk::preorder} 9 algo::{generate}
10}; 10};
11 11
12type ScopeId = usize; 12type ScopeId = usize;
@@ -51,7 +51,7 @@ impl FnScopes {
51 res 51 res
52 } 52 }
53 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { 53 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
54 let entries = preorder(pat.syntax()) 54 let entries = pat.syntax().descendants()
55 .filter_map(ast::BindPat::cast) 55 .filter_map(ast::BindPat::cast)
56 .filter_map(ScopeEntry::new); 56 .filter_map(ScopeEntry::new);
57 self.scopes[scope].entries.extend(entries); 57 self.scopes[scope].entries.extend(entries);
@@ -66,7 +66,7 @@ impl FnScopes {
66 self.scope_for.insert(node.owned(), scope); 66 self.scope_for.insert(node.owned(), scope);
67 } 67 }
68 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { 68 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
69 ancestors(node) 69 node.ancestors()
70 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope)) 70 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
71 .next() 71 .next()
72 } 72 }
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
index 917984177..e5cc5ca28 100644
--- a/crates/ra_editor/src/symbols.rs
+++ b/crates/ra_editor/src/symbols.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 ast::{self, NameOwner}, 3 ast::{self, NameOwner},
4 algo::{ 4 algo::{
5 visit::{visitor, Visitor}, 5 visit::{visitor, Visitor},
6 walk::{walk, WalkEvent, preorder}, 6 walk::{walk, WalkEvent},
7 }, 7 },
8}; 8};
9use TextRange; 9use TextRange;
@@ -25,7 +25,7 @@ pub struct FileSymbol {
25} 25}
26 26
27pub fn file_symbols(file: &File) -> Vec<FileSymbol> { 27pub fn file_symbols(file: &File) -> Vec<FileSymbol> {
28 preorder(file.syntax()) 28 file.syntax().descendants()
29 .filter_map(to_symbol) 29 .filter_map(to_symbol)
30 .collect() 30 .collect()
31} 31}
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 0f4e7e0d0..512076941 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -4,7 +4,6 @@ use ra_syntax::{
4 TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind, 4 TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind,
5 ast, 5 ast,
6 algo::{ 6 algo::{
7 walk::preorder,
8 find_covering_node, 7 find_covering_node,
9 }, 8 },
10 text_utils::{intersect, contains_offset_nonstrict}, 9 text_utils::{intersect, contains_offset_nonstrict},
@@ -33,7 +32,7 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
33 }; 32 };
34 let node = find_covering_node(file.syntax(), range); 33 let node = find_covering_node(file.syntax(), range);
35 let mut edit = EditBuilder::new(); 34 let mut edit = EditBuilder::new();
36 for node in preorder(node) { 35 for node in node.descendants() {
37 let text = match node.leaf_text() { 36 let text = match node.leaf_text() {
38 Some(text) => text, 37 Some(text) => text,
39 None => continue, 38 None => continue,
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs
index 8de44c586..a6678093d 100644
--- a/crates/ra_syntax/src/algo/mod.rs
+++ b/crates/ra_syntax/src/algo/mod.rs
@@ -94,29 +94,9 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe
94 common_ancestor(left, right) 94 common_ancestor(left, right)
95} 95}
96 96
97pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
98 generate(Some(node), |&node| node.parent())
99}
100
101#[derive(Debug)]
102pub enum Direction {
103 Forward,
104 Backward,
105}
106
107pub fn siblings<'a>(
108 node: SyntaxNodeRef<'a>,
109 direction: Direction
110) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
111 generate(Some(node), move |&node| match direction {
112 Direction::Forward => node.next_sibling(),
113 Direction::Backward => node.prev_sibling(),
114 })
115}
116
117fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> { 97fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
118 for p in ancestors(n1) { 98 for p in n1.ancestors() {
119 if ancestors(n2).any(|a| a == p) { 99 if n2.ancestors().any(|a| a == p) {
120 return p; 100 return p;
121 } 101 }
122 } 102 }
diff --git a/crates/ra_syntax/src/algo/walk.rs b/crates/ra_syntax/src/algo/walk.rs
index 536ee705f..8e294d965 100644
--- a/crates/ra_syntax/src/algo/walk.rs
+++ b/crates/ra_syntax/src/algo/walk.rs
@@ -3,12 +3,6 @@ use {
3 algo::generate, 3 algo::generate,
4}; 4};
5 5
6pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
7 walk(root).filter_map(|event| match event {
8 WalkEvent::Enter(node) => Some(node),
9 WalkEvent::Exit(_) => None,
10 })
11}
12 6
13#[derive(Debug, Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
14pub enum WalkEvent<'a> { 8pub enum WalkEvent<'a> {
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index c7eda4563..738664afd 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -51,7 +51,7 @@ pub use {
51 ast::AstNode, 51 ast::AstNode,
52 lexer::{tokenize, Token}, 52 lexer::{tokenize, Token},
53 syntax_kinds::SyntaxKind, 53 syntax_kinds::SyntaxKind,
54 yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError}, 54 yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError, Direction},
55 reparsing::AtomEdit, 55 reparsing::AtomEdit,
56}; 56};
57 57
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs
index e3c200d1e..dcafd2c40 100644
--- a/crates/ra_syntax/src/reparsing.rs
+++ b/crates/ra_syntax/src/reparsing.rs
@@ -112,7 +112,7 @@ fn find_reparsable_node<'node>(
112 range: TextRange, 112 range: TextRange,
113) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { 113) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> {
114 let node = algo::find_covering_node(node, range); 114 let node = algo::find_covering_node(node, range);
115 return algo::ancestors(node) 115 return node.ancestors()
116 .filter_map(|node| reparser(node).map(|r| (node, r))) 116 .filter_map(|node| reparser(node).map(|r| (node, r)))
117 .next(); 117 .next();
118 118
diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs
index 8bc5f0e24..e274f7471 100644
--- a/crates/ra_syntax/src/utils.rs
+++ b/crates/ra_syntax/src/utils.rs
@@ -1,6 +1,6 @@
1use std::fmt::Write; 1use std::fmt::Write;
2use { 2use {
3 algo::walk::{preorder, walk, WalkEvent}, 3 algo::walk::{walk, WalkEvent},
4 SyntaxKind, File, SyntaxNodeRef 4 SyntaxKind, File, SyntaxNodeRef
5}; 5};
6 6
@@ -56,7 +56,7 @@ pub fn check_fuzz_invariants(text: &str) {
56 56
57pub(crate) fn validate_block_structure(root: SyntaxNodeRef) { 57pub(crate) fn validate_block_structure(root: SyntaxNodeRef) {
58 let mut stack = Vec::new(); 58 let mut stack = Vec::new();
59 for node in preorder(root) { 59 for node in root.descendants() {
60 match node.kind() { 60 match node.kind() {
61 SyntaxKind::L_CURLY => { 61 SyntaxKind::L_CURLY => {
62 stack.push(node) 62 stack.push(node)
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs
index c621b1d6a..710320f47 100644
--- a/crates/ra_syntax/src/yellow/mod.rs
+++ b/crates/ra_syntax/src/yellow/mod.rs
@@ -53,15 +53,37 @@ impl<R: TreeRoot<RaTypes>> Hash for SyntaxNode<R> {
53 } 53 }
54} 54}
55 55
56impl SyntaxNode<OwnedRoot> { 56impl SyntaxNode {
57 pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxNode { 57 pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxNode {
58 SyntaxNode(::rowan::SyntaxNode::new(green, errors)) 58 SyntaxNode(::rowan::SyntaxNode::new(green, errors))
59 } 59 }
60} 60}
61impl<'a> SyntaxNode<RefRoot<'a>> { 61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum Direction {
64 Next,
65 Prev,
66}
67
68impl<'a> SyntaxNodeRef<'a> {
62 pub fn leaf_text(self) -> Option<&'a SmolStr> { 69 pub fn leaf_text(self) -> Option<&'a SmolStr> {
63 self.0.leaf_text() 70 self.0.leaf_text()
64 } 71 }
72 pub fn ancestors(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
73 ::algo::generate(Some(self), |&node| node.parent())
74 }
75 pub fn descendants(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
76 ::algo::walk::walk(self).filter_map(|event| match event {
77 ::algo::walk::WalkEvent::Enter(node) => Some(node),
78 ::algo::walk::WalkEvent::Exit(_) => None,
79 })
80 }
81 pub fn siblings(self, direction: Direction) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
82 ::algo::generate(Some(self), move |&node| match direction {
83 Direction::Next => node.next_sibling(),
84 Direction::Prev => node.prev_sibling(),
85 })
86 }
65} 87}
66 88
67impl<R: TreeRoot<RaTypes>> SyntaxNode<R> { 89impl<R: TreeRoot<RaTypes>> SyntaxNode<R> {
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs
index affd7f9c7..0db1049de 100644
--- a/crates/ra_syntax/src/yellow/syntax_text.rs
+++ b/crates/ra_syntax/src/yellow/syntax_text.rs
@@ -4,7 +4,6 @@ use std::{
4 4
5use { 5use {
6 SyntaxNodeRef, TextRange, TextUnit, 6 SyntaxNodeRef, TextRange, TextUnit,
7 algo::walk::preorder,
8 text_utils::{intersect, contains_offset_nonstrict}, 7 text_utils::{intersect, contains_offset_nonstrict},
9}; 8};
10 9
@@ -23,7 +22,8 @@ impl<'a> SyntaxText<'a> {
23 } 22 }
24 pub fn chunks(&self) -> impl Iterator<Item=&'a str> { 23 pub fn chunks(&self) -> impl Iterator<Item=&'a str> {
25 let range = self.range; 24 let range = self.range;
26 preorder(self.node) 25 self.node
26 .descendants()
27 .filter_map(move |node| { 27 .filter_map(move |node| {
28 let text = node.leaf_text()?; 28 let text = node.leaf_text()?;
29 let range = intersect(range, node.range())?; 29 let range = intersect(range, node.range())?;