Make editor::Rewrap respect paragraphs (#32046)

Closes #32021 

Release Notes:

- Changed the behavior of `editor::Rewrap` to not join paragraphs
together.
This commit is contained in:
Cole Miller 2025-06-04 18:14:38 -04:00 committed by GitHub
parent 17c3b741ec
commit 8191a5339d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 120 additions and 20 deletions

View file

@ -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 {