readStyle function

void readStyle(
  1. List<SgrParam> params,
  2. StyleState out
)

Implementation

void readStyle(List<SgrParam> params, StyleState out) {
  // Upstream: `third_party/ultraviolet/styled.go` (`ReadStyle`).
  if (params.isEmpty) {
    out.style = const UvStyle();
    return;
  }

  var style = out.style;

  for (var i = 0; i < params.length; i++) {
    final p = params[i];
    final param = p.value;

    switch (param) {
      case 0:
        style = const UvStyle();
      case 1:
        style = style.copyWith(attrs: style.attrs | Attr.bold);
      case 2:
        style = style.copyWith(attrs: style.attrs | Attr.faint);
      case 3:
        style = style.copyWith(attrs: style.attrs | Attr.italic);
      case 4:
        // Underline with optional subparameter (4:3 etc).
        if (p.hasSub) {
          final next = p.sub.first;
          style = style.copyWith(
            underline: switch (next) {
              0 => UnderlineStyle.none,
              1 => UnderlineStyle.single,
              2 => UnderlineStyle.double,
              3 => UnderlineStyle.curly,
              4 => UnderlineStyle.dotted,
              5 => UnderlineStyle.dashed,
              _ => UnderlineStyle.single,
            },
          );
        } else {
          style = style.copyWith(underline: UnderlineStyle.single);
        }
      case 5:
        style = style.copyWith(attrs: style.attrs | Attr.blink);
      case 6:
        style = style.copyWith(attrs: style.attrs | Attr.rapidBlink);
      case 7:
        style = style.copyWith(attrs: style.attrs | Attr.reverse);
      case 8:
        style = style.copyWith(attrs: style.attrs | Attr.conceal);
      case 9:
        style = style.copyWith(attrs: style.attrs | Attr.strikethrough);

      // Reset variants used in upstream tests.
      case 22:
        style = style.copyWith(attrs: style.attrs & ~(Attr.bold | Attr.faint));
      case 23:
        style = style.copyWith(attrs: style.attrs & ~Attr.italic);
      case 24:
        style = style.copyWith(underline: UnderlineStyle.none);
      case 25:
        style = style.copyWith(
          attrs: style.attrs & ~(Attr.blink | Attr.rapidBlink),
        );
      case 27:
        style = style.copyWith(attrs: style.attrs & ~Attr.reverse);
      case 28:
        style = style.copyWith(attrs: style.attrs & ~Attr.conceal);
      case 29:
        style = style.copyWith(attrs: style.attrs & ~Attr.strikethrough);

      // Foreground colors: 30-37, 90-97
      case >= 30 && <= 37:
        style = style.copyWith(fg: UvColor.basic16(param - 30));
      case >= 90 && <= 97:
        style = style.copyWith(fg: UvColor.basic16(param - 90, bright: true));

      // Background colors: 40-47, 100-107
      case >= 40 && <= 47:
        style = style.copyWith(bg: UvColor.basic16(param - 40));
      case >= 100 && <= 107:
        style = style.copyWith(bg: UvColor.basic16(param - 100, bright: true));

      // Default colors
      case 39:
        style = style.copyWith(clearFg: true);
      case 49:
        style = style.copyWith(clearBg: true);
      case 59:
        style = style.copyWith(clearUnderlineColor: true);

      // Extended colors, semicolon form:
      // 38;5;<n>, 48;5;<n>, 38;2;r;g;b, 48;2;r;g;b
      // Underline color:
      // - 58;5;<n>, 58;2;r;g;b
      // - 58:5:<n>, 58:2::r:g:b
      case 38 || 48:
        final isFg = param == 38;

        // Colon form groups (e.g. 38:2::r:g:b) come in as a single param with sub.
        if (p.hasSub) {
          if (p.sub.isEmpty) break;
          final mode = p.sub[0];
          if (mode == 5 && p.sub.length >= 2) {
            final idx = p.sub[1];
            style = isFg
                ? style.copyWith(fg: UvColor.indexed256(idx))
                : style.copyWith(bg: UvColor.indexed256(idx));
          } else if (mode == 2 && p.sub.length >= 5) {
            // 38:2::<r>:<g>:<b>
            final r = p.sub[2];
            final g = p.sub[3];
            final b = p.sub[4];
            style = isFg
                ? style.copyWith(fg: UvColor.rgb(r, g, b))
                : style.copyWith(bg: UvColor.rgb(r, g, b));
          }
          break;
        }

        if (i + 1 >= params.length) break;
        final mode = params[i + 1].value;
        if (mode == 5 && i + 2 < params.length) {
          final idx = params[i + 2].value;
          style = isFg
              ? style.copyWith(fg: UvColor.indexed256(idx))
              : style.copyWith(bg: UvColor.indexed256(idx));
          i += 2;
        } else if (mode == 2 && i + 4 < params.length) {
          final r = params[i + 2].value;
          final g = params[i + 3].value;
          final b = params[i + 4].value;
          style = isFg
              ? style.copyWith(fg: UvColor.rgb(r, g, b))
              : style.copyWith(bg: UvColor.rgb(r, g, b));
          i += 4;
        }
      case 58:
        // Underline color (SGR 58). Supports both semicolon and colon forms.
        // - Semicolon: 58;5;<n> or 58;2;r;g;b
        // - Colon: 58:5:<n> or 58:2::r:g:b
        if (p.hasSub) {
          if (p.sub.isEmpty) break;
          final mode = p.sub[0];
          if (mode == 5 && p.sub.length >= 2) {
            style = style.copyWith(
              underlineColor: UvColor.indexed256(p.sub[1]),
            );
          } else if (mode == 2) {
            // 58:2::r:g:b  -> sub = [2,0,r,g,b]
            // 58:2:r:g:b   -> sub = [2,r,g,b]
            if (p.sub.length >= 5) {
              final r = p.sub[2];
              final g = p.sub[3];
              final b = p.sub[4];
              style = style.copyWith(underlineColor: UvColor.rgb(r, g, b));
            } else if (p.sub.length >= 4) {
              final r = p.sub[1];
              final g = p.sub[2];
              final b = p.sub[3];
              style = style.copyWith(underlineColor: UvColor.rgb(r, g, b));
            }
          }
          break;
        }

        if (i + 1 >= params.length) break;
        final mode = params[i + 1].value;
        if (mode == 5 && i + 2 < params.length) {
          style = style.copyWith(
            underlineColor: UvColor.indexed256(params[i + 2].value),
          );
          i += 2;
        } else if (mode == 2 && i + 4 < params.length) {
          final r = params[i + 2].value;
          final g = params[i + 3].value;
          final b = params[i + 4].value;
          style = style.copyWith(underlineColor: UvColor.rgb(r, g, b));
          i += 4;
        }
    }
  }

  out.style = style;
}