fix: clear search highlighting on Normal escape
This commit is contained in:
@@ -176,6 +176,8 @@ Normal `*` highlights the primary caret's word without moving any caret when it
|
||||
|
||||
`n`/`N` and an empty `/` submission retain the whole-word setting; a nonempty `/` query returns to literal substring search. Cancelling `/` preserves both the previous query and its matching behavior.
|
||||
|
||||
Normal-mode Escape hides search highlights without forgetting the query or matching mode. The next `*` re-highlights without moving; `n`/`N` or submitting `/` resumes navigation and restores highlighting. Escape used to cancel a prompt, selection, or pending motion keeps its existing behavior.
|
||||
|
||||
Submitting an empty search repeats the last query. Esc cancels without moving the cursor or replacing the previous query/match. A missing match reports the query and leaves the cursor unchanged; searching without a previous query also leaves the cursor unchanged. Search never edits text or adds undo history. Buffer edits and undo/redo retain the query and recompute its visible highlights, so subsequent navigation searches the current text again.
|
||||
|
||||
## Commands, saving, and pasted input
|
||||
|
||||
+18
-2
@@ -1575,6 +1575,7 @@ struct ViewState {
|
||||
linewise: bool,
|
||||
search_query: String,
|
||||
search_whole_word: bool,
|
||||
search_highlight: bool,
|
||||
search_match: Option<SearchMatch>,
|
||||
command_line: String,
|
||||
caret_reveal_revision: u64,
|
||||
@@ -1594,6 +1595,7 @@ impl ViewState {
|
||||
linewise: false,
|
||||
search_query: String::new(),
|
||||
search_whole_word: false,
|
||||
search_highlight: false,
|
||||
search_match: None,
|
||||
command_line: String::new(),
|
||||
caret_reveal_revision: 0,
|
||||
@@ -1613,6 +1615,7 @@ impl ViewState {
|
||||
linewise: self.linewise,
|
||||
search_query: self.search_query.clone(),
|
||||
search_whole_word: self.search_whole_word,
|
||||
search_highlight: self.search_highlight,
|
||||
search_match: self.search_match,
|
||||
command_line: self.command_line.clone(),
|
||||
caret_reveal_revision: self.caret_reveal_revision,
|
||||
@@ -6491,7 +6494,11 @@ impl Editor {
|
||||
self.active.view.search_match
|
||||
}
|
||||
pub fn search_matches_on_row(&self, row: usize) -> impl Iterator<Item = SearchMatch> + '_ {
|
||||
let query = self.active.view.search_query.as_str();
|
||||
let query = if self.active.view.search_highlight {
|
||||
self.active.view.search_query.as_str()
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let line = &self.active.lines[row];
|
||||
let columns = grapheme_count(query);
|
||||
search_match_bytes(line, query, self.active.view.search_whole_word).map(move |byte| {
|
||||
@@ -7934,6 +7941,8 @@ impl Editor {
|
||||
&& (!self.message.is_empty() || self.diagnostic_at_cursor().is_some())
|
||||
{
|
||||
self.notification_visible = false;
|
||||
self.active.view.search_highlight = false;
|
||||
self.active.view.search_match = None;
|
||||
return None;
|
||||
}
|
||||
if matches!(self.active.view.mode, Mode::Normal | Mode::Visual)
|
||||
@@ -8379,6 +8388,8 @@ impl Editor {
|
||||
}
|
||||
Action::Normal => {
|
||||
if self.active.view.mode == Mode::Normal {
|
||||
self.active.view.search_highlight = false;
|
||||
self.active.view.search_match = None;
|
||||
self.collapse_primary();
|
||||
} else if self.active.view.mode == Mode::Insert {
|
||||
self.finish_insert();
|
||||
@@ -8452,11 +8463,15 @@ impl Editor {
|
||||
.map_or(line.len(), |(position, _)| position);
|
||||
let query = &line[start..end];
|
||||
let whole_word = kind == WordKind::Keyword;
|
||||
let newly_active = self.active.view.search_query != query
|
||||
let newly_active = !self.active.view.search_highlight
|
||||
|| self.active.view.search_query != query
|
||||
|| self.active.view.search_whole_word != whole_word;
|
||||
if newly_active {
|
||||
if self.active.view.search_query != query {
|
||||
self.active.view.search_query = query.into();
|
||||
}
|
||||
self.active.view.search_whole_word = whole_word;
|
||||
self.active.view.search_highlight = true;
|
||||
}
|
||||
Some((
|
||||
Cursor {
|
||||
@@ -8491,6 +8506,7 @@ impl Editor {
|
||||
self.set_message("No previous search");
|
||||
return;
|
||||
}
|
||||
self.active.view.search_highlight = true;
|
||||
let query = self.active.view.search_query.as_str();
|
||||
let whole_word = self.active.view.search_whole_word;
|
||||
// ponytail: O(buffer graphemes × query bytes) scan; index matches if large buffers need it.
|
||||
|
||||
@@ -120,6 +120,36 @@ fn wait_until(session: &mut EditorSession, ready: impl Fn(&EditorSession) -> boo
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normal_escape_hides_highlights_but_retains_search_and_rearms_star() {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor("cat cat");
|
||||
keys(&mut editor, "*");
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 2);
|
||||
editor.handle(Input::Escape);
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 0);
|
||||
assert_eq!(editor.search_match(), None);
|
||||
assert_eq!(editor.cursor(), Cursor::default());
|
||||
keys(&mut editor, "*");
|
||||
assert_eq!(editor.cursor(), Cursor::default());
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 2);
|
||||
keys(&mut editor, "*");
|
||||
assert_eq!(editor.cursor(), Cursor { row: 0, column: 4 });
|
||||
editor.handle(Input::Escape);
|
||||
keys(&mut editor, "n");
|
||||
assert_eq!(editor.cursor(), Cursor::default());
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 2);
|
||||
keys(&mut editor, "/missing");
|
||||
editor.handle(Input::Escape);
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 2);
|
||||
editor.handle(Input::Escape);
|
||||
editor.handle(Input::Char('/'));
|
||||
editor.handle(Input::Enter);
|
||||
assert_eq!(editor.cursor(), Cursor { row: 0, column: 4 });
|
||||
assert_eq!(editor.search_matches_on_row(0).count(), 2);
|
||||
assert!(!editor.dirty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn star_search_arms_without_moving_then_navigates_and_rearms_for_a_new_word_or_mode() {
|
||||
let fixture = Fixture::new();
|
||||
|
||||
Reference in New Issue
Block a user