Skip to content

Commit

Permalink
improve handling of VS15 and VS16
Browse files Browse the repository at this point in the history
These modifiers have the effect of forcing us to consider the grapheme
as being either a single cell (VS15) or two cells (VS16) in the
terminal model.

These don't affect font choice as wezterm doesn't know whether a given
font in the fallback has a textual vs. an emoji version of a given
glyph, or whether a later font in the fallback has one or the other
because we can't know until we fall back, and that has a very high
cost--we perform fallback asynchronously in another thread because
of its high cost.

Depending on the selected glyph, it may or may not render as double
wide.

refs: #997
  • Loading branch information
wez committed Aug 3, 2021
1 parent 2590e49 commit 76b72e4
Showing 1 changed file with 57 additions and 4 deletions.
61 changes: 57 additions & 4 deletions termwiz/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,15 +707,29 @@ pub fn grapheme_column_width(s: &str) -> usize {
// Let's check for emoji-ness for ourselves first
use xi_unicode::EmojiExt;
let mut emoji = false;
let mut implied_emoji_presentation = false;

for c in s.chars() {
if c.is_emoji_modifier_base() || c.is_emoji_modifier() {
// treat modifier sequences as double wide
if c == '\u{FE0F}' {
// Explicit emoji presentation
return 2;
}
if c.is_emoji() {
} else if c == '\u{FE0E}' {
// Explicit text presentation
return 1;
} else if c.is_emoji_modifier_base() || c.is_emoji_modifier() {
// We'll probably use emoji presentation for this,
// but defer the decision until we've had a chance
// to look for an explicit presentation selection.
implied_emoji_presentation = true;
} else if c.is_emoji() {
emoji = true;
}
}

if implied_emoji_presentation {
return 2;
}

let width = UnicodeWidthStr::width(s);
if emoji {
// For sequences such as "deaf man", UnicodeWidthStr::width()
Expand Down Expand Up @@ -834,4 +848,43 @@ mod test {
eprintln!("font_awesome_star {}", font_awesome_star.escape_debug());
assert_eq!(unicode_column_width(font_awesome_star), 1);
}

#[test]
fn issue_997() {
use unicode_segmentation::UnicodeSegmentation;
let waving_hand = "\u{270c}";
let waving_hand_text_presentation = "\u{270c}\u{fe0e}";

assert_eq!(unicode_column_width(waving_hand_text_presentation), 1);
assert_eq!(unicode_column_width(waving_hand), 2);

assert_eq!(
waving_hand_text_presentation
.graphemes(true)
.collect::<Vec<_>>(),
vec![waving_hand_text_presentation.to_string()]
);
assert_eq!(
waving_hand.graphemes(true).collect::<Vec<_>>(),
vec![waving_hand.to_string()]
);

let copyright_emoji_presentation = "\u{00A9}\u{FE0F}";
assert_eq!(
copyright_emoji_presentation
.graphemes(true)
.collect::<Vec<_>>(),
vec![copyright_emoji_presentation.to_string()]
);
assert_eq!(unicode_column_width(copyright_emoji_presentation), 2);

let copyright_text_presentation = "\u{00A9}";
assert_eq!(
copyright_text_presentation
.graphemes(true)
.collect::<Vec<_>>(),
vec![copyright_text_presentation.to_string()]
);
assert_eq!(unicode_column_width(copyright_text_presentation), 1);
}
}

0 comments on commit 76b72e4

Please # to comment.