@@ -11551,7 +11551,7 @@ impl Editor {
end
} else {
text.push('\n');
- Point::new(rows.end.0, 0)
+ Point::new(rows.start.0, 0)
}
} else {
text.push('\n');
@@ -11567,11 +11567,57 @@ impl Editor {
}
}
- self.transact(window, cx, |this, _, cx| {
+ self.transact(window, cx, |this, window, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, None, cx);
});
+ // When duplicating upward with whole lines, move the cursor to the duplicated line
+ if upwards && whole_lines {
+ let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+ this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
+ let mut new_ranges = Vec::new();
+ let selections = s.all::<Point>(&display_map);
+ let mut selections_iter = selections.iter().peekable();
+
+ while let Some(first_selection) = selections_iter.next() {
+ // Group contiguous selections together to find the total row span
+ let mut group_selections = vec![first_selection];
+ let mut rows = first_selection.spanned_rows(false, &display_map);
+
+ while let Some(next_selection) = selections_iter.peek() {
+ let next_rows = next_selection.spanned_rows(false, &display_map);
+ if next_rows.start < rows.end {
+ rows.end = next_rows.end;
+ group_selections.push(selections_iter.next().unwrap());
+ } else {
+ break;
+ }
+ }
+
+ let row_count = rows.end.0 - rows.start.0;
+
+ // Move all selections in this group up by the total number of duplicated rows
+ for selection in group_selections {
+ let new_start = Point::new(
+ selection.start.row.saturating_sub(row_count),
+ selection.start.column,
+ );
+
+ let new_end = Point::new(
+ selection.end.row.saturating_sub(row_count),
+ selection.end.column,
+ );
+
+ new_ranges.push(new_start..new_end);
+ }
+ }
+
+ s.select_ranges(new_ranges);
+ });
+ }
+
this.request_autoscroll(Autoscroll::fit(), cx);
});
}
@@ -5646,8 +5646,8 @@ fn test_duplicate_line(cx: &mut TestAppContext) {
);
});
- // With `move_upwards` the selections stay in place, except for
- // the lines inserted above them
+ // With `duplicate_line_up` the selections move to the duplicated lines,
+ // which are inserted above the original lines
let editor = cx.add_window(|window, cx| {
let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
build_editor(buffer, window, cx)
@@ -5669,7 +5669,7 @@ fn test_duplicate_line(cx: &mut TestAppContext) {
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1),
DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2),
DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0),
- DisplayPoint::new(DisplayRow(6), 0)..DisplayPoint::new(DisplayRow(6), 0),
+ DisplayPoint::new(DisplayRow(5), 0)..DisplayPoint::new(DisplayRow(5), 0),
]
);
});
@@ -26888,8 +26888,8 @@ fn test_duplicate_line_up_on_last_line_without_newline(cx: &mut TestAppContext)
assert_eq!(
editor.selections.display_ranges(cx),
- vec![DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0)],
- "Selection should remain on the original line"
+ vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)],
+ "Selection should move to the duplicated line"
);
})
.unwrap();