class BlockLevelPass {
private $DTopen = false;
private $inPre = false;
- private $lastSection = '';
+ private $lastParagraph = '';
private $lineStart;
private $text;
}
/**
- * Private constructor
+ * @param string $text
+ * @param bool $lineStart
*/
private function __construct( $text, $lineStart ) {
$this->text = $text;
$this->lineStart = $lineStart;
}
+ /**
+ * @return bool
+ */
+ private function hasOpenParagraph() {
+ return $this->lastParagraph !== '';
+ }
+
/**
* If a pre or p is open, return the corresponding close tag and update
* the state. If no tag is open, return an empty string.
+ * @param bool $atTheEnd Omit trailing newline if we've reached the end.
* @return string
*/
- private function closeParagraph() {
+ private function closeParagraph( $atTheEnd = false ) {
$result = '';
- if ( $this->lastSection !== '' ) {
- $result = '</' . $this->lastSection . ">\n";
+ if ( $this->hasOpenParagraph() ) {
+ $result = '</' . $this->lastParagraph . '>';
+ if ( !$atTheEnd ) {
+ $result .= "\n";
+ }
}
$this->inPre = false;
- $this->lastSection = '';
+ $this->lastParagraph = '';
return $result;
}
private function openList( $char ) {
$result = $this->closeParagraph();
- if ( '*' === $char ) {
+ if ( $char === '*' ) {
$result .= "<ul><li>";
- } elseif ( '#' === $char ) {
+ } elseif ( $char === '#' ) {
$result .= "<ol><li>";
- } elseif ( ':' === $char ) {
+ } elseif ( $char === ':' ) {
$result .= "<dl><dd>";
- } elseif ( ';' === $char ) {
+ } elseif ( $char === ';' ) {
$result .= "<dl><dt>";
$this->DTopen = true;
} else {
* @return string
*/
private function nextItem( $char ) {
- if ( '*' === $char || '#' === $char ) {
+ if ( $char === '*' || $char === '#' ) {
return "</li>\n<li>";
- } elseif ( ':' === $char || ';' === $char ) {
+ } elseif ( $char === ':' || $char === ';' ) {
$close = "</dd>\n";
if ( $this->DTopen ) {
$close = "</dt>\n";
}
- if ( ';' === $char ) {
+ if ( $char === ';' ) {
$this->DTopen = true;
return $close . '<dt>';
} else {
* @return string
*/
private function closeList( $char ) {
- if ( '*' === $char ) {
+ if ( $char === '*' ) {
$text = "</li></ul>";
- } elseif ( '#' === $char ) {
+ } elseif ( $char === '#' ) {
$text = "</li></ol>";
- } elseif ( ':' === $char ) {
+ } elseif ( $char === ':' ) {
if ( $this->DTopen ) {
$this->DTopen = false;
$text = "</dt></dl>";
$pendingPTag = false;
$inBlockquote = false;
- foreach ( $textLines as $inputLine ) {
+ for ( $textLines->rewind(); $textLines->valid(); ) {
+ $inputLine = $textLines->current();
+ $textLines->next();
+ $notLastLine = $textLines->valid();
+
# Fix up $lineStart
if ( !$this->lineStart ) {
$output .= $inputLine;
$char = $prefix[$commonPrefixLength];
$output .= $this->openList( $char );
- if ( ';' === $char ) {
+ if ( $char === ';' ) {
# @todo FIXME: This is dupe of code above
if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
$t = $t2;
}
# If we have no prefixes, go to paragraph mode.
- if ( 0 == $prefixLength ) {
+ if ( $prefixLength == 0 ) {
# No prefix (not in list)--go to paragraph mode
# @todo consider using a stack for nestable elements like span, table and div
}
$inBlockElem = !$closeMatch;
} elseif ( !$inBlockElem && !$this->inPre ) {
- if ( ' ' == substr( $t, 0, 1 )
- && ( $this->lastSection === 'pre' || trim( $t ) != '' )
+ if ( substr( $t, 0, 1 ) == ' '
+ && ( $this->lastParagraph === 'pre' || trim( $t ) != '' )
&& !$inBlockquote
) {
# pre
- if ( $this->lastSection !== 'pre' ) {
+ if ( $this->lastParagraph !== 'pre' ) {
$pendingPTag = false;
$output .= $this->closeParagraph() . '<pre>';
- $this->lastSection = 'pre';
+ $this->lastParagraph = 'pre';
}
$t = substr( $t, 1 );
} elseif ( preg_match( '/^(?:<style\\b[^>]*>.*?<\\/style>\s*|<link\\b[^>]*>\s*)+$/iS', $t ) ) {
if ( $pendingPTag ) {
$output .= $this->closeParagraph();
$pendingPTag = false;
- $this->lastSection = '';
}
} else {
# paragraph
if ( $pendingPTag ) {
$output .= $pendingPTag . '<br />';
$pendingPTag = false;
- $this->lastSection = 'p';
+ $this->lastParagraph = 'p';
} else {
- if ( $this->lastSection !== 'p' ) {
+ if ( $this->lastParagraph !== 'p' ) {
$output .= $this->closeParagraph();
- $this->lastSection = '';
$pendingPTag = '<p>';
} else {
$pendingPTag = '</p><p>';
if ( $pendingPTag ) {
$output .= $pendingPTag;
$pendingPTag = false;
- $this->lastSection = 'p';
- } elseif ( $this->lastSection !== 'p' ) {
+ $this->lastParagraph = 'p';
+ } elseif ( $this->lastParagraph !== 'p' ) {
$output .= $this->closeParagraph() . '<p>';
- $this->lastSection = 'p';
+ $this->lastParagraph = 'p';
}
}
}
if ( $pendingPTag === false ) {
if ( $prefixLength === 0 ) {
$output .= $t;
- $output .= "\n";
+ // Add a newline if there's an open paragraph
+ // or we've yet to reach the last line.
+ if ( $notLastLine || $this->hasOpenParagraph() ) {
+ $output .= "\n";
+ }
} else {
// Trim whitespace in list items
$output .= trim( $t );
while ( $prefixLength ) {
$output .= $this->closeList( $prefix2[$prefixLength - 1] );
--$prefixLength;
- if ( !$prefixLength ) {
+ // Note that a paragraph is only ever opened when `prefixLength`
+ // is zero, but we'll choose to be overly cautious.
+ if ( !$prefixLength && $this->hasOpenParagraph() ) {
$output .= "\n";
}
}
- if ( $this->lastSection !== '' ) {
- $output .= '</' . $this->lastSection . '>';
- $this->lastSection = '';
- }
-
+ $output .= $this->closeParagraph( true );
return $output;
}