Detailed changes
@@ -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();
@@ -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)
})
});
}
@@ -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
@@ -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();
+ async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) {
+ cx.update(|cx| {
+ init_test(cx);
+ });
- 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,
+ 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));
+
+ 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
+ });
+ 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));
+
+ assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
+
+ let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details);
+
+ // 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)
+ ),
);
- 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));
+ let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details);
- assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
+ // 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)
+ ),
+ );
- // 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 col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details);
- // 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)),
- );
+ // 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)
+ ),
+ );
- // 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 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::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 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);
}
}
@@ -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;
}
@@ -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);
@@ -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,
+ )
}
}
@@ -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 {
@@ -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 {
@@ -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;
}
@@ -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);
@@ -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;
};