1<?php 2/** 3 * @copyright Copyright (c) 2014 Carsten Brandt 4 * @license https://github.com/cebe/markdown/blob/master/LICENSE 5 * @link https://github.com/cebe/markdown#readme 6 */ 7 8namespace cebe\markdown; 9 10/** 11 * Markdown parser for the [initial markdown spec](http://daringfireball.net/projects/markdown/syntax). 12 * 13 * @author Carsten Brandt <mail@cebe.cc> 14 */ 15class Markdown extends Parser 16{ 17 // include block element parsing using traits 18 use block\CodeTrait; 19 use block\HeadlineTrait; 20 use block\HtmlTrait { 21 parseInlineHtml as private; 22 } 23 use block\ListTrait { 24 // Check Ul List before headline 25 identifyUl as protected identifyBUl; 26 consumeUl as protected consumeBUl; 27 } 28 use block\QuoteTrait; 29 use block\RuleTrait { 30 // Check Hr before checking lists 31 identifyHr as protected identifyAHr; 32 consumeHr as protected consumeAHr; 33 } 34 35 // include inline element parsing using traits 36 use inline\CodeTrait; 37 use inline\EmphStrongTrait; 38 use inline\LinkTrait; 39 40 /** 41 * @var boolean whether to format markup according to HTML5 spec. 42 * Defaults to `false` which means that markup is formatted as HTML4. 43 */ 44 public $html5 = false; 45 46 /** 47 * @var array these are "escapeable" characters. When using one of these prefixed with a 48 * backslash, the character will be outputted without the backslash and is not interpreted 49 * as markdown. 50 */ 51 protected $escapeCharacters = [ 52 '\\', // backslash 53 '`', // backtick 54 '*', // asterisk 55 '_', // underscore 56 '{', '}', // curly braces 57 '[', ']', // square brackets 58 '(', ')', // parentheses 59 '#', // hash mark 60 '+', // plus sign 61 '-', // minus sign (hyphen) 62 '.', // dot 63 '!', // exclamation mark 64 '<', '>', 65 ]; 66 67 68 /** 69 * @inheritDoc 70 */ 71 protected function prepare() 72 { 73 // reset references 74 $this->references = []; 75 } 76 77 /** 78 * Consume lines for a paragraph 79 * 80 * Allow headlines and code to break paragraphs 81 */ 82 protected function consumeParagraph($lines, $current) 83 { 84 // consume until newline 85 $content = []; 86 for ($i = $current, $count = count($lines); $i < $count; $i++) { 87 $line = $lines[$i]; 88 89 // a list may break a paragraph when it is inside of a list 90 if (isset($this->context[1]) && $this->context[1] === 'list' && !ctype_alpha($line[0]) && ( 91 $this->identifyUl($line, $lines, $i) || $this->identifyOl($line, $lines, $i))) { 92 break; 93 } 94 95 if ($line === '' || ltrim($line) === '' || $this->identifyHeadline($line, $lines, $i)) { 96 break; 97 } elseif ($line[0] === "\t" || $line[0] === " " && strncmp($line, ' ', 4) === 0) { 98 // possible beginning of a code block 99 // but check for continued inline HTML 100 // e.g. <img src="file.jpg" 101 // alt="some alt aligned with src attribute" title="some text" /> 102 if (preg_match('~<\w+([^>]+)$~s', implode("\n", $content))) { 103 $content[] = $line; 104 } else { 105 break; 106 } 107 } else { 108 $content[] = $line; 109 } 110 } 111 $block = [ 112 'paragraph', 113 'content' => $this->parseInline(implode("\n", $content)), 114 ]; 115 return [$block, --$i]; 116 } 117 118 119 /** 120 * @inheritdocs 121 * 122 * Parses a newline indicated by two spaces on the end of a markdown line. 123 */ 124 protected function renderText($text) 125 { 126 return str_replace(" \n", $this->html5 ? "<br>\n" : "<br />\n", $text[1]); 127 } 128} 129