From 27a86cb7df5e1764c85f5eeb8bb85885072f782e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Wed, 10 Oct 2018 12:37:06 +0200 Subject: Collapse comments upon join --- crates/ra_editor/src/typing.rs | 79 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 15 deletions(-) (limited to 'crates/ra_editor') 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 { } else { range }; + let node = find_covering_node(file.syntax(), range); let mut edit = EditBuilder::new(); for node in node.descendants() { @@ -140,30 +141,71 @@ fn remove_newline( offset: TextUnit, ) { if node.kind() == WHITESPACE && node_text.bytes().filter(|&b| b == b'\n').count() == 1 { + // Special case that turns something like: + // + // ``` + // my_function({<|> + // + // }) + // ``` + // + // into `my_function()` if join_single_expr_block(edit, node).is_some() { return } - match (node.prev_sibling(), node.next_sibling()) { - (Some(prev), Some(next)) => { - let range = TextRange::from_to(prev.range().start(), node.range().end()); - if is_trailing_comma(prev.kind(), next.kind()) { - edit.delete(range); - } else if no_space_required(prev.kind(), next.kind()) { - edit.delete(node.range()); - } else if prev.kind() == COMMA && next.kind() == R_CURLY { - edit.replace(range, " ".to_string()); + + if let (Some(prev), Some(next)) = (node.prev_sibling(), node.next_sibling()) { + let range = TextRange::from_to(prev.range().start(), node.range().end()); + if is_trailing_comma(prev.kind(), next.kind()) { + // Removes: trailing comma, newline (incl. surrounding whitespace) + edit.delete(range); + } else if no_space_required(prev.kind(), next.kind()) { + // Removes: newline (incl. surrounding whitespace) + edit.delete(node.range()); + } else if prev.kind() == COMMA && next.kind() == R_CURLY { + // Removes: comma, newline (incl. surrounding whitespace) + // Adds: a single whitespace + edit.replace(range, " ".to_string()); + } else if prev.kind() == COMMENT && next.kind() == COMMENT { + // Removes: newline (incl. surrounding whitespace), start of the next comment + + // FIXME: I guess it is safe to unwrap here? A comment always has text, right? + let comment_text = next.leaf_text().unwrap().as_str(); + let comment_start_length = comment_start_length(comment_text); + + if let Some(newline_pos) = comment_text.find('\n') { + // Special case for multi-line c-like comments: join the comment content but + // keep the leading `/*` + + let newline_offset = next.range().start() + + TextUnit::from(newline_pos as u32) + + TextUnit::of_char('\n'); + + edit.insert(newline_offset, "/*".to_string()); + edit.delete(TextRange::from_to( + node.range().start(), + next.range().start() + comment_start_length + )); } else { - edit.replace( - node.range(), - compute_ws(prev, next).to_string(), - ); + // Single-line comments + edit.delete(TextRange::from_to( + node.range().start(), + next.range().start() + comment_start_length + )); } - return; + } else { + // Remove newline but add a computed amount of whitespace characters + edit.replace( + node.range(), + compute_ws(prev, next).to_string(), + ); } - _ => (), + + return; } } + // FIXME: do we ever reach this point? What does it mean to be here? I think we should document it let suff = &node_text[TextRange::from_to( offset - node.range().start() + TextUnit::of_char('\n'), TextUnit::of_str(node_text), @@ -176,6 +218,13 @@ fn remove_newline( ); } +// Return the start length of the comment (e.g. 2 for `//` and 3 for `//!`) +fn comment_start_length(_text: &str) -> TextUnit { + // TODO: use the parser here instead of reimplementing comment parsing? + // Otherwise, reimplement comment parsing :) + return TextUnit::from(2); +} + fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { match (left, right) { (COMMA, R_PAREN) | (COMMA, R_BRACK) => true, -- cgit v1.2.3