aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/join_lines.rs74
1 files changed, 62 insertions, 12 deletions
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 2c077ed1f..7fcae13e0 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -7,6 +7,7 @@ use syntax::{
7 SyntaxKind::{self, USE_TREE, WHITESPACE}, 7 SyntaxKind::{self, USE_TREE, WHITESPACE},
8 SyntaxNode, SyntaxToken, TextRange, TextSize, T, 8 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
9}; 9};
10use test_utils::mark;
10use text_edit::{TextEdit, TextEditBuilder}; 11use text_edit::{TextEdit, TextEditBuilder};
11 12
12// Feature: Join Lines 13// Feature: Join Lines
@@ -44,9 +45,9 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
44 let text = token.text(); 45 let text = token.text();
45 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { 46 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
46 let pos: TextSize = (pos as u32).into(); 47 let pos: TextSize = (pos as u32).into();
47 let off = token.text_range().start() + range.start() + pos; 48 let offset = token.text_range().start() + range.start() + pos;
48 if !edit.invalidates_offset(off) { 49 if !edit.invalidates_offset(offset) {
49 remove_newline(&mut edit, &token, off); 50 remove_newline(&mut edit, &token, offset);
50 } 51 }
51 } 52 }
52 } 53 }
@@ -56,14 +57,25 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
56 57
57fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { 58fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) {
58 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { 59 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 {
59 // The node is either the first or the last in the file 60 let mut string_open_quote = false;
60 let suff = &token.text()[TextRange::new( 61 if let Some(string) = ast::String::cast(token.clone()) {
61 offset - token.text_range().start() + TextSize::of('\n'), 62 if let Some(range) = string.open_quote_text_range() {
62 TextSize::of(token.text()), 63 mark::hit!(join_string_literal);
63 )]; 64 string_open_quote = range.end() == offset;
64 let spaces = suff.bytes().take_while(|&b| b == b' ').count(); 65 }
65 66 }
66 edit.replace(TextRange::at(offset, ((spaces + 1) as u32).into()), " ".to_string()); 67
68 let n_spaces_after_line_break = {
69 let suff = &token.text()[TextRange::new(
70 offset - token.text_range().start() + TextSize::of('\n'),
71 TextSize::of(token.text()),
72 )];
73 suff.bytes().take_while(|&b| b == b' ').count()
74 };
75
76 let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into());
77 let replace_with = if string_open_quote { "" } else { " " };
78 edit.replace(range, replace_with.to_string());
67 return; 79 return;
68 } 80 }
69 81
@@ -194,7 +206,7 @@ fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
194#[cfg(test)] 206#[cfg(test)]
195mod tests { 207mod tests {
196 use syntax::SourceFile; 208 use syntax::SourceFile;
197 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; 209 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range, mark};
198 210
199 use super::*; 211 use super::*;
200 212
@@ -771,4 +783,42 @@ fn foo() {
771 ", 783 ",
772 ); 784 );
773 } 785 }
786
787 #[test]
788 fn join_string_literal() {
789 mark::check!(join_string_literal);
790 check_join_lines(
791 r#"
792fn main() {
793 $0"
794hello
795";
796}
797"#,
798 r#"
799fn main() {
800 $0"hello
801";
802}
803"#,
804 );
805
806 check_join_lines(
807 r#"
808fn main() {
809 "
810$0hello
811world
812";
813}
814"#,
815 r#"
816fn main() {
817 "
818$0hello world
819";
820}
821"#,
822 );
823 }
774} 824}