@@ -226,6 +226,19 @@ impl DisplaySnapshot {
}
}
+ pub fn prev_line_boundary(&self, mut point: Point) -> Point {
+ loop {
+ point.column = 0;
+ let mut display_point = self.point_to_display_point(point, Bias::Left);
+ *display_point.column_mut() = 0;
+ let next_point = self.display_point_to_point(display_point, Bias::Left);
+ if next_point == point {
+ return point;
+ }
+ point = next_point;
+ }
+ }
+
pub fn next_line_boundary(&self, mut point: Point) -> Point {
loop {
point.column = self.buffer_snapshot.line_len(point.row);
@@ -247,16 +260,6 @@ impl DisplaySnapshot {
DisplayPoint(block_point)
}
- fn point_to_display_point_with_clipping(&self, point: Point, bias: Bias) -> DisplayPoint {
- let fold_point = point.to_fold_point(&self.folds_snapshot, bias);
- let tab_point = self.tabs_snapshot.to_tab_point(fold_point);
- let wrap_point = self
- .wraps_snapshot
- .from_tab_point_with_clipping(tab_point, bias);
- let block_point = self.blocks_snapshot.to_block_point(wrap_point);
- DisplayPoint(block_point)
- }
-
fn display_point_to_point(&self, point: DisplayPoint, bias: Bias) -> Point {
let block_point = point.0;
let wrap_point = self.blocks_snapshot.to_wrap_point(block_point);
@@ -284,16 +284,8 @@ trait SelectionExt {
fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
- fn spanned_rows(
- &self,
- include_end_if_at_line_start: bool,
- map: &DisplaySnapshot,
- ) -> SpannedRows;
-}
-
-struct SpannedRows {
- buffer_rows: Range<u32>,
- display_rows: Range<u32>,
+ fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
+ -> Range<u32>;
}
#[derive(Clone, Debug)]
@@ -1577,12 +1569,12 @@ impl Editor {
let mut edit_ranges = Vec::new();
let mut selections = selections.iter().peekable();
while let Some(selection) = selections.next() {
- let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
+ let mut rows = selection.spanned_rows(false, &display_map);
let goal_display_column = selection.head().to_display_point(&display_map).column();
// Accumulate contiguous regions of rows that we want to delete.
while let Some(next_selection) = selections.peek() {
- let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
+ let next_rows = next_selection.spanned_rows(false, &display_map);
if next_rows.start <= rows.end {
rows.end = next_rows.end;
selections.next().unwrap();
@@ -1645,10 +1637,10 @@ impl Editor {
let mut selections_iter = selections.iter().peekable();
while let Some(selection) = selections_iter.next() {
// Avoid duplicating the same lines twice.
- let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
+ let mut rows = selection.spanned_rows(false, &display_map);
while let Some(next_selection) = selections_iter.peek() {
- let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
+ let next_rows = next_selection.spanned_rows(false, &display_map);
if next_rows.start <= rows.end - 1 {
rows.end = next_rows.end;
selections_iter.next().unwrap();
@@ -1693,92 +1685,98 @@ impl Editor {
}
pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
-
- let selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = self.buffer.read(cx).snapshot(cx);
let mut edits = Vec::new();
- let mut new_selection_ranges = Vec::new();
- let mut old_folds = Vec::new();
- let mut new_folds = Vec::new();
+ let mut unfold_ranges = Vec::new();
+ let mut refold_ranges = Vec::new();
+ let selections = self.local_selections::<Point>(cx);
let mut selections = selections.iter().peekable();
- let mut contiguous_selections = Vec::new();
+ let mut contiguous_row_selections = Vec::new();
+ let mut new_selections = Vec::new();
+
while let Some(selection) = selections.next() {
- // Accumulate contiguous regions of rows that we want to move.
- contiguous_selections.push(selection.point_range(&buffer));
- let SpannedRows {
- mut buffer_rows,
- mut display_rows,
- } = selection.spanned_rows(false, &display_map);
+ // Find all the selections that span a contiguous row range
+ contiguous_row_selections.push(selection.clone());
+ let start_row = selection.start.row;
+ let mut end_row = if selection.end.column > 0 || selection.is_empty() {
+ display_map.next_line_boundary(selection.end).row + 1
+ } else {
+ selection.end.row
+ };
while let Some(next_selection) = selections.peek() {
- let SpannedRows {
- buffer_rows: next_buffer_rows,
- display_rows: next_display_rows,
- } = next_selection.spanned_rows(false, &display_map);
- if next_buffer_rows.start <= buffer_rows.end {
- buffer_rows.end = next_buffer_rows.end;
- display_rows.end = next_display_rows.end;
- contiguous_selections.push(next_selection.point_range(&buffer));
- selections.next().unwrap();
+ if next_selection.start.row <= end_row {
+ end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
+ display_map.next_line_boundary(next_selection.end).row + 1
+ } else {
+ next_selection.end.row
+ };
+ contiguous_row_selections.push(selections.next().unwrap().clone());
} else {
break;
}
}
- // Cut the text from the selected rows and paste it at the start of the previous line.
- if display_rows.start != 0 {
- let start = Point::new(buffer_rows.start, 0).to_offset(&buffer);
- let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
- .to_offset(&buffer);
-
- let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0);
- let prev_row_buffer_start = display_map.prev_row_boundary(prev_row_display_start).1;
- let prev_row_buffer_start_offset = prev_row_buffer_start.to_offset(&buffer);
-
- let mut text = String::new();
- text.extend(buffer.text_for_range(start..end));
- text.push('\n');
- edits.push((
- prev_row_buffer_start_offset..prev_row_buffer_start_offset,
- text,
- ));
- edits.push((start - 1..end, String::new()));
-
- let row_delta = buffer_rows.start - prev_row_buffer_start.row;
-
- // Move selections up.
- for range in &mut contiguous_selections {
- range.start.row -= row_delta;
- range.end.row -= row_delta;
- }
-
- // Move folds up.
- old_folds.push(start..end);
- for fold in display_map.folds_in_range(start..end) {
- let mut start = fold.start.to_point(&buffer);
- let mut end = fold.end.to_point(&buffer);
- start.row -= row_delta;
- end.row -= row_delta;
- new_folds.push(start..end);
+ // Move the text spanned by the row range to be before the line preceding the row range
+ if start_row > 0 {
+ let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
+ ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
+ let insertion_point = display_map.prev_line_boundary(Point::new(start_row - 1, 0));
+
+ // Don't move lines across excerpts
+ if !buffer.range_contains_excerpt_boundary(insertion_point..range_to_move.end) {
+ let text = buffer
+ .text_for_range(range_to_move.clone())
+ .flat_map(|s| s.chars())
+ .skip(1)
+ .chain(['\n'])
+ .collect::<String>();
+
+ edits.push((insertion_point..insertion_point, text));
+ edits.push((range_to_move.clone(), String::new()));
+
+ let row_delta = range_to_move.start.row - insertion_point.row + 1;
+
+ // Move selections up
+ new_selections.extend(contiguous_row_selections.drain(..).map(
+ |mut selection| {
+ selection.start.row -= row_delta;
+ selection.end.row -= row_delta;
+ selection
+ },
+ ));
+
+ // Move folds up
+ unfold_ranges.push(range_to_move.clone());
+ for fold in display_map.folds_in_range(
+ buffer.anchor_before(range_to_move.start)
+ ..buffer.anchor_after(range_to_move.end),
+ ) {
+ let mut start = fold.start.to_point(&buffer);
+ let mut end = fold.end.to_point(&buffer);
+ start.row -= row_delta;
+ end.row -= row_delta;
+ refold_ranges.push(start..end);
+ }
}
}
- new_selection_ranges.extend(contiguous_selections.drain(..));
+ // If we didn't move line(s), preserve the existing selections
+ new_selections.extend(contiguous_row_selections.drain(..));
}
- self.unfold_ranges(old_folds, cx);
+ self.start_transaction(cx);
+ self.unfold_ranges(unfold_ranges, cx);
self.buffer.update(cx, |buffer, cx| {
for (range, text) in edits.into_iter().rev() {
- buffer.edit(Some(range), text, cx);
+ buffer.edit([range], text, cx);
}
});
- self.fold_ranges(new_folds, cx);
- self.select_ranges(new_selection_ranges, Some(Autoscroll::Fit), cx);
-
+ self.fold_ranges(refold_ranges, cx);
+ self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
self.end_transaction(cx);
}
@@ -1822,38 +1820,43 @@ impl Editor {
if end_row <= buffer.max_point().row {
let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0));
- let mut text = String::from("\n");
- text.extend(buffer.text_for_range(range_to_move.clone()));
- text.pop(); // Drop trailing newline
- edits.push((range_to_move.clone(), String::new()));
- edits.push((insertion_point..insertion_point, text));
-
- let row_delta = insertion_point.row - range_to_move.end.row + 1;
-
- // Make the selections relative to the insertion row
- new_selections.extend(contiguous_row_selections.drain(..).map(|mut selection| {
- selection.start.row += row_delta;
- selection.end.row += row_delta;
- selection
- }));
-
- // Unfold all the folds spanned by these rows
- unfold_ranges.push(range_to_move.clone());
-
- // Refold ranges relative to the insertion row
- for fold in display_map.folds_in_range(
- buffer.anchor_before(range_to_move.start)
- ..buffer.anchor_after(range_to_move.end),
- ) {
- let mut start = fold.start.to_point(&buffer);
- let mut end = fold.end.to_point(&buffer);
- start.row += row_delta;
- end.row += row_delta;
- refold_ranges.push(start..end);
+
+ // Don't move lines across excerpt boundaries
+ if !buffer.range_contains_excerpt_boundary(range_to_move.start..insertion_point) {
+ let mut text = String::from("\n");
+ text.extend(buffer.text_for_range(range_to_move.clone()));
+ text.pop(); // Drop trailing newline
+ edits.push((range_to_move.clone(), String::new()));
+ edits.push((insertion_point..insertion_point, text));
+
+ let row_delta = insertion_point.row - range_to_move.end.row + 1;
+
+ // Move selections down
+ new_selections.extend(contiguous_row_selections.drain(..).map(
+ |mut selection| {
+ selection.start.row += row_delta;
+ selection.end.row += row_delta;
+ selection
+ },
+ ));
+
+ // Move folds down
+ unfold_ranges.push(range_to_move.clone());
+ for fold in display_map.folds_in_range(
+ buffer.anchor_before(range_to_move.start)
+ ..buffer.anchor_after(range_to_move.end),
+ ) {
+ let mut start = fold.start.to_point(&buffer);
+ let mut end = fold.end.to_point(&buffer);
+ start.row += row_delta;
+ end.row += row_delta;
+ refold_ranges.push(start..end);
+ }
}
- } else {
- new_selections.extend(contiguous_row_selections.drain(..));
}
+
+ // If we didn't move line(s), preserve the existing selections
+ new_selections.extend(contiguous_row_selections.drain(..));
}
self.start_transaction(cx);
@@ -2405,7 +2408,7 @@ impl Editor {
let mut selections = self.local_selections::<Point>(cx);
let max_point = display_map.buffer_snapshot.max_point();
for selection in &mut selections {
- let rows = selection.spanned_rows(true, &display_map).buffer_rows;
+ let rows = selection.spanned_rows(true, &display_map);
selection.start = Point::new(rows.start, 0);
selection.end = cmp::min(max_point, Point::new(rows.end, 0));
selection.reversed = false;
@@ -3778,30 +3781,20 @@ impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
&self,
include_end_if_at_line_start: bool,
map: &DisplaySnapshot,
- ) -> SpannedRows {
- let display_start = self
- .start
- .to_point(&map.buffer_snapshot)
- .to_display_point(map);
- let mut display_end = self
- .end
- .to_point(&map.buffer_snapshot)
- .to_display_point(map);
+ ) -> Range<u32> {
+ let start = self.start.to_point(&map.buffer_snapshot);
+ let mut end = self.end.to_point(&map.buffer_snapshot);
if !include_end_if_at_line_start
- && display_end.row() != map.max_point().row()
- && display_start.row() != display_end.row()
- && display_end.column() == 0
+ && end.row != map.buffer_snapshot.max_point().row
+ && start.row != end.row
+ && end.column == 0
{
- *display_end.row_mut() -= 1;
+ end.row -= 1;
}
- let (display_start, buffer_start) = map.prev_row_boundary(display_start);
- let (display_end, buffer_end) = map.next_row_boundary(display_end);
-
- SpannedRows {
- buffer_rows: buffer_start.row..buffer_end.row + 1,
- display_rows: display_start.row()..display_end.row() + 1,
- }
+ let buffer_start = map.prev_line_boundary(start);
+ let buffer_end = map.next_line_boundary(end);
+ buffer_start.row..buffer_end.row + 1
}
}