feat: add Vim-style word search

This commit is contained in:
Valdemar Lorenzen
2026-10-15 11:59:07 +02:00
parent 2fd240aca8
commit 7b3b3866fd
6 changed files with 206 additions and 19 deletions
+111
View File
@@ -120,6 +120,92 @@ fn wait_until(session: &mut EditorSession, ready: impl Fn(&EditorSession) -> boo
}
}
#[test]
fn star_search_keeps_whole_word_counts_history_and_literal_search_distinct() {
let fixture = Fixture::new();
let text = "cat\nscatter\ncat_cat\ncat2\n2cat\nCat\ncat\ncat\n\n";
let mut editor = fixture.editor(text);
keys(&mut editor, "l*");
assert_eq!(editor.cursor(), Cursor { row: 6, column: 0 });
assert_eq!(editor.search_match().unwrap().end_column, 3);
keys(&mut editor, "nN2*");
assert_eq!(editor.cursor(), Cursor { row: 0, column: 0 });
editor.handle(Input::Ctrl('o'));
assert_eq!(editor.cursor(), Cursor { row: 6, column: 0 });
editor.handle(Input::Char('\t'));
assert_eq!(editor.cursor(), Cursor { row: 0, column: 0 });
keys(&mut editor, "/scatter");
editor.handle(Input::Escape);
editor.handle(Input::Char('/'));
editor.handle(Input::Enter);
assert_eq!(editor.cursor(), Cursor { row: 6, column: 0 });
keys(&mut editor, "gb*");
assert_eq!(editor.cursor(), Cursor { row: 9, column: 0 });
keys(&mut editor, "n");
assert_eq!(editor.cursor(), Cursor { row: 0, column: 0 });
keys(&mut editor, "/cat");
editor.handle(Input::Enter);
assert_eq!(editor.cursor(), Cursor { row: 1, column: 1 });
assert_eq!(editor.search_match().unwrap().end_column, 4);
assert_eq!(editor.context().text, text);
assert!(!editor.dirty());
}
#[test]
fn star_search_uses_unicode_words_and_vim_same_line_fallbacks() {
let fixture = Fixture::new();
for (text, positioning, row, length) in [
("e\u{301}lan\ne\u{301}lanx\ne\u{301}lan", "l", 2, 4),
("世界\n世界中\n世界", "l", 2, 2),
("snake_case\nsnake_case2\nsnake_case", "3l", 2, 10),
("\t-- word\nword", "", 1, 4),
("-- word\nword", "", 1, 4),
("word --\n--", "$", 1, 2),
(" .* \n.*", "", 1, 2),
("👩‍🚀\n👩\n👩‍🚀", "", 2, 1),
("only", "l", 0, 4),
] {
let mut editor = fixture.editor(text);
keys(&mut editor, positioning);
editor.handle(Input::Char('*'));
assert_eq!(editor.cursor(), Cursor { row, column: 0 }, "{text:?}");
assert_eq!(
editor.search_match().unwrap().end_column,
length,
"{text:?}"
);
keys(&mut editor, "Nn");
assert_eq!(editor.cursor(), Cursor { row, column: 0 }, "{text:?}");
assert!(!editor.dirty());
}
}
#[test]
fn star_search_rebinding_moves_all_carets_and_remains_view_local() {
let fixture = Fixture::new();
let mut session = fixture.session(
"cat cat_cat cat cat\ncat cat_cat cat cat",
" config.bind '*', nil\n config.bind 'q', config.core.search_word",
);
session.handle(Input::Ctrl('e'));
session_keys(&mut session, "2q");
assert_eq!(
session.editor().carets(),
[Cursor { row: 0, column: 16 }, Cursor { row: 1, column: 16 }]
);
session_keys(&mut session, "|2N");
assert_eq!(session.editor().cursor(), Cursor { row: 1, column: 0 });
session_keys(&mut session, "/cat");
session.handle(Input::Enter);
assert_eq!(session.editor().cursor(), Cursor { row: 1, column: 4 });
session.handle(Input::Alt('h'));
session_keys(&mut session, "2N");
assert_eq!(session.editor().cursor(), Cursor { row: 1, column: 0 });
assert!(!session.editor().dirty());
}
#[test]
fn counted_character_seeks_move_every_native_caret_independently() {
let fixture = Fixture::new();
@@ -352,6 +438,31 @@ fn readonly_before_and_historical_after_seeks_preserve_snapshots_and_folded_exce
column: second_x
}
);
session_keys(&mut session, "*");
assert_eq!(
session.editor().cursor(),
Cursor {
row: 20,
column: 12
}
);
assert_eq!(session.editor().search_match().unwrap().end_column, 13);
session_keys(&mut session, "3*N");
assert_eq!(
session.editor().cursor(),
Cursor {
row: 18,
column: 12
}
);
session_keys(&mut session, "3n");
assert_eq!(
session.editor().cursor(),
Cursor {
row: 19,
column: second_x
}
);
session_keys(&mut session, "Fxvfx");
assert_eq!(
session.editor().selections(),