mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 18:41:56 +03:00
Fix visual selection of trailing newline
This commit is contained in:
parent
9cb0ce7745
commit
645c149344
@ -353,27 +353,30 @@ impl DisplaySnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
// used by line_mode selections and tries to match vim behaviour
|
||||
pub fn expand_to_line(&self, range: Range<Point>) -> Range<Point> {
|
||||
let mut new_start = self.prev_line_boundary(range.start).0;
|
||||
if range.end.column == 0 {
|
||||
return new_start..range.end;
|
||||
}
|
||||
let mut new_end = self.next_line_boundary(range.end).0;
|
||||
let new_start = if range.start.row == 0 {
|
||||
Point::new(0, 0)
|
||||
} else if range.start.row == self.max_buffer_row()
|
||||
|| (range.end.column > 0 && range.end.row == self.max_buffer_row())
|
||||
{
|
||||
Point::new(range.start.row - 1, self.line_len(range.start.row - 1))
|
||||
} else {
|
||||
self.prev_line_boundary(range.start).0
|
||||
};
|
||||
|
||||
if new_start.row == range.start.row && new_end.row == range.end.row {
|
||||
if new_end.row < self.buffer_snapshot.max_point().row {
|
||||
new_end.row += 1;
|
||||
new_end.column = 0;
|
||||
} else if new_start.row > 0 {
|
||||
new_start.row -= 1;
|
||||
new_start.column = self.buffer_snapshot.line_len(new_start.row);
|
||||
}
|
||||
}
|
||||
let new_end = if range.end.column == 0 {
|
||||
range.end
|
||||
} else if range.end.row < self.max_buffer_row() {
|
||||
Point::new(range.end.row + 1, 0)
|
||||
} else {
|
||||
self.buffer_snapshot.max_point()
|
||||
};
|
||||
|
||||
new_start..new_end
|
||||
}
|
||||
|
||||
fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
|
||||
pub fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
||||
|
@ -850,13 +850,16 @@ impl EditorElement {
|
||||
let mut cursor_column = cursor_position.column() as usize;
|
||||
let mut cursor_row = cursor_position.row();
|
||||
|
||||
// highlight the last character in a selection
|
||||
if CursorShape::Block == selection.cursor_shape
|
||||
&& !selection.range.is_empty()
|
||||
&& !selection.reversed
|
||||
{
|
||||
if cursor_column > 0 {
|
||||
cursor_column -= 1;
|
||||
} else if cursor_row > 0 {
|
||||
} else if cursor_row > 0
|
||||
&& cursor_position != layout.position_map.snapshot.max_point()
|
||||
{
|
||||
cursor_row -= 1;
|
||||
cursor_column =
|
||||
layout.position_map.snapshot.line_len(cursor_row) as usize;
|
||||
@ -2186,7 +2189,19 @@ impl Element<Editor> for EditorElement {
|
||||
for selection in &local_selections {
|
||||
let is_empty = selection.start == selection.end;
|
||||
let selection_start = snapshot.prev_line_boundary(selection.start).1;
|
||||
let selection_end = snapshot.next_line_boundary(selection.end).1;
|
||||
let mut selection_end = snapshot.next_line_boundary(selection.end).1;
|
||||
|
||||
// in vim visual mode the newline is considered at the end of the previous line
|
||||
// instead of at the start of the current line
|
||||
if editor.cursor_shape == CursorShape::Block
|
||||
&& !is_empty
|
||||
&& !selection.reversed
|
||||
&& selection.end.column == 0
|
||||
&& selection_end.row() > 0
|
||||
&& selection_end.row() < snapshot.max_buffer_row()
|
||||
{
|
||||
selection_end = DisplayPoint::new(selection_end.row() - 1, 0);
|
||||
}
|
||||
for row in cmp::max(selection_start.row(), start_row)
|
||||
..=cmp::min(selection_end.row(), end_row)
|
||||
{
|
||||
|
@ -49,7 +49,14 @@ pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContex
|
||||
// our motions assume the current character is after the cursor,
|
||||
// but in (forward) visual mode the current character is just
|
||||
// before the end of the selection.
|
||||
if !selection.reversed {
|
||||
|
||||
// If the file ends with a newline (which is common) we don't do this.
|
||||
// so that if you go to the end of such a file you can use "up" to go
|
||||
// to the previous line and have it work somewhat as expected.
|
||||
if !selection.reversed
|
||||
&& !selection.is_empty()
|
||||
&& !(selection.end.column() == 0 && selection.end == map.max_point())
|
||||
{
|
||||
current_head = movement::left(map, selection.end)
|
||||
}
|
||||
|
||||
@ -60,8 +67,11 @@ pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContex
|
||||
|
||||
// ensure the current character is included in the selection.
|
||||
if !selection.reversed {
|
||||
let next_point = movement::right(map, selection.end);
|
||||
if !(next_point.column() == 0 && next_point == map.max_point()) {
|
||||
selection.end = movement::right(map, selection.end)
|
||||
}
|
||||
}
|
||||
|
||||
// vim always ensures the anchor character stays selected.
|
||||
// if our selection has reversed, we need to move the opposite end
|
||||
@ -494,6 +504,27 @@ mod test {
|
||||
a
|
||||
ˇb"})
|
||||
.await;
|
||||
|
||||
// it should work at the end of the document
|
||||
cx.set_shared_state(indoc! {"
|
||||
a
|
||||
b
|
||||
ˇ"})
|
||||
.await;
|
||||
let cursor = cx.update_editor(|editor, _| editor.pixel_position_of_cursor());
|
||||
cx.simulate_shared_keystrokes(["shift-v"]).await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
a
|
||||
b
|
||||
ˇ"})
|
||||
.await;
|
||||
assert_eq!(cx.mode(), cx.neovim_mode().await);
|
||||
cx.update_editor(|editor, _| assert_eq!(cursor, editor.pixel_position_of_cursor()));
|
||||
cx.simulate_shared_keystrokes(["x"]).await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
a
|
||||
ˇb"})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -8,3 +8,8 @@
|
||||
{"Get":{"state":"a\n«\nˇ»b","mode":{"Visual":{"line":true}}}}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"a\nˇb","mode":"Normal"}}
|
||||
{"Put":{"state":"a\nb\nˇ"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Get":{"state":"a\nb\nˇ","mode":{"Visual":{"line":true}}}}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"a\nˇb","mode":"Normal"}}
|
||||
|
Loading…
Reference in New Issue
Block a user