Commit 3e3948d8 by Carsten Brandt

fix breaking changes in markdown for console and API

API is not finished. issue #5082
parent b66c4cf4
...@@ -40,7 +40,7 @@ class ApiMarkdown extends GithubMarkdown ...@@ -40,7 +40,7 @@ class ApiMarkdown extends GithubMarkdown
if (isset($block['language'])) { if (isset($block['language'])) {
$class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : ''; $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : '';
return "<pre><code$class>" . $this->highlight($block['content'] . "\n", $block['language']) . '</code></pre>'; return "<pre><code$class>" . $this->highlight($block['content'] . "\n", $block['language']) . "</code></pre>\n";
} else { } else {
return parent::renderCode($block); return parent::renderCode($block);
} }
...@@ -49,7 +49,7 @@ class ApiMarkdown extends GithubMarkdown ...@@ -49,7 +49,7 @@ class ApiMarkdown extends GithubMarkdown
public static function highlight($code, $language) public static function highlight($code, $language)
{ {
if ($language !== 'php') { if ($language !== 'php') {
return htmlspecialchars($code, ENT_NOQUOTES, 'UTF-8'); return htmlspecialchars($code, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
} }
// TODO improve code highlighting // TODO improve code highlighting
...@@ -68,39 +68,32 @@ class ApiMarkdown extends GithubMarkdown ...@@ -68,39 +68,32 @@ class ApiMarkdown extends GithubMarkdown
return $text; return $text;
} }
protected function inlineMarkers()
{
return array_merge(parent::inlineMarkers(), [
'[[' => 'parseApiLinks',
]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function renderHeadline($block) protected function renderHeadline($block)
{ {
$content = $this->parseInline($block['content']); $content = $this->renderAbsy($block['content']);
$hash = Inflector::slug(strip_tags($content)); $hash = Inflector::slug(strip_tags($content));
$hashLink = "<a href=\"#$hash\" name=\"$hash\" class=\"hashlink\">&para;</a>"; $hashLink = "<a href=\"#$hash\" name=\"$hash\" class=\"hashlink\">&para;</a>";
$tag = 'h' . $block['level'];
$tag = 'h' . $block['level'];
return "<$tag>$content $hashLink</$tag>"; return "<$tag>$content $hashLink</$tag>";
} }
/** /**
* @inheritdoc * @inheritdoc
*/ */
protected function parseLink($markdown) protected function renderLink($block)
{ {
list($result, $skip) = parent::parseLink($markdown); $result = parent::renderLink($block);
// add special syntax for linking to the guide // add special syntax for linking to the guide
$result = preg_replace_callback('/href="guide:([A-z0-9-.#]+)"/i', function($match) { $result = preg_replace_callback('/href="guide:([A-z0-9-.#]+)"/i', function($match) {
return 'href="' . static::$renderer->generateGuideUrl($match[1]) . '"'; return 'href="' . static::$renderer->generateGuideUrl($match[1]) . '"';
}, $result, 1); }, $result, 1);
return [$result, $skip]; return $result;
} }
/** /**
......
...@@ -30,21 +30,11 @@ class ApiMarkdownLaTeX extends GithubMarkdown ...@@ -30,21 +30,11 @@ class ApiMarkdownLaTeX extends GithubMarkdown
protected $renderingContext; protected $renderingContext;
protected function inlineMarkers() protected function renderApiLink($block)
{ {
return array_merge(parent::inlineMarkers(), [
'[[' => 'parseApiLinksLatex',
]);
}
protected function parseApiLinksLatex($text)
{
list($html, $offset) = $this->parseApiLinks($text);
// TODO allow break also on camel case // TODO allow break also on camel case
$latex = '\texttt{'.str_replace(['\\textbackslash', '::'], ['\allowbreak{}\\textbackslash', '\allowbreak{}::\allowbreak{}'], $this->escapeLatex(strip_tags($html))).'}'; $latex = '\texttt{'.str_replace(['\\textbackslash', '::'], ['\allowbreak{}\\textbackslash', '\allowbreak{}::\allowbreak{}'], $this->escapeLatex(strip_tags($block[1]))).'}';
return $latex;
return [$latex, $offset];
} }
/** /**
......
...@@ -20,7 +20,6 @@ trait ApiMarkdownTrait ...@@ -20,7 +20,6 @@ trait ApiMarkdownTrait
{ {
/** /**
* @marker [[ * @marker [[
* TODO adjust implementation
*/ */
protected function parseApiLinks($text) protected function parseApiLinks($text)
{ {
...@@ -49,7 +48,7 @@ trait ApiMarkdownTrait ...@@ -49,7 +48,7 @@ trait ApiMarkdownTrait
]; ];
return [ return [
'<span style="background: #f00;">' . $typeName . '::' . $subjectName . '</span>', ['text', '<span style="background: #f00;">' . $typeName . '::' . $subjectName . '</span>'],
$offset $offset
]; ];
} else { } else {
...@@ -62,7 +61,7 @@ trait ApiMarkdownTrait ...@@ -62,7 +61,7 @@ trait ApiMarkdownTrait
} }
return [ return [
static::$renderer->createSubjectLink($subject, $title), ['apiLink', static::$renderer->createSubjectLink($subject, $title)],
$offset $offset
]; ];
} else { } else {
...@@ -72,14 +71,14 @@ trait ApiMarkdownTrait ...@@ -72,14 +71,14 @@ trait ApiMarkdownTrait
]; ];
return [ return [
'<span style="background: #ff0;">' . $type->name . '</span><span style="background: #f00;">::' . $subjectName . '</span>', ['text', '<span style="background: #ff0;">' . $type->name . '</span><span style="background: #f00;">::' . $subjectName . '</span>'],
$offset $offset
]; ];
} }
} }
} elseif ($context !== null && ($subject = $context->findSubject($object)) !== null) { } elseif ($context !== null && ($subject = $context->findSubject($object)) !== null) {
return [ return [
static::$renderer->createSubjectLink($subject, $title), ['apiLink', static::$renderer->createSubjectLink($subject, $title)],
$offset $offset
]; ];
} }
...@@ -90,12 +89,12 @@ trait ApiMarkdownTrait ...@@ -90,12 +89,12 @@ trait ApiMarkdownTrait
} }
if (($type = static::$renderer->apiContext->getType($object)) !== null) { if (($type = static::$renderer->apiContext->getType($object)) !== null) {
return [ return [
static::$renderer->createTypeLink($type, null, $title), ['apiLink', static::$renderer->createTypeLink($type, null, $title)],
$offset $offset
]; ];
} elseif (strpos($typeLink = static::$renderer->createTypeLink($object, null, $title), '<a href') !== false) { } elseif (strpos($typeLink = static::$renderer->createTypeLink($object, null, $title), '<a href') !== false) {
return [ return [
$typeLink, ['apiLink', $typeLink],
$offset $offset
]; ];
} }
...@@ -105,11 +104,16 @@ trait ApiMarkdownTrait ...@@ -105,11 +104,16 @@ trait ApiMarkdownTrait
]; ];
return [ return [
'<span style="background: #f00;">' . $object . '</span>', ['text', '<span style="background: #f00;">' . $object . '</span>'],
$offset $offset
]; ];
} }
return ['[[', 2]; return [['text', '[['], 2];
}
protected function renderApiLink($block)
{
return $block[1];
} }
} }
...@@ -28,13 +28,13 @@ class IndexFileAnalyzer extends Markdown ...@@ -28,13 +28,13 @@ class IndexFileAnalyzer extends Markdown
protected function renderHeadline($block) protected function renderHeadline($block)
{ {
if ($this->_chapter === 0) { if ($this->_chapter === 0) {
$this->title = $block['content']; // TODO adjust implementation $this->title = $this->renderAbsy($block['content']);
$this->introduction = ''; $this->introduction = '';
$this->_chapter++; $this->_chapter++;
} else { } else {
$this->_chapter++; $this->_chapter++;
$this->_chapters[$this->_chapter] = [ $this->_chapters[$this->_chapter] = [
'headline' => $block['content'], 'headline' => $this->renderAbsy($block['content']),
'content' => [], 'content' => [],
]; ];
} }
...@@ -44,7 +44,7 @@ class IndexFileAnalyzer extends Markdown ...@@ -44,7 +44,7 @@ class IndexFileAnalyzer extends Markdown
protected function renderParagraph($block) protected function renderParagraph($block)
{ {
if ($this->_chapter < 1) { if ($this->_chapter < 1) {
$this->introduction .= implode("\n", $block['content']); $this->introduction .= $this->renderAbsy($block['content']);
} }
return parent::renderParagraph($block); return parent::renderParagraph($block);
} }
...@@ -53,7 +53,7 @@ class IndexFileAnalyzer extends Markdown ...@@ -53,7 +53,7 @@ class IndexFileAnalyzer extends Markdown
{ {
if ($this->_chapter > 0) { if ($this->_chapter > 0) {
foreach ($block['items'] as $item => $itemLines) { foreach ($block['items'] as $item => $itemLines) {
if (preg_match('~\[([^\]]+)\]\(([^\)]+)\)(.*)~', implode("\n", $itemLines), $matches)) { if (preg_match('~\[([^\]]+)\]\(([^\)]+)\)(.*)~', $this->renderAbsy($itemLines), $matches)) {
$this->_chapters[$this->_chapter]['content'][] = [ $this->_chapters[$this->_chapter]['content'][] = [
'headline' => $matches[1], 'headline' => $matches[1],
'file' => $matches[2], 'file' => $matches[2],
......
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
namespace yii\console; namespace yii\console;
use cebe\markdown\block\FencedCodeTrait;
use cebe\markdown\inline\CodeTrait;
use cebe\markdown\inline\EmphStrongTrait;
use cebe\markdown\inline\StrikeoutTrait;
use yii\helpers\Console; use yii\helpers\Console;
/** /**
...@@ -19,6 +23,11 @@ use yii\helpers\Console; ...@@ -19,6 +23,11 @@ use yii\helpers\Console;
*/ */
class Markdown extends \cebe\markdown\Parser class Markdown extends \cebe\markdown\Parser
{ {
use FencedCodeTrait;
use CodeTrait;
use EmphStrongTrait;
use StrikeoutTrait;
/** /**
* @var array these are "escapeable" characters. When using one of these prefixed with a * @var array these are "escapeable" characters. When using one of these prefixed with a
* backslash, the character will be outputted without the backslash and is not interpreted * backslash, the character will be outputted without the backslash and is not interpreted
...@@ -29,51 +38,11 @@ class Markdown extends \cebe\markdown\Parser ...@@ -29,51 +38,11 @@ class Markdown extends \cebe\markdown\Parser
'`', // backtick '`', // backtick
'*', // asterisk '*', // asterisk
'_', // underscore '_', // underscore
'~', // tilde
]; ];
/** /**
* @inheritDoc
*/
protected function identifyLine($lines, $current)
{
if (isset($lines[$current]) && (strncmp($lines[$current], '```', 3) === 0 || strncmp($lines[$current], '~~~', 3) === 0)) {
return 'fencedCode';
}
return parent::identifyLine($lines, $current);
}
/**
* Consume lines for a fenced code block
*
* @param array $lines
* @param integer $current
* @return array
*/
protected function consumeFencedCode($lines, $current)
{
// consume until ```
$block = [
'type' => 'code',
'content' => [],
];
$line = rtrim($lines[$current]);
$fence = substr($line, 0, $pos = strrpos($line, $line[0]) + 1);
$language = substr($line, $pos);
if (!empty($language)) {
$block['language'] = $language;
}
for ($i = $current + 1, $count = count($lines); $i < $count; $i++) {
if (rtrim($line = $lines[$i]) !== $fence) {
$block['content'][] = $line;
} else {
break;
}
}
return [$block, $i];
}
/**
* Renders a code block * Renders a code block
* *
* @param array $block * @param array $block
...@@ -81,7 +50,7 @@ class Markdown extends \cebe\markdown\Parser ...@@ -81,7 +50,7 @@ class Markdown extends \cebe\markdown\Parser
*/ */
protected function renderCode($block) protected function renderCode($block)
{ {
return Console::ansiFormat(implode("\n", $block['content']), [Console::NEGATIVE]) . "\n"; return Console::ansiFormat($block['content'], [Console::NEGATIVE]) . "\n\n";
} }
/** /**
...@@ -89,102 +58,46 @@ class Markdown extends \cebe\markdown\Parser ...@@ -89,102 +58,46 @@ class Markdown extends \cebe\markdown\Parser
*/ */
protected function renderParagraph($block) protected function renderParagraph($block)
{ {
return rtrim($this->parseInline(implode("\n", $block['content']))) . "\n"; return rtrim($this->renderAbsy($block['content'])) . "\n\n";
} }
/** /**
* @inheritDoc * Renders an inline code span `` ` ``.
*/ * @param array $element
protected function inlineMarkers() * @return string
{
return [
'*' => 'parseEmphStrong',
'_' => 'parseEmphStrong',
'\\' => 'parseEscape',
'`' => 'parseCode',
'~~' => 'parseStrike',
];
}
/**
* Parses an inline code span `` ` ``.
* @param string $text
* @return array
*/ */
protected function parseCode($text) protected function renderInlineCode($element)
{ {
// skip fenced code return Console::ansiFormat($element[1], [Console::UNDERLINE]);
if (strncmp($text, '```', 3) === 0) {
return [$text[0], 1];
}
if (preg_match('/^(`+) (.+?) \1/', $text, $matches)) { // code with enclosed backtick
return [
Console::ansiFormat($matches[2], [Console::UNDERLINE]),
strlen($matches[0])
];
} elseif (preg_match('/^`(.+?)`/', $text, $matches)) {
return [
Console::ansiFormat($matches[1], [Console::UNDERLINE]),
strlen($matches[0])
];
}
return [$text[0], 1];
} }
/** /**
* Parses empathized and strong elements. * Renders empathized elements.
* @param string $text * @param array $element
* @return array * @return string
*/ */
protected function parseEmphStrong($text) protected function renderEmph($element)
{ {
$marker = $text[0]; return Console::ansiFormat($this->renderAbsy($element[1]), Console::ITALIC);
if (!isset($text[1])) {
return [$text[0], 1];
}
if ($marker == $text[1]) { // strong
if ($marker == '*' && preg_match('/^[*]{2}((?:[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', $text, $matches) ||
$marker == '_' && preg_match('/^__((?:[^_]|_[^_]*_)+?)__(?!_)/us', $text, $matches)) {
return [Console::ansiFormat($this->parseInline($matches[1]), Console::BOLD), strlen($matches[0])];
}
} else { // emph
if ($marker == '*' && preg_match('/^[*]((?:[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', $text, $matches) ||
$marker == '_' && preg_match('/^_((?:[^_]|__[^_]*__)+?)_(?!_)\b/us', $text, $matches)) {
return [Console::ansiFormat($this->parseInline($matches[1]), Console::ITALIC), strlen($matches[0])];
}
}
return [$text[0], 1];
} }
/** /**
* Parses the strikethrough feature. * Renders strong elements.
* @param string $markdown * @param array $element
* @return array * @return string
*/ */
protected function parseStrike($markdown) protected function renderStrong($element)
{ {
if (preg_match('/^~~(.+?)~~/', $markdown, $matches)) { return Console::ansiFormat($this->renderAbsy($element[1]), Console::BOLD);
return [
Console::ansiFormat($this->parseInline($matches[1]), [Console::CROSSED_OUT]),
strlen($matches[0])
];
}
return [$markdown[0] . $markdown[1], 2];
} }
/** /**
* Parses escaped special characters. * Renders the strike through feature.
* @param string $text * @param array $element
* @return array * @return string
*/ */
protected function parseEscape($text) protected function renderStrike($element)
{ {
if (isset($text[1]) && in_array($text[1], $this->escapeCharacters)) { return Console::ansiFormat($this->parseInline($this->renderAbsy($element[1])), [Console::CROSSED_OUT]);
return [$text[1], 2];
}
return [$text[0], 1];
} }
} }
...@@ -16,6 +16,7 @@ use yii\helpers\VarDumper; ...@@ -16,6 +16,7 @@ use yii\helpers\VarDumper;
* Allows you to combine and compress your JavaScript and CSS files. * Allows you to combine and compress your JavaScript and CSS files.
* *
* Usage: * Usage:
*
* 1. Create a configuration file using the `template` action: * 1. Create a configuration file using the `template` action:
* *
* yii asset/template /path/to/myapp/config.php * yii asset/template /path/to/myapp/config.php
......
...@@ -16,16 +16,17 @@ use yii\console\Exception; ...@@ -16,16 +16,17 @@ use yii\console\Exception;
/** /**
* Allows you to flush cache. * Allows you to flush cache.
* *
* ~~~ * see list of available components to flush:
* #see list of available components to flush *
* yii cache * yii cache
* *
* #flush particular components specified by their names * flush particular components specified by their names:
*
* yii cache/flush first second third * yii cache/flush first second third
* *
* #flush all cache components that can be found in the system * flush all cache components that can be found in the system
*
* yii cache/flush-all * yii cache/flush-all
* ~~~
* *
* @author Alexander Makarov <sam@rmcreative.ru> * @author Alexander Makarov <sam@rmcreative.ru>
* @author Mark Jebri <mark.github@yandex.ru> * @author Mark Jebri <mark.github@yandex.ru>
......
...@@ -37,6 +37,10 @@ class BaseMarkdown ...@@ -37,6 +37,10 @@ class BaseMarkdown
'html5' => true, 'html5' => true,
'enableNewlines' => true, 'enableNewlines' => true,
], ],
'extra' => [
'class' => 'cebe\markdown\MarkdownExtra',
'html5' => true,
],
]; ];
/** /**
* @var string the markdown flavor to use when none is specified explicitly. * @var string the markdown flavor to use when none is specified explicitly.
......
...@@ -15,6 +15,7 @@ namespace yii\helpers; ...@@ -15,6 +15,7 @@ namespace yii\helpers;
* ```php * ```php
* $myHtml = Markdown::process($myText); // use original markdown flavor * $myHtml = Markdown::process($myText); // use original markdown flavor
* $myHtml = Markdown::process($myText, 'gfm'); // use github flavored markdown * $myHtml = Markdown::process($myText, 'gfm'); // use github flavored markdown
* $myHtml = Markdown::process($myText, 'extra'); // use markdown extra
* ``` * ```
* *
* You can configure multiple flavors using the [[$flavors]] property. * You can configure multiple flavors using the [[$flavors]] property.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment