From cac920d992329b64974264b545129835085e74a5 Mon Sep 17 00:00:00 2001 From: Dino Date: Mon, 29 Sep 2025 23:43:05 +0100 Subject: [PATCH] vim: Add support for ignorecase and noignorecase options (#37459) Update the list of supported options in vim mode so that the following are now available: - `:set ignorecase` - `:set noignorecase` - `:set ic` - `:set noic` This controls whether the case-sensitive search option is disabled or enabled when using the buffer and project searches, with `ignorecase` disabling the search option and `noignorecase` enabling it. Release Notes: - Added support for `:set ignorecase` and `:set noignorecase` in vim mode --------- Co-authored-by: Conrad Irwin --- crates/vim/src/command.rs | 73 +++++++++++++++++++++++++++++++++++++-- docs/src/vim.md | 1 + 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/crates/vim/src/command.rs b/crates/vim/src/command.rs index a60942d79e913ac51de6c7be03697605ead980d8..275432433000b730a6bb88da46c7583aaeffd8b4 100644 --- a/crates/vim/src/command.rs +++ b/crates/vim/src/command.rs @@ -2,7 +2,7 @@ use anyhow::{Result, anyhow}; use collections::{HashMap, HashSet}; use command_palette_hooks::CommandInterceptResult; use editor::{ - Bias, Editor, SelectionEffects, ToPoint, + Bias, Editor, EditorSettings, SelectionEffects, ToPoint, actions::{SortLinesCaseInsensitive, SortLinesCaseSensitive}, display_map::ToDisplayPoint, }; @@ -16,6 +16,7 @@ use regex::Regex; use schemars::JsonSchema; use search::{BufferSearchBar, SearchOptions}; use serde::Deserialize; +use settings::{Settings, SettingsStore}; use std::{ iter::Peekable, ops::{Deref, Range}, @@ -80,6 +81,7 @@ pub enum VimOption { Wrap(bool), Number(bool), RelativeNumber(bool), + IgnoreCase(bool), } impl VimOption { @@ -122,6 +124,10 @@ impl VimOption { (None, VimOption::RelativeNumber(false)), (Some("rnu"), VimOption::RelativeNumber(true)), (Some("nornu"), VimOption::RelativeNumber(false)), + (None, VimOption::IgnoreCase(true)), + (None, VimOption::IgnoreCase(false)), + (Some("ic"), VimOption::IgnoreCase(true)), + (Some("noic"), VimOption::IgnoreCase(false)), ] .into_iter() .filter(move |(prefix, option)| prefix.unwrap_or(option.to_string()).starts_with(query)) @@ -143,6 +149,11 @@ impl VimOption { "norelativenumber" => Some(Self::RelativeNumber(false)), "nornu" => Some(Self::RelativeNumber(false)), + "ignorecase" => Some(Self::IgnoreCase(true)), + "ic" => Some(Self::IgnoreCase(true)), + "noignorecase" => Some(Self::IgnoreCase(false)), + "noic" => Some(Self::IgnoreCase(false)), + _ => None, } } @@ -155,6 +166,8 @@ impl VimOption { VimOption::Number(false) => "nonumber", VimOption::RelativeNumber(true) => "relativenumber", VimOption::RelativeNumber(false) => "norelativenumber", + VimOption::IgnoreCase(true) => "ignorecase", + VimOption::IgnoreCase(false) => "noignorecase", } } } @@ -257,6 +270,13 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { VimOption::RelativeNumber(enabled) => { editor.set_relative_line_number(Some(*enabled), cx); } + VimOption::IgnoreCase(enabled) => { + let mut settings = EditorSettings::get_global(cx).clone(); + settings.search.case_sensitive = !*enabled; + SettingsStore::update(cx, |store, _| { + store.override_global(settings); + }); + } }); } }); @@ -2045,9 +2065,10 @@ mod test { state::Mode, test::{NeovimBackedTestContext, VimTestContext}, }; - use editor::Editor; + use editor::{Editor, EditorSettings}; use gpui::{Context, TestAppContext}; use indoc::indoc; + use settings::Settings; use util::path; use workspace::Workspace; @@ -2605,4 +2626,52 @@ mod test { assert_active_item(workspace, path!("/root/dir/file_3.rs"), "", cx); }); } + + #[gpui::test] + async fn test_ignorecase_command(cx: &mut TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + cx.read(|cx| { + assert_eq!( + EditorSettings::get_global(cx).search.case_sensitive, + false, + "The `case_sensitive` setting should be `false` by default." + ); + }); + cx.simulate_keystrokes(": set space noignorecase"); + cx.simulate_keystrokes("enter"); + cx.read(|cx| { + assert_eq!( + EditorSettings::get_global(cx).search.case_sensitive, + true, + "The `case_sensitive` setting should have been enabled with `:set noignorecase`." + ); + }); + cx.simulate_keystrokes(": set space ignorecase"); + cx.simulate_keystrokes("enter"); + cx.read(|cx| { + assert_eq!( + EditorSettings::get_global(cx).search.case_sensitive, + false, + "The `case_sensitive` setting should have been disabled with `:set ignorecase`." + ); + }); + cx.simulate_keystrokes(": set space noic"); + cx.simulate_keystrokes("enter"); + cx.read(|cx| { + assert_eq!( + EditorSettings::get_global(cx).search.case_sensitive, + true, + "The `case_sensitive` setting should have been enabled with `:set noic`." + ); + }); + cx.simulate_keystrokes(": set space ic"); + cx.simulate_keystrokes("enter"); + cx.read(|cx| { + assert_eq!( + EditorSettings::get_global(cx).search.case_sensitive, + false, + "The `case_sensitive` setting should have been disabled with `:set ic`." + ); + }); + } } diff --git a/docs/src/vim.md b/docs/src/vim.md index b55faaf3b63b3ea25093a90d7c26769ee8ca84c9..7ebac0b3a6e1110da91ecd101632ecd6bf60f0d1 100644 --- a/docs/src/vim.md +++ b/docs/src/vim.md @@ -352,6 +352,7 @@ These commands modify editor options locally for the current buffer. | `:se[t] [no]wrap` | Lines longer than the width of the window will wrap and displaying continues on the next line | | `:se[t] [no]nu[mber]` | Print the line number in front of each line | | `:se[t] [no]r[elative]nu[mber]` | Changes the displayed number to be relative to the cursor | +| `:se[t] [no]i[gnore]c[ase]` | Controls whether the buffer and project search use case-sensitive matching | ### Command mnemonics