Merge pull request #470 from foriequal0/emoji-presentation

fix: Fix miscalculating the width of numbers and some symbols
This commit is contained in:
Ed Page 2022-04-28 09:36:18 -05:00 committed by GitHub
commit 93608f47f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -254,7 +254,7 @@ fn calculate_visible_column_width(str: &str) -> usize {
result += if grapheme == "\t" { result += if grapheme == "\t" {
// TODO: config tab width // TODO: config tab width
1 1
} else if grapheme.chars().any(unic_emoji_char::is_emoji) { } else if is_emoji(grapheme) {
// UnicodeWidthStr::width doesn't cover for emoji according to their README. // UnicodeWidthStr::width doesn't cover for emoji according to their README.
// See: https://github.com/unicode-rs/unicode-width#unicode-width // See: https://github.com/unicode-rs/unicode-width#unicode-width
// Also, the actual rendered column width may differ from calculation, especially for emojis. // Also, the actual rendered column width may differ from calculation, especially for emojis.
@ -268,6 +268,20 @@ fn calculate_visible_column_width(str: &str) -> usize {
result result
} }
fn is_emoji(grapheme: &str) -> bool {
if grapheme.is_ascii() {
return false;
}
for ch in grapheme.chars() {
if unic_emoji_char::is_emoji(ch) {
return true;
}
}
false
}
fn context_display<'c>(context: &'c Option<Context<'c>>) -> &'c dyn std::fmt::Display { fn context_display<'c>(context: &'c Option<Context<'c>>) -> &'c dyn std::fmt::Display {
context context
.as_ref() .as_ref()
@ -284,3 +298,80 @@ impl Report for PrintJson {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_visible_column_width_visible_ascii() {
for c in '!'..'~' {
assert_eq!(1, calculate_visible_column_width(&c.to_string()));
}
}
#[test]
fn test_calculate_visible_column_width_horizontal_tab() {
assert_eq!(1, calculate_visible_column_width("\t"));
}
#[test]
fn test_calculate_visible_column_width_latin_cyrillic() {
let latin_cyrillic_chars = [
"À", /* U+00C0; Latin Capital Letter A with Grave */
"", /* U+0041 U+0300; Latin Capital Letter A, Combining Grave Accent */
"А", /* U+0410 Cyrillic Capital Letter A */
];
for (i, ch) in latin_cyrillic_chars.iter().enumerate() {
let width = calculate_visible_column_width(ch);
assert_eq!(1, width, "latin_cyrillic[{}]: {}", i, ch,);
}
}
#[test]
fn test_calculate_visible_column_width_cjk() {
let cjk_chars = [
"", /* U+4E2D */
"", /* U+3042 */
"", /* U+1F635 U+200D U+1F4AB, NFC Korean */
"", /* U+1F441 U+FE0F U+200D U+1F5E8 U+FE0F, NFD Korean */
];
for (i, ch) in cjk_chars.iter().enumerate() {
let width = calculate_visible_column_width(ch);
assert_eq!(2, width, "cjk[{}]: {}", i, ch);
}
}
#[test]
fn test_calculate_visible_column_width_simple_emojis() {
// First non-component emojis of each gropus in "Full Emoji List, v14.0"
// https://unicode.org/Public/emoji/14.0/emoji-test.txt
let simple_emojis = [
"😀", /* U+1F600 */
"👋", /* U+1F44B */
"🐵", /* U+1F435 */
"🍇", /* U+1F347 */
"🌍", /* U+1F30D */
"🎃", /* U+1F383 */
"👓", /* U+1F453 */
"🏧", /* U+1F3E7 */
"🏁", /* U+1F3C1 */
];
for (i, ch) in simple_emojis.iter().enumerate() {
let width = calculate_visible_column_width(ch);
assert_eq!(2, width, "emoji[{}]: {}", i, ch);
}
}
#[test]
fn test_calculate_visible_column_width_zwj_sequences() {
let zwj_sequences = [
"😵‍💫", /* U+1F635 U+200D U+1F4AB */
"👁️‍🗨️", /* U+1F441 U+FE0F U+200D U+1F5E8 U+FE0F */
];
for (i, ch) in zwj_sequences.iter().enumerate() {
let width = calculate_visible_column_width(ch);
assert_eq!(2, width, "zwj[{}]: {}", i, ch);
}
}
}