Detailed changes
@@ -6736,9 +6736,31 @@ impl Editor {
}
}
- let row = selection.head().row;
- let indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
- let indent_end = Point::new(row, indent_size.len);
+ // 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
+ // of the lines.
+ //
+ // If there is a tie, we use the deepest indent.
+ let (indent_size, indent_end) = {
+ let mut indent_size_occurrences = HashMap::default();
+ let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
+
+ for row in start_row..=end_row {
+ let indent = buffer.indent_size_for_line(MultiBufferRow(row));
+ rows_by_indent_size.entry(indent).or_default().push(row);
+ *indent_size_occurrences.entry(indent).or_insert(0) += 1;
+ }
+
+ let indent_size = indent_size_occurrences
+ .into_iter()
+ .max_by_key(|(indent, count)| (*count, indent.len))
+ .map(|(indent, _)| indent)
+ .unwrap_or_default();
+ let row = rows_by_indent_size[&indent_size][0];
+ let indent_end = Point::new(row, indent_size.len);
+
+ (indent_size, indent_end)
+ };
let mut line_prefix = indent_size.chars().collect::<String>();
@@ -6788,10 +6810,22 @@ impl Editor {
let start = Point::new(start_row, 0);
let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
let selection_text = buffer.text_for_range(start..end).collect::<String>();
- let unwrapped_text = selection_text
+ let Some(lines_without_prefixes) = selection_text
.lines()
- .map(|line| line.strip_prefix(&line_prefix).unwrap())
- .join(" ");
+ .map(|line| {
+ line.strip_prefix(&line_prefix)
+ .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
+ .ok_or_else(|| {
+ anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
+ })
+ })
+ .collect::<Result<Vec<_>, _>>()
+ .log_err()
+ else {
+ continue;
+ };
+
+ let unwrapped_text = lines_without_prefixes.join(" ");
let wrap_column = buffer
.settings_at(Point::new(start_row, 0), cx)
.preferred_line_length as usize;
@@ -4249,6 +4249,80 @@ async fn test_rewrap(cx: &mut TestAppContext) {
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
cx.assert_editor_state(wrapped_text);
}
+
+ // Test rewrapping unaligned comments in a selection.
+ {
+ let language = Arc::new(Language::new(
+ LanguageConfig {
+ line_comments: vec!["// ".into(), "/// ".into()],
+ ..LanguageConfig::default()
+ },
+ Some(tree_sitter_rust::LANGUAGE.into()),
+ ));
+ cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
+
+ let unwrapped_text = indoc! {"
+ fn foo() {
+ if true {
+ ยซ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
+ // Praesent semper egestas tellus id dignissim.หยป
+ do_something();
+ } else {
+ //
+ }
+
+ }
+ "};
+
+ let wrapped_text = indoc! {"
+ fn foo() {
+ if true {
+ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
+ // mollis elit purus, a ornare lacus gravida vitae. Praesent semper
+ // egestas tellus id dignissim.ห
+ do_something();
+ } else {
+ //
+ }
+
+ }
+ "};
+
+ cx.set_state(unwrapped_text);
+ cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
+ cx.assert_editor_state(wrapped_text);
+
+ let unwrapped_text = indoc! {"
+ fn foo() {
+ if true {
+ ยซห // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
+ // Praesent semper egestas tellus id dignissim.ยป
+ do_something();
+ } else {
+ //
+ }
+
+ }
+ "};
+
+ let wrapped_text = indoc! {"
+ fn foo() {
+ if true {
+ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
+ // mollis elit purus, a ornare lacus gravida vitae. Praesent semper
+ // egestas tellus id dignissim.ห
+ do_something();
+ } else {
+ //
+ }
+
+ }
+ "};
+
+ cx.set_state(unwrapped_text);
+ cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
+ cx.assert_editor_state(wrapped_text);
+ }
}
#[gpui::test]
@@ -144,7 +144,7 @@ pub struct BufferSnapshot {
/// The kind and amount of indentation in a particular line. For now,
/// assumes that indentation is all the same character.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct IndentSize {
/// The number of bytes that comprise the indentation.
pub len: u32,
@@ -153,7 +153,7 @@ pub struct IndentSize {
}
/// A whitespace character that's used for indentation.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum IndentKind {
/// An ASCII space character.
#[default]