diff options
Diffstat (limited to 'crates/ra_editor')
-rw-r--r-- | crates/ra_editor/src/typing.rs | 143 |
1 files changed, 68 insertions, 75 deletions
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index ae82ff89b..3ebdf153e 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs | |||
@@ -131,78 +131,77 @@ fn remove_newline( | |||
131 | node_text: &str, | 131 | node_text: &str, |
132 | offset: TextUnit, | 132 | offset: TextUnit, |
133 | ) { | 133 | ) { |
134 | if node.kind() == WHITESPACE && node_text.bytes().filter(|&b| b == b'\n').count() == 1 { | 134 | if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 { |
135 | // Special case that turns something like: | 135 | // The node is either the first or the last in the file |
136 | // | 136 | let suff = &node_text[TextRange::from_to( |
137 | // ``` | 137 | offset - node.range().start() + TextUnit::of_char('\n'), |
138 | // my_function({<|> | 138 | TextUnit::of_str(node_text), |
139 | // <some-expr> | 139 | )]; |
140 | // }) | 140 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); |
141 | // ``` | 141 | |
142 | // | 142 | edit.replace( |
143 | // into `my_function(<some-expr>)` | 143 | TextRange::offset_len(offset, ((spaces + 1) as u32).into()), |
144 | if join_single_expr_block(edit, node).is_some() { | 144 | " ".to_string(), |
145 | return | 145 | ); |
146 | } | 146 | return; |
147 | } | ||
147 | 148 | ||
148 | if let (Some(prev), Some(next)) = (node.prev_sibling(), node.next_sibling()) { | 149 | // Special case that turns something like: |
149 | let range = TextRange::from_to(prev.range().start(), node.range().end()); | 150 | // |
150 | if is_trailing_comma(prev.kind(), next.kind()) { | 151 | // ``` |
151 | // Removes: trailing comma, newline (incl. surrounding whitespace) | 152 | // my_function({<|> |
152 | edit.delete(range); | 153 | // <some-expr> |
153 | } else if no_space_required(prev.kind(), next.kind()) { | 154 | // }) |
154 | // Removes: newline (incl. surrounding whitespace) | 155 | // ``` |
155 | edit.delete(node.range()); | 156 | // |
156 | } else if prev.kind() == COMMA && next.kind() == R_CURLY { | 157 | // into `my_function(<some-expr>)` |
157 | // Removes: comma, newline (incl. surrounding whitespace) | 158 | if join_single_expr_block(edit, node).is_some() { |
158 | // Adds: a single whitespace | 159 | return |
159 | edit.replace(range, " ".to_string()); | 160 | } |
160 | } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { | ||
161 | // Removes: newline (incl. surrounding whitespace), start of the next comment | ||
162 | let comment_text = next.text(); | ||
163 | if let Some(newline_pos) = comment_text.find('\n') { | ||
164 | // Special case for multi-line c-like comments: join the comment content but | ||
165 | // keep the leading `/*` | ||
166 | |||
167 | let newline_offset = next.syntax().range().start() | ||
168 | + TextUnit::from(newline_pos as u32) | ||
169 | + TextUnit::of_char('\n'); | ||
170 | |||
171 | edit.insert(newline_offset, "/*".to_string()); | ||
172 | edit.delete(TextRange::from_to( | ||
173 | node.range().start(), | ||
174 | next.syntax().range().start() + TextUnit::of_str(next.prefix()) | ||
175 | )); | ||
176 | } else { | ||
177 | // Single-line comments | ||
178 | edit.delete(TextRange::from_to( | ||
179 | node.range().start(), | ||
180 | next.syntax().range().start() + TextUnit::of_str(next.prefix()) | ||
181 | )); | ||
182 | } | ||
183 | } else { | ||
184 | // Remove newline but add a computed amount of whitespace characters | ||
185 | edit.replace( | ||
186 | node.range(), | ||
187 | compute_ws(prev, next).to_string(), | ||
188 | ); | ||
189 | } | ||
190 | 161 | ||
191 | return; | 162 | // The node is between two other nodes |
163 | let prev = node.prev_sibling().unwrap(); | ||
164 | let next = node.next_sibling().unwrap(); | ||
165 | if is_trailing_comma(prev.kind(), next.kind()) { | ||
166 | // Removes: trailing comma, newline (incl. surrounding whitespace) | ||
167 | edit.delete(TextRange::from_to(prev.range().start(), node.range().end())); | ||
168 | } else if prev.kind() == COMMA && next.kind() == R_CURLY { | ||
169 | // Removes: comma, newline (incl. surrounding whitespace) | ||
170 | // Adds: a single whitespace | ||
171 | edit.replace( | ||
172 | TextRange::from_to(prev.range().start(), node.range().end()), | ||
173 | " ".to_string() | ||
174 | ); | ||
175 | } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { | ||
176 | // Removes: newline (incl. surrounding whitespace), start of the next comment | ||
177 | let comment_text = next.text(); | ||
178 | if let Some(newline_pos) = comment_text.find('\n') { | ||
179 | // Special case for multiline comments: join the comment content but | ||
180 | // keep the leading `/*` | ||
181 | |||
182 | let newline_offset = next.syntax().range().start() | ||
183 | + TextUnit::from(newline_pos as u32) | ||
184 | + TextUnit::of_char('\n'); | ||
185 | |||
186 | edit.insert(newline_offset, "/*".to_string()); | ||
187 | edit.delete(TextRange::from_to( | ||
188 | node.range().start(), | ||
189 | next.syntax().range().start() + TextUnit::of_str(next.prefix()) | ||
190 | )); | ||
191 | } else { | ||
192 | // Single-line comments | ||
193 | edit.delete(TextRange::from_to( | ||
194 | node.range().start(), | ||
195 | next.syntax().range().start() + TextUnit::of_str(next.prefix()) | ||
196 | )); | ||
192 | } | 197 | } |
198 | } else { | ||
199 | // Remove newline but add a computed amount of whitespace characters | ||
200 | edit.replace( | ||
201 | node.range(), | ||
202 | compute_ws(prev, next).to_string(), | ||
203 | ); | ||
193 | } | 204 | } |
194 | |||
195 | // The node is either the first or the last in the file | ||
196 | let suff = &node_text[TextRange::from_to( | ||
197 | offset - node.range().start() + TextUnit::of_char('\n'), | ||
198 | TextUnit::of_str(node_text), | ||
199 | )]; | ||
200 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); | ||
201 | |||
202 | edit.replace( | ||
203 | TextRange::offset_len(offset, ((spaces + 1) as u32).into()), | ||
204 | " ".to_string(), | ||
205 | ); | ||
206 | } | 205 | } |
207 | 206 | ||
208 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | 207 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { |
@@ -212,13 +211,6 @@ fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | |||
212 | } | 211 | } |
213 | } | 212 | } |
214 | 213 | ||
215 | fn no_space_required(left: SyntaxKind, right: SyntaxKind) -> bool { | ||
216 | match (left, right) { | ||
217 | (_, DOT) => true, | ||
218 | _ => false | ||
219 | } | ||
220 | } | ||
221 | |||
222 | fn join_single_expr_block( | 214 | fn join_single_expr_block( |
223 | edit: &mut EditBuilder, | 215 | edit: &mut EditBuilder, |
224 | node: SyntaxNodeRef, | 216 | node: SyntaxNodeRef, |
@@ -260,6 +252,7 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { | |||
260 | } | 252 | } |
261 | match right.kind() { | 253 | match right.kind() { |
262 | R_PAREN | R_BRACK => return "", | 254 | R_PAREN | R_BRACK => return "", |
255 | DOT => return "", | ||
263 | _ => (), | 256 | _ => (), |
264 | } | 257 | } |
265 | " " | 258 | " " |