listMarkerAt function

ListMarker? listMarkerAt(
  1. String line
)

The list marker opening line — -, + or *, or up to nine digits and . or ) — followed by whitespace or the end of the line.

One to four spaces after the marker set where the content starts. Five or more count as one (CommonMark reads the rest as indented code inside the item), and so does an empty item, whose content starts on the next line.

Implementation

ListMarker? listMarkerAt(String line) {
  var idx = 0;
  var indent = 0;
  while (idx < line.length) {
    final c = line.codeUnitAt(idx);
    if (c == _space) {
      indent += 1;
    } else if (c == _tab) {
      indent += 4;
    } else {
      break;
    }
    idx += 1;
  }
  if (idx >= line.length) {
    return null;
  }
  final first = line.codeUnitAt(idx);
  var ordered = false;
  var number = 0;
  int delimiter;
  var end = idx;
  if (first == 0x2D /* - */ ||
      first == 0x2B /* + */ ||
      first == 0x2A /* * */ ) {
    delimiter = first;
    end = idx + 1;
  } else {
    while (end < line.length &&
        end - idx < 10 &&
        line.codeUnitAt(end) >= _zero &&
        line.codeUnitAt(end) <= _nine) {
      end += 1;
    }
    final digits = end - idx;
    if (digits == 0 || digits > 9 || end >= line.length) {
      return null;
    }
    delimiter = line.codeUnitAt(end);
    if (delimiter != 0x2E /* . */ && delimiter != 0x29 /* ) */ ) {
      return null;
    }
    ordered = true;
    number = int.parse(line.substring(idx, end));
    end += 1;
  }
  final markerCol = indent + (end - idx);
  if (end == line.length) {
    return ListMarker(
      indent: indent,
      ordered: ordered,
      delimiter: delimiter,
      number: number,
      contentCol: markerCol + 1,
      content: '',
      blank: true,
    );
  }
  final after = line.codeUnitAt(end);
  if (after != _space && after != _tab) {
    return null;
  }
  var spaceEnd = end;
  var width = 0;
  while (spaceEnd < line.length) {
    final c = line.codeUnitAt(spaceEnd);
    if (c == _space) {
      width += 1;
    } else if (c == _tab) {
      width += 4 - (markerCol + width) % 4;
    } else {
      break;
    }
    spaceEnd += 1;
  }
  if (spaceEnd == line.length) {
    return ListMarker(
      indent: indent,
      ordered: ordered,
      delimiter: delimiter,
      number: number,
      contentCol: markerCol + 1,
      content: '',
      blank: true,
    );
  }
  if (width > 4) {
    return ListMarker(
      indent: indent,
      ordered: ordered,
      delimiter: delimiter,
      number: number,
      contentCol: markerCol + 1,
      content: line.substring(end + 1),
      blank: false,
    );
  }
  return ListMarker(
    indent: indent,
    ordered: ordered,
    delimiter: delimiter,
    number: number,
    contentCol: markerCol + width,
    content: line.substring(spaceEnd),
    blank: false,
  );
}