in src/unparsed-blocks/ListItem.php [49:183]
public static function consume(
Context $context,
Lines $lines,
): ?(ListItem, Lines) {
$max_indent = $context->getContext(self::MAX_INDENT_CONTEXT);
invariant(
$max_indent is int,
'expected to get a maximum indentation from context, got a %s',
\gettype($max_indent),
);
// Consume leading whitespace
list($column, $line, $lines) = $lines->getColumnFirstLineAndRest();
list($_, $line, $n) = Lines::stripUpToNLeadingWhitespace(
$line,
$max_indent,
$column,
);
$matches = Regex\first_match(
$line,
re"/^(?<marker>[-+*]|(?<digits>[0-9]{1,9})[.)])/",
);
if ($matches is null) {
return null;
}
// Consume marker
$marker_length = Str\length($matches[0]);
$indent_cols = $n + $marker_length;
$column += $indent_cols;
$line = Str\slice($line, $marker_length);
// Consume post-marker whitespace
if (Lines::isBlankLine($line)) {
$line = null;
$n = 1;
} else if (Lines::stripNLeadingWhitespace($line, 5, $column) !== null) {
// `- foo` is `<li><pre><code>foo</pre></code></li>`
list($_, $line, $n) =
Lines::stripUpToNLeadingWhitespace($line, 1, $column);
} else {
list($_, $line, $n) =
Lines::stripUpToNLeadingWhitespace($line, 4, $column);
}
if ($n === 0) {
return null;
}
$indent_cols += $n;
$column += $n;
$ordered = ($matches['digits'] ?? '') !== '';
$number = $ordered ? ((int) $matches['digits']) : null;
$delimiter = Str\trim_left($matches['marker'], '0123456789');
$matched = vec[];
if ($line !== null) {
$matched[] = tuple($column, $line);
}
$pre_blank_line = null;
while (!$lines->isEmpty()) {
list($column, $line, $rest) = $lines->getColumnFirstLineAndRest();
if (Lines::isBlankLine($line)) {
if (C\is_empty($matched)) {
break;
}
if ($pre_blank_line === null) {
$pre_blank_line = tuple($matched, $lines);
}
$matched[] = tuple($column, $line);
$lines = $rest;
continue;
}
$indented = Lines::stripNLeadingWhitespace($line, $indent_cols, $column);
if ($indented !== null) {
$matched[] = tuple($column + $indent_cols, $indented);
$pre_blank_line = null;
$lines = $rest;
continue;
}
$maybe_thematic_break = ThematicBreak::consume($context, $lines);
if ($maybe_thematic_break !== null) {
break;
}
if ($pre_blank_line !== null) {
break;
}
if (C\is_empty($matched)) {
break;
}
// Laziness - explicitly check for a list item as empty list items are
// valid paragraph continuation text
try {
$context->pushContext(self::MAX_INDENT_CONTEXT, $indent_cols - 1);
if (ListItem::consume($context, $lines) !== null) {
break;
}
} finally {
$context->popContext(self::MAX_INDENT_CONTEXT);
}
if (!_Private\is_paragraph_continuation_text($context, $lines)) {
break;
}
$matched[] = tuple($column, $line);
$lines = $rest;
}
if (C\is_empty($matched) && $context->isInParagraphContinuation()) {
return null;
}
if ($pre_blank_line !== null) {
list($matched, $lines) = $pre_blank_line;
}
return tuple(
static::createFromContents(
$context,
$indent_cols,
$delimiter,
$number,
new Lines($matched),
),
$lines,
);
}