Add server side highlighting, fixes #139
This commit is contained in:
parent
57b3848430
commit
92db87e00d
@ -27,7 +27,8 @@
|
|||||||
"symfony/polyfill-intl-icu": "^1.10",
|
"symfony/polyfill-intl-icu": "^1.10",
|
||||||
"symfony/process": "^4.0",
|
"symfony/process": "^4.0",
|
||||||
"webuni/commonmark-table-extension": "0.9.*",
|
"webuni/commonmark-table-extension": "0.9.*",
|
||||||
"webuni/front-matter": "^1.0.0"
|
"webuni/front-matter": "^1.0.0",
|
||||||
|
"scrivo/highlight.php": "^9.15"
|
||||||
},
|
},
|
||||||
"suggest":{
|
"suggest":{
|
||||||
"ext-intl": "Allows to translate the modified at date"
|
"ext-intl": "Allows to translate the modified at date"
|
||||||
|
81
composer.lock
generated
81
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "c2a8f08a3622dfcd70136f48e4f5a0ce",
|
"content-hash": "3df8e368fea890f0e123788f898cddc9",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
@ -244,9 +244,9 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Colin O'Dell",
|
"name": "Colin O'Dell",
|
||||||
"role": "Lead Developer",
|
|
||||||
"email": "colinodell@gmail.com",
|
"email": "colinodell@gmail.com",
|
||||||
"homepage": "https://www.colinodell.com"
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "PHP Markdown parser based on the CommonMark spec",
|
"description": "PHP Markdown parser based on the CommonMark spec",
|
||||||
@ -500,6 +500,73 @@
|
|||||||
"description": "A polyfill for getallheaders.",
|
"description": "A polyfill for getallheaders.",
|
||||||
"time": "2016-02-11T07:05:27+00:00"
|
"time": "2016-02-11T07:05:27+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "scrivo/highlight.php",
|
||||||
|
"version": "v9.15.10.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/scrivo/highlight.php.git",
|
||||||
|
"reference": "9ad3adb4456dc91196327498dbbce6aa1ba1239e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/scrivo/highlight.php/zipball/9ad3adb4456dc91196327498dbbce6aa1ba1239e",
|
||||||
|
"reference": "9ad3adb4456dc91196327498dbbce6aa1ba1239e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=5.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8|^5.7",
|
||||||
|
"symfony/finder": "^2.8"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-dom": "Needed to make use of the features in the utilities namespace"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Highlight\\": "",
|
||||||
|
"HighlightUtilities\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"HighlightUtilities/functions.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Geert Bergman",
|
||||||
|
"role": "Project Author",
|
||||||
|
"homepage": "http://www.scrivo.org/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vladimir Jimenez",
|
||||||
|
"role": "Contributor",
|
||||||
|
"homepage": "https://allejo.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Martin Folkers",
|
||||||
|
"role": "Contributor",
|
||||||
|
"homepage": "https://twobrain.io"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js",
|
||||||
|
"keywords": [
|
||||||
|
"code",
|
||||||
|
"highlight",
|
||||||
|
"highlight.js",
|
||||||
|
"highlight.php",
|
||||||
|
"syntax"
|
||||||
|
],
|
||||||
|
"time": "2019-08-27T04:27:48+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v4.3.4",
|
"version": "v4.3.4",
|
||||||
@ -1503,8 +1570,8 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Frank Kleine",
|
"name": "Frank Kleine",
|
||||||
"homepage": "http://frankkleine.de/",
|
"role": "Developer",
|
||||||
"role": "Developer"
|
"homepage": "http://frankkleine.de/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Virtual file system to mock the real file system in unit tests.",
|
"description": "Virtual file system to mock the real file system in unit tests.",
|
||||||
@ -2018,8 +2085,8 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
"email": "sebastian@phpunit.de",
|
"role": "lead",
|
||||||
"role": "lead"
|
"email": "sebastian@phpunit.de"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Utility class for timing",
|
"description": "Utility class for timing",
|
||||||
|
@ -2,21 +2,27 @@ Highlight.js highlights syntax in code examples on blogs, forums and in fact on
|
|||||||
|
|
||||||
You can even use [Github Flavored Markdown](!Features/CommonMark_compliant)
|
You can even use [Github Flavored Markdown](!Features/CommonMark_compliant)
|
||||||
|
|
||||||
|
We also use the [scrivo/highlight.php](https://github.com/scrivo/highlight.php) package to highlight on rendering when possible.
|
||||||
|
Highlight.js is a powerful but heavy library, since we don't know which languages you'll use we included all of them.
|
||||||
|
|
||||||
|
The good news is; if you use a fenced code block (` ``` `) with the language defined, the rendering is done on server side and entirely skips loading Highlight.js on the page. While still having the same end-result on your code.
|
||||||
|
|
||||||
|
|
||||||
**Python**
|
**Python**
|
||||||
|
|
||||||
@requires_authorization
|
```python
|
||||||
def somefunc(param1='', param2=0):
|
@requires_authorization
|
||||||
r'''A docstring'''
|
def somefunc(param1='', param2=0):
|
||||||
if param1 > param2: # interesting
|
r'''A docstring'''
|
||||||
print 'Gre\'ater'
|
if param1 > param2: # interesting
|
||||||
return (param2 - param1 + 1) or None
|
print 'Gre\'ater'
|
||||||
|
return (param2 - param1 + 1) or None
|
||||||
|
|
||||||
class SomeClass:<br> pass
|
class SomeClass:<br> pass
|
||||||
|
|
||||||
>>> message = '''interpreter
|
|
||||||
... prompt'''
|
|
||||||
|
|
||||||
|
>>> message = '''interpreter
|
||||||
|
... prompt'''
|
||||||
|
```
|
||||||
|
|
||||||
**Python's profiler output**
|
**Python's profiler output**
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ class CommonMarkConverter extends \Todaymade\Daux\ContentTypes\Markdown\CommonMa
|
|||||||
{
|
{
|
||||||
parent::extendEnvironment($environment, $config);
|
parent::extendEnvironment($environment, $config);
|
||||||
|
|
||||||
|
$environment->addBlockRenderer('FencedCode', new FencedCodeRenderer());
|
||||||
|
|
||||||
$environment->addDocumentProcessor(new TOC\Processor($config));
|
$environment->addDocumentProcessor(new TOC\Processor($config));
|
||||||
$environment->addBlockRenderer('Todaymade\Daux\ContentTypes\Markdown\TableOfContents', new TOC\Renderer($config));
|
$environment->addBlockRenderer('Todaymade\Daux\ContentTypes\Markdown\TableOfContents', new TOC\Renderer($config));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
<?php namespace Todaymade\Daux\Format\HTML\ContentTypes\Markdown;
|
||||||
|
|
||||||
|
use Highlight\Highlighter;
|
||||||
|
use League\CommonMark\Block\Element\AbstractBlock;
|
||||||
|
use League\CommonMark\Block\Element\FencedCode;
|
||||||
|
use League\CommonMark\Block\Renderer\BlockRendererInterface;
|
||||||
|
use League\CommonMark\ElementRendererInterface;
|
||||||
|
use League\CommonMark\HtmlElement;
|
||||||
|
use League\CommonMark\Util\Xml;
|
||||||
|
|
||||||
|
class FencedCodeRenderer implements BlockRendererInterface
|
||||||
|
{
|
||||||
|
function __construct() {
|
||||||
|
$this->hl = new Highlighter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AbstractBlock $block
|
||||||
|
* @param HtmlRendererInterface $htmlRenderer
|
||||||
|
* @param bool $inTightList
|
||||||
|
*
|
||||||
|
* @return HtmlElement|string
|
||||||
|
*/
|
||||||
|
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, $inTightList = false)
|
||||||
|
{
|
||||||
|
if (!($block instanceof FencedCode)) {
|
||||||
|
throw new \InvalidArgumentException('Incompatible block type: ' . get_class($block));
|
||||||
|
}
|
||||||
|
|
||||||
|
$attrs = [];
|
||||||
|
foreach ($block->getData('attributes', []) as $key => $value) {
|
||||||
|
$attrs[$key] = Xml::escape($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $block->getStringContent();
|
||||||
|
|
||||||
|
$language = $this->getLanguage($block->getInfoWords());
|
||||||
|
$highlighted = false;
|
||||||
|
if ($language) {
|
||||||
|
$attrs['class'] = isset($attrs['class']) ? $attrs['class'] . ' ' : '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$highlighted = $this->hl->highlight($language, $content);
|
||||||
|
$content = $highlighted->value;
|
||||||
|
$attrs['class'] .= 'hljs ' . $highlighted->language;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$attrs['class'] .= 'language-' . $language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$highlighted) {
|
||||||
|
$content = Xml::escape($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HtmlElement(
|
||||||
|
'pre',
|
||||||
|
[],
|
||||||
|
new HtmlElement('code', $attrs, $content)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLanguage($infoWords)
|
||||||
|
{
|
||||||
|
if (count($infoWords) === 0 || strlen($infoWords[0]) === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Xml::escape($infoWords[0], true);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user