@@ -10873,14 +10873,54 @@ impl Editor {
pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
let buffer = self.buffer.read(cx).snapshot(cx);
let selections = self.selections.all::<Point>(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::<RangeInclusive<u32>>::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::<String>();
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 {
@@ -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,