/**
  * @param Text  $text
  * @param array $options
  */
 public function processFencedCodeBlock(Text $text, array $options = [])
 {
     /** @noinspection PhpUnusedParameterInspection */
     $text->replace('{
         (?:\\n\\n|\\A)
         (?:
             ([`~]{3})[ ]*         #1 fence ` or ~
                 ([a-zA-Z0-9]*?)?  #2 language [optional]
             \\n+
             (.*?)\\n                #3 code block
             \\1                    # matched #1
         )
     }smx', function (Text $w, Text $fence, Text $lang, Text $code) use($options) {
         $rendererOptions = [];
         if (!$lang->isEmpty()) {
             if ($options['pygments'] && class_exists('KzykHys\\Pygments\\Pygments')) {
                 $pygments = new Pygments();
                 $html = $pygments->highlight($code, $lang, 'html');
                 return "\n\n" . $html . "\n\n";
             }
             $rendererOptions = ['attr' => ['class' => 'prettyprint lang-' . $lang->lower()]];
         }
         $code->escapeHtml(ENT_NOQUOTES);
         $this->markdown->emit('detab', array($code));
         $code->replace('/\\A\\n+/', '');
         $code->replace('/\\s+\\z/', '');
         return "\n\n" . $this->getRenderer()->renderCodeBlock($code, $rendererOptions) . "\n\n";
     });
 }
 /**
  * Convert line breaks
  *
  * @param Text $text
  */
 public function initialize(Text $text)
 {
     $text->replaceString("\r\n", "\n");
     $text->replaceString("\r", "\n");
     $text->append("\n\n");
     $this->markdown->emit('detab', array($text));
     $text->replace('/^[ \\t]+$/m', '');
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $this->hashes = $this->generateSpecialCharsHash();
     $markdown->on('escape.special_chars', array($this, 'escapeSpecialChars'));
     $markdown->on('inline', array($this, 'escapeSpecialChars'), 20);
     $markdown->on('inline', array($this, 'escapeAmpsAndBrackets'), 60);
     $markdown->on('finalize', array($this, 'unescapeSpecialChars'), 20);
 }
Exemple #4
0
 protected function guessLineOfCode()
 {
     $pattern = sprintf('/%s/m', preg_quote($this->text, '/'));
     $rawContent = $this->markdown->getRawContent();
     $rawContent->replaceString("\r\n", "\n");
     $rawContent->replaceString("\r", "\n");
     $lines = $rawContent->split('/\\n/');
     $lines->each(function (Text $line, $index) use($pattern) {
         if ($line->match($pattern)) {
             $this->markdownLineNo = $index + 1;
             return false;
         }
         return true;
     });
 }
 /**
  * handle inline images:  ![alt text](url "optional title")
  *
  * @param Text  $text
  * @param array $options
  */
 public function processInlineImage(Text $text, array $options = array())
 {
     if (!$text->contains('![')) {
         return;
     }
     /** @xnoinspection PhpUnusedParameterInspection */
     $text->replace('{
             (               # wrap whole match in $1
               !\\[
                 (.*?)       # alt text = $2
               \\]
               \\(            # literal paren
                 [ \\t]*
                 <?(\\S+?)>?  # src url = $3
                 [ \\t]*
                 (           # $4
                   ([\'"])   # quote char = $5
                   (.*?)     # title = $6
                   \\5        # matching quote
                   [ \\t]*
                 )?          # title is optional
               \\)
             )
         }xs', function (Text $w, Text $whole, Text $alt, Text $url, Text $a = null, Text $q = null, Text $title = null) use($options) {
         $attr = array('alt' => $alt->replace('/"/', '&quot;'));
         $this->markdown->emit('escape.special_chars', [$url->replace('/(?<!\\\\)_/', '\\\\_')]);
         $url->escapeHtml();
         if ($title) {
             $attr['title'] = $title->replace('/"/', '&quot;')->escapeHtml();
         }
         return $this->getRenderer()->renderImage($url, array('attr' => $attr));
     });
 }
