[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Plugins/PipeTables/ -> Parser.php (source)

   1  <?php
   2  
   3  /**
   4  * @package   s9e\TextFormatter
   5  * @copyright Copyright (c) 2010-2020 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\TextFormatter\Plugins\PipeTables;
   9  
  10  use s9e\TextFormatter\Plugins\ParserBase;
  11  
  12  class Parser extends ParserBase
  13  {
  14      /**
  15      * @var integer Position of the cursor while parsing tables or adding tags
  16      */
  17      protected $pos;
  18  
  19      /**
  20      * @var array Current table being parsed
  21      */
  22      protected $table;
  23  
  24      /**
  25      * @var \s9e\TextFormatter\Parser\Tag
  26      */
  27      protected $tableTag;
  28  
  29      /**
  30      * @var array[] List of tables
  31      */
  32      protected $tables;
  33  
  34      /**
  35      * @var string Text being parsed
  36      */
  37      protected $text;
  38  
  39      /**
  40      * {@inheritdoc}
  41      */
  42  	public function parse($text, array $matches)
  43      {
  44          $this->text = $text;
  45          if ($this->config['overwriteMarkdown'])
  46          {
  47              $this->overwriteMarkdown();
  48          }
  49          if ($this->config['overwriteEscapes'])
  50          {
  51              $this->overwriteEscapes();
  52          }
  53  
  54          $this->captureTables();
  55          $this->processTables();
  56  
  57          unset($this->tables);
  58          unset($this->text);
  59      }
  60  
  61      /**
  62      * Add current line to a table
  63      *
  64      * @param  string $line Line of text
  65      * @return void
  66      */
  67  	protected function addLine($line)
  68      {
  69          $ignoreLen = 0;
  70  
  71          if (!isset($this->table))
  72          {
  73              $this->table = [];
  74  
  75              // Make the table start at the first non-space character
  76              preg_match('/^ */', $line, $m);
  77              $ignoreLen = strlen($m[0]);
  78              $line      = substr($line, $ignoreLen);
  79          }
  80  
  81          // Overwrite the outermost pipes
  82          $line = preg_replace('/^( *)\\|/', '$1 ', $line);
  83          $line = preg_replace('/\\|( *)$/', ' $1', $line);
  84  
  85          $this->table['rows'][] = ['line' => $line, 'pos' => $this->pos + $ignoreLen];
  86      }
  87  
  88      /**
  89      * Process current table's body
  90      *
  91      * @return void
  92      */
  93  	protected function addTableBody()
  94      {
  95          $i   = 1;
  96          $cnt = count($this->table['rows']);
  97          while (++$i < $cnt)
  98          {
  99              $this->addTableRow('TD', $this->table['rows'][$i]);
 100          }
 101  
 102          $this->createBodyTags($this->table['rows'][2]['pos'], $this->pos);
 103      }
 104  
 105      /**
 106      * Add a cell's tags for current table at current position
 107      *
 108      * @param  string $tagName Either TD or TH
 109      * @param  string $align   Either "left", "center", "right" or ""
 110      * @param  string $content Cell's text content
 111      * @return void
 112      */
 113  	protected function addTableCell($tagName, $align, $content)
 114      {
 115          $startPos  = $this->pos;
 116          $endPos    = $startPos + strlen($content);
 117          $this->pos = $endPos;
 118  
 119          preg_match('/^( *).*?( *)$/', $content, $m);
 120          if ($m[1])
 121          {
 122              $ignoreLen = strlen($m[1]);
 123              $this->createIgnoreTag($startPos, $ignoreLen);
 124              $startPos += $ignoreLen;
 125          }
 126          if ($m[2])
 127          {
 128              $ignoreLen = strlen($m[2]);
 129              $this->createIgnoreTag($endPos - $ignoreLen, $ignoreLen);
 130              $endPos -= $ignoreLen;
 131          }
 132  
 133          $this->createCellTags($tagName, $startPos, $endPos, $align);
 134      }
 135  
 136      /**
 137      * Process current table's head
 138      *
 139      * @return void
 140      */
 141  	protected function addTableHead()
 142      {
 143          $this->addTableRow('TH', $this->table['rows'][0]);
 144          $this->createHeadTags($this->table['rows'][0]['pos'], $this->pos);
 145      }
 146  
 147      /**
 148      * Process given table row
 149      *
 150      * @param  string $tagName Either TD or TH
 151      * @param  array  $row
 152      * @return void
 153      */
 154  	protected function addTableRow($tagName, $row)
 155      {
 156          $this->pos = $row['pos'];
 157          foreach (explode('|', $row['line']) as $i => $str)
 158          {
 159              if ($i > 0)
 160              {
 161                  $this->createIgnoreTag($this->pos, 1);
 162                  ++$this->pos;
 163              }
 164  
 165              $align = (empty($this->table['cols'][$i])) ? '' : $this->table['cols'][$i];
 166              $this->addTableCell($tagName, $align, $str);
 167          }
 168  
 169          $this->createRowTags($row['pos'], $this->pos);
 170      }
 171  
 172      /**
 173      * Capture all pipe tables in current text
 174      *
 175      * @return void
 176      */
 177  	protected function captureTables()
 178      {
 179          unset($this->table);
 180          $this->tables = [];
 181  
 182          $this->pos = 0;
 183          foreach (explode("\n", $this->text) as $line)
 184          {
 185              if (strpos($line, '|') === false)
 186              {
 187                  $this->endTable();
 188              }
 189              else
 190              {
 191                  $this->addLine($line);
 192              }
 193              $this->pos += 1 + strlen($line);
 194          }
 195          $this->endTable();
 196      }
 197  
 198      /**
 199      * Create a pair of TBODY tags for given text span
 200      *
 201      * @param  integer $startPos
 202      * @param  integer $endPos
 203      * @return void
 204      */
 205  	protected function createBodyTags($startPos, $endPos)
 206      {
 207          $this->parser->addTagPair('TBODY', $startPos, 0, $endPos, 0, -103);
 208      }
 209  
 210      /**
 211      * Create a pair of TD or TH tags for given text span
 212      *
 213      * @param  string  $tagName  Either TD or TH
 214      * @param  integer $startPos
 215      * @param  integer $endPos
 216      * @param  string  $align    Either "left", "center", "right" or ""
 217      * @return void
 218      */
 219  	protected function createCellTags($tagName, $startPos, $endPos, $align)
 220      {
 221          if ($startPos === $endPos)
 222          {
 223              $tag = $this->parser->addSelfClosingTag($tagName, $startPos, 0, -101);
 224          }
 225          else
 226          {
 227              $tag = $this->parser->addTagPair($tagName, $startPos, 0, $endPos, 0, -101);
 228          }
 229          if ($align)
 230          {
 231              $tag->setAttribute('align', $align);
 232          }
 233      }
 234  
 235      /**
 236      * Create a pair of THEAD tags for given text span
 237      *
 238      * @param  integer $startPos
 239      * @param  integer $endPos
 240      * @return void
 241      */
 242  	protected function createHeadTags($startPos, $endPos)
 243      {
 244          $this->parser->addTagPair('THEAD', $startPos, 0, $endPos, 0, -103);
 245      }
 246  
 247      /**
 248      * Create an ignore tag for given text span
 249      *
 250      * @param  integer $pos
 251      * @param  integer $len
 252      * @return void
 253      */
 254  	protected function createIgnoreTag($pos, $len)
 255      {
 256          $this->tableTag->cascadeInvalidationTo($this->parser->addIgnoreTag($pos, $len, 1000));
 257      }
 258  
 259      /**
 260      * Create a pair of TR tags for given text span
 261      *
 262      * @param  integer $startPos
 263      * @param  integer $endPos
 264      * @return void
 265      */
 266  	protected function createRowTags($startPos, $endPos)
 267      {
 268          $this->parser->addTagPair('TR', $startPos, 0, $endPos, 0, -102);
 269      }
 270  
 271      /**
 272      * Create an ignore tag for given separator row
 273      *
 274      * @param  array $row
 275      * @return void
 276      */
 277  	protected function createSeparatorTag(array $row)
 278      {
 279          $this->createIgnoreTag($row['pos'] - 1, 1 + strlen($row['line']));
 280      }
 281  
 282      /**
 283      * Create a pair of TABLE tags for given text span
 284      *
 285      * @param  integer $startPos
 286      * @param  integer $endPos
 287      * @return void
 288      */
 289  	protected function createTableTags($startPos, $endPos)
 290      {
 291          $this->tableTag = $this->parser->addTagPair('TABLE', $startPos, 0, $endPos, 0, -104);
 292      }
 293  
 294      /**
 295      * End current buffered table
 296      *
 297      * @return void
 298      */
 299  	protected function endTable()
 300      {
 301          if ($this->hasValidTable())
 302          {
 303              $this->table['cols'] = $this->parseColumnAlignments($this->table['rows'][1]['line']);
 304              $this->tables[]      = $this->table;
 305          }
 306          unset($this->table);
 307      }
 308  
 309      /**
 310      * Test whether a valid table is currently buffered
 311      *
 312      * @return bool
 313      */
 314  	protected function hasValidTable()
 315      {
 316          return (isset($this->table) && count($this->table['rows']) > 2 && $this->isValidSeparator($this->table['rows'][1]['line']));
 317      }
 318  
 319      /**
 320      * Test whether given line is a valid separator
 321      *
 322      * @param  string $line
 323      * @return bool
 324      */
 325  	protected function isValidSeparator($line)
 326      {
 327          return (bool) preg_match('/^ *:?-+:?(?:(?:\\+| *\\| *):?-+:?)+ *$/', $line);
 328      }
 329  
 330      /**
 331      * Overwrite right angle brackets in given match
 332      *
 333      * @param  string[] $m
 334      * @return string
 335      */
 336  	protected function overwriteBlockquoteCallback(array $m)
 337      {
 338          return strtr($m[0], '!>', '  ');
 339      }
 340  
 341      /**
 342      * Overwrite escape sequences in current text
 343      *
 344      * @return void
 345      */
 346  	protected function overwriteEscapes()
 347      {
 348          if (strpos($this->text, '\\|') !== false)
 349          {
 350              $this->text = preg_replace('/\\\\[\\\\|]/', '..', $this->text);
 351          }
 352      }
 353  
 354      /**
 355      * Overwrite backticks in given match
 356      *
 357      * @param  string[] $m
 358      * @return string
 359      */
 360  	protected function overwriteInlineCodeCallback(array $m)
 361      {
 362          return strtr($m[0], '|', '.');
 363      }
 364  
 365      /**
 366      * Overwrite Markdown-style markup in current text
 367      *
 368      * @return void
 369      */
 370  	protected function overwriteMarkdown()
 371      {
 372          // Overwrite inline code spans
 373          if (strpos($this->text, '`') !== false)
 374          {
 375              $this->text = preg_replace_callback('/`[^`]*`/', [$this, 'overwriteInlineCodeCallback'], $this->text);
 376          }
 377  
 378          // Overwrite blockquotes
 379          if (strpos($this->text, '>') !== false)
 380          {
 381              $this->text = preg_replace_callback('/^(?:>!? ?)+/m', [$this, 'overwriteBlockquoteCallback'], $this->text);
 382          }
 383      }
 384  
 385      /**
 386      * Parse and return column alignments in given separator line
 387      *
 388      * @param  string   $line
 389      * @return string[]
 390      */
 391  	protected function parseColumnAlignments($line)
 392      {
 393          // Use a bitfield to represent the colons' presence and map it to the CSS value
 394          $align = [
 395              0b00 => '',
 396              0b01 => 'right',
 397              0b10 => 'left',
 398              0b11 => 'center'
 399          ];
 400  
 401          $cols = [];
 402          preg_match_all('/(:?)-+(:?)/', $line, $matches, PREG_SET_ORDER);
 403          foreach ($matches as $m)
 404          {
 405              $key = (!empty($m[1]) ? 2 : 0) + (!empty($m[2]) ? 1 : 0);
 406              $cols[] = $align[$key];
 407          }
 408  
 409          return $cols;
 410      }
 411  
 412      /**
 413      * Process current table declaration
 414      *
 415      * @return void
 416      */
 417  	protected function processCurrentTable()
 418      {
 419          $firstRow = $this->table['rows'][0];
 420          $lastRow  = end($this->table['rows']);
 421          $this->createTableTags($firstRow['pos'], $lastRow['pos'] + strlen($lastRow['line']));
 422  
 423          $this->addTableHead();
 424          $this->createSeparatorTag($this->table['rows'][1]);
 425          $this->addTableBody();
 426      }
 427  
 428      /**
 429      * Process all the captured tables
 430      *
 431      * @return void
 432      */
 433  	protected function processTables()
 434      {
 435          foreach ($this->tables as $table)
 436          {
 437              $this->table = $table;
 438              $this->processCurrentTable();
 439          }
 440      }
 441  }


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1