/src/community/vendor/s9e/text-formatter/src/Plugins/PipeTables/Parser.php

https://bitbucket.org/ke2083/transfans.co.uk-website · PHP · 210 lines · 204 code · 1 blank · 5 comment · 16 complexity · 984b11b1024e8c2068869a726d2f8c83 MD5 · raw file

  1. <?php
  2. /*
  3. * @package s9e\TextFormatter
  4. * @copyright Copyright (c) 2010-2017 The s9e Authors
  5. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  6. */
  7. namespace s9e\TextFormatter\Plugins\PipeTables;
  8. use s9e\TextFormatter\Plugins\ParserBase;
  9. class Parser extends ParserBase
  10. {
  11. protected $pos;
  12. protected $table;
  13. protected $tableTag;
  14. protected $tables;
  15. protected $text;
  16. public function parse($text, array $matches)
  17. {
  18. $this->text = $text;
  19. if ($this->config['overwriteMarkdown'])
  20. $this->overwriteMarkdown();
  21. if ($this->config['overwriteEscapes'])
  22. $this->overwriteEscapes();
  23. $this->captureTables();
  24. $this->processTables();
  25. unset($this->tables);
  26. unset($this->text);
  27. }
  28. protected function addLine($line)
  29. {
  30. $ignoreLen = 0;
  31. if (!isset($this->table))
  32. {
  33. $this->table = [];
  34. \preg_match('/^ */', $line, $m);
  35. $ignoreLen = \strlen($m[0]);
  36. $line = \substr($line, $ignoreLen);
  37. }
  38. $line = \preg_replace('/^( *)\\|/', '$1 ', $line);
  39. $line = \preg_replace('/\\|( *)$/', ' $1', $line);
  40. $this->table['rows'][] = ['line' => $line, 'pos' => $this->pos + $ignoreLen];
  41. }
  42. protected function addTableBody()
  43. {
  44. $i = 1;
  45. $cnt = \count($this->table['rows']);
  46. while (++$i < $cnt)
  47. $this->addTableRow('TD', $this->table['rows'][$i]);
  48. $this->createBodyTags($this->table['rows'][2]['pos'], $this->pos);
  49. }
  50. protected function addTableCell($tagName, $align, $text)
  51. {
  52. $startPos = $this->pos;
  53. $endPos = $startPos + \strlen($text);
  54. $this->pos = $endPos;
  55. \preg_match('/^( *).*?( *)$/', $text, $m);
  56. if ($m[1])
  57. {
  58. $ignoreLen = \strlen($m[1]);
  59. $this->createIgnoreTag($startPos, $ignoreLen);
  60. $startPos += $ignoreLen;
  61. }
  62. if ($m[2])
  63. {
  64. $ignoreLen = \strlen($m[2]);
  65. $this->createIgnoreTag($endPos - $ignoreLen, $ignoreLen);
  66. $endPos -= $ignoreLen;
  67. }
  68. $this->createCellTags($tagName, $startPos, $endPos, $align);
  69. }
  70. protected function addTableHead()
  71. {
  72. $this->addTableRow('TH', $this->table['rows'][0]);
  73. $this->createHeadTags($this->table['rows'][0]['pos'], $this->pos);
  74. }
  75. protected function addTableRow($tagName, $row)
  76. {
  77. $this->pos = $row['pos'];
  78. foreach (\explode('|', $row['line']) as $i => $str)
  79. {
  80. if ($i > 0)
  81. {
  82. $this->createIgnoreTag($this->pos, 1);
  83. ++$this->pos;
  84. }
  85. $align = (empty($this->table['cols'][$i])) ? '' : $this->table['cols'][$i];
  86. $this->addTableCell($tagName, $align, $str);
  87. }
  88. $this->createRowTags($row['pos'], $this->pos);
  89. }
  90. protected function captureTables()
  91. {
  92. unset($this->table);
  93. $this->tables = [];
  94. $this->pos = 0;
  95. foreach (\explode("\n", $this->text) as $line)
  96. {
  97. if (\strpos($line, '|') === \false)
  98. $this->endTable();
  99. else
  100. $this->addLine($line);
  101. $this->pos += 1 + \strlen($line);
  102. }
  103. $this->endTable();
  104. }
  105. protected function createBodyTags($startPos, $endPos)
  106. {
  107. $this->parser->addTagPair('TBODY', $startPos, 0, $endPos, 0, -103);
  108. }
  109. protected function createCellTags($tagName, $startPos, $endPos, $align)
  110. {
  111. if ($startPos === $endPos)
  112. $tag = $this->parser->addSelfClosingTag($tagName, $startPos, 0, -101);
  113. else
  114. $tag = $this->parser->addTagPair($tagName, $startPos, 0, $endPos, 0, -101);
  115. if ($align)
  116. $tag->setAttribute('align', $align);
  117. }
  118. protected function createHeadTags($startPos, $endPos)
  119. {
  120. $this->parser->addTagPair('THEAD', $startPos, 0, $endPos, 0, -103);
  121. }
  122. protected function createIgnoreTag($pos, $len)
  123. {
  124. $this->tableTag->cascadeInvalidationTo($this->parser->addIgnoreTag($pos, $len, 1000));
  125. }
  126. protected function createRowTags($startPos, $endPos)
  127. {
  128. $this->parser->addTagPair('TR', $startPos, 0, $endPos, 0, -102);
  129. }
  130. protected function createSeparatorTag(array $row)
  131. {
  132. $this->createIgnoreTag($row['pos'] - 1, 1 + \strlen($row['line']));
  133. }
  134. protected function createTableTags($startPos, $endPos)
  135. {
  136. $this->tableTag = $this->parser->addTagPair('TABLE', $startPos, 0, $endPos, 0, -104);
  137. }
  138. protected function endTable()
  139. {
  140. if ($this->hasValidTable())
  141. {
  142. $this->table['cols'] = $this->parseColumnAlignments($this->table['rows'][1]['line']);
  143. $this->tables[] = $this->table;
  144. }
  145. unset($this->table);
  146. }
  147. protected function hasValidTable()
  148. {
  149. return (isset($this->table) && \count($this->table['rows']) > 2 && $this->isValidSeparator($this->table['rows'][1]['line']));
  150. }
  151. protected function isValidSeparator($line)
  152. {
  153. return (bool) \preg_match('/^ *:?-+:?(?:(?:\\+| *\\| *):?-+:?)+ *$/', $line);
  154. }
  155. protected function overwriteBlockquoteCallback(array $m)
  156. {
  157. return \strtr($m[0], '>', ' ');
  158. }
  159. protected function overwriteEscapes()
  160. {
  161. if (\strpos($this->text, '\\|') !== \false)
  162. $this->text = \preg_replace('/\\\\[\\\\|]/', '..', $this->text);
  163. }
  164. protected function overwriteInlineCodeCallback(array $m)
  165. {
  166. return \strtr($m[0], '|', '.');
  167. }
  168. protected function overwriteMarkdown()
  169. {
  170. if (\strpos($this->text, '`') !== \false)
  171. $this->text = \preg_replace_callback('/`[^`]*`/', [$this, 'overwriteInlineCodeCallback'], $this->text);
  172. if (\strpos($this->text, '>') !== \false)
  173. $this->text = \preg_replace_callback('/^(?:> ?)+/m', [$this, 'overwriteBlockquoteCallback'], $this->text);
  174. }
  175. protected function parseColumnAlignments($line)
  176. {
  177. $align = [
  178. 0b00 => '',
  179. 0b01 => 'right',
  180. 0b10 => 'left',
  181. 0b11 => 'center'
  182. ];
  183. $cols = [];
  184. \preg_match_all('/(:?)-+(:?)/', $line, $matches, \PREG_SET_ORDER);
  185. foreach ($matches as $m)
  186. {
  187. $key = (!empty($m[1]) ? 2 : 0) + (!empty($m[2]) ? 1 : 0);
  188. $cols[] = $align[$key];
  189. }
  190. return $cols;
  191. }
  192. protected function processCurrentTable()
  193. {
  194. $firstRow = $this->table['rows'][0];
  195. $lastRow = \end($this->table['rows']);
  196. $this->createTableTags($firstRow['pos'], $lastRow['pos'] + \strlen($lastRow['line']));
  197. $this->addTableHead();
  198. $this->createSeparatorTag($this->table['rows'][1]);
  199. $this->addTableBody();
  200. }
  201. protected function processTables()
  202. {
  203. foreach ($this->tables as $table)
  204. {
  205. $this->table = $table;
  206. $this->processCurrentTable();
  207. }
  208. }
  209. }