Exemple #6
0
 /**
  * @param Text $text
  */
 public function processAtxHeader(Text $text)
 {
     /** @noinspection PhpUnusedParameterInspection */
     $text->replace('{
         ^(\\#{1,6})  # $1 = string of #\'s
         [ \\t]*
         (.+?)       # $2 = Header text
         [ \\t]*
         \\#*         # optional closing #\'s (not counted)
         \\n+
     }mx', function (Text $whole, Text $marks, Text $content) {
         $level = strlen($marks);
         $this->markdown->emit('inline', array($content));
         return $this->getRenderer()->renderHeader($content, array('level' => $level)) . "\n\n";
     });
 }
 /**
  * @param Text $text
  */
 public function buildParagraph(Text $text)
 {
     $parts = $text->replace('/\\A\\n+/', '')->replace('/\\n+\\z/', '')->split('/\\n{2,}/', PREG_SPLIT_NO_EMPTY);
     $parts->apply(function (Text $part) {
         if (!$this->markdown->getHashRegistry()->exists($part)) {
             $this->markdown->emit('inline', array($part));
             $part->replace('/^([ \\t]*)/', '');
             $part->setString($this->getRenderer()->renderParagraph((string) $part));
         }
         return $part;
     });
     $parts->apply(function (Text $part) {
         if ($this->markdown->getHashRegistry()->exists($part)) {
             $part->setString(trim($this->markdown->getHashRegistry()->get($part)));
         }
         return $part;
     });
     $text->setString($parts->join("\n\n"));
 }
Exemple #8
0
 /**
  * @param Text  $text
  * @param array $options
  */
 public function processCodeBlock(Text $text, array $options = array())
 {
     /** @noinspection PhpUnusedParameterInspection */
     $text->replace('{
         (?:\\n\\n|\\A)
         (                                               # $1 = the code block -- one or more lines, starting with a space/tab
           (?:
             (?:[ ]{' . $options['tabWidth'] . '} | \\t)  # Lines must start with a tab or a tab-width of spaces
             .*\\n+
           )+
         )
         (?:(?=^[ ]{0,' . $options['tabWidth'] . '}\\S)|\\Z) # Lookahead for non-space at line-start, or end of doc
     }mx', function (Text $whole, Text $code) {
         $this->markdown->emit('outdent', array($code));
         $code->escapeHtml(ENT_NOQUOTES);
         $this->markdown->emit('detab', array($code));
         $code->replace('/\\A\\n+/', '');
         $code->replace('/\\s+\\z/', '');
         return "\n\n" . $this->getRenderer()->renderCodeBlock($code) . "\n\n";
     });
 }
 /**
  * @param Text $text
  */
 public function processBlockQuote(Text $text)
 {
     $text->replace('{
         (?:
         (?:
           ^[ \\t]*&gt;[ \\t]? # > at the start of a line
             .+\\n            # rest of the first line
           (?:.+\\n)*         # subsequent consecutive lines
           \\n*               # blanks
         )+
         )
         }mx', function (Text $bq) {
         $bq->replace('/^[ \\t]*&gt;[ \\t]?/m', '');
         $bq->replace('/^[ \\t]+$/m', '');
         $this->markdown->emit('block', [$bq]);
         $bq->replace('|\\s*<pre>.+?</pre>|s', function (Text $pre) {
             return $pre->replace('/^  /m', '');
         });
         return $this->getRenderer()->renderBlockQuote($bq) . "\n\n";
     });
 }
 /**
  * @param Text $text
  */
 public function processFencedCodeBlock(Text $text)
 {
     /** @noinspection PhpUnusedParameterInspection */
     $text->replace('{
         (?:\\n\\n|\\A)
         (?:
             ([`~]{3})[ ]*         #1 fence ` or ~
                 ([a-zA-Z0-9]*?)?  #2 language [optional]
             \\n+
             (.*?)\\n                #3 code block
             \\1                    # matched #1
         )
     }smx', function (Text $w, Text $fence, Text $lang, Text $code) {
         $options = array();
         if (!$lang->isEmpty()) {
             $options = array('attr' => array('class' => 'prettyprint lang-' . $lang->lower()));
         }
         $code->escapeHtml(ENT_NOQUOTES);
         $this->markdown->emit('detab', array($code));
         $code->replace('/\\A\\n+/', '');
         $code->replace('/\\s+\\z/', '');
         return "\n\n" . $this->getRenderer()->renderCodeBlock($code, $options) . "\n\n";
     });
 }
 /**
  * Make links out of things like `<http://example.com/>`
  *
  * @param Text $text
  */
 public function processAutoLink(Text $text)
 {
     if (!$text->contains('<')) {
         return;
     }
     $text->replace('{<((?:https?|ftp):[^\'">\\s]+)>}', function (Text $w, Text $url) {
         $this->markdown->emit('escape.special_chars', [$url->replace('/(?<!\\\\)_/', '\\\\_')]);
         return $this->getRenderer()->renderLink($url, ['href' => $url->getString()]);
     });
     /** @noinspection PhpUnusedParameterInspection */
     $text->replace('{
         <
         (?:mailto:)?
         (
             [-.\\w]+
             \\@
             [-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+
         )
         >
     }ix', function (Text $w, Text $address) {
         $address = "mailto:" . $address;
         $encode = array(function ($char) {
             return '&#' . ord($char) . ';';
         }, function ($char) {
             return '&#x' . dechex(ord($char)) . ';';
         }, function ($char) {
             return $char;
         });
         $chars = new Collection(str_split($address));
         $chars->apply(function ($char) use($encode) {
             if ($char == '@') {
                 return $encode[rand(0, 1)]($char);
             } elseif ($char != ':') {
                 $rand = rand(0, 100);
                 $key = $rand > 90 ? 2 : ($rand < 45 ? 0 : 1);
                 return $encode[$key]($char);
             }
             return $char;
         });
         $address = $chars->join();
         $text = $chars->slice(7)->join();
         return $this->getRenderer()->renderLink($text, ['href' => $address]);
     });
 }
