Implement add_cursor_above and add_cursor_below for buffer

This commit is contained in:
Antonio Scandurra
2021-05-11 12:35:27 +02:00
parent af6ab2762f
commit 0baff0c61d
4 changed files with 188 additions and 56 deletions
+2 -2
View File
@@ -3285,14 +3285,14 @@ mod tests {
start: self.anchor_before(range.end)?,
end: self.anchor_before(range.start)?,
reversed: true,
goal_column: None,
goal: SelectionGoal::None,
});
} else {
selections.push(Selection {
start: self.anchor_after(range.start)?,
end: self.anchor_before(range.end)?,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
});
}
}
+8 -1
View File
@@ -12,12 +12,19 @@ use std::{cmp::Ordering, mem, ops::Range};
pub type SelectionSetId = time::Lamport;
pub type SelectionsVersion = usize;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SelectionGoal {
None,
Column(u32),
ColumnRange { start: u32, end: u32 },
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Selection {
pub start: Anchor,
pub end: Anchor,
pub reversed: bool,
pub goal_column: Option<u32>,
pub goal: SelectionGoal,
}
impl Selection {
+159 -42
View File
@@ -1,6 +1,6 @@
use super::{
buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
Selection, SelectionSetId, ToOffset, ToPoint,
Selection, SelectionGoal, SelectionSetId, ToOffset, ToPoint,
};
use crate::{settings::Settings, workspace, worktree::FileHandle};
use anyhow::Result;
@@ -149,6 +149,16 @@ pub fn init(app: &mut MutableAppContext) {
"buffer:split_selection_into_lines",
Some("BufferView"),
),
Binding::new(
"ctrl-shift-up",
"buffer:add_cursor_above",
Some("BufferView"),
),
Binding::new(
"ctrl-shift-down",
"buffer:add_cursor_below",
Some("BufferView"),
),
Binding::new("pageup", "buffer:page_up", Some("BufferView")),
Binding::new("pagedown", "buffer:page_down", Some("BufferView")),
Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")),
@@ -244,6 +254,8 @@ pub fn init(app: &mut MutableAppContext) {
"buffer:split_selection_into_lines",
BufferView::split_selection_into_lines,
);
app.add_action("buffer:add_cursor_above", BufferView::add_cursor_above);
app.add_action("buffer:add_cursor_below", BufferView::add_cursor_below);
app.add_action("buffer:page_up", BufferView::page_up);
app.add_action("buffer:page_down", BufferView::page_down);
app.add_action("buffer:fold", BufferView::fold);
@@ -311,7 +323,7 @@ impl BufferView {
start: buffer.anchor_before(0).unwrap(),
end: buffer.anchor_before(0).unwrap(),
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
}],
Some(ctx),
)
@@ -483,7 +495,7 @@ impl BufferView {
start: cursor.clone(),
end: cursor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
};
if !add {
@@ -552,7 +564,7 @@ impl BufferView {
start: buffer.anchor_before(start).unwrap(),
end: buffer.anchor_before(end).unwrap(),
reversed,
goal_column: None,
goal: SelectionGoal::None,
});
}
self.update_selections(selections, autoscroll, ctx);
@@ -582,7 +594,7 @@ impl BufferView {
.display_map
.anchor_before(end, Bias::Left, ctx.as_ref())?,
reversed,
goal_column: None,
goal: SelectionGoal::None,
});
}
self.update_selections(selections, false, ctx);
@@ -623,7 +635,7 @@ impl BufferView {
start: anchor.clone(),
end: anchor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
}
})
.collect();
@@ -662,7 +674,7 @@ impl BufferView {
)
.unwrap();
selection.set_head(&buffer, cursor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
}
@@ -693,7 +705,7 @@ impl BufferView {
)
.unwrap();
selection.set_head(&buffer, cursor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
}
@@ -774,7 +786,7 @@ impl BufferView {
start: anchor.clone(),
end: anchor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
})
.collect();
self.buffer
@@ -1145,7 +1157,7 @@ impl BufferView {
start: new_selection_start.clone(),
end: new_selection_start,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
});
});
}
@@ -1196,7 +1208,7 @@ impl BufferView {
selection.end = cursor;
}
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1220,7 +1232,7 @@ impl BufferView {
)
.unwrap();
selection.set_head(&buffer, cursor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1255,7 +1267,7 @@ impl BufferView {
selection.end = cursor;
}
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1280,7 +1292,7 @@ impl BufferView {
)
.unwrap();
selection.set_head(&buffer, cursor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1303,18 +1315,18 @@ impl BufferView {
.to_display_point(&self.display_map, app)
.unwrap();
if start != end {
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
let (start, goal_column) =
movement::up(&self.display_map, start, selection.goal_column, app).unwrap();
let (start, goal) =
movement::up(&self.display_map, start, selection.goal, app).unwrap();
let cursor = self
.display_map
.anchor_before(start, Bias::Left, app)
.unwrap();
selection.start = cursor.clone();
selection.end = cursor;
selection.goal_column = goal_column;
selection.goal = goal;
selection.reversed = false;
}
}
@@ -1332,15 +1344,15 @@ impl BufferView {
.head()
.to_display_point(&self.display_map, app)
.unwrap();
let (head, goal_column) =
movement::up(&self.display_map, head, selection.goal_column, app).unwrap();
let (head, goal) =
movement::up(&self.display_map, head, selection.goal, app).unwrap();
selection.set_head(
&buffer,
self.display_map
.anchor_before(head, Bias::Left, app)
.unwrap(),
);
selection.goal_column = goal_column;
selection.goal = goal;
}
}
self.update_selections(selections, true, ctx);
@@ -1363,18 +1375,18 @@ impl BufferView {
.to_display_point(&self.display_map, app)
.unwrap();
if start != end {
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
let (start, goal_column) =
movement::down(&self.display_map, end, selection.goal_column, app).unwrap();
let (start, goal) =
movement::down(&self.display_map, end, selection.goal, app).unwrap();
let cursor = self
.display_map
.anchor_before(start, Bias::Right, app)
.unwrap();
selection.start = cursor.clone();
selection.end = cursor;
selection.goal_column = goal_column;
selection.goal = goal;
selection.reversed = false;
}
}
@@ -1392,15 +1404,15 @@ impl BufferView {
.head()
.to_display_point(&self.display_map, app)
.unwrap();
let (head, goal_column) =
movement::down(&self.display_map, head, selection.goal_column, app).unwrap();
let (head, goal) =
movement::down(&self.display_map, head, selection.goal, app).unwrap();
selection.set_head(
&buffer,
self.display_map
.anchor_before(head, Bias::Right, app)
.unwrap(),
);
selection.goal_column = goal_column;
selection.goal = goal;
}
}
self.update_selections(selections, true, ctx);
@@ -1423,7 +1435,7 @@ impl BufferView {
selection.start = anchor.clone();
selection.end = anchor;
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1445,7 +1457,7 @@ impl BufferView {
.anchor_before(new_head, Bias::Left, app)
.unwrap();
selection.set_head(buffer, anchor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1475,7 +1487,7 @@ impl BufferView {
selection.start = anchor.clone();
selection.end = anchor;
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1497,7 +1509,7 @@ impl BufferView {
.anchor_before(new_head, Bias::Left, app)
.unwrap();
selection.set_head(buffer, anchor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1528,7 +1540,7 @@ impl BufferView {
selection.start = anchor.clone();
selection.end = anchor;
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1555,7 +1567,7 @@ impl BufferView {
.anchor_before(new_head, Bias::Left, app)
.unwrap();
selection.set_head(buffer, anchor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1585,7 +1597,7 @@ impl BufferView {
selection.start = anchor.clone();
selection.end = anchor;
selection.reversed = false;
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1607,7 +1619,7 @@ impl BufferView {
.anchor_before(new_head, Bias::Left, app)
.unwrap();
selection.set_head(buffer, anchor);
selection.goal_column = None;
selection.goal = SelectionGoal::None;
}
}
self.update_selections(selections, true, ctx);
@@ -1627,7 +1639,7 @@ impl BufferView {
start: cursor.clone(),
end: cursor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
};
self.update_selections(vec![selection], true, ctx);
}
@@ -1645,7 +1657,7 @@ impl BufferView {
start: cursor.clone(),
end: cursor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
};
self.update_selections(vec![selection], true, ctx);
}
@@ -1661,7 +1673,7 @@ impl BufferView {
start: Anchor::Start,
end: Anchor::End,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
};
self.update_selections(vec![selection], false, ctx);
}
@@ -1697,7 +1709,7 @@ impl BufferView {
start: selection.start.clone(),
end: selection.start.clone(),
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
});
}
for row in range.start.row + 1..range.end.row {
@@ -1708,14 +1720,14 @@ impl BufferView {
start: cursor.clone(),
end: cursor,
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
});
}
new_selections.push(Selection {
start: selection.end.clone(),
end: selection.end.clone(),
reversed: false,
goal_column: None,
goal: SelectionGoal::None,
});
to_unfold.push(range);
}
@@ -1723,6 +1735,111 @@ impl BufferView {
self.update_selections(new_selections, true, ctx);
}
pub fn add_cursor_above(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
use super::RangeExt;
let app = ctx.as_ref();
let buffer = self.buffer.read(app);
let mut new_selections = Vec::new();
for selection in self.selections(app) {
let range = selection.display_range(&self.display_map, app).sorted();
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;
for row in (0..range.start.row()).rev() {
let line_len = self.display_map.line_len(row, app).unwrap();
if start_column < line_len || (is_empty && start_column == line_len) {
let start = DisplayPoint::new(row, start_column);
let end = DisplayPoint::new(row, cmp::min(end_column, line_len));
new_selections.push(Selection {
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,
},
});
break;
}
}
new_selections.push(selection.clone());
}
new_selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
self.update_selections(new_selections, true, ctx);
}
pub fn add_cursor_below(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
use super::RangeExt;
let app = ctx.as_ref();
let buffer = self.buffer.read(app);
let max_point = self.display_map.max_point(app);
let mut new_selections = Vec::new();
for selection in self.selections(app) {
let range = selection.display_range(&self.display_map, app).sorted();
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;
for row in range.end.row() + 1..=max_point.row() {
let line_len = self.display_map.line_len(row, app).unwrap();
if start_column < line_len || (is_empty && start_column == line_len) {
let start = DisplayPoint::new(row, start_column);
let end = DisplayPoint::new(row, cmp::min(end_column, line_len));
new_selections.push(Selection {
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,
},
});
break;
}
}
new_selections.push(selection.clone());
}
new_selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
self.update_selections(new_selections, true, ctx);
}
pub fn selections_in_range<'a>(
&'a self,
range: Range<DisplayPoint>,
+19 -11
View File
@@ -1,4 +1,4 @@
use super::{DisplayMap, DisplayPoint};
use super::{DisplayMap, DisplayPoint, SelectionGoal};
use anyhow::Result;
use gpui::AppContext;
use std::cmp;
@@ -27,36 +27,44 @@ pub fn right(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Res
pub fn up(
map: &DisplayMap,
mut point: DisplayPoint,
goal_column: Option<u32>,
goal: SelectionGoal,
app: &AppContext,
) -> Result<(DisplayPoint, Option<u32>)> {
let goal_column = goal_column.or(Some(point.column()));
) -> Result<(DisplayPoint, SelectionGoal)> {
let goal_column = if let SelectionGoal::Column(column) = goal {
column
} else {
point.column()
};
if point.row() > 0 {
*point.row_mut() -= 1;
*point.column_mut() = cmp::min(goal_column.unwrap(), map.line_len(point.row(), app)?);
*point.column_mut() = cmp::min(goal_column, map.line_len(point.row(), app)?);
} else {
point = DisplayPoint::new(0, 0);
}
Ok((point, goal_column))
Ok((point, SelectionGoal::Column(goal_column)))
}
pub fn down(
map: &DisplayMap,
mut point: DisplayPoint,
goal_column: Option<u32>,
goal: SelectionGoal,
app: &AppContext,
) -> Result<(DisplayPoint, Option<u32>)> {
let goal_column = goal_column.or(Some(point.column()));
) -> Result<(DisplayPoint, SelectionGoal)> {
let goal_column = if let SelectionGoal::Column(column) = goal {
column
} else {
point.column()
};
let max_point = map.max_point(app);
if point.row() < max_point.row() {
*point.row_mut() += 1;
*point.column_mut() = cmp::min(goal_column.unwrap(), map.line_len(point.row(), app)?)
*point.column_mut() = cmp::min(goal_column, map.line_len(point.row(), app)?)
} else {
point = max_point;
}
Ok((point, goal_column))
Ok((point, SelectionGoal::Column(goal_column)))
}
pub fn line_beginning(