Split multi-line selection when starting a new columnar selection

This commit is contained in:
Antonio Scandurra 2021-05-11 11:54:53 +02:00
parent 951aa0e443
commit 0622722ab7

View file

@ -1797,92 +1797,92 @@ impl BufferView {
use super::RangeExt; use super::RangeExt;
let app = ctx.as_ref(); 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() { let mut state = if let Some(state) = self.add_selections_state.take() {
state state
} else { } else {
let (ix, oldest_selection) = selections let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
.iter() let range = oldest_selection
.enumerate() .display_range(&self.display_map, app)
.min_by_key(|(_, s)| s.id) .sorted();
.unwrap();
selections = &selections[ix..ix + 1]; selections.clear();
AddSelectionsState { let mut stack = Vec::new();
above, if range.start.row() == range.end.row() {
stack: vec![oldest_selection.id], 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 last_added_selection = *state.stack.last().unwrap();
let mut new_selections = Vec::new(); let mut new_selections = Vec::new();
if above == state.above { 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 { if selection.id == last_added_selection {
let range = selection.display_range(&self.display_map, app).sorted(); let range = selection.display_range(&self.display_map, app).sorted();
debug_assert_eq!(range.start.row(), range.end.row());
let mut row = if above { let mut row = range.start.row();
range.start.row() let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
{
start..end
} else { } 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 { if above {
row -= 1; row -= 1;
} else { } else {
row += 1; row += 1;
} }
let line_len = self.display_map.line_len(row, app).unwrap(); if let Some(new_selection) =
if start_column < line_len || (is_empty && start_column == line_len) { self.build_columnar_selection(row, &columns, selection.reversed, app)
let id = post_inc(&mut self.next_selection_id); {
let start = DisplayPoint::new(row, start_column); state.stack.push(new_selection.id);
let end = DisplayPoint::new(row, cmp::min(end_column, line_len)); if above {
new_selections.push(Selection { new_selections.push(new_selection);
id, new_selections.push(selection);
start: self } else {
.display_map new_selections.push(selection);
.anchor_before(start, Bias::Left, app) new_selections.push(new_selection);
.unwrap(), }
end: self
.display_map continue 'outer;
.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;
} }
} }
} }
new_selections.push(selection.clone()); new_selections.push(selection);
} }
new_selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
} else { } else {
new_selections.extend( new_selections = selections;
selections new_selections.retain(|s| s.id != last_added_selection);
.into_iter()
.filter(|s| s.id != last_added_selection)
.cloned(),
);
state.stack.pop(); state.stack.pop();
} }
@ -1892,6 +1892,39 @@ impl BufferView {
} }
} }
fn build_columnar_selection(
&mut self,
row: u32,
columns: &Range<u32>,
reversed: bool,
ctx: &AppContext,
) -> Option<Selection> {
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>( pub fn selections_in_range<'a>(
&'a self, &'a self,
range: Range<DisplayPoint>, range: Range<DisplayPoint>,