GithubMarkdown.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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\latex;
  8. use cebe\markdown\block\FencedCodeTrait;
  9. use cebe\markdown\block\TableTrait;
  10. use cebe\markdown\inline\StrikeoutTrait;
  11. use cebe\markdown\inline\UrlLinkTrait;
  12. /**
  13. * Markdown parser for github flavored markdown.
  14. *
  15. * - uses the [tabularx](http://www.ctan.org/pkg/tabularx) environment for tables.
  16. *
  17. * @author Carsten Brandt <mail@cebe.cc>
  18. */
  19. class GithubMarkdown extends Markdown
  20. {
  21. // include block element parsing using traits
  22. use TableTrait;
  23. use FencedCodeTrait;
  24. // include inline element parsing using traits
  25. use StrikeoutTrait;
  26. use UrlLinkTrait;
  27. /**
  28. * @var boolean whether to interpret newlines as `<br />`-tags.
  29. * This feature is useful for comments where newlines are often meant to be real new lines.
  30. */
  31. public $enableNewlines = false;
  32. /**
  33. * @inheritDoc
  34. */
  35. protected $escapeCharacters = [
  36. // from Markdown
  37. '\\', // backslash
  38. '`', // backtick
  39. '*', // asterisk
  40. '_', // underscore
  41. '{', '}', // curly braces
  42. '[', ']', // square brackets
  43. '(', ')', // parentheses
  44. '#', // hash mark
  45. '+', // plus sign
  46. '-', // minus sign (hyphen)
  47. '.', // dot
  48. '!', // exclamation mark
  49. '<', '>',
  50. // added by GithubMarkdown
  51. ':', // colon
  52. '|', // pipe
  53. ];
  54. /**
  55. * Consume lines for a paragraph
  56. *
  57. * Allow headlines, lists and code to break paragraphs
  58. */
  59. protected function consumeParagraph($lines, $current)
  60. {
  61. // consume until newline
  62. $content = [];
  63. for ($i = $current, $count = count($lines); $i < $count; $i++) {
  64. $line = $lines[$i];
  65. if (!empty($line) && ltrim($line) !== '' &&
  66. !($line[0] === "\t" || $line[0] === " " && strncmp($line, ' ', 4) === 0) &&
  67. !$this->identifyHeadline($line, $lines, $i) &&
  68. !$this->identifyUl($line, $lines, $i) &&
  69. !$this->identifyOl($line, $lines, $i))
  70. {
  71. $content[] = $line;
  72. } else {
  73. break;
  74. }
  75. }
  76. $block = [
  77. 'paragraph',
  78. 'content' => $this->parseInline(implode("\n", $content)),
  79. ];
  80. return [$block, --$i];
  81. }
  82. /**
  83. * @inheritdoc
  84. */
  85. protected function renderCode($block)
  86. {
  87. // make sure this is not replaced by the trait
  88. return parent::renderCode($block);
  89. }
  90. /**
  91. * @inheritdoc
  92. */
  93. protected function renderAutoUrl($block)
  94. {
  95. return '\url{' . $this->escapeUrl($block[1]) . '}';
  96. }
  97. /**
  98. * @inheritdoc
  99. */
  100. protected function renderStrike($block)
  101. {
  102. return '\sout{' . $this->renderAbsy($block[1]) . '}';
  103. }
  104. /**
  105. * @inheritdocs
  106. *
  107. * Parses a newline indicated by two spaces on the end of a markdown line.
  108. */
  109. protected function renderText($text)
  110. {
  111. if ($this->enableNewlines) {
  112. return preg_replace("/( \n|\n)/", "\\\\\\\\\n", $this->escapeLatex($text[1]));
  113. } else {
  114. return parent::renderText($text);
  115. }
  116. }
  117. private $_tableCellHead = false;
  118. private $_tds = 0;
  119. protected function renderTable($block)
  120. {
  121. $align = [];
  122. foreach($block['cols'] as $col) {
  123. if (empty($col)) {
  124. $align[] = 'X';
  125. } else {
  126. $align[] = $col[0];
  127. }
  128. }
  129. $align = implode('|', $align);
  130. $content = '';
  131. $first = true;
  132. $numThs = 0;
  133. foreach($block['rows'] as $row) {
  134. $this->_tableCellHead = $first;
  135. $this->_tds = 0;
  136. $content .= $this->renderAbsy($this->parseInline($row)); // TODO move this to the consume step
  137. if ($first) {
  138. $numThs = $this->_tds;
  139. } else {
  140. while ($this->_tds < $numThs) {
  141. $content .= ' & ';
  142. $this->_tds++;
  143. }
  144. }
  145. $content .= "\\\\ \\hline\n";
  146. $first = false;
  147. }
  148. return "\n\\noindent\\begin{tabularx}{\\textwidth}{|$align|}\\hline\n$content\\end{tabularx}\n\n";
  149. }
  150. /**
  151. * @marker |
  152. */
  153. protected function parseTd($markdown)
  154. {
  155. if (isset($this->context[1]) && $this->context[1] === 'table') {
  156. $this->_tds++;
  157. return [['tableSep'], 1];
  158. }
  159. return [['text', $markdown[0]], 1];
  160. }
  161. protected function renderTableSep($block)
  162. {
  163. return '&';
  164. }
  165. }