mirror of
https://github.com/helix-editor/helix.git
synced 2025-01-19 05:27:07 +04:00
Search selection with word boundary detection (#12126)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
This commit is contained in:
parent
95e6c11ebc
commit
7676106960
@ -160,7 +160,8 @@ ### Search
|
|||||||
| `?` | Search for previous pattern | `rsearch` |
|
| `?` | Search for previous pattern | `rsearch` |
|
||||||
| `n` | Select next search match | `search_next` |
|
| `n` | Select next search match | `search_next` |
|
||||||
| `N` | Select previous search match | `search_prev` |
|
| `N` | Select previous search match | `search_prev` |
|
||||||
| `*` | Use current selection as the search pattern | `search_selection` |
|
| `*` | Use current selection as the search pattern, automatically wrapping with `\b` on word boundaries | `search_selection_detect_word_boundaries` |
|
||||||
|
| `Alt-*` | Use current selection as the search pattern | `search_selection` |
|
||||||
|
|
||||||
### Minor modes
|
### Minor modes
|
||||||
|
|
||||||
|
@ -353,6 +353,7 @@ pub fn doc(&self) -> &str {
|
|||||||
extend_search_next, "Add next search match to selection",
|
extend_search_next, "Add next search match to selection",
|
||||||
extend_search_prev, "Add previous search match to selection",
|
extend_search_prev, "Add previous search match to selection",
|
||||||
search_selection, "Use current selection as search pattern",
|
search_selection, "Use current selection as search pattern",
|
||||||
|
search_selection_detect_word_boundaries, "Use current selection as the search pattern, automatically wrapping with `\\b` on word boundaries",
|
||||||
make_search_word_bounded, "Modify current search to make it word bounded",
|
make_search_word_bounded, "Modify current search to make it word bounded",
|
||||||
global_search, "Global search in workspace folder",
|
global_search, "Global search in workspace folder",
|
||||||
extend_line, "Select current line, if already selected, extend to another line based on the anchor",
|
extend_line, "Select current line, if already selected, extend to another line based on the anchor",
|
||||||
@ -2243,14 +2244,53 @@ fn extend_search_prev(cx: &mut Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_selection(cx: &mut Context) {
|
fn search_selection(cx: &mut Context) {
|
||||||
|
search_selection_impl(cx, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_selection_detect_word_boundaries(cx: &mut Context) {
|
||||||
|
search_selection_impl(cx, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_selection_impl(cx: &mut Context, detect_word_boundaries: bool) {
|
||||||
|
fn is_at_word_start(text: RopeSlice, index: usize) -> bool {
|
||||||
|
let ch = text.char(index);
|
||||||
|
if index == 0 {
|
||||||
|
return char_is_word(ch);
|
||||||
|
}
|
||||||
|
let prev_ch = text.char(index - 1);
|
||||||
|
|
||||||
|
!char_is_word(prev_ch) && char_is_word(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_at_word_end(text: RopeSlice, index: usize) -> bool {
|
||||||
|
if index == 0 || index == text.len_chars() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let ch = text.char(index);
|
||||||
|
let prev_ch = text.char(index - 1);
|
||||||
|
|
||||||
|
char_is_word(prev_ch) && !char_is_word(ch)
|
||||||
|
}
|
||||||
|
|
||||||
let register = cx.register.unwrap_or('/');
|
let register = cx.register.unwrap_or('/');
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let contents = doc.text().slice(..);
|
let text = doc.text().slice(..);
|
||||||
|
|
||||||
let regex = doc
|
let regex = doc
|
||||||
.selection(view.id)
|
.selection(view.id)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|selection| regex::escape(&selection.fragment(contents)))
|
.map(|selection| {
|
||||||
|
let add_boundary_prefix =
|
||||||
|
detect_word_boundaries && is_at_word_start(text, selection.from());
|
||||||
|
let add_boundary_suffix =
|
||||||
|
detect_word_boundaries && is_at_word_end(text, selection.to());
|
||||||
|
|
||||||
|
let prefix = if add_boundary_prefix { "\\b" } else { "" };
|
||||||
|
let suffix = if add_boundary_suffix { "\\b" } else { "" };
|
||||||
|
|
||||||
|
let word = regex::escape(&selection.fragment(text));
|
||||||
|
format!("{}{}{}", prefix, word, suffix)
|
||||||
|
})
|
||||||
.collect::<HashSet<_>>() // Collect into hashset to deduplicate identical regexes
|
.collect::<HashSet<_>>() // Collect into hashset to deduplicate identical regexes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -140,7 +140,8 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
|
|||||||
"?" => rsearch,
|
"?" => rsearch,
|
||||||
"n" => search_next,
|
"n" => search_next,
|
||||||
"N" => search_prev,
|
"N" => search_prev,
|
||||||
"*" => search_selection,
|
"*" => search_selection_detect_word_boundaries,
|
||||||
|
"A-*" => search_selection,
|
||||||
|
|
||||||
"u" => undo,
|
"u" => undo,
|
||||||
"U" => redo,
|
"U" => redo,
|
||||||
|
Loading…
Reference in New Issue
Block a user