diff --git a/composer.json b/composer.json
index 45ae7b8..24c5592 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,8 @@
"symfony/polyfill-intl-icu": "^1.10",
"symfony/process": "^4.0",
"webuni/commonmark-table-extension": "0.9.*",
- "webuni/front-matter": "^1.0.0"
+ "webuni/front-matter": "^1.0.0",
+ "scrivo/highlight.php": "^9.15"
},
"suggest":{
"ext-intl": "Allows to translate the modified at date"
diff --git a/composer.lock b/composer.lock
index 22b08ed..dffd4ef 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "c2a8f08a3622dfcd70136f48e4f5a0ce",
+ "content-hash": "3df8e368fea890f0e123788f898cddc9",
"packages": [
{
"name": "guzzlehttp/guzzle",
@@ -244,9 +244,9 @@
"authors": [
{
"name": "Colin O'Dell",
- "role": "Lead Developer",
"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",
@@ -500,6 +500,73 @@
"description": "A polyfill for getallheaders.",
"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",
"version": "v4.3.4",
@@ -1503,8 +1570,8 @@
"authors": [
{
"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.",
@@ -2018,8 +2085,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "role": "lead",
+ "email": "sebastian@phpunit.de"
}
],
"description": "Utility class for timing",
diff --git a/docs/02_Examples/05_Code_Highlighting.md b/docs/02_Examples/05_Code_Highlighting.md
index e723d73..0d0807b 100644
--- a/docs/02_Examples/05_Code_Highlighting.md
+++ b/docs/02_Examples/05_Code_Highlighting.md
@@ -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)
+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**
- @requires_authorization
- def somefunc(param1='', param2=0):
- r'''A docstring'''
- if param1 > param2: # interesting
- print 'Gre\'ater'
- return (param2 - param1 + 1) or None
+```python
+@requires_authorization
+def somefunc(param1='', param2=0):
+ r'''A docstring'''
+ if param1 > param2: # interesting
+ print 'Gre\'ater'
+ return (param2 - param1 + 1) or None
- class SomeClass:
pass
-
- >>> message = '''interpreter
- ... prompt'''
+class SomeClass:
pass
+>>> message = '''interpreter
+... prompt'''
+```
**Python's profiler output**
diff --git a/libs/Format/HTML/ContentTypes/Markdown/CommonMarkConverter.php b/libs/Format/HTML/ContentTypes/Markdown/CommonMarkConverter.php
index 8fd5ea2..96d8f37 100644
--- a/libs/Format/HTML/ContentTypes/Markdown/CommonMarkConverter.php
+++ b/libs/Format/HTML/ContentTypes/Markdown/CommonMarkConverter.php
@@ -9,6 +9,8 @@ class CommonMarkConverter extends \Todaymade\Daux\ContentTypes\Markdown\CommonMa
{
parent::extendEnvironment($environment, $config);
+ $environment->addBlockRenderer('FencedCode', new FencedCodeRenderer());
+
$environment->addDocumentProcessor(new TOC\Processor($config));
$environment->addBlockRenderer('Todaymade\Daux\ContentTypes\Markdown\TableOfContents', new TOC\Renderer($config));
}
diff --git a/libs/Format/HTML/ContentTypes/Markdown/FencedCodeRenderer.php b/libs/Format/HTML/ContentTypes/Markdown/FencedCodeRenderer.php
new file mode 100644
index 0000000..44f0d0a
--- /dev/null
+++ b/libs/Format/HTML/ContentTypes/Markdown/FencedCodeRenderer.php
@@ -0,0 +1,70 @@
+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);
+ }
+}