aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/typing.rs79
1 files changed, 64 insertions, 15 deletions
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 3384389d1..6c1a91ffb 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -30,6 +30,7 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
30 } else { 30 } else {
31 range 31 range
32 }; 32 };
33
33 let node = find_covering_node(file.syntax(), range); 34 let node = find_covering_node(file.syntax(), range);
34 let mut edit = EditBuilder::new(); 35 let mut edit = EditBuilder::new();
35 for node in node.descendants() { 36 for node in node.descendants() {
@@ -140,30 +141,71 @@ fn remove_newline(
140 offset: TextUnit, 141 offset: TextUnit,
141) { 142) {
142 if node.kind() == WHITESPACE && node_text.bytes().filter(|&b| b == b'\n').count() == 1 { 143 if node.kind() == WHITESPACE && node_text.bytes().filter(|&b| b == b'\n').count() == 1 {
144 // Special case that turns something like:
145 //
146 // ```
147 // my_function({<|>
148 // <some-expr>
149 // })
150 // ```
151 //
152 // into `my_function(<some-expr>)`
143 if join_single_expr_block(edit, node).is_some() { 153 if join_single_expr_block(edit, node).is_some() {
144 return 154 return
145 } 155 }
146 match (node.prev_sibling(), node.next_sibling()) { 156
147 (Some(prev), Some(next)) => { 157 if let (Some(prev), Some(next)) = (node.prev_sibling(), node.next_sibling()) {
148 let range = TextRange::from_to(prev.range().start(), node.range().end()); 158 let range = TextRange::from_to(prev.range().start(), node.range().end());
149 if is_trailing_comma(prev.kind(), next.kind()) { 159 if is_trailing_comma(prev.kind(), next.kind()) {
150 edit.delete(range); 160 // Removes: trailing comma, newline (incl. surrounding whitespace)
151 } else if no_space_required(prev.kind(), next.kind()) { 161 edit.delete(range);
152 edit.delete(node.range()); 162 } else if no_space_required(prev.kind(), next.kind()) {
153 } else if prev.kind() == COMMA && next.kind() == R_CURLY { 163 // Removes: newline (incl. surrounding whitespace)
154 edit.replace(range, " ".to_string()); 164 edit.delete(node.range());
165 } else if prev.kind() == COMMA && next.kind() == R_CURLY {
166 // Removes: comma, newline (incl. surrounding whitespace)
167 // Adds: a single whitespace
168 edit.replace(range, " ".to_string());
169 } else if prev.kind() == COMMENT && next.kind() == COMMENT {
170 // Removes: newline (incl. surrounding whitespace), start of the next comment
171
172 // FIXME: I guess it is safe to unwrap here? A comment always has text, right?
173 let comment_text = next.leaf_text().unwrap().as_str();
174 let comment_start_length = comment_start_length(comment_text);
175
176 if let Some(newline_pos) = comment_text.find('\n') {
177 // Special case for multi-line c-like comments: join the comment content but
178 // keep the leading `/*`
179
180 let newline_offset = next.range().start()
181 + TextUnit::from(newline_pos as u32)
182 + TextUnit::of_char('\n');
183
184 edit.insert(newline_offset, "/*".to_string());
185 edit.delete(TextRange::from_to(
186 node.range().start(),
187 next.range().start() + comment_start_length
188 ));
155 } else { 189 } else {
156 edit.replace( 190 // Single-line comments
157 node.range(), 191 edit.delete(TextRange::from_to(
158 compute_ws(prev, next).to_string(), 192 node.range().start(),
159 ); 193 next.range().start() + comment_start_length
194 ));
160 } 195 }
161 return; 196 } else {
197 // Remove newline but add a computed amount of whitespace characters
198 edit.replace(
199 node.range(),
200 compute_ws(prev, next).to_string(),
201 );
162 } 202 }
163 _ => (), 203
204 return;
164 } 205 }
165 } 206 }
166 207
208 // FIXME: do we ever reach this point? What does it mean to be here? I think we should document it
167 let suff = &node_text[TextRange::from_to( 209 let suff = &node_text[TextRange::from_to(
168 offset - node.range().start() + TextUnit::of_char('\n'), 210 offset - node.range().start() + TextUnit::of_char('\n'),
169 TextUnit::of_str(node_text), 211 TextUnit::of_str(node_text),
@@ -176,6 +218,13 @@ fn remove_newline(
176 ); 218 );
177} 219}
178 220
221// Return the start length of the comment (e.g. 2 for `//` and 3 for `//!`)
222fn comment_start_length(_text: &str) -> TextUnit {
223 // TODO: use the parser here instead of reimplementing comment parsing?
224 // Otherwise, reimplement comment parsing :)
225 return TextUnit::from(2);
226}
227
179fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { 228fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
180 match (left, right) { 229 match (left, right) {
181 (COMMA, R_PAREN) | (COMMA, R_BRACK) => true, 230 (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,