diff --git a/TODO.md b/TODO.md index d81cf30246989..90e7e4509d38d 100644 --- a/TODO.md +++ b/TODO.md @@ -22,8 +22,6 @@ as you type completion! - [ ] lsp: signature help -- [ ] search: smart case by default: insensitive unless upper detected - 2 - [ ] macro recording - [ ] extend selection (treesitter select parent node) (replaces viw, vi(, va( etc ) diff --git a/book/src/configuration.md b/book/src/configuration.md index 5a28362d7d21d..90cdd8a7cc84d 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -17,6 +17,7 @@ To override global configuration parameters, create a `config.toml` file located | `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` | | `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`
Windows: `["cmd", "/C"]` | | `line-number` | Line number display (`absolute`, `relative`) | `absolute` | +| `smart-case` | Enable smart case regex searching (case insensitive unless pattern contains upper case characters) | `true` | ## LSP diff --git a/book/src/keymap.md b/book/src/keymap.md index 4fa5033d35b20..16d2420df0ba6 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -104,8 +104,7 @@ ### Search -> TODO: The search implementation isn't ideal yet -- we don't support searching -in reverse, or searching via smartcase. +> TODO: The search implementation isn't ideal yet -- we don't support searching in reverse. | Key | Description | Command | | ----- | ----------- | ------- | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 703b92d1b062b..e02231187c5cd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -5,7 +5,7 @@ use helix_core::{ match_brackets, movement::{self, Direction}, object, pos_at_coords, - regex::{self, Regex}, + regex::{self, Regex, RegexBuilder}, register::Register, search, selection, surround, textobject, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril, Transaction, @@ -1154,7 +1154,8 @@ fn search_next_impl(cx: &mut Context, extend: bool) { if let Some(query) = registers.read('/') { let query = query.last().unwrap(); let contents = doc.text().slice(..).to_string(); - if let Ok(regex) = Regex::new(query) { + let case_insensitive = if cx.editor.config.smart_case { !query.chars().any(char::is_uppercase) } else { false }; + if let Ok(regex) = RegexBuilder::new(query).case_insensitive(case_insensitive).build() { search_impl(doc, view, &contents, ®ex, extend); } else { // get around warning `mutable_borrow_reservation_conflict` diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 07eef3525d879..a70d8383743f2 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -20,6 +20,7 @@ pub use spinner::{ProgressSpinners, Spinner}; pub use text::Text; use helix_core::regex::Regex; +use helix_core::regex::RegexBuilder; use helix_view::{Document, Editor, View}; use std::path::PathBuf; @@ -53,7 +54,9 @@ pub fn regex_prompt( return; } - match Regex::new(input) { + let case_insensitive = if cx.editor.config.smart_case { !input.chars().any(char::is_uppercase) } else { false }; + + match RegexBuilder::new(input).case_insensitive(case_insensitive).build() { Ok(regex) => { let (view, doc) = current!(cx.editor); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index a3d0d0323fcc4..b7df4a9bf01c2 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -39,6 +39,8 @@ pub struct Config { pub line_number: LineNumber, /// Middle click paste support. Defaults to true pub middle_click_paste: bool, + /// Smart case: Case insensitive searching unless pattern contains upper case characters. Defaults to true. + pub smart_case: bool, } #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] @@ -64,6 +66,7 @@ impl Default for Config { }, line_number: LineNumber::Absolute, middle_click_paste: true, + smart_case: true, } } }