mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 00:39:51 +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;
|
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>,
|
||||||
|
|
Loading…
Reference in a new issue