mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 05:15:00 +00:00
Split multi-line selection when starting a new columnar selection
This commit is contained in:
parent
951aa0e443
commit
0622722ab7
1 changed files with 93 additions and 60 deletions
|
@ -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<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>(
|
||||
&'a self,
|
||||
range: Range<DisplayPoint>,
|
||||
|
|
Loading…
Reference in a new issue