Exemple #12
0
 /**
  * Process the contents of a single ordered or unordered list, splitting it into individual list items.
  *
  * @param Text  $list
  * @param array $options
  * @param int   $level
  */
 public function processListItems(Text $list, array $options = array(), $level = 0)
 {
     $list->replace('/\\n{2,}\\z/', "\n");
     /** @noinspection PhpUnusedParameterInspection */
     $list->replace('{
         (\\n)?                                 # leading line = $1
         (^[ \\t]*)                             # leading whitespace = $2
         (' . $this->getPattern() . ') [ \\t]+  # list marker = $3
         ((?s:.+?)                             # list item text   = $4
         (\\n{1,2}))
         (?= \\n* (\\z | \\2 (' . $this->getPattern() . ') [ \\t]+))
     }mx', function (Text $w, Text $leadingLine, Text $ls, Text $m, Text $item) use($options, $level) {
         if ((string) $leadingLine || $item->match('/\\n{2,}/')) {
             $this->markdown->emit('outdent', array($item));
             $this->markdown->emit('block', array($item));
         } else {
             $this->markdown->emit('outdent', array($item));
             $this->processList($item, $options, ++$level);
             $item->rtrim();
             $this->markdown->emit('inline', array($item));
         }
         return $this->getRenderer()->renderListItem($item) . "\n";
     });
 }
Exemple #13
0
 /**
  * @param Text       $body
  * @param Collection $baseTags
  *
  * @return Collection
  */
 protected function parseBody(Text $body, Collection $baseTags)
 {
     $rows = new Collection();
     $body->split('/\\n/')->each(function (Text $row, $index) use($baseTags, &$rows) {
         $row->trim()->trim('|');
         $cells = new Collection();
         try {
             $row->split('/\\|/')->each(function (Text $cell, $index) use(&$baseTags, &$cells) {
                 /* @var Tag $tag */
                 $tag = clone $baseTags->get($index);
                 $this->markdown->emit('inline', array($cell));
                 $tag->setText($cell->trim());
                 $cells->add($tag);
             });
         } catch (\OutOfBoundsException $e) {
             throw new SyntaxError(sprintf('Too much cells on table body (row #%d).', $index), $this, $row, $this->markdown, $e);
         }
         if ($baseTags->count() != $cells->count()) {
             throw new SyntaxError('Unexpected number of table cells in body.', $this, $row, $this->markdown);
         }
         $rows->add($cells);
     });
     return $rows;
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('inline', [$this, 'processStandardUrl'], 35);
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('inline', array($this, 'processBold'), 70);
     $markdown->on('inline', array($this, 'processItalic'), 71);
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('block', array($this, 'processHorizontalRule'), 20);
 }
Exemple #17
0
 public function testDefaultOptions()
 {
     $markdown = new Markdown(new HtmlRenderer());
     $this->assertEquals(['tabWidth' => 4, 'nestedTagLevel' => 3, 'strict' => false, 'pygments' => false], $markdown->getOptions());
 }
Exemple #18
0
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('block', array($this, 'processComment'), 50);
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('inline', array($this, 'processMultipleUnderScore'), 10);
     $markdown->on('inline', array($this, 'processStrikeThrough'), 70);
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('tag', array($this, 'processBlockTags'));
 }
Exemple #21
0
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('inline', [$this, 'processNewLines']);
 }
Exemple #22
0
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $this->markdown = $markdown;
     $markdown->on('inline', array($this, 'processPullRequest'));
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('inline', array($this, 'processHardBreak'), 75);
 }
 /**
  * @param Text $text
  */
 public function unhashHtmlBlocks(Text $text)
 {
     foreach ($this->markdown->getHashRegistry() as $hash => $html) {
         $text->replaceString($hash, trim($html));
     }
 }
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('block', array($this, 'processDefinitionList'), 30);
     $markdown->on('block', array($this, 'processWikiDefinitionList'), 30);
 }
Exemple #26
0
 /**
  * {@inheritdoc}
  */
 public function register(Markdown $markdown)
 {
     $markdown->on('block', array($this, 'processHeader'), 10);
 }