class BlockLevelPass {
private $DTopen = false;
private $inPre = false;
- private $lastSection = '';
+ private $lastParagraph = '';
private $lineStart;
private $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;
}
$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;
$inBlockElem = !$closeMatch;
} elseif ( !$inBlockElem && !$this->inPre ) {
if ( substr( $t, 0, 1 ) == ' '
- && ( $this->lastSection === 'pre' || trim( $t ) != '' )
+ && ( $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 .= $pendingPTag . '<br />';
$pendingPTag = false;
- $this->lastSection = 'p';
+ $this->lastParagraph = 'p';
+ } elseif ( $this->lastParagraph !== 'p' ) {
+ $output .= $this->closeParagraph();
+ $pendingPTag = '<p>';
} else {
- if ( $this->lastSection !== 'p' ) {
- $output .= $this->closeParagraph();
- $pendingPTag = '<p>';
- } else {
- $pendingPTag = '</p><p>';
- }
- }
- } else {
- if ( $pendingPTag ) {
- $output .= $pendingPTag;
- $pendingPTag = false;
- $this->lastSection = 'p';
- } elseif ( $this->lastSection !== 'p' ) {
- $output .= $this->closeParagraph() . '<p>';
- $this->lastSection = 'p';
+ $pendingPTag = '</p><p>';
}
+ } elseif ( $pendingPTag ) {
+ $output .= $pendingPTag;
+ $pendingPTag = false;
+ $this->lastParagraph = 'p';
+ } elseif ( $this->lastParagraph !== 'p' ) {
+ $output .= $this->closeParagraph() . '<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;
}