'ol', 'attr' => [], 'items' => [], 'loose' => false, ]; return $this->consumeList($lines, $current, $block, 'ol'); } /** * Consume lines for an unordered list. */ protected function consumeUl($lines, $current): array { $block = [ 'list', 'list' => 'ul', 'items' => [], 'loose' => false, ]; return $this->consumeList($lines, $current, $block, 'ul'); } private function consumeList($lines, $current, $block, $type): array { $item = 0; $marker = ''; $mw = 0; $nums = []; // Consume until end condition... for ($i = $current, $count = count($lines); $i < $count; $i++) { $line = $lines[$i]; $pattern = ($type === 'ol') ? '/^( {0,3})(\d{1,9})([\.\)])([ \t]+|$)/' : '/^( {0,3})([\-\+\*])([ \t]+|$)/' ; // If not the first item, marker indentation must be less than // width of preceeding marker - otherwise it is a continuation // of the current item containing a marker for a sub-list item. if ( preg_match($pattern, $line, $matches) && ($i === $current || strlen($matches[1]) < $mw) ) { // Capture the ol item number. if ($type === 'ol') { $nums[] = intval($matches[2]); } if ($i === $current) { // First item. // Store the marker for comparison. $marker = $type === 'ol' ? $matches[3] : $matches[2] ; } else { $item++; $newMarker = $type === 'ol' ? $matches[3] : $matches[2] ; // Marker has changed: end of list. if (strcmp($marker, $newMarker) !== 0) { --$i; break; } } $mw = strlen($matches[0]); $line = substr($line, $mw); $block['items'][$item][] = $line; } elseif ($line === '' || ltrim($line) === '') { // No more lines: end of list. if (!isset($lines[$i + 1])) { break; } $next = $lines[$i + 1]; $line = substr($line, $mw); if ($next === '' || ltrim($next) === '') { // Next line is also blank. $block['items'][$item][] = $line; } elseif (strspn($next, " \t") >= $mw) { // Next line is indented enough to continue this item. $block['items'][$item][] = $line; } elseif (preg_match($pattern, $next)) { // Next line is the next item in this list: loose list. $block['items'][$item][] = $line; $block['loose'] = true; } else { // next line is not list content. break; } } elseif ( strlen($line) > $mw && strspn($line, " \t") >= $mw ) { // Line is indented enough to continue this item. $line = substr($line, $mw); $block['items'][$item][] = $line; } else { // Everything else ends the list. --$i; break; } // If next line is