Improve case insensitivity consistency (#10884)

# Description

Add an extension trait `IgnoreCaseExt` to nu_utils which adds some case
insensitivity helpers, and use them throughout nu to improve the
handling of case insensitivity. Proper case folding is done via unicase,
which is already a dependency via mime_guess from nu-command.

In actuality a lot of code still does `to_lowercase`, because unicase
only provides immediate comparison and doesn't expose a `to_folded_case`
yet. And since we do a lot of `contains`/`starts_with`/`ends_with`, it's
not sufficient to just have `eq_ignore_case`. But if we get access in
the future, this makes us ready to use it with a change in one place.

Plus, it's clearer what the purpose is at the call site to call
`to_folded_case` instead of `to_lowercase` if it's exclusively for the
purpose of case insensitive comparison, even if it just does
`to_lowercase` still.

# User-Facing Changes

- Some commands that were supposed to be case insensitive remained only
insensitive to ASCII case (a-z), and now are case insensitive w.r.t.
non-ASCII characters as well.

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

---------

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
This commit is contained in:
Christopher Durham
2023-11-08 17:58:54 -05:00
committed by GitHub
parent aed4b626b8
commit 0f600bc3f5
35 changed files with 176 additions and 122 deletions

View File

@ -8,7 +8,7 @@ where
crate::lev_distance::find_best_match_for_name_with_substrings(&possibilities, input, None)
.map(|s| s.to_string());
if let Some(suggestion) = &suggestion {
if suggestion.len() == 1 && suggestion.to_lowercase() != input.to_lowercase() {
if suggestion.len() == 1 && !suggestion.eq_ignore_ascii_case(input) {
return None;
}
}

View File

@ -20,8 +20,8 @@ pub use custom_value::CustomValue;
use fancy_regex::Regex;
pub use from_value::FromValue;
pub use lazy_record::LazyRecord;
use nu_utils::get_system_locale;
use nu_utils::locale::get_system_locale_string;
use nu_utils::{get_system_locale, IgnoreCaseExt};
use num_format::ToFormattedString;
pub use range::*;
pub use record::Record;
@ -1008,7 +1008,7 @@ impl Value {
// Make reverse iterate to avoid duplicate column leads to first value, actually last value is expected.
if let Some(found) = val.iter().rev().find(|x| {
if insensitive {
x.0.to_lowercase() == column_name.to_lowercase()
x.0.eq_ignore_case(column_name)
} else {
x.0 == column_name
}