aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/assists.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/assists.rs')
-rw-r--r--crates/ra_editor/src/assists.rs39
1 files changed, 31 insertions, 8 deletions
diff --git a/crates/ra_editor/src/assists.rs b/crates/ra_editor/src/assists.rs
index 57b78342a..f839f6a7a 100644
--- a/crates/ra_editor/src/assists.rs
+++ b/crates/ra_editor/src/assists.rs
@@ -9,12 +9,15 @@ mod add_impl;
9mod introduce_variable; 9mod introduce_variable;
10mod change_visibility; 10mod change_visibility;
11mod split_import; 11mod split_import;
12mod replace_if_let_with_match;
12 13
13use ra_text_edit::{TextEdit, TextEditBuilder}; 14use ra_text_edit::{TextEdit, TextEditBuilder};
14use ra_syntax::{ 15use ra_syntax::{
15 Direction, SyntaxNodeRef, TextUnit, TextRange,SourceFileNode, AstNode, 16 Direction, SyntaxNode, TextUnit, TextRange, SourceFile, AstNode,
16 algo::{find_leaf_at_offset, find_covering_node, LeafAtOffset}, 17 algo::{find_leaf_at_offset, find_covering_node, LeafAtOffset},
18 ast::{self, AstToken},
17}; 19};
20use itertools::Itertools;
18 21
19use crate::find_node_at_offset; 22use crate::find_node_at_offset;
20 23
@@ -25,10 +28,11 @@ pub use self::{
25 introduce_variable::introduce_variable, 28 introduce_variable::introduce_variable,
26 change_visibility::change_visibility, 29 change_visibility::change_visibility,
27 split_import::split_import, 30 split_import::split_import,
31 replace_if_let_with_match::replace_if_let_with_match,
28}; 32};
29 33
30/// Return all the assists applicable at the given position. 34/// Return all the assists applicable at the given position.
31pub fn assists(file: &SourceFileNode, range: TextRange) -> Vec<LocalEdit> { 35pub fn assists(file: &SourceFile, range: TextRange) -> Vec<LocalEdit> {
32 let ctx = AssistCtx::new(file, range); 36 let ctx = AssistCtx::new(file, range);
33 [ 37 [
34 flip_comma, 38 flip_comma,
@@ -37,6 +41,7 @@ pub fn assists(file: &SourceFileNode, range: TextRange) -> Vec<LocalEdit> {
37 introduce_variable, 41 introduce_variable,
38 change_visibility, 42 change_visibility,
39 split_import, 43 split_import,
44 replace_if_let_with_match,
40 ] 45 ]
41 .iter() 46 .iter()
42 .filter_map(|&assist| ctx.clone().apply(assist)) 47 .filter_map(|&assist| ctx.clone().apply(assist))
@@ -50,7 +55,7 @@ pub struct LocalEdit {
50 pub cursor_position: Option<TextUnit>, 55 pub cursor_position: Option<TextUnit>,
51} 56}
52 57
53fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { 58fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> {
54 node.siblings(direction) 59 node.siblings(direction)
55 .skip(1) 60 .skip(1)
56 .find(|node| !node.kind().is_trivia()) 61 .find(|node| !node.kind().is_trivia())
@@ -88,7 +93,7 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta
88/// easier to just compute the edit eagarly :-) 93/// easier to just compute the edit eagarly :-)
89#[derive(Debug, Clone)] 94#[derive(Debug, Clone)]
90pub struct AssistCtx<'a> { 95pub struct AssistCtx<'a> {
91 source_file: &'a SourceFileNode, 96 source_file: &'a SourceFile,
92 range: TextRange, 97 range: TextRange,
93 should_compute_edit: bool, 98 should_compute_edit: bool,
94} 99}
@@ -106,7 +111,7 @@ struct AssistBuilder {
106} 111}
107 112
108impl<'a> AssistCtx<'a> { 113impl<'a> AssistCtx<'a> {
109 pub fn new(source_file: &'a SourceFileNode, range: TextRange) -> AssistCtx { 114 pub fn new(source_file: &'a SourceFile, range: TextRange) -> AssistCtx {
110 AssistCtx { 115 AssistCtx {
111 source_file, 116 source_file,
112 range, 117 range,
@@ -145,13 +150,13 @@ impl<'a> AssistCtx<'a> {
145 })) 150 }))
146 } 151 }
147 152
148 pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<SyntaxNodeRef<'a>> { 153 pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> {
149 find_leaf_at_offset(self.source_file.syntax(), self.range.start()) 154 find_leaf_at_offset(self.source_file.syntax(), self.range.start())
150 } 155 }
151 pub(crate) fn node_at_offset<N: AstNode<'a>>(&self) -> Option<N> { 156 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> {
152 find_node_at_offset(self.source_file.syntax(), self.range.start()) 157 find_node_at_offset(self.source_file.syntax(), self.range.start())
153 } 158 }
154 pub(crate) fn covering_node(&self) -> SyntaxNodeRef<'a> { 159 pub(crate) fn covering_node(&self) -> &'a SyntaxNode {
155 find_covering_node(self.source_file.syntax(), self.range) 160 find_covering_node(self.source_file.syntax(), self.range)
156 } 161 }
157} 162}
@@ -160,6 +165,13 @@ impl AssistBuilder {
160 fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 165 fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
161 self.edit.replace(range, replace_with.into()) 166 self.edit.replace(range, replace_with.into())
162 } 167 }
168 fn replace_node_and_indent(&mut self, node: &SyntaxNode, replace_with: impl Into<String>) {
169 let mut replace_with = replace_with.into();
170 if let Some(indent) = calc_indent(node) {
171 replace_with = reindent(&replace_with, indent)
172 }
173 self.replace(node.range(), replace_with)
174 }
163 #[allow(unused)] 175 #[allow(unused)]
164 fn delete(&mut self, range: TextRange) { 176 fn delete(&mut self, range: TextRange) {
165 self.edit.delete(range) 177 self.edit.delete(range)
@@ -172,6 +184,17 @@ impl AssistBuilder {
172 } 184 }
173} 185}
174 186
187fn calc_indent(node: &SyntaxNode) -> Option<&str> {
188 let prev = node.prev_sibling()?;
189 let ws_text = ast::Whitespace::cast(prev)?.text();
190 ws_text.rfind('\n').map(|pos| &ws_text[pos + 1..])
191}
192
193fn reindent(text: &str, indent: &str) -> String {
194 let indent = format!("\n{}", indent);
195 text.lines().intersperse(&indent).collect()
196}
197
175#[cfg(test)] 198#[cfg(test)]
176fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) { 199fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) {
177 crate::test_utils::check_action(before, after, |file, off| { 200 crate::test_utils::check_action(before, after, |file, off| {