mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 11:05:56 +02:00
NEW: Github style code fence blocks. (Fixes #22)
This commit is contained in:
parent
440a2cbaa5
commit
3b27cd6b2b
@ -1,24 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser wrapping the Markdown Extra parser (see http://michelf.com/projects/php-markdown/extra/).
|
* Parser wrapping the Markdown Extra parser.
|
||||||
|
*
|
||||||
|
* @see http://michelf.com/projects/php-markdown/extra/
|
||||||
*
|
*
|
||||||
* @package docsviewer
|
* @package docsviewer
|
||||||
*/
|
*/
|
||||||
class DocumentationParser {
|
class DocumentationParser {
|
||||||
|
|
||||||
/**
|
const CODE_BLOCK_BACKTICK = 1;
|
||||||
* @var String Rewriting of api links in the format "[api:MyClass]" or "[api:MyClass::$my_property]".
|
const CODE_BLOCK_COLON = 2;
|
||||||
*/
|
|
||||||
static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
|
|
||||||
|
|
||||||
static $heading_counts = array();
|
/**
|
||||||
|
* @var string Rewriting of api links in the format "[api:MyClass]" or "[api:MyClass::$my_property]".
|
||||||
|
*/
|
||||||
|
public static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $heading_counts = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a given path to the documentation for a file. Performs a case
|
* Parse a given path to the documentation for a file. Performs a case
|
||||||
* insensitive lookup on the file system. Automatically appends the file
|
* insensitive lookup on the file system. Automatically appends the file
|
||||||
* extension to one of the markdown extensions as well so /install/ in a
|
* extension to one of the markdown extensions as well so /install/ in a
|
||||||
* web browser will match /install.md or /INSTALL.md
|
* web browser will match /install.md or /INSTALL.md.
|
||||||
*
|
*
|
||||||
* Filepath: /var/www/myproject/src/cms/en/folder/subfolder/page.md
|
* Filepath: /var/www/myproject/src/cms/en/folder/subfolder/page.md
|
||||||
* URL: http://myhost/mywebroot/dev/docs/2.4/cms/en/folder/subfolder/page
|
* URL: http://myhost/mywebroot/dev/docs/2.4/cms/en/folder/subfolder/page
|
||||||
@ -27,8 +35,9 @@ class DocumentationParser {
|
|||||||
* Pathparts: folder/subfolder/page
|
* Pathparts: folder/subfolder/page
|
||||||
*
|
*
|
||||||
* @param DocumentationPage $page
|
* @param DocumentationPage $page
|
||||||
* @param String $baselink Link relative to webroot, up until the "root" of the module.
|
* @param String $baselink Link relative to webroot, up until the "root"
|
||||||
* Necessary to rewrite relative links
|
* of the module. Necessary to rewrite relative
|
||||||
|
* links
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
@ -56,38 +65,110 @@ class DocumentationParser {
|
|||||||
public static function rewrite_code_blocks($md) {
|
public static function rewrite_code_blocks($md) {
|
||||||
$started = false;
|
$started = false;
|
||||||
$inner = false;
|
$inner = false;
|
||||||
|
$mode = false;
|
||||||
|
$end = false;
|
||||||
|
|
||||||
$lines = explode("\n", $md);
|
$lines = explode("\n", $md);
|
||||||
|
$output = array();
|
||||||
|
|
||||||
foreach($lines as $i => $line) {
|
foreach($lines as $i => $line) {
|
||||||
if(!$started && preg_match('/^\t*:::\s*(.*)/', $line, $matches)) {
|
if(!$started && preg_match('/^\t*:::\s*(.*)/', $line, $matches)) {
|
||||||
// first line with custom formatting
|
// first line with custom formatting
|
||||||
$started = true;
|
$started = true;
|
||||||
$lines[$i] = sprintf('<pre class="brush: %s">', $matches[1]);
|
$mode = self::CODE_BLOCK_COLON;
|
||||||
} elseif(preg_match('/^\t(.*)/', $line, $matches)) {
|
$output[$i] = sprintf('<pre class="brush: %s">', (isset($matches[1])) ? $matches[1] : "");
|
||||||
// inner line of ::: block, or first line of standard markdown code block
|
}
|
||||||
|
elseif(!$started && preg_match('/^\t*```\s*(.*)/', $line, $matches)) {
|
||||||
|
$started = true;
|
||||||
|
$mode = self::CODE_BLOCK_BACKTICK;
|
||||||
|
$output[$i] = sprintf('<pre class="brush: %s">', (isset($matches[1])) ? $matches[1] : "");
|
||||||
|
}
|
||||||
|
elseif($started && $mode == self::CODE_BLOCK_BACKTICK) {
|
||||||
|
// inside a backtick fenced box
|
||||||
|
if(preg_match('/^\t*```\s*/', $line, $matches)) {
|
||||||
|
// end of the backtick fenced box. Unset the line that contains the backticks
|
||||||
|
$end = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// still inside the line.
|
||||||
|
$output[$i] = ($started) ? '' : '<pre>' . "\n";
|
||||||
|
$output[$i] .= htmlentities($line, ENT_COMPAT, 'UTF-8');
|
||||||
|
$inner = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif(preg_match('/^\t(.*)/', $line, $matches)) {
|
||||||
|
// inner line of block, or first line of standard markdown code block
|
||||||
// regex removes first tab (any following tabs are part of the code).
|
// regex removes first tab (any following tabs are part of the code).
|
||||||
$lines[$i] = ($started) ? '' : '<pre>' . "\n";
|
$output[$i] = ($started) ? '' : '<pre>' . "\n";
|
||||||
$lines[$i] .= htmlentities($matches[1], ENT_COMPAT, 'UTF-8');
|
$output[$i] .= htmlentities($matches[1], ENT_COMPAT, 'UTF-8');
|
||||||
$inner = true;
|
$inner = true;
|
||||||
$started = true;
|
$started = true;
|
||||||
} elseif($started && $inner) {
|
}
|
||||||
// remove any previous blank lines
|
elseif($started && $inner && $mode == self::CODE_BLOCK_COLON && trim($line) === "") {
|
||||||
$j = $i-1;
|
// still inside a colon based block, if the line is only whitespace
|
||||||
while(isset($lines[$j]) && preg_match('/^[\t\s]*$/', $lines[$j])) {
|
// then continue with with it. We can continue with it for now as
|
||||||
unset($lines[$j]);
|
// it'll be tidied up later in the $end section.
|
||||||
|
$inner = true;
|
||||||
|
$output[$i] = $line;
|
||||||
|
}
|
||||||
|
elseif($started && $inner) {
|
||||||
|
// line contains something other than whitespace, or tabbed. E.g
|
||||||
|
// > code
|
||||||
|
// > \n
|
||||||
|
// > some message
|
||||||
|
//
|
||||||
|
// So actually want to reset $i to the line before this new line
|
||||||
|
// and include this line. The edge case where this will fail is
|
||||||
|
// new the following segment contains a code block as well as it
|
||||||
|
// will not open.
|
||||||
|
$end = true;
|
||||||
|
$output[$i] = $line;
|
||||||
|
$i = $i -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$output[$i] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($end) {
|
||||||
|
$output = self::finalize_code_output($i, $output);
|
||||||
|
|
||||||
|
// reset state
|
||||||
|
$started = $inner = $mode = $end = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($started) {
|
||||||
|
$output = self::finalize_code_output($i, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return join("\n", $output);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int
|
||||||
|
* @param array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function finalize_code_output($i, $output) {
|
||||||
|
$j = $i;
|
||||||
|
|
||||||
|
while(isset($output[$j]) && trim($output[$j]) === "") {
|
||||||
|
unset($output[$j]);
|
||||||
|
|
||||||
$j--;
|
$j--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last line, close pre
|
if(isset($output[$j])) {
|
||||||
$lines[$i] = '</pre>' . "\n\n" . $line;
|
$output[$j] .= "</pre>\n";
|
||||||
|
|
||||||
// reset state
|
|
||||||
$started = $inner = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return join("\n", $lines);
|
else {
|
||||||
|
$output[$j] = "</pre>\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function rewrite_image_links($md, $page) {
|
static function rewrite_image_links($md, $page) {
|
||||||
|
@ -3,19 +3,13 @@
|
|||||||
The custom Markdown parser can render custom prefixes for code blocks, and
|
The custom Markdown parser can render custom prefixes for code blocks, and
|
||||||
render it via a [javascript syntax highlighter](http://alexgorbatchev.com/SyntaxHighlighter).
|
render it via a [javascript syntax highlighter](http://alexgorbatchev.com/SyntaxHighlighter).
|
||||||
|
|
||||||
In:
|
To see examples of the syntax, check out the source of this file in docs/en/
|
||||||
|
|
||||||
:::php
|
|
||||||
my sourcecode
|
|
||||||
|
|
||||||
Out:
|
|
||||||
|
|
||||||
<pre class="brush: php">
|
|
||||||
my sourcecode
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
To include the syntax highlighter source, add the following to your `DocumentationViewer->init()`:
|
To include the syntax highlighter source, add the following to your `DocumentationViewer->init()`:
|
||||||
|
|
||||||
|
|
||||||
|
```php
|
||||||
|
|
||||||
Requirements::javascript(THIRDPARTY_DIR .'/jquery/jquery.js');
|
Requirements::javascript(THIRDPARTY_DIR .'/jquery/jquery.js');
|
||||||
Requirements::javascript('sapphiredocs/thirdparty/syntaxhighlighter/scripts/shCore.js');
|
Requirements::javascript('sapphiredocs/thirdparty/syntaxhighlighter/scripts/shCore.js');
|
||||||
Requirements::javascript('sapphiredocs/thirdparty/syntaxhighlighter/scripts/shBrushJScript.js');
|
Requirements::javascript('sapphiredocs/thirdparty/syntaxhighlighter/scripts/shBrushJScript.js');
|
||||||
@ -38,6 +32,7 @@ To include the syntax highlighter source, add the following to your `Documentati
|
|||||||
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCore.css');
|
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCore.css');
|
||||||
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCoreDefault.css');
|
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCoreDefault.css');
|
||||||
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shThemeRDark.css');
|
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shThemeRDark.css');
|
||||||
|
```
|
||||||
|
|
||||||
You can overload the `DocumentationViewer` class and add a custom route through `Director::addRule()`
|
You can overload the `DocumentationViewer` class and add a custom route through `Director::addRule()`
|
||||||
if you prefer not to modify the module file.
|
if you prefer not to modify the module file.
|
||||||
|
19
lang/en.yml
Normal file
19
lang/en.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
en:
|
||||||
|
DocumentationSearch:
|
||||||
|
SEARCH: Search
|
||||||
|
SEARCHRESULTS: 'Search Results'
|
||||||
|
DocumentationViewer:
|
||||||
|
CHANGE: Change
|
||||||
|
KEYWORDS: Keywords
|
||||||
|
LANGUAGE: Language
|
||||||
|
MODULES: Modules
|
||||||
|
OPENSEARCHDESC: 'Search the documentation'
|
||||||
|
OPENSEARCHNAME: 'Documentation Search'
|
||||||
|
OPENSEARCHTAGS: documentation
|
||||||
|
SEARCH: Search
|
||||||
|
VERSIONS: Versions
|
||||||
|
DocumentationViewer_home.ss:
|
||||||
|
DOCUMENTEDMODULES: 'Documented Modules'
|
||||||
|
NOMODULEDOCUMENTATION: 'No modules with documentation installed could be found.'
|
||||||
|
DocumentationViewer_results.ss:
|
||||||
|
ADVANCEDSEARCH: 'Advanced Search'
|
@ -26,21 +26,40 @@ code block
|
|||||||
with multiple
|
with multiple
|
||||||
lines
|
lines
|
||||||
and tab indent
|
and tab indent
|
||||||
and escaped < brackets
|
and escaped < brackets</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
Normal text after code block
|
Normal text after code block
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
|
|
||||||
$this->assertContains($expected, $result, 'Custom code blocks with ::: prefix');
|
$this->assertContains($expected, $result, 'Custom code blocks with ::: prefix');
|
||||||
|
|
||||||
$expected = <<<HTML
|
$expected = <<<HTML
|
||||||
<pre>
|
<pre>
|
||||||
code block
|
code block
|
||||||
without formatting prefix
|
without formatting prefix</pre>
|
||||||
</pre>
|
|
||||||
HTML;
|
HTML;
|
||||||
$this->assertContains($expected, $result, 'Traditional markdown code blocks');
|
$this->assertContains($expected, $result, 'Traditional markdown code blocks');
|
||||||
|
|
||||||
|
$expected = <<<HTML
|
||||||
|
<pre class="brush: ">
|
||||||
|
Fenced code block
|
||||||
|
</pre>
|
||||||
|
HTML;
|
||||||
|
$this->assertContains($expected, $result, 'Backtick code blocks');
|
||||||
|
|
||||||
|
$expected = <<<HTML
|
||||||
|
<pre class="brush: php">
|
||||||
|
Fenced box with
|
||||||
|
|
||||||
|
new lines in
|
||||||
|
|
||||||
|
between
|
||||||
|
|
||||||
|
content
|
||||||
|
</pre>
|
||||||
|
HTML;
|
||||||
|
$this->assertContains($expected, $result, 'Backtick with newlines');
|
||||||
}
|
}
|
||||||
|
|
||||||
function testImageRewrites() {
|
function testImageRewrites() {
|
||||||
|
@ -25,6 +25,22 @@ Normal text after code block
|
|||||||
code block
|
code block
|
||||||
without formatting prefix
|
without formatting prefix
|
||||||
|
|
||||||
|
```
|
||||||
|
Fenced code block
|
||||||
|
```
|
||||||
|
|
||||||
|
Did the fence work?
|
||||||
|
|
||||||
|
```php
|
||||||
|
Fenced box with
|
||||||
|
|
||||||
|
new lines in
|
||||||
|
|
||||||
|
between
|
||||||
|
|
||||||
|
content
|
||||||
|
```
|
||||||
|
|
||||||
# Heading one
|
# Heading one
|
||||||
|
|
||||||
# Heading with custom anchor {#custom-anchor}
|
# Heading with custom anchor {#custom-anchor}
|
||||||
|
Loading…
Reference in New Issue
Block a user