diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index a95e2a900..6c221ed32 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -67,6 +67,7 @@ use crate::{ use crate::job::{self, Jobs}; use std::{ + char::{ToLowercase, ToUppercase}, cmp::Ordering, collections::{HashMap, HashSet}, error::Error, @@ -1727,17 +1728,48 @@ where exit_select_mode(cx); } +enum CaseSwitcher { + Upper(ToUppercase), + Lower(ToLowercase), + Keep(Option), +} + +impl Iterator for CaseSwitcher { + type Item = char; + + fn next(&mut self) -> Option { + match self { + CaseSwitcher::Upper(upper) => upper.next(), + CaseSwitcher::Lower(lower) => lower.next(), + CaseSwitcher::Keep(ch) => ch.take(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + CaseSwitcher::Upper(upper) => upper.size_hint(), + CaseSwitcher::Lower(lower) => lower.size_hint(), + CaseSwitcher::Keep(ch) => { + let n = if ch.is_some() { 1 } else { 0 }; + (n, Some(n)) + } + } + } +} + +impl ExactSizeIterator for CaseSwitcher {} + fn switch_case(cx: &mut Context) { switch_case_impl(cx, |string| { string .chars() .flat_map(|ch| { if ch.is_lowercase() { - ch.to_uppercase().collect() + CaseSwitcher::Upper(ch.to_uppercase()) } else if ch.is_uppercase() { - ch.to_lowercase().collect() + CaseSwitcher::Lower(ch.to_lowercase()) } else { - vec![ch] + CaseSwitcher::Keep(Some(ch)) } }) .collect()