stringWidth method

int stringWidth(
  1. String s
)

Calculates the display width of s using grapheme cluster iteration.

Each grapheme cluster is measured individually. Clusters containing U+FE0F (emoji presentation selector) are widened to emojiPresentationWidth when the base rune would otherwise be narrow.

Implementation

int stringWidth(String s) {
  final asciiWidth = _asciiStringWidth(s);
  if (asciiWidth != null) return asciiWidth;

  final cachedWidth = _unicodeStringWidthCache[s];
  if (cachedWidth != null) return cachedWidth;

  final simpleUnicodeWidth = _simpleUnicodeStringWidth(s);
  if (simpleUnicodeWidth != null) {
    _cacheUnicodeStringWidth(s, simpleUnicodeWidth);
    return simpleUnicodeWidth;
  }

  var width = 0;
  // Count display width per grapheme cluster to avoid double-counting
  // multi-codepoint clusters (e.g. ZWJ emoji sequences).
  for (final g in uni.graphemes(s)) {
    final iterator = g.runes.iterator;
    if (!iterator.moveNext()) continue;

    final first = iterator.current;
    var hasEmojiPresentationSelector = first == 0xFE0F;
    while (iterator.moveNext()) {
      if (iterator.current == 0xFE0F) {
        hasEmojiPresentationSelector = true;
        break;
      }
    }

    var w = runeWidth(first);
    // If the grapheme contains U+FE0F (variation selector 16 — emoji
    // presentation), terminals render the base character at emoji width
    // even if runeWidth() returned 1.
    if (w == 1 && hasEmojiPresentationSelector) {
      w = emojiPresentationWidth;
    }
    width += w;
  }
  _cacheUnicodeStringWidth(s, width);
  return width;
}