From 0622722ab7e1f8470d7852f32f1926a5f06648e3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 11 May 2021 11:54:53 +0200 Subject: [PATCH] Split multi-line selection when starting a new columnar selection --- zed/src/editor/buffer_view.rs | 153 +++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 60 deletions(-) diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 70c2f905c81eabf3e20e69191842fb25d094b7b5..9a496b6dee7cb2234e498d2f165de801e85aa6d8 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -1797,92 +1797,92 @@ impl BufferView { use super::RangeExt; let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - let mut selections = self.selections(app); + + let mut selections = self.selections(app).to_vec(); let mut state = if let Some(state) = self.add_selections_state.take() { state } else { - let (ix, oldest_selection) = selections - .iter() - .enumerate() - .min_by_key(|(_, s)| s.id) - .unwrap(); - selections = &selections[ix..ix + 1]; - AddSelectionsState { - above, - stack: vec![oldest_selection.id], + let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); + let range = oldest_selection + .display_range(&self.display_map, app) + .sorted(); + + selections.clear(); + let mut stack = Vec::new(); + if range.start.row() == range.end.row() { + stack.push(oldest_selection.id); + selections.push(oldest_selection); + } else { + let columns = cmp::min(range.start.column(), range.end.column()) + ..cmp::max(range.start.column(), range.end.column()); + for row in range.start.row()..=range.end.row() { + if let Some(selection) = + self.build_columnar_selection(row, &columns, oldest_selection.reversed, app) + { + stack.push(selection.id); + selections.push(selection); + } + } + + if above { + stack.reverse(); + } } + + AddSelectionsState { above, stack } }; let last_added_selection = *state.stack.last().unwrap(); let mut new_selections = Vec::new(); if above == state.above { - for selection in selections { + let end_row = if above { + 0 + } else { + self.display_map.max_point(app).row() + }; + + 'outer: for selection in selections { if selection.id == last_added_selection { let range = selection.display_range(&self.display_map, app).sorted(); - - let mut row = if above { - range.start.row() + debug_assert_eq!(range.start.row(), range.end.row()); + let mut row = range.start.row(); + let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal + { + start..end } else { - range.end.row() + cmp::min(range.start.column(), range.end.column()) + ..cmp::max(range.start.column(), range.end.column()) }; - let start_column; - let end_column; - if let SelectionGoal::ColumnRange { start, end } = selection.goal { - start_column = start; - end_column = end; - } else { - start_column = cmp::min(range.start.column(), range.end.column()); - end_column = cmp::max(range.start.column(), range.end.column()); - } - let is_empty = start_column == end_column; - while row > 0 && row < self.display_map.max_point(app).row() { + while row != end_row { if above { row -= 1; } else { row += 1; } - let line_len = self.display_map.line_len(row, app).unwrap(); - if start_column < line_len || (is_empty && start_column == line_len) { - let id = post_inc(&mut self.next_selection_id); - let start = DisplayPoint::new(row, start_column); - let end = DisplayPoint::new(row, cmp::min(end_column, line_len)); - new_selections.push(Selection { - id, - start: self - .display_map - .anchor_before(start, Bias::Left, app) - .unwrap(), - end: self - .display_map - .anchor_before(end, Bias::Left, app) - .unwrap(), - reversed: selection.reversed - && range.start.row() == range.end.row(), - goal: SelectionGoal::ColumnRange { - start: start_column, - end: end_column, - }, - }); - state.stack.push(id); - break; + if let Some(new_selection) = + self.build_columnar_selection(row, &columns, selection.reversed, app) + { + state.stack.push(new_selection.id); + if above { + new_selections.push(new_selection); + new_selections.push(selection); + } else { + new_selections.push(selection); + new_selections.push(new_selection); + } + + continue 'outer; } } } - new_selections.push(selection.clone()); + new_selections.push(selection); } - - new_selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap()); } else { - new_selections.extend( - selections - .into_iter() - .filter(|s| s.id != last_added_selection) - .cloned(), - ); + new_selections = selections; + new_selections.retain(|s| s.id != last_added_selection); state.stack.pop(); } @@ -1892,6 +1892,39 @@ impl BufferView { } } + fn build_columnar_selection( + &mut self, + row: u32, + columns: &Range, + reversed: bool, + ctx: &AppContext, + ) -> Option { + let is_empty = columns.start == columns.end; + let line_len = self.display_map.line_len(row, ctx).unwrap(); + if columns.start < line_len || (is_empty && columns.start == line_len) { + let start = DisplayPoint::new(row, columns.start); + let end = DisplayPoint::new(row, cmp::min(columns.end, line_len)); + Some(Selection { + id: post_inc(&mut self.next_selection_id), + start: self + .display_map + .anchor_before(start, Bias::Left, ctx) + .unwrap(), + end: self + .display_map + .anchor_before(end, Bias::Left, ctx) + .unwrap(), + reversed, + goal: SelectionGoal::ColumnRange { + start: columns.start, + end: columns.end, + }, + }) + } else { + None + } + } + pub fn selections_in_range<'a>( &'a self, range: Range,