diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 50b7cab5f..8b5243213 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2097,20 +2097,31 @@ fn search_impl( // use find_at to find the next match after the cursor, loop around the end // Careful, `Regex` uses `bytes` as offsets, not character indices! - let mut mat = match direction { - Direction::Forward => regex.find(doc.regex_input_at_bytes(start..)), - Direction::Backward => regex.find_iter(doc.regex_input_at_bytes(..start)).last(), - }; + let mut cap = regex.create_captures(); + match direction { + Direction::Forward => regex.captures(doc.regex_input_at_bytes(start..), &mut cap), + Direction::Backward => { + cap = regex + .captures_iter(doc.regex_input_at_bytes(..start)) + .last() + .unwrap_or(cap) + } + } - if mat.is_none() { + if !cap.is_match() { if wrap_around { - mat = match direction { - Direction::Forward => regex.find(doc.regex_input()), - Direction::Backward => regex.find_iter(doc.regex_input_at_bytes(start..)).last(), + match direction { + Direction::Forward => regex.captures(doc.regex_input(), &mut cap), + Direction::Backward => { + cap = regex + .captures_iter(doc.regex_input_at_bytes(start..)) + .last() + .unwrap_or(cap) + } }; } if show_warnings { - if wrap_around && mat.is_some() { + if wrap_around && cap.is_match() { editor.set_status("Wrapped around document"); } else { editor.set_error("No more matches"); @@ -2122,7 +2133,7 @@ fn search_impl( let text = doc.text().slice(..); let selection = doc.selection(view.id); - if let Some(mat) = mat { + if let Some(mat) = cap.get_match() { let start = text.byte_to_char(mat.start()); let end = text.byte_to_char(mat.end()); @@ -2135,11 +2146,49 @@ fn search_impl( let primary = selection.primary(); let range = Range::new(start, end).with_direction(primary.direction()); + let should_update_search_results = + selection.len() == editor.registers.search_result_count(); let selection = match movement { Movement::Extend => selection.clone().push(range), - Movement::Move => selection.clone().replace(selection.primary_index(), range), + Movement::Move => { + if should_update_search_results { + editor + .registers + .remove_search_result(selection.primary_index()); + } + selection.clone().replace(selection.primary_index(), range) + } }; + let capture_groups = cap + .iter() + .map(|span| { + span.map(|span| text.slice(span.range()).to_string()) + .unwrap_or_default() + }) + .collect(); + if should_update_search_results { + if selection.len() == editor.registers.search_result_count() { + editor + .registers + .remove_search_result(selection.primary_index()); + } + editor + .registers + .insert_search_result(selection.primary_index(), capture_groups); + } else { + editor.registers.write_search_results(vec![ + vec!["".to_string(); selection.len()]; + regex.captures_len() + ]); + editor + .registers + .remove_search_result(selection.primary_index()); + editor + .registers + .insert_search_result(selection.primary_index(), capture_groups); + } + doc.set_selection(view.id, selection); view.ensure_cursor_in_view_center(doc, scrolloff); }; diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs index 9a5459576..18ce3919f 100644 --- a/helix-view/src/register.rs +++ b/helix-view/src/register.rs @@ -155,6 +155,20 @@ impl Registers { } } + pub fn insert_search_result(&mut self, idx: usize, search_results: Vec) { + let idx = self.search_result_count() - idx; + let len = search_results.len(); + for (i, value) in search_results.into_iter().enumerate() { + let entry = self.inner.entry(search_register_name(i)).or_default(); + entry.insert(idx, value); + } + for i in len..=9 { + if let Some(entry) = self.inner.get_mut(&search_register_name(i)) { + entry.insert(idx, String::new()); + } + } + } + pub fn remove_search_result(&mut self, idx: usize) { let idx = self.search_result_count() - idx - 1; for i in 0..=9 {