Merge branch 'main' into vim-softwrap-word

This commit is contained in:
Conrad Irwin 2023-09-01 11:05:12 -07:00
commit aa7b65bbaf
111 changed files with 4173 additions and 1585 deletions

View file

@ -590,12 +590,12 @@ pub(crate) fn next_word_start(
ignore_punctuation: bool,
times: usize,
) -> DisplayPoint {
let language = map.buffer_snapshot.language_at(point.to_point(map));
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
for _ in 0..times {
let mut crossed_newline = false;
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
let left_kind = char_kind(language, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(language, right).coerce_punctuation(ignore_punctuation);
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
let at_newline = right == '\n';
let found = (left_kind != right_kind && right_kind != CharKind::Whitespace)
@ -615,7 +615,7 @@ fn next_word_end(
ignore_punctuation: bool,
times: usize,
) -> DisplayPoint {
let language = map.buffer_snapshot.language_at(point.to_point(map));
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
for _ in 0..times {
if point.column() < map.line_len(point.row()) {
*point.column_mut() += 1;
@ -623,10 +623,9 @@ fn next_word_end(
*point.row_mut() += 1;
*point.column_mut() = 0;
}
// *point.column_mut() += 1;
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
let left_kind = char_kind(language, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(language, right).coerce_punctuation(ignore_punctuation);
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
left_kind != right_kind && left_kind != CharKind::Whitespace
});
@ -652,14 +651,14 @@ fn previous_word_start(
ignore_punctuation: bool,
times: usize,
) -> DisplayPoint {
let language = map.buffer_snapshot.language_at(point.to_point(map));
let scope = map.buffer_snapshot.language_scope_at(point.to_point(map));
for _ in 0..times {
// This works even though find_preceding_boundary is called for every character in the line containing
// cursor because the newline is checked only once.
point =
movement::find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
let left_kind = char_kind(language, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(language, right).coerce_punctuation(ignore_punctuation);
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
(left_kind != right_kind && !right.is_whitespace()) || left == '\n'
});
@ -673,7 +672,7 @@ fn first_non_whitespace(
from: DisplayPoint,
) -> DisplayPoint {
let mut last_point = start_of_line(map, display_lines, from);
let language = map.buffer_snapshot.language_at(from.to_point(map));
let scope = map.buffer_snapshot.language_scope_at(from.to_point(map));
for (ch, point) in map.chars_at(last_point) {
if ch == '\n' {
return from;
@ -681,7 +680,7 @@ fn first_non_whitespace(
last_point = point;
if char_kind(language, ch) != CharKind::Whitespace {
if char_kind(&scope, ch) != CharKind::Whitespace {
break;
}
}

View file

@ -89,22 +89,21 @@ fn expand_changed_word_selection(
ignore_punctuation: bool,
) -> bool {
if times.is_none() || times.unwrap() == 1 {
let language = map
let scope = map
.buffer_snapshot
.language_at(selection.start.to_point(map));
.language_scope_at(selection.start.to_point(map));
let in_word = map
.chars_at(selection.head())
.next()
.map(|(c, _)| char_kind(language, c) != CharKind::Whitespace)
.map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace)
.unwrap_or_default();
if in_word {
selection.end =
movement::find_boundary(map, selection.end, FindRange::MultiLine, |left, right| {
let left_kind =
char_kind(language, left).coerce_punctuation(ignore_punctuation);
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
let right_kind =
char_kind(language, right).coerce_punctuation(ignore_punctuation);
char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
left_kind != right_kind && left_kind != CharKind::Whitespace
});

View file

@ -67,7 +67,8 @@ fn scroll_editor(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContex
let top_anchor = editor.scroll_manager.anchor().anchor;
editor.change_selections(None, cx, |s| {
s.move_heads_with(|map, head, goal| {
s.move_with(|map, selection| {
let head = selection.head();
let top = top_anchor.to_display_point(map);
let min_row = top.row() + VERTICAL_SCROLL_MARGIN as u32;
let max_row = top.row() + visible_rows - VERTICAL_SCROLL_MARGIN as u32 - 1;
@ -79,7 +80,11 @@ fn scroll_editor(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContex
} else {
head
};
(new_head, goal)
if selection.is_empty() {
selection.collapse_to(new_head, selection.goal)
} else {
selection.set_head(new_head, selection.goal)
};
})
});
}
@ -90,12 +95,35 @@ mod test {
use crate::{state::Mode, test::VimTestContext};
use gpui::geometry::vector::vec2f;
use indoc::indoc;
use language::Point;
#[gpui::test]
async fn test_scroll(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.set_state(indoc! {"ˇa\nb\nc\nd\ne\n"}, Mode::Normal);
let window = cx.window;
let line_height =
cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache()));
window.simulate_resize(vec2f(1000., 8.0 * line_height - 1.0), &mut cx);
cx.set_state(
indoc!(
"ˇone
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
"
),
Mode::Normal,
);
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.))
@ -112,5 +140,33 @@ mod test {
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.))
});
// does not select in normal mode
cx.simulate_keystrokes(["g", "g"]);
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.))
});
cx.simulate_keystrokes(["ctrl-d"]);
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.0));
assert_eq!(
editor.selections.newest(cx).range(),
Point::new(5, 0)..Point::new(5, 0)
)
});
// does select in visual mode
cx.simulate_keystrokes(["g", "g"]);
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.))
});
cx.simulate_keystrokes(["v", "ctrl-d"]);
cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.0));
assert_eq!(
editor.selections.newest(cx).range(),
Point::new(0, 0)..Point::new(5, 1)
)
});
}
}

View file

@ -182,19 +182,22 @@ fn in_word(
ignore_punctuation: bool,
) -> Option<Range<DisplayPoint>> {
// Use motion::right so that we consider the character under the cursor when looking for the start
let language = map.buffer_snapshot.language_at(relative_to.to_point(map));
let scope = map
.buffer_snapshot
.language_scope_at(relative_to.to_point(map));
let start = movement::find_preceding_boundary(
map,
right(map, relative_to, 1),
movement::FindRange::SingleLine,
|left, right| {
char_kind(language, left).coerce_punctuation(ignore_punctuation)
!= char_kind(language, right).coerce_punctuation(ignore_punctuation)
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
},
);
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
char_kind(language, left).coerce_punctuation(ignore_punctuation)
!= char_kind(language, right).coerce_punctuation(ignore_punctuation)
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
});
Some(start..end)
@ -217,11 +220,13 @@ fn around_word(
relative_to: DisplayPoint,
ignore_punctuation: bool,
) -> Option<Range<DisplayPoint>> {
let language = map.buffer_snapshot.language_at(relative_to.to_point(map));
let scope = map
.buffer_snapshot
.language_scope_at(relative_to.to_point(map));
let in_word = map
.chars_at(relative_to)
.next()
.map(|(c, _)| char_kind(language, c) != CharKind::Whitespace)
.map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace)
.unwrap_or(false);
if in_word {
@ -245,22 +250,24 @@ fn around_next_word(
relative_to: DisplayPoint,
ignore_punctuation: bool,
) -> Option<Range<DisplayPoint>> {
let language = map.buffer_snapshot.language_at(relative_to.to_point(map));
let scope = map
.buffer_snapshot
.language_scope_at(relative_to.to_point(map));
// Get the start of the word
let start = movement::find_preceding_boundary(
map,
right(map, relative_to, 1),
FindRange::SingleLine,
|left, right| {
char_kind(language, left).coerce_punctuation(ignore_punctuation)
!= char_kind(language, right).coerce_punctuation(ignore_punctuation)
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
},
);
let mut word_found = false;
let end = movement::find_boundary(map, relative_to, FindRange::MultiLine, |left, right| {
let left_kind = char_kind(language, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(language, right).coerce_punctuation(ignore_punctuation);
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
let found = (word_found && left_kind != right_kind) || right == '\n' && left == '\n';