129 lines
3.2KB

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