writeString method

void writeString(
  1. int x,
  2. int y,
  3. String text,
  4. Style style,
)

Writes styled text to the buffer starting at (x, y).

Newlines (\n) will wrap to y + 1 at the starting column x. Any characters that fall out of bounds are clipped.

Implementation

void writeString(int x, int y, String text, Style style) {
  final startX = x;
  var currentX = x;
  var currentY = y;

  if (text.runes.length == text.length) {
    final len = text.length;
    final fg = style.foreground?.argb ?? 0;
    final bg = style.background?.argb ?? 0;
    final modifiers = style.modifiers;
    final hasFg = style.foreground != null;
    final hasBg = style.background != null;

    for (var i = 0; i < len; i++) {
      final codeUnit = text.codeUnitAt(i);
      if (codeUnit == 10) {
        // '\n'
        currentX = startX;
        currentY++;
        continue;
      }
      if (currentX >= 0 &&
          currentX < width &&
          currentY >= 0 &&
          currentY < height) {
        final idx = currentY * width + currentX;
        final char = String.fromCharCode(codeUnit);

        // Clear potential wide char we are about to overwrite
        if (characters[idx] == '') {
          if (currentX - 1 >= 0) {
            final prevIdx = idx - 1;
            if (isWideGrapheme(characters[prevIdx])) {
              characters[prevIdx] = ' ';
            }
          }
        } else if (isWideGrapheme(characters[idx])) {
          if (currentX + 1 < width) {
            final nextIdx = idx + 1;
            if (characters[nextIdx] == '') {
              characters[nextIdx] = ' ';
            }
          }
        }

        final isWide = isWideCodePoint(codeUnit);
        if (isWide && currentX == width - 1) {
          characters[idx] = ' ';
          final attrIdx = idx * 3;
          attributes[attrIdx + 0] = hasFg ? fg : 0;
          if (hasBg) attributes[attrIdx + 1] = bg;
          attributes[attrIdx + 2] = modifiers;
          currentX += 1;
        } else {
          characters[idx] = char;
          final attrIdx = idx * 3;
          attributes[attrIdx + 0] = hasFg ? fg : 0;
          if (hasBg) attributes[attrIdx + 1] = bg;
          attributes[attrIdx + 2] = modifiers;
          if (isWide) {
            if (currentX + 1 < width) {
              final nextIdx = idx + 1;
              // Clear potential wide char we are overwriting in the next cell
              if (isWideGrapheme(characters[nextIdx]) &&
                  currentX + 2 < width) {
                final nextNextIdx = idx + 2;
                if (characters[nextNextIdx] == '') {
                  characters[nextNextIdx] = ' ';
                }
              }
              characters[nextIdx] = '';
              final nextAttrIdx = nextIdx * 3;
              attributes[nextAttrIdx + 0] = hasFg ? fg : 0;
              if (hasBg) attributes[nextAttrIdx + 1] = bg;
              attributes[nextAttrIdx + 2] = modifiers;
            }
            currentX += 2;
          } else {
            currentX += 1;
          }
        }
      } else {
        currentX += 1;
      }
    }
    return;
  }

  final chars = text.characters;
  final fg = style.foreground?.argb ?? 0;
  final bg = style.background?.argb ?? 0;
  final modifiers = style.modifiers;
  final hasFg = style.foreground != null;
  final hasBg = style.background != null;

  for (final char in chars) {
    if (char == '\n') {
      currentX = startX;
      currentY++;
      continue;
    }
    if (currentX >= 0 &&
        currentX < width &&
        currentY >= 0 &&
        currentY < height) {
      final idx = currentY * width + currentX;
      // Clear potential wide char we are about to overwrite
      if (characters[idx] == '') {
        if (currentX - 1 >= 0) {
          final prevIdx = idx - 1;
          if (isWideGrapheme(characters[prevIdx])) {
            characters[prevIdx] = ' ';
          }
        }
      } else if (isWideGrapheme(characters[idx])) {
        if (currentX + 1 < width) {
          final nextIdx = idx + 1;
          if (characters[nextIdx] == '') {
            characters[nextIdx] = ' ';
          }
        }
      }

      final isWide = isWideGrapheme(char);
      if (isWide && currentX == width - 1) {
        // Can't fit wide character in the last column, write a space instead
        characters[idx] = ' ';
        final attrIdx = idx * 3;
        attributes[attrIdx + 0] = hasFg ? fg : 0;
        if (hasBg) attributes[attrIdx + 1] = bg;
        attributes[attrIdx + 2] = modifiers;
        currentX += 1;
      } else {
        characters[idx] = char;
        final attrIdx = idx * 3;
        attributes[attrIdx + 0] = hasFg ? fg : 0;
        if (hasBg) attributes[attrIdx + 1] = bg;
        attributes[attrIdx + 2] = modifiers;
        if (isWide) {
          if (currentX + 1 < width) {
            final nextIdx = idx + 1;
            // Clear potential wide char we are overwriting in the next cell
            if (isWideGrapheme(characters[nextIdx]) && currentX + 2 < width) {
              final nextNextIdx = idx + 2;
              if (characters[nextNextIdx] == '') {
                characters[nextNextIdx] = ' ';
              }
            }
            characters[nextIdx] = '';
            final nextAttrIdx = nextIdx * 3;
            attributes[nextAttrIdx + 0] = hasFg ? fg : 0;
            if (hasBg) attributes[nextAttrIdx + 1] = bg;
            attributes[nextAttrIdx + 2] = modifiers;
          }
          currentX += 2;
        } else {
          currentX += 1;
        }
      }
    } else {
      currentX += 1;
    }
  }
}