diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 06cdc68ce6ba8e75e680dc91a118e640a2cffb4a..9e5704b2cdedf0b2abb4160a71797d8fadb7cdae 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -10873,14 +10873,54 @@ impl Editor { pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context) { let buffer = self.buffer.read(cx).snapshot(cx); let selections = self.selections.all::(cx); - let mut selections = selections.iter().peekable(); + + // Shrink and split selections to respect paragraph boundaries. + let ranges = selections.into_iter().flat_map(|selection| { + let language_settings = buffer.language_settings_at(selection.head(), cx); + let language_scope = buffer.language_scope_at(selection.head()); + + let Some(start_row) = (selection.start.row..=selection.end.row) + .find(|row| !buffer.is_line_blank(MultiBufferRow(*row))) + else { + return vec![]; + }; + let Some(end_row) = (selection.start.row..=selection.end.row) + .rev() + .find(|row| !buffer.is_line_blank(MultiBufferRow(*row))) + else { + return vec![]; + }; + + let mut row = start_row; + let mut ranges = Vec::new(); + while let Some(blank_row) = + (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row))) + { + let next_paragraph_start = (blank_row + 1..=end_row) + .find(|row| !buffer.is_line_blank(MultiBufferRow(*row))) + .unwrap(); + ranges.push(( + language_settings.clone(), + language_scope.clone(), + Point::new(row, 0)..Point::new(blank_row - 1, 0), + )); + row = next_paragraph_start; + } + ranges.push(( + language_settings.clone(), + language_scope.clone(), + Point::new(row, 0)..Point::new(end_row, 0), + )); + + ranges + }); let mut edits = Vec::new(); let mut rewrapped_row_ranges = Vec::>::new(); - while let Some(selection) = selections.next() { - let mut start_row = selection.start.row; - let mut end_row = selection.end.row; + for (language_settings, language_scope, range) in ranges { + let mut start_row = range.start.row; + let mut end_row = range.end.row; // Skip selections that overlap with a range that has already been rewrapped. let selection_range = start_row..end_row; @@ -10891,7 +10931,7 @@ impl Editor { continue; } - let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size; + let tab_size = language_settings.tab_size; // Since not all lines in the selection may be at the same indent // level, choose the indent size that is the most common between all @@ -10922,25 +10962,20 @@ impl Editor { let mut line_prefix = indent_size.chars().collect::(); let mut inside_comment = false; - if let Some(comment_prefix) = - buffer - .language_scope_at(selection.head()) - .and_then(|language| { - language - .line_comment_prefixes() - .iter() - .find(|prefix| buffer.contains_str_at(indent_end, prefix)) - .cloned() - }) - { + if let Some(comment_prefix) = language_scope.and_then(|language| { + language + .line_comment_prefixes() + .iter() + .find(|prefix| buffer.contains_str_at(indent_end, prefix)) + .cloned() + }) { line_prefix.push_str(&comment_prefix); inside_comment = true; } - let language_settings = buffer.language_settings_at(selection.head(), cx); let allow_rewrap_based_on_language = match language_settings.allow_rewrap { RewrapBehavior::InComments => inside_comment, - RewrapBehavior::InSelections => !selection.is_empty(), + RewrapBehavior::InSelections => !range.is_empty(), RewrapBehavior::Anywhere => true, }; @@ -10951,11 +10986,12 @@ impl Editor { continue; } - if selection.is_empty() { + if range.is_empty() { 'expand_upwards: while start_row > 0 { let prev_row = start_row - 1; if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix) && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len() + && !buffer.is_line_blank(MultiBufferRow(prev_row)) { start_row = prev_row; } else { @@ -10967,6 +11003,7 @@ impl Editor { let next_row = end_row + 1; if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix) && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len() + && !buffer.is_line_blank(MultiBufferRow(next_row)) { end_row = next_row; } else { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 585462e3bc9dc1d69c895c3ca4f61964a881837f..e4bd79f6e87bc6b01b4c7715f9ee85c9bdc8ca59 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -5111,7 +5111,7 @@ async fn test_rewrap(cx: &mut TestAppContext) { nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. "}, - plaintext_language, + plaintext_language.clone(), &mut cx, ); @@ -5174,6 +5174,69 @@ async fn test_rewrap(cx: &mut TestAppContext) { &mut cx, ); + assert_rewrap( + indoc! {" + «ˇone one one one one one one one one one one one one one one one one one one one one one one one one + + two» + + three + + «ˇ\t + + four four four four four four four four four four four four four four four four four four four four» + + «ˇfive five five five five five five five five five five five five five five five five five five five + \t» + six six six six six six six six six six six six six six six six six six six six six six six six six + "}, + indoc! {" + «ˇone one one one one one one one one one one one one one one one one one one one + one one one one one + + two» + + three + + «ˇ\t + + four four four four four four four four four four four four four four four four + four four four four» + + «ˇfive five five five five five five five five five five five five five five five + five five five five + \t» + six six six six six six six six six six six six six six six six six six six six six six six six six + "}, + plaintext_language.clone(), + &mut cx, + ); + + assert_rewrap( + indoc! {" + //ˇ long long long long long long long long long long long long long long long long long long long long long long long long long long long long + //ˇ + //ˇ long long long long long long long long long long long long long long long long long long long long long long long long long long long long + //ˇ short short short + int main(void) { + return 17; + } + "}, + indoc! {" + //ˇ long long long long long long long long long long long long long long long + // long long long long long long long long long long long long long + //ˇ + //ˇ long long long long long long long long long long long long long long long + //ˇ long long long long long long long long long long long long long short short + // short + int main(void) { + return 17; + } + "}, + language_with_c_comments, + &mut cx, + ); + #[track_caller] fn assert_rewrap( unwrapped_text: &str,