From d89c84d2a7418cec347c7f5ff8d9d8c8d707645e Mon Sep 17 00:00:00 2001 From: Yahya Badran Date: Thu, 4 Sep 2025 12:06:36 +0200 Subject: [PATCH 1/2] feat: add literal (non-regex) search commands Introduce `search_literal` and `rsearch_literal` commands for forward and reverse literal (non-regex) text search. This allows searching for text containing regex metacharacters without needing to escape them. --- helix-term/src/commands.rs | 20 +++++++++++++++++--- helix-term/src/ui/mod.rs | 8 ++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8edf59441f76..7a5ac6e7eaaa 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -374,6 +374,8 @@ impl MappableCommand { merge_consecutive_selections, "Merge consecutive selections", search, "Search for regex pattern", rsearch, "Reverse search for regex pattern", + search_literal, "Search for literal text (non-regex)", + rsearch_literal, "Reverse search for literal text (non-regex)", search_next, "Select next search match", search_prev, "Select previous search match", extend_search_next, "Add next search match to selection", @@ -2100,6 +2102,7 @@ fn select_regex(cx: &mut Context) { cx.editor.set_error("nothing selected"); } }, + false, ); } @@ -2119,6 +2122,7 @@ fn split_selection(cx: &mut Context) { let selection = selection::split_on_matches(text, doc.selection(view.id), ®ex); doc.set_selection(view.id, selection); }, + false, ); } @@ -2234,14 +2238,22 @@ fn search_completions(cx: &mut Context, reg: Option) -> Vec { } fn search(cx: &mut Context) { - searcher(cx, Direction::Forward) + searcher(cx, Direction::Forward, false) } fn rsearch(cx: &mut Context) { - searcher(cx, Direction::Backward) + searcher(cx, Direction::Backward, false) } -fn searcher(cx: &mut Context, direction: Direction) { +fn search_literal(cx: &mut Context) { + searcher(cx, Direction::Forward, true) +} + +fn rsearch_literal(cx: &mut Context) { + searcher(cx, Direction::Backward, true) +} + +fn searcher(cx: &mut Context, direction: Direction, literal_search: bool) { let reg = cx.register.unwrap_or('/'); let config = cx.editor.config(); let scrolloff = config.scrolloff; @@ -2282,6 +2294,7 @@ fn searcher(cx: &mut Context, direction: Direction) { false, ); }, + literal_search, ); } @@ -5166,6 +5179,7 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) { cx.editor.set_error("no selections remaining"); } }, + false, ) } diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 089f8e971e92..efd9c2b44aaa 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -78,6 +78,7 @@ pub fn regex_prompt( history_register: Option, completion_fn: impl FnMut(&Editor, &str) -> Vec + 'static, fun: impl Fn(&mut crate::compositor::Context, rope::Regex, PromptEvent) + 'static, + literal_search: bool, ) { raw_regex_prompt( cx, @@ -85,6 +86,7 @@ pub fn regex_prompt( history_register, completion_fn, move |cx, regex, _, event| fun(cx, regex, event), + literal_search, ); } pub fn raw_regex_prompt( @@ -93,6 +95,7 @@ pub fn raw_regex_prompt( history_register: Option, completion_fn: impl FnMut(&Editor, &str) -> Vec + 'static, fun: impl Fn(&mut crate::compositor::Context, rope::Regex, &str, PromptEvent) + 'static, + literal_search: bool, ) { let (view, doc) = current!(cx.editor); let doc_id = view.doc; @@ -105,6 +108,11 @@ pub fn raw_regex_prompt( history_register, completion_fn, move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| { + let input = if literal_search { + &helix_core::regex::escape(input) + } else { + input + }; match event { PromptEvent::Abort => { let (view, doc) = current!(cx.editor); From ece29eff58c1aedca44353f86a2b00286316205d Mon Sep 17 00:00:00 2001 From: Yahya Badran Date: Thu, 4 Sep 2025 12:16:46 +0200 Subject: [PATCH 2/2] add docgen docs --- book/src/generated/static-cmd.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/book/src/generated/static-cmd.md b/book/src/generated/static-cmd.md index 1b347290b9f1..952e15f149bf 100644 --- a/book/src/generated/static-cmd.md +++ b/book/src/generated/static-cmd.md @@ -72,6 +72,8 @@ | `merge_consecutive_selections` | Merge consecutive selections | normal: `` ``, select: `` `` | | `search` | Search for regex pattern | normal: `` / ``, `` Z/ ``, `` z/ ``, select: `` / ``, `` Z/ ``, `` z/ `` | | `rsearch` | Reverse search for regex pattern | normal: `` ? ``, `` Z? ``, `` z? ``, select: `` ? ``, `` Z? ``, `` z? `` | +| `search_literal` | Search for literal text (non-regex) | | +| `rsearch_literal` | Reverse search for literal text (non-regex) | | | `search_next` | Select next search match | normal: `` n ``, `` Zn ``, `` zn ``, select: `` Zn ``, `` zn `` | | `search_prev` | Select previous search match | normal: `` N ``, `` ZN ``, `` zN ``, select: `` ZN ``, `` zN `` | | `extend_search_next` | Add next search match to selection | select: `` n `` |