mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
fix: match double-width roman characters (closes #1149)
This commit is contained in:
parent
b17e93890a
commit
1dead2b3c6
|
|
@ -1,6 +1,7 @@
|
|||
//! Byte/Char helpers
|
||||
use super::Score;
|
||||
use super::constants::SEPARATOR_TABLE;
|
||||
use crate::fuzzy_matcher::util::char_equal;
|
||||
use memchr::{memchr, memrchr};
|
||||
|
||||
pub(super) trait Atom: PartialEq + Into<char> + Copy {
|
||||
|
|
@ -112,9 +113,15 @@ impl Atom for u8 {
|
|||
}
|
||||
impl Atom for char {
|
||||
#[inline(always)]
|
||||
fn eq_ignore_case(self, b: Self) -> bool {
|
||||
self.to_lowercase().eq(b.to_lowercase())
|
||||
fn eq(self, other: Self, respect_case: bool) -> bool {
|
||||
char_equal(self, other, respect_case)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn eq_ignore_case(self, b: Self) -> bool {
|
||||
char_equal(self, b, false)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_lowercase(self) -> bool {
|
||||
self.is_lowercase()
|
||||
|
|
@ -179,6 +186,8 @@ mod tests {
|
|||
fn char_atom_eq_and_case() {
|
||||
assert!('a'.eq('A', false));
|
||||
assert!(!'a'.eq('A', true));
|
||||
assert!('a'.eq('a', true));
|
||||
assert!('A'.eq('a', false));
|
||||
assert!('a'.is_lowercase());
|
||||
assert!(!'A'.is_lowercase());
|
||||
// Default (non-SIMD) find impls for char.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ fn test_match_or_not() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fullwidth_ascii_matches_ascii_query() {
|
||||
let matcher = SkimMatcherV2::default();
|
||||
let (_, indices) = matcher
|
||||
.fuzzy_indices("abc", "abc")
|
||||
.expect("fullwidth ASCII should match");
|
||||
assert_eq!(indices, vec![0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_quality() {
|
||||
let matcher = SkimMatcherV2::default().ignore_case();
|
||||
|
|
|
|||
|
|
@ -22,15 +22,34 @@ pub fn cheap_matches(choice: &[char], pattern: &[char], case_sensitive: bool) ->
|
|||
}
|
||||
}
|
||||
|
||||
/// Given 2 character, check if they are equal (considering ascii case)
|
||||
/// Convert the Unicode fullwidth form of an ASCII character to ASCII.
|
||||
#[inline]
|
||||
fn narrow_ascii_width(ch: char) -> char {
|
||||
match ch {
|
||||
'\u{3000}' => ' ',
|
||||
'\u{FF01}'..='\u{FF5E}' => char::from_u32(ch as u32 - 0xFEE0).unwrap_or(ch),
|
||||
_ => ch,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given two characters, check if they are equal after folding ASCII width and,
|
||||
/// when requested, case.
|
||||
/// e.g. ('a', 'A', true) => false
|
||||
/// e.g. ('a', 'A', false) => true
|
||||
/// e.g. ('a', 'a', true) => true
|
||||
#[inline]
|
||||
pub fn char_equal(a: char, b: char, case_sensitive: bool) -> bool {
|
||||
if a == b {
|
||||
return true;
|
||||
}
|
||||
|
||||
let a = narrow_ascii_width(a);
|
||||
let b = narrow_ascii_width(b);
|
||||
|
||||
if a == b {
|
||||
return true;
|
||||
}
|
||||
|
||||
if case_sensitive {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -156,6 +175,16 @@ mod tests {
|
|||
assert!(!char_equal('a', 'b', false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_equal_folds_fullwidth_ascii() {
|
||||
assert!(char_equal('a', 'a', true));
|
||||
assert!(char_equal('A', 'A', true));
|
||||
assert!(!char_equal('A', 'a', true));
|
||||
assert!(char_equal('A', 'a', false));
|
||||
assert!(char_equal('1', '1', true));
|
||||
assert!(char_equal(' ', ' ', true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_equal_multichar_lowercase_mismatch() {
|
||||
// 'İ' (U+0130) lowercases to two chars ("i" + combining dot), so it is
|
||||
|
|
|
|||
Loading…
Reference in a new issue