mirror of
https://github.com/zed-industries/zed.git
synced 2026-08-10 17:49:15 +00:00
editor: Treat punctuation as separate word boundaries (#62224)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
# Objective Fixes FR-149 - Make word movement and selection predictable around punctuation. - Prior art: [#58882](https://github.com/zed-industries/zed/pull/58882), [#61916](https://github.com/zed-industries/zed/pull/61916), and their revert [#62213](https://github.com/zed-industries/zed/pull/62213). ## Solution - Treat words and punctuation runs as separate movement units in both directions. - This adds a stop between leading punctuation and its following word, such as `.▏foo`. ## Testing - Added table-driven coverage for reported examples, delimiters, operators, punctuation runs, and Unicode punctuation. - Tested editor movement, selection, and deletion behavior. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed word movement and selection stopping on the wrong side of punctuation.
This commit is contained in:
parent
b914ba5cb3
commit
101ca00a13
4 changed files with 159 additions and 97 deletions
|
|
@ -2886,44 +2886,44 @@ fn test_prev_next_word_boundary(cx: &mut TestAppContext) {
|
|||
assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges("use stdˇ::str::{foo, bar}\n\nˇ {baz.qux()}", editor, cx);
|
||||
assert_selection_ranges("use stdˇ::str::{foo, bar}\n\n ˇ{baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges("use ˇstd::str::{foo, bar}\nˇ\n {baz.qux()}", editor, cx);
|
||||
assert_selection_ranges("use ˇstd::str::{foo, bar}\n\nˇ {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges("ˇuse std::str::{foo, bar}\nˇ\n {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges("ˇuse std::str::{foo, barˇ}\n\n {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_previous_word_start(&MoveToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges("ˇuse std::str::{foo, ˇbar}\n\n {baz.qux()}", editor, cx);
|
||||
editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx);
|
||||
assert_selection_ranges("useˇ std::str::{foo, bar}ˇ\n\n {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx);
|
||||
assert_selection_ranges("useˇ std::str::{foo, barˇ}\n\n {baz.qux()}", editor, cx);
|
||||
assert_selection_ranges("use stdˇ::str::{foo, bar}\nˇ\n {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx);
|
||||
assert_selection_ranges("use stdˇ::str::{foo, bar}ˇ\n\n {baz.qux()}", editor, cx);
|
||||
|
||||
editor.move_to_next_word_end(&MoveToNextWordEnd, window, cx);
|
||||
assert_selection_ranges("use std::ˇstr::{foo, bar}\nˇ\n {baz.qux()}", editor, cx);
|
||||
assert_selection_ranges("use std::ˇstr::{foo, bar}\n\n {ˇbaz.qux()}", editor, cx);
|
||||
|
||||
editor.move_right(&MoveRight, window, cx);
|
||||
editor.select_to_previous_word_start(&SelectToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges(
|
||||
"use std::«ˇs»tr::{foo, bar}\n«ˇ\n» {baz.qux()}",
|
||||
"use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}",
|
||||
editor,
|
||||
cx,
|
||||
);
|
||||
|
||||
editor.select_to_previous_word_start(&SelectToPreviousWordStart, window, cx);
|
||||
assert_selection_ranges(
|
||||
"use std«ˇ::s»tr::{foo, bar«ˇ}\n\n» {baz.qux()}",
|
||||
"use std«ˇ::s»tr::{foo, bar}\n\n «ˇ{b»az.qux()}",
|
||||
editor,
|
||||
cx,
|
||||
);
|
||||
|
||||
editor.select_to_next_word_end(&SelectToNextWordEnd, window, cx);
|
||||
assert_selection_ranges(
|
||||
"use std::«ˇs»tr::{foo, bar}«ˇ\n\n» {baz.qux()}",
|
||||
"use std::«ˇs»tr::{foo, bar}\n\n {«ˇb»az.qux()}",
|
||||
editor,
|
||||
cx,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -988,7 +988,7 @@ impl Editor {
|
|||
s.move_with(&mut |map, selection| {
|
||||
if selection.is_empty() {
|
||||
let mut cursor = if action.ignore_newlines {
|
||||
movement::previous_word_start(map, selection.head())
|
||||
movement::previous_word_start(map, selection.head(), true)
|
||||
} else {
|
||||
movement::previous_word_start_or_newline(map, selection.head())
|
||||
};
|
||||
|
|
@ -1053,7 +1053,7 @@ impl Editor {
|
|||
s.move_with(&mut |map, selection| {
|
||||
if selection.is_empty() {
|
||||
let mut cursor = if action.ignore_newlines {
|
||||
movement::next_word_end(map, selection.head())
|
||||
movement::next_word_end(map, selection.head(), true)
|
||||
} else {
|
||||
movement::next_word_end_or_newline(map, selection.head())
|
||||
};
|
||||
|
|
|
|||
|
|
@ -263,14 +263,18 @@ pub fn line_end(
|
|||
|
||||
/// Returns a position of the previous word boundary, where a word character is defined as either
|
||||
/// uppercase letter, lowercase letter, '_' character or language-specific word character (like '-' in CSS).
|
||||
pub fn previous_word_start(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
pub fn previous_word_start(
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
skip_punctuation: bool,
|
||||
) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let classifier = map.buffer_snapshot().char_classifier_at(raw_point);
|
||||
|
||||
let mut is_first_iteration = true;
|
||||
find_preceding_boundary_display_point(map, point, FindRange::MultiLine, &mut |left, right| {
|
||||
// Make alt-left skip punctuation to respect VSCode behaviour. For example: hello.| goes to |hello.
|
||||
if is_first_iteration
|
||||
if skip_punctuation
|
||||
&& is_first_iteration
|
||||
&& classifier.is_punctuation(right)
|
||||
&& !classifier.is_punctuation(left)
|
||||
&& left != '\n'
|
||||
|
|
@ -438,13 +442,17 @@ pub fn is_subword_start(left: char, right: char, classifier: &CharClassifier) ->
|
|||
|
||||
/// Returns a position of the next word boundary, where a word character is defined as either
|
||||
/// uppercase letter, lowercase letter, '_' character or language-specific word character (like '-' in CSS).
|
||||
pub fn next_word_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
pub fn next_word_end(
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
skip_punctuation: bool,
|
||||
) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let classifier = map.buffer_snapshot().char_classifier_at(raw_point);
|
||||
let mut is_first_iteration = true;
|
||||
find_boundary(map, point, FindRange::MultiLine, &mut |left, right| {
|
||||
// Make alt-right skip punctuation to respect VSCode behaviour. For example: |.hello goes to .hello|
|
||||
if is_first_iteration
|
||||
if skip_punctuation
|
||||
&& is_first_iteration
|
||||
&& classifier.is_punctuation(left)
|
||||
&& !classifier.is_punctuation(right)
|
||||
&& right != '\n'
|
||||
|
|
@ -1037,42 +1045,127 @@ mod tests {
|
|||
use settings::SettingsStore;
|
||||
use util::post_inc;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum WordMovement {
|
||||
PreviousStart,
|
||||
NextEnd,
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_previous_word_start(cx: &mut gpui::App) {
|
||||
fn test_word_movement(cx: &mut gpui::App) {
|
||||
init_test(cx);
|
||||
|
||||
fn assert(marked_text: &str, cx: &mut gpui::App) {
|
||||
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
|
||||
let actual = previous_word_start(&snapshot, display_points[1]);
|
||||
let expected = display_points[0];
|
||||
if actual != expected {
|
||||
eprintln!(
|
||||
"previous_word_start mismatch for '{}': actual={:?}, expected={:?}",
|
||||
marked_text, actual, expected
|
||||
);
|
||||
}
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
let cases = [
|
||||
(WordMovement::PreviousStart, " ˇlorˇem"),
|
||||
(WordMovement::PreviousStart, "\nlorem\nˇ ˇipsum"),
|
||||
(WordMovement::PreviousStart, "\n\nˇ\nˇ"),
|
||||
(WordMovement::PreviousStart, "ˇlorem_ˇipsum"),
|
||||
(WordMovement::PreviousStart, " ˇbcΔˇ"),
|
||||
(WordMovement::PreviousStart, "foo ˇaˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ..ˇ bar"),
|
||||
(WordMovement::PreviousStart, "wordˇ.ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ...ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ,;:!?ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ()[]{}ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ+-=*/&|^~ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ\"'`ˇ"),
|
||||
(WordMovement::PreviousStart, "wordˇ—…。ˇ"),
|
||||
(WordMovement::PreviousStart, "foo ˇ.ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ...ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ()[]{}ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ+-=*/&|^~ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ\"'`ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ—…。ˇ bar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ@ˇbar"),
|
||||
(WordMovement::PreviousStart, "foo ˇ..ˇ.bar"),
|
||||
(WordMovement::PreviousStart, "foo @ˇbarˇ baz"),
|
||||
(WordMovement::PreviousStart, "foo @ˇbˇar"),
|
||||
(WordMovement::PreviousStart, "foo ..ˇbarˇ baz"),
|
||||
(WordMovement::PreviousStart, ".ˇhelloˇ"),
|
||||
(WordMovement::PreviousStart, "@ˇwordˇ"),
|
||||
(WordMovement::PreviousStart, "*ˇConnectorˇ"),
|
||||
(WordMovement::PreviousStart, "\"ˇwordˇ\""),
|
||||
(WordMovement::PreviousStart, "\"expected ˇresultˇ\""),
|
||||
(WordMovement::PreviousStart, "\"ˇexpected ˇresult\""),
|
||||
(WordMovement::PreviousStart, "\\\"ˇunexpectedˇ\\\""),
|
||||
(WordMovement::PreviousStart, "'ˇwordˇ'"),
|
||||
(WordMovement::PreviousStart, "`ˇcodeˇ`"),
|
||||
(WordMovement::PreviousStart, "(ˇargsˇ)"),
|
||||
(WordMovement::PreviousStart, "[ˇitemˇ]"),
|
||||
(WordMovement::PreviousStart, "{ˇvalueˇ}"),
|
||||
(WordMovement::PreviousStart, "a-b-ˇcˇ"),
|
||||
(WordMovement::PreviousStart, "a.b.ˇcˇ"),
|
||||
(WordMovement::PreviousStart, "foo.ˇbarˇ"),
|
||||
(WordMovement::PreviousStart, "a@ˇbˇ"),
|
||||
(WordMovement::PreviousStart, "left::ˇrightˇ"),
|
||||
(WordMovement::PreviousStart, "foo/ˇbarˇ"),
|
||||
(WordMovement::PreviousStart, "foo->ˇbarˇ"),
|
||||
(WordMovement::PreviousStart, "foo&&ˇbarˇ"),
|
||||
(WordMovement::PreviousStart, "func(ˇargsˇ)"),
|
||||
(WordMovement::PreviousStart, "map[string]ˇboolˇ"),
|
||||
(WordMovement::PreviousStart, "if (foo.ˇbarˇ)"),
|
||||
(WordMovement::PreviousStart, "[2001:4860:4860::8888ˇ] ˇ"),
|
||||
(WordMovement::NextEnd, " lorˇemˇ"),
|
||||
(WordMovement::NextEnd, "loremˇ ipsumˇ"),
|
||||
(WordMovement::NextEnd, "\nˇ\nˇ\n\n"),
|
||||
(WordMovement::NextEnd, "loremˇ_ipsumˇ"),
|
||||
(WordMovement::NextEnd, " ˇbcΔˇ"),
|
||||
(WordMovement::NextEnd, "foo ˇaˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ..ˇ bar"),
|
||||
(WordMovement::NextEnd, "wordˇ.ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ...ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ,;:!?ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ()[]{}ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ+-=*/&|^~ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ\"'`ˇ"),
|
||||
(WordMovement::NextEnd, "wordˇ—…。ˇ"),
|
||||
(WordMovement::NextEnd, "foo ˇ.ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ...ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ()[]{}ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ+-=*/&|^~ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ\"'`ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ—…。ˇ bar"),
|
||||
(WordMovement::NextEnd, "ˇ.ˇhello"),
|
||||
(WordMovement::NextEnd, "ˇ@ˇword"),
|
||||
(WordMovement::NextEnd, "ˇ*ˇConnector"),
|
||||
(WordMovement::NextEnd, "ˇ\"ˇword\""),
|
||||
(WordMovement::NextEnd, "\"ˇexpectedˇ result\""),
|
||||
(WordMovement::NextEnd, "ˇ\\\"ˇunexpected\\\""),
|
||||
(WordMovement::NextEnd, "ˇ'ˇword'"),
|
||||
(WordMovement::NextEnd, "ˇ`ˇcode`"),
|
||||
(WordMovement::NextEnd, "ˇ(ˇargs)"),
|
||||
(WordMovement::NextEnd, "ˇ[ˇitem]"),
|
||||
(WordMovement::NextEnd, "ˇ{ˇvalue}"),
|
||||
(WordMovement::NextEnd, "display_pointsˇ[ˇ0]"),
|
||||
(WordMovement::NextEnd, "fooˇ.ˇ bar"),
|
||||
(WordMovement::NextEnd, "foo ˇ@ˇbar baz"),
|
||||
(WordMovement::NextEnd, "foo.ˇ..ˇbar"),
|
||||
(WordMovement::NextEnd, "aˇ-ˇb-c"),
|
||||
(WordMovement::NextEnd, "aˇ.ˇb.c"),
|
||||
(WordMovement::NextEnd, "aˇ@ˇb"),
|
||||
(WordMovement::NextEnd, "leftˇ::ˇright"),
|
||||
(WordMovement::NextEnd, "fooˇ/ˇbar"),
|
||||
(WordMovement::NextEnd, "fooˇ->ˇbar"),
|
||||
(WordMovement::NextEnd, "fooˇ&&ˇbar"),
|
||||
(WordMovement::NextEnd, "funcˇ(ˇargs)"),
|
||||
(WordMovement::NextEnd, "map[stringˇ]ˇbool"),
|
||||
(WordMovement::NextEnd, "if ˇ(ˇfoo.bar)"),
|
||||
(WordMovement::NextEnd, "[2001:4860:4860::8888ˇ]ˇ "),
|
||||
];
|
||||
|
||||
assert("\nˇ ˇlorem", cx);
|
||||
assert("ˇ\nˇ lorem", cx);
|
||||
assert(" ˇloremˇ", cx);
|
||||
assert("ˇ ˇlorem", cx);
|
||||
assert(" ˇlorˇem", cx);
|
||||
assert("\nlorem\nˇ ˇipsum", cx);
|
||||
assert("\n\nˇ\nˇ", cx);
|
||||
assert(" ˇlorem ˇipsum", cx);
|
||||
assert("ˇlorem-ˇipsum", cx);
|
||||
assert("loremˇ-#$@ˇipsum", cx);
|
||||
assert("ˇlorem_ˇipsum", cx);
|
||||
assert(" ˇdefγˇ", cx);
|
||||
assert(" ˇbcΔˇ", cx);
|
||||
// Test punctuation skipping behavior
|
||||
assert("ˇhello.ˇ", cx);
|
||||
assert("helloˇ...ˇ", cx);
|
||||
assert("helloˇ.---..ˇtest", cx);
|
||||
assert("test ˇ.--ˇtest", cx);
|
||||
assert("oneˇ,;:!?ˇtwo", cx);
|
||||
for (movement, marked_text) in cases {
|
||||
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
|
||||
assert_eq!(display_points.len(), 2, "{marked_text:?}");
|
||||
let (start, expected) = match movement {
|
||||
WordMovement::PreviousStart => (display_points[1], display_points[0]),
|
||||
WordMovement::NextEnd => (display_points[0], display_points[1]),
|
||||
};
|
||||
let actual = match movement {
|
||||
WordMovement::PreviousStart => previous_word_start(&snapshot, start, false),
|
||||
WordMovement::NextEnd => next_word_end(&snapshot, start, false),
|
||||
};
|
||||
assert_eq!(actual, expected, "{movement:?} failed for {marked_text:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
|
@ -1221,43 +1314,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_next_word_end(cx: &mut gpui::App) {
|
||||
init_test(cx);
|
||||
|
||||
fn assert(marked_text: &str, cx: &mut gpui::App) {
|
||||
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
|
||||
let actual = next_word_end(&snapshot, display_points[0]);
|
||||
let expected = display_points[1];
|
||||
if actual != expected {
|
||||
eprintln!(
|
||||
"next_word_end mismatch for '{}': actual={:?}, expected={:?}",
|
||||
marked_text, actual, expected
|
||||
);
|
||||
}
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
assert("\nˇ loremˇ", cx);
|
||||
assert(" ˇloremˇ", cx);
|
||||
assert(" lorˇemˇ", cx);
|
||||
assert(" loremˇ ˇ\nipsum\n", cx);
|
||||
assert("\nˇ\nˇ\n\n", cx);
|
||||
assert("loremˇ ipsumˇ ", cx);
|
||||
assert("loremˇ-ipsumˇ", cx);
|
||||
assert("loremˇ#$@-ˇipsum", cx);
|
||||
assert("loremˇ_ipsumˇ", cx);
|
||||
assert(" ˇbcΔˇ", cx);
|
||||
assert(" abˇ——ˇcd", cx);
|
||||
// Test punctuation skipping behavior
|
||||
assert("ˇ.helloˇ", cx);
|
||||
assert("display_pointsˇ[0ˇ]", cx);
|
||||
assert("ˇ...ˇhello", cx);
|
||||
assert("helloˇ.---..ˇtest", cx);
|
||||
assert("testˇ.--ˇ test", cx);
|
||||
assert("oneˇ,;:!?ˇtwo", cx);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_next_subword_end(cx: &mut gpui::App) {
|
||||
init_test(cx);
|
||||
|
|
@ -1546,7 +1602,7 @@ mod tests {
|
|||
// Ctrl+Right from before fold ("hello |⋯ world") should skip past the fold.
|
||||
// Cursor at column 6 = start of fold.
|
||||
let before_fold = DisplayPoint::new(DisplayRow(0), 6);
|
||||
let after_fold = next_word_end(&snapshot, before_fold);
|
||||
let after_fold = next_word_end(&snapshot, before_fold, false);
|
||||
// Should land past the fold, not get stuck at fold start.
|
||||
assert!(
|
||||
after_fold > before_fold,
|
||||
|
|
@ -1557,7 +1613,7 @@ mod tests {
|
|||
|
||||
// Ctrl+Right from "hello" should jump past "hello" to the fold or past it.
|
||||
let at_start = DisplayPoint::new(DisplayRow(0), 0);
|
||||
let after_hello = next_word_end(&snapshot, at_start);
|
||||
let after_hello = next_word_end(&snapshot, at_start, false);
|
||||
assert_eq!(
|
||||
after_hello,
|
||||
DisplayPoint::new(DisplayRow(0), 5),
|
||||
|
|
@ -1567,7 +1623,7 @@ mod tests {
|
|||
// Ctrl+Left from after fold should move to before the fold.
|
||||
// "⋯" ends at column 9. " world" starts at 9. Column 15 = end of "world".
|
||||
let after_world = DisplayPoint::new(DisplayRow(0), 15);
|
||||
let before_world = previous_word_start(&snapshot, after_world);
|
||||
let before_world = previous_word_start(&snapshot, after_world, false);
|
||||
assert_eq!(
|
||||
before_world,
|
||||
DisplayPoint::new(DisplayRow(0), 10),
|
||||
|
|
@ -1576,7 +1632,7 @@ mod tests {
|
|||
|
||||
// Ctrl+Left from start of "world" should land before fold.
|
||||
let start_of_world = DisplayPoint::new(DisplayRow(0), 10);
|
||||
let landed = previous_word_start(&snapshot, start_of_world);
|
||||
let landed = previous_word_start(&snapshot, start_of_world, false);
|
||||
// The fold acts as a word, so we should land at the fold start (column 6).
|
||||
assert_eq!(
|
||||
landed,
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ impl Editor {
|
|||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_cursors_with(&mut |map, head, _| {
|
||||
(
|
||||
movement::previous_word_start(map, head),
|
||||
movement::previous_word_start(map, head, false),
|
||||
SelectionGoal::None,
|
||||
)
|
||||
});
|
||||
|
|
@ -417,7 +417,7 @@ impl Editor {
|
|||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_heads_with(&mut |map, head, _| {
|
||||
(
|
||||
movement::previous_word_start(map, head),
|
||||
movement::previous_word_start(map, head, false),
|
||||
SelectionGoal::None,
|
||||
)
|
||||
});
|
||||
|
|
@ -448,7 +448,10 @@ impl Editor {
|
|||
) {
|
||||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_cursors_with(&mut |map, head, _| {
|
||||
(movement::next_word_end(map, head), SelectionGoal::None)
|
||||
(
|
||||
movement::next_word_end(map, head, false),
|
||||
SelectionGoal::None,
|
||||
)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
@ -474,7 +477,10 @@ impl Editor {
|
|||
) {
|
||||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_heads_with(&mut |map, head, _| {
|
||||
(movement::next_word_end(map, head), SelectionGoal::None)
|
||||
(
|
||||
movement::next_word_end(map, head, false),
|
||||
SelectionGoal::None,
|
||||
)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue