Get the project running!

This commit is contained in:
Conrad Irwin 2023-09-28 21:39:24 -06:00
parent e7badb38e9
commit ef7e2c5d86
12 changed files with 353 additions and 183 deletions

View File

@ -1392,19 +1392,28 @@ pub mod tests {
movement::down(
&snapshot,
DisplayPoint::new(0, 7),
SelectionGoal::Column(10),
false
SelectionGoal::HorizontalPosition(x),
false,
&text_layout_details
),
(DisplayPoint::new(1, 10), SelectionGoal::Column(10))
(
DisplayPoint::new(1, 10),
SelectionGoal::HorizontalPosition(x)
)
);
dbg!("starting down...");
assert_eq!(
movement::down(
&snapshot,
DisplayPoint::new(1, 10),
SelectionGoal::Column(10),
false
SelectionGoal::HorizontalPosition(x),
false,
&text_layout_details
),
(DisplayPoint::new(2, 4), SelectionGoal::Column(10))
(
DisplayPoint::new(2, 4),
SelectionGoal::HorizontalPosition(x)
)
);
let ix = snapshot.buffer_snapshot.text().find("seven").unwrap();

View File

@ -4988,6 +4988,7 @@ impl Editor {
}
pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
let text_layout_details = TextLayoutDetails::new(&self, cx);
self.transact(cx, |this, cx| {
let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
let mut edits: Vec<(Range<usize>, String)> = Default::default();
@ -5011,7 +5012,10 @@ impl Editor {
*head.column_mut() += 1;
head = display_map.clip_point(head, Bias::Right);
selection.collapse_to(head, SelectionGoal::Column(head.column()));
let goal = SelectionGoal::HorizontalPosition(
display_map.x_for_point(head, &text_layout_details),
);
selection.collapse_to(head, goal);
let transpose_start = display_map
.buffer_snapshot
@ -5355,13 +5359,20 @@ impl Editor {
return;
}
let text_layout_details = TextLayoutDetails::new(&self, cx);
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
let line_mode = s.line_mode;
s.move_with(|map, selection| {
if !selection.is_empty() && !line_mode {
selection.goal = SelectionGoal::None;
}
let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
let (cursor, goal) = movement::down(
map,
selection.end,
selection.goal,
false,
&text_layout_details,
);
selection.collapse_to(cursor, goal);
});
});
@ -5398,22 +5409,32 @@ impl Editor {
Autoscroll::fit()
};
let text_layout_details = TextLayoutDetails::new(&self, cx);
self.change_selections(Some(autoscroll), cx, |s| {
let line_mode = s.line_mode;
s.move_with(|map, selection| {
if !selection.is_empty() && !line_mode {
selection.goal = SelectionGoal::None;
}
let (cursor, goal) =
movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
let (cursor, goal) = movement::down_by_rows(
map,
selection.end,
row_count,
selection.goal,
false,
&text_layout_details,
);
selection.collapse_to(cursor, goal);
});
});
}
pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
let text_layout_details = TextLayoutDetails::new(&self, cx);
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
s.move_heads_with(|map, head, goal| {
movement::down(map, head, goal, false, &text_layout_details)
})
});
}
@ -6286,6 +6307,7 @@ impl Editor {
}
pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
let text_layout_details = TextLayoutDetails::new(&self, cx);
self.transact(cx, |this, cx| {
let mut selections = this.selections.all::<Point>(cx);
let mut edits = Vec::new();
@ -6528,7 +6550,10 @@ impl Editor {
point.row += 1;
point = snapshot.clip_point(point, Bias::Left);
let display_point = point.to_display_point(display_snapshot);
(display_point, SelectionGoal::Column(display_point.column()))
let goal = SelectionGoal::HorizontalPosition(
display_snapshot.x_for_point(display_point, &text_layout_details),
);
(display_point, goal)
})
});
}

View File

@ -847,6 +847,7 @@ fn test_move_cursor(cx: &mut TestAppContext) {
#[gpui::test]
fn test_move_cursor_multibyte(cx: &mut TestAppContext) {
todo!();
init_test(cx, |_| {});
let view = cx

View File

@ -83,8 +83,16 @@ pub fn down(
start: DisplayPoint,
goal: SelectionGoal,
preserve_column_at_end: bool,
text_layout_details: &TextLayoutDetails,
) -> (DisplayPoint, SelectionGoal) {
down_by_rows(map, start, 1, goal, preserve_column_at_end)
down_by_rows(
map,
start,
1,
goal,
preserve_column_at_end,
text_layout_details,
)
}
pub fn up_by_rows(
@ -130,29 +138,32 @@ pub fn down_by_rows(
row_count: u32,
goal: SelectionGoal,
preserve_column_at_end: bool,
text_layout_details: &TextLayoutDetails,
) -> (DisplayPoint, SelectionGoal) {
let mut goal_column = match goal {
SelectionGoal::Column(column) => column,
SelectionGoal::ColumnRange { end, .. } => end,
_ => map.column_to_chars(start.row(), start.column()),
let mut goal_x = match goal {
SelectionGoal::HorizontalPosition(x) => x,
SelectionGoal::HorizontalRange { end, .. } => end,
_ => map.x_for_point(start, text_layout_details),
};
let new_row = start.row() + row_count;
let mut point = map.clip_point(DisplayPoint::new(new_row, 0), Bias::Right);
if point.row() > start.row() {
*point.column_mut() = map.column_from_chars(point.row(), goal_column);
*point.column_mut() = map
.column_for_x(point.row(), goal_x, text_layout_details)
.unwrap_or(map.line_len(point.row()));
} else if preserve_column_at_end {
return (start, goal);
} else {
point = map.max_point();
goal_column = map.column_to_chars(point.row(), point.column())
goal_x = map.x_for_point(point, text_layout_details)
}
let mut clipped_point = map.clip_point(point, Bias::Right);
if clipped_point.row() > point.row() {
clipped_point = map.clip_point(point, Bias::Left);
}
(clipped_point, SelectionGoal::Column(goal_column))
(clipped_point, SelectionGoal::HorizontalPosition(goal_x))
}
pub fn line_beginning(
@ -426,9 +437,12 @@ pub fn split_display_range_by_lines(
mod tests {
use super::*;
use crate::{
display_map::Inlay, test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange,
InlayId, MultiBuffer,
display_map::Inlay,
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer,
};
use language::language_settings::AllLanguageSettings;
use project::Project;
use settings::SettingsStore;
use util::post_inc;
@ -721,129 +735,173 @@ mod tests {
}
#[gpui::test]
fn test_move_up_and_down_with_excerpts(cx: &mut gpui::AppContext) {
/*
init_test(cx);
let family_id = cx
.font_cache()
.load_family(&["Helvetica"], &Default::default())
.unwrap();
let font_id = cx
.font_cache()
.select_font(family_id, &Default::default())
.unwrap();
let buffer =
cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn"));
let multibuffer = cx.add_model(|cx| {
let mut multibuffer = MultiBuffer::new(0);
multibuffer.push_excerpts(
buffer.clone(),
[
ExcerptRange {
context: Point::new(0, 0)..Point::new(1, 4),
primary: None,
},
ExcerptRange {
context: Point::new(2, 0)..Point::new(3, 2),
primary: None,
},
],
cx,
);
multibuffer
async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) {
cx.update(|cx| {
init_test(cx);
});
let display_map =
cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx));
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
let mut cx = EditorTestContext::new(cx).await;
let editor = cx.editor.clone();
let window = cx.window.clone();
cx.update_window(window, |cx| {
let text_layout_details =
editor.read_with(cx, |editor, cx| TextLayoutDetails::new(editor, cx));
assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
let family_id = cx
.font_cache()
.load_family(&["Helvetica"], &Default::default())
.unwrap();
let font_id = cx
.font_cache()
.select_font(family_id, &Default::default())
.unwrap();
// Can't move up into the first excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 2),
SelectionGoal::Column(2),
false
),
(
DisplayPoint::new(2, 0),
SelectionGoal::HorizontalPosition(0.0)
),
);
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 0),
SelectionGoal::None,
false
),
(DisplayPoint::new(2, 0), SelectionGoal::Column(0)),
);
let buffer =
cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn"));
let multibuffer = cx.add_model(|cx| {
let mut multibuffer = MultiBuffer::new(0);
multibuffer.push_excerpts(
buffer.clone(),
[
ExcerptRange {
context: Point::new(0, 0)..Point::new(1, 4),
primary: None,
},
ExcerptRange {
context: Point::new(2, 0)..Point::new(3, 2),
primary: None,
},
],
cx,
);
multibuffer
});
let display_map =
cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx));
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
// Move up and down within first excerpt
assert_eq!(
up(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::Column(4),
false
),
(DisplayPoint::new(2, 3), SelectionGoal::Column(4)),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(2, 3),
SelectionGoal::Column(4),
false
),
(DisplayPoint::new(3, 4), SelectionGoal::Column(4)),
);
assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
// Move up and down across second excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(6, 5),
SelectionGoal::Column(5),
false
),
(DisplayPoint::new(3, 4), SelectionGoal::Column(5)),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::Column(5),
false
),
(DisplayPoint::new(6, 5), SelectionGoal::Column(5)),
);
let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details);
// Can't move down off the end
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 0),
SelectionGoal::Column(0),
false
),
(DisplayPoint::new(7, 2), SelectionGoal::Column(2)),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 2),
SelectionGoal::Column(2),
false
),
(DisplayPoint::new(7, 2), SelectionGoal::Column(2)),
);
*/
// Can't move up into the first excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 2),
SelectionGoal::HorizontalPosition(col_2_x),
false,
&text_layout_details
),
(
DisplayPoint::new(2, 0),
SelectionGoal::HorizontalPosition(0.0)
),
);
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 0),
SelectionGoal::None,
false,
&text_layout_details
),
(
DisplayPoint::new(2, 0),
SelectionGoal::HorizontalPosition(0.0)
),
);
let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details);
// Move up and down within first excerpt
assert_eq!(
up(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_4_x),
false,
&text_layout_details
),
(
DisplayPoint::new(2, 3),
SelectionGoal::HorizontalPosition(col_4_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(2, 3),
SelectionGoal::HorizontalPosition(col_4_x),
false,
&text_layout_details
),
(
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_4_x)
),
);
let col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details);
// Move up and down across second excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(6, 5),
SelectionGoal::HorizontalPosition(col_5_x),
false,
&text_layout_details
),
(
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_5_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_5_x),
false,
&text_layout_details
),
(
DisplayPoint::new(6, 5),
SelectionGoal::HorizontalPosition(col_5_x)
),
);
let max_point_x = snapshot.x_for_point(DisplayPoint::new(7, 2), &text_layout_details);
// Can't move down off the end
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 0),
SelectionGoal::HorizontalPosition(0.0),
false,
&text_layout_details
),
(
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x),
false,
&text_layout_details
),
(
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x)
),
);
});
}
fn init_test(cx: &mut gpui::AppContext) {
@ -851,5 +909,6 @@ mod tests {
theme::init((), cx);
language::init(cx);
crate::init(cx);
Project::init_settings(cx);
}
}

View File

@ -3,7 +3,7 @@ use std::cmp;
use editor::{
char_kind,
display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint},
movement::{self, find_boundary, find_preceding_boundary, FindRange},
movement::{self, find_boundary, find_preceding_boundary, FindRange, TextLayoutDetails},
Bias, CharKind, DisplayPoint, ToOffset,
};
use gpui::{actions, impl_actions, AppContext, WindowContext};
@ -361,6 +361,7 @@ impl Motion {
point: DisplayPoint,
goal: SelectionGoal,
maybe_times: Option<usize>,
text_layout_details: &TextLayoutDetails,
) -> Option<(DisplayPoint, SelectionGoal)> {
let times = maybe_times.unwrap_or(1);
use Motion::*;
@ -373,13 +374,13 @@ impl Motion {
} => down(map, point, goal, times),
Down {
display_lines: true,
} => down_display(map, point, goal, times),
} => down_display(map, point, goal, times, &text_layout_details),
Up {
display_lines: false,
} => up(map, point, goal, times),
Up {
display_lines: true,
} => up_display(map, point, goal, times),
} => up_display(map, point, goal, times, &text_layout_details),
Right => (right(map, point, times), SelectionGoal::None),
NextWordStart { ignore_punctuation } => (
next_word_start(map, point, *ignore_punctuation, times),
@ -442,10 +443,15 @@ impl Motion {
selection: &mut Selection<DisplayPoint>,
times: Option<usize>,
expand_to_surrounding_newline: bool,
text_layout_details: &TextLayoutDetails,
) -> bool {
if let Some((new_head, goal)) =
self.move_point(map, selection.head(), selection.goal, times)
{
if let Some((new_head, goal)) = self.move_point(
map,
selection.head(),
selection.goal,
times,
&text_layout_details,
) {
selection.set_head(new_head, goal);
if self.linewise() {
@ -566,9 +572,10 @@ fn down_display(
mut point: DisplayPoint,
mut goal: SelectionGoal,
times: usize,
text_layout_details: &TextLayoutDetails,
) -> (DisplayPoint, SelectionGoal) {
for _ in 0..times {
(point, goal) = movement::down(map, point, goal, true);
(point, goal) = movement::down(map, point, goal, true, text_layout_details);
}
(point, goal)
@ -606,9 +613,10 @@ fn up_display(
mut point: DisplayPoint,
mut goal: SelectionGoal,
times: usize,
text_layout_details: &TextLayoutDetails,
) -> (DisplayPoint, SelectionGoal) {
for _ in 0..times {
(point, goal) = movement::up(map, point, goal, true);
(point, goal) = movement::up(map, point, goal, true, &text_layout_details);
}
(point, goal)
@ -707,7 +715,7 @@ fn previous_word_start(
point
}
fn first_non_whitespace(
pub(crate) fn first_non_whitespace(
map: &DisplaySnapshot,
display_lines: bool,
from: DisplayPoint,
@ -890,7 +898,11 @@ fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) ->
first_non_whitespace(map, false, correct_line)
}
fn next_line_end(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> DisplayPoint {
pub(crate) fn next_line_end(
map: &DisplaySnapshot,
mut point: DisplayPoint,
times: usize,
) -> DisplayPoint {
if times > 1 {
point = down(map, point, SelectionGoal::None, times - 1).0;
}

View File

@ -12,13 +12,13 @@ mod yank;
use std::sync::Arc;
use crate::{
motion::{self, Motion},
motion::{self, first_non_whitespace, next_line_end, right, Motion},
object::Object,
state::{Mode, Operator},
Vim,
};
use collections::HashSet;
use editor::scroll::autoscroll::Autoscroll;
use editor::{movement::TextLayoutDetails, scroll::autoscroll::Autoscroll};
use editor::{Bias, DisplayPoint};
use gpui::{actions, AppContext, ViewContext, WindowContext};
use language::SelectionGoal;
@ -177,10 +177,11 @@ pub(crate) fn move_cursor(
cx: &mut WindowContext,
) {
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.move_cursors_with(|map, cursor, goal| {
motion
.move_point(map, cursor, goal, times)
.move_point(map, cursor, goal, times, &text_layout_details)
.unwrap_or((cursor, goal))
})
})
@ -193,8 +194,8 @@ fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext<Workspa
vim.switch_mode(Mode::Insert, false, cx);
vim.update_active_editor(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.maybe_move_cursors_with(|map, cursor, goal| {
Motion::Right.move_point(map, cursor, goal, None)
s.move_cursors_with(|map, cursor, goal| {
(right(map, cursor, 1), SelectionGoal::None)
});
});
});
@ -218,11 +219,11 @@ fn insert_first_non_whitespace(
vim.switch_mode(Mode::Insert, false, cx);
vim.update_active_editor(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.maybe_move_cursors_with(|map, cursor, goal| {
Motion::FirstNonWhitespace {
display_lines: false,
}
.move_point(map, cursor, goal, None)
s.move_cursors_with(|map, cursor, goal| {
(
first_non_whitespace(map, false, cursor),
SelectionGoal::None,
)
});
});
});
@ -235,8 +236,8 @@ fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewConte
vim.switch_mode(Mode::Insert, false, cx);
vim.update_active_editor(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.maybe_move_cursors_with(|map, cursor, goal| {
Motion::CurrentLine.move_point(map, cursor, goal, None)
s.move_cursors_with(|map, cursor, goal| {
(next_line_end(map, cursor, 1), SelectionGoal::None)
});
});
});
@ -281,6 +282,7 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
vim.start_recording(cx);
vim.switch_mode(Mode::Insert, false, cx);
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.transact(cx, |editor, cx| {
let (map, old_selections) = editor.selections.all_display(cx);
@ -299,7 +301,13 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
});
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.maybe_move_cursors_with(|map, cursor, goal| {
Motion::CurrentLine.move_point(map, cursor, goal, None)
Motion::CurrentLine.move_point(
map,
cursor,
goal,
None,
&text_layout_details,
)
});
});
editor.edit_with_autoindent(edits, cx);

View File

@ -2,7 +2,7 @@ use crate::{motion::Motion, object::Object, state::Mode, utils::copy_selections_
use editor::{
char_kind,
display_map::DisplaySnapshot,
movement::{self, FindRange},
movement::{self, FindRange, TextLayoutDetails},
scroll::autoscroll::Autoscroll,
CharKind, DisplayPoint,
};
@ -20,6 +20,7 @@ pub fn change_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &m
| Motion::StartOfLine { .. }
);
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.transact(cx, |editor, cx| {
// We are swapping to insert mode anyway. Just set the line end clipping behavior now
editor.set_clip_at_line_ends(false, cx);
@ -27,9 +28,15 @@ pub fn change_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &m
s.move_with(|map, selection| {
motion_succeeded |= if let Motion::NextWordStart { ignore_punctuation } = motion
{
expand_changed_word_selection(map, selection, times, ignore_punctuation)
expand_changed_word_selection(
map,
selection,
times,
ignore_punctuation,
&text_layout_details,
)
} else {
motion.expand_selection(map, selection, times, false)
motion.expand_selection(map, selection, times, false, &text_layout_details)
};
});
});
@ -81,6 +88,7 @@ fn expand_changed_word_selection(
selection: &mut Selection<DisplayPoint>,
times: Option<usize>,
ignore_punctuation: bool,
text_layout_details: &TextLayoutDetails,
) -> bool {
if times.is_none() || times.unwrap() == 1 {
let scope = map
@ -103,11 +111,22 @@ fn expand_changed_word_selection(
});
true
} else {
Motion::NextWordStart { ignore_punctuation }
.expand_selection(map, selection, None, false)
Motion::NextWordStart { ignore_punctuation }.expand_selection(
map,
selection,
None,
false,
&text_layout_details,
)
}
} else {
Motion::NextWordStart { ignore_punctuation }.expand_selection(map, selection, times, false)
Motion::NextWordStart { ignore_punctuation }.expand_selection(
map,
selection,
times,
false,
&text_layout_details,
)
}
}

View File

@ -1,12 +1,15 @@
use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim};
use collections::{HashMap, HashSet};
use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Bias};
use editor::{
display_map::ToDisplayPoint, movement::TextLayoutDetails, scroll::autoscroll::Autoscroll, Bias,
};
use gpui::WindowContext;
use language::Point;
pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
vim.stop_recording();
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.transact(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
let mut original_columns: HashMap<_, _> = Default::default();
@ -14,7 +17,7 @@ pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &m
s.move_with(|map, selection| {
let original_head = selection.head();
original_columns.insert(selection.id, original_head.column());
motion.expand_selection(map, selection, times, true);
motion.expand_selection(map, selection, times, true, &text_layout_details);
// Motion::NextWordStart on an empty line should delete it.
if let Motion::NextWordStart {

View File

@ -1,8 +1,10 @@
use std::{borrow::Cow, cmp};
use editor::{
display_map::ToDisplayPoint, movement, scroll::autoscroll::Autoscroll, ClipboardSelection,
DisplayPoint,
display_map::ToDisplayPoint,
movement::{self, TextLayoutDetails},
scroll::autoscroll::Autoscroll,
ClipboardSelection, DisplayPoint,
};
use gpui::{impl_actions, AppContext, ViewContext};
use language::{Bias, SelectionGoal};
@ -30,6 +32,7 @@ fn paste(_: &mut Workspace, action: &Paste, cx: &mut ViewContext<Workspace>) {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.transact(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
@ -168,8 +171,14 @@ fn paste(_: &mut Workspace, action: &Paste, cx: &mut ViewContext<Workspace>) {
let mut cursor = anchor.to_display_point(map);
if *line_mode {
if !before {
cursor =
movement::down(map, cursor, SelectionGoal::None, false).0;
cursor = movement::down(
map,
cursor,
SelectionGoal::None,
false,
&text_layout_details,
)
.0;
}
cursor = movement::indented_line_beginning(map, cursor, true);
} else if !is_multiline {

View File

@ -1,9 +1,13 @@
use editor::movement;
use editor::movement::{self, TextLayoutDetails};
use gpui::{actions, AppContext, WindowContext};
use language::Point;
use workspace::Workspace;
use crate::{motion::Motion, utils::copy_selections_content, Mode, Vim};
use crate::{
motion::{right, Motion},
utils::copy_selections_content,
Mode, Vim,
};
actions!(vim, [Substitute, SubstituteLine]);
@ -32,10 +36,17 @@ pub fn substitute(vim: &mut Vim, count: Option<usize>, line_mode: bool, cx: &mut
vim.update_active_editor(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
editor.transact(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.change_selections(None, cx, |s| {
s.move_with(|map, selection| {
if selection.start == selection.end {
Motion::Right.expand_selection(map, selection, count, true);
Motion::Right.expand_selection(
map,
selection,
count,
true,
&text_layout_details,
);
}
if line_mode {
// in Visual mode when the selection contains the newline at the end
@ -43,7 +54,13 @@ pub fn substitute(vim: &mut Vim, count: Option<usize>, line_mode: bool, cx: &mut
if !selection.is_empty() && selection.end.column() == 0 {
selection.end = movement::left(map, selection.end);
}
Motion::CurrentLine.expand_selection(map, selection, None, false);
Motion::CurrentLine.expand_selection(
map,
selection,
None,
false,
&text_layout_details,
);
if let Some((point, _)) = (Motion::FirstNonWhitespace {
display_lines: false,
})
@ -52,6 +69,7 @@ pub fn substitute(vim: &mut Vim, count: Option<usize>, line_mode: bool, cx: &mut
selection.start,
selection.goal,
None,
&text_layout_details,
) {
selection.start = point;
}

View File

@ -1,9 +1,11 @@
use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim};
use collections::HashMap;
use editor::movement::TextLayoutDetails;
use gpui::WindowContext;
pub fn yank_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
editor.transact(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
let mut original_positions: HashMap<_, _> = Default::default();
@ -11,7 +13,7 @@ pub fn yank_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut
s.move_with(|map, selection| {
let original_position = (selection.head(), selection.goal);
original_positions.insert(selection.id, original_position);
motion.expand_selection(map, selection, times, true);
motion.expand_selection(map, selection, times, true, &text_layout_details);
});
});
copy_selections_content(editor, motion.linewise(), cx);

View File

@ -4,7 +4,7 @@ use std::{cmp, sync::Arc};
use collections::HashMap;
use editor::{
display_map::{DisplaySnapshot, ToDisplayPoint},
movement,
movement::{self, TextLayoutDetails},
scroll::autoscroll::Autoscroll,
Bias, DisplayPoint, Editor,
};
@ -57,6 +57,7 @@ pub fn init(cx: &mut AppContext) {
pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
Vim::update(cx, |vim, cx| {
vim.update_active_editor(cx, |editor, cx| {
let text_layout_details = TextLayoutDetails::new(editor, cx);
if vim.state().mode == Mode::VisualBlock
&& !matches!(
motion,
@ -67,7 +68,7 @@ pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContex
{
let is_up_or_down = matches!(motion, Motion::Up { .. } | Motion::Down { .. });
visual_block_motion(is_up_or_down, editor, cx, |map, point, goal| {
motion.move_point(map, point, goal, times)
motion.move_point(map, point, goal, times, &text_layout_details)
})
} else {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
@ -89,9 +90,13 @@ pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContex
current_head = movement::left(map, selection.end)
}
let Some((new_head, goal)) =
motion.move_point(map, current_head, selection.goal, times)
else {
let Some((new_head, goal)) = motion.move_point(
map,
current_head,
selection.goal,
times,
&text_layout_details,
) else {
return;
};