Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Parser.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 8.91 KiB


001  <?php
002   
003  /**
004  * @package   s9e\TextFormatter
005  * @copyright Copyright (c) 2010-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\TextFormatter\Plugins\PipeTables;
009   
010  use s9e\TextFormatter\Plugins\ParserBase;
011   
012  class Parser extends ParserBase
013  {
014      /**
015      * @var integer Position of the cursor while parsing tables or adding tags
016      */
017      protected $pos;
018   
019      /**
020      * @var array Current table being parsed
021      */
022      protected $table;
023   
024      /**
025      * @var \s9e\TextFormatter\Parser\Tag
026      */
027      protected $tableTag;
028   
029      /**
030      * @var array[] List of tables
031      */
032      protected $tables;
033   
034      /**
035      * @var string Text being parsed
036      */
037      protected $text;
038   
039      /**
040      * {@inheritdoc}
041      */
042      public function parse($text, array $matches)
043      {
044          $this->text = $text;
045          if ($this->config['overwriteMarkdown'])
046          {
047              $this->overwriteMarkdown();
048          }
049          if ($this->config['overwriteEscapes'])
050          {
051              $this->overwriteEscapes();
052          }
053   
054          $this->captureTables();
055          $this->processTables();
056   
057          unset($this->tables);
058          unset($this->text);
059      }
060   
061      /**
062      * Add current line to a table
063      *
064      * @param  string $line Line of text
065      * @return void
066      */
067      protected function addLine($line)
068      {
069          $ignoreLen = 0;
070   
071          if (!isset($this->table))
072          {
073              $this->table = [];
074   
075              // Make the table start at the first non-space character
076              preg_match('/^ */', $line, $m);
077              $ignoreLen = strlen($m[0]);
078              $line      = substr($line, $ignoreLen);
079          }
080   
081          // Overwrite the outermost pipes
082          $line = preg_replace('/^( *)\\|/', '$1 ', $line);
083          $line = preg_replace('/\\|( *)$/', ' $1', $line);
084   
085          $this->table['rows'][] = ['line' => $line, 'pos' => $this->pos + $ignoreLen];
086      }
087   
088      /**
089      * Process current table's body
090      *
091      * @return void
092      */
093      protected function addTableBody()
094      {
095          $i   = 1;
096          $cnt = count($this->table['rows']);
097          while (++$i < $cnt)
098          {
099              $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  }