gl-website-deployer/vendor/doctrine/rst-parser/lib/Parser/LineChecker.php
2024-11-19 08:02:04 +01:00

159 lines
5.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace Doctrine\RST\Parser;
use function in_array;
use function preg_match;
use function preg_replace;
use function str_repeat;
use function strlen;
use function strpos;
use function trim;
class LineChecker
{
private const HEADER_LETTERS = ['=', '-', '~', '*', '+', '^', '"', '.', '`', "'", '_', '#', ':'];
/**
* A regex matching all bullet list markers and a subset of the enumerated list markers.
*
* @see https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#bullet-lists
* @see https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#enumerated-lists
*/
public const LIST_MARKER = '/
^(
[-+*\x{2022}\x{2023}\x{2043}] # match bullet list markers: "*", "+", "-", "•", "‣", or ""
|(?:[\d#]+\.|[\d#]+\)|\([\d#]+\)) # match arabic (1-9) or auto-enumerated ("#") lists with formats: "1.", "1)", or "(1)"
)
(?:\s+|$) # capture the spaces between marker and text to determine the list item text offset (or eol, if text starts on a new line)
/ux';
public function isSpecialLine(string $line): ?string
{
if (strlen($line) < 2) {
return null;
}
$letter = $line[0];
if (! in_array($letter, self::HEADER_LETTERS, true)) {
return null;
}
for ($i = 1; $i < strlen($line); $i++) {
if ($line[$i] !== $letter) {
return null;
}
}
return $letter;
}
/**
* Checks if this line is the start of a list item.
*
* @see self::LIST_MARKER
*
* @param string|null $listMarker if provided, this function only returns "true" if the
* same list marker format is used (e.g. all dashes).
* @param int|null $listOffset if this line is a list, this will be set to the column
* number of the start of the list item content (used to
* match multiline items)
* @param string|null $nextLine if set, this line must also be a valid list line or
* indented content for enumerated lists
*/
public function isListLine(string $line, ?string &$listMarker = null, ?int &$listOffset = 0, ?string $nextLine = null): bool
{
$isList = preg_match(self::LIST_MARKER, $line, $m) > 0;
if (! $isList) {
return false;
}
$offset = strlen($m[0]);
$normalizedMarker = preg_replace('/\d+/', 'd', $m[1]);
if (
// validate if next line can be considered part of a list for enumerated lists
$normalizedMarker !== $m[1]
&& $nextLine !== null
&& trim($nextLine) !== ''
&& ! $this->isBlockLine($nextLine, $offset)
&& ! $this->isListLine($nextLine, $normalizedMarker)
) {
return false;
}
if ($listMarker !== null) {
$isList = $normalizedMarker === $listMarker;
}
if ($isList) {
$listOffset = $offset;
$listMarker = $normalizedMarker;
}
return $isList;
}
/**
* Is this line "indented"?
*
* A blank line also counts as a "block" line, as it
* may be the empty line between, for example, a
* ".. note::" directive and the indented content on the
* next lines.
*
* @param int $minIndent can be used to require a specific level of
* indentation for non-blank lines (number of spaces)
*/
public function isBlockLine(string $line, int $minIndent = 1): bool
{
return (trim($line) === '' || $this->isIndented($line, $minIndent)) && ! $this->isComment($line);
}
public function isComment(string $line): bool
{
return preg_match('/^\.\.(?: [^_]((?:(?!::).)*))?$/mUsi', $line) > 0;
}
public function isDirective(string $line): bool
{
return preg_match('/^\.\. (\|(.+)\| |)([^\s]+)::( (.*)|)$/mUsi', $line) > 0;
}
/**
* Check if line is an indented one.
*
* This does *not* include blank lines, use {@see isBlockLine()} to check
* for blank or indented lines.
*
* @param int $minIndent can be used to require a specific level of indentation (number of spaces)
*/
public function isIndented(string $line, int $minIndent = 1): bool
{
return strpos($line, str_repeat(' ', $minIndent)) === 0;
}
/**
* Checks if the current line can be considered part of the definition list.
*
* Either the current line, or the next line must be indented to be considered
* definition.
*
* @see https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#definition-lists
*/
public function isDefinitionListEnded(string $line, string $nextLine): bool
{
if (trim($line) === '') {
return false;
}
if ($this->isIndented($line)) {
return false;
}
return ! $this->isIndented($nextLine);
}
}