diff --git a/.gitignore b/.gitignore index b150d9a..669d0be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.idea/ composer.lock /vendor +README.html diff --git a/README.md b/README.md index 67c4bad..285789d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A super fast, highly extensible markdown parser for PHP [![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png)](https://packagist.org/packages/cebe/markdown) [![Build Status](https://secure.travis-ci.org/cebe/markdown.png)](http://travis-ci.org/cebe/markdown) -[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/cebe/markdown/badges/quality-score.png?s=17448ca4d140429fd687c58ff747baeb6568d528)](https://scrutinizer-ci.com/g/cebe/markdown/) + [![Code Coverage](https://scrutinizer-ci.com/g/cebe/markdown/badges/coverage.png?s=db6af342d55bea649307ef311fbd536abb9bab76)](https://scrutinizer-ci.com/g/cebe/markdown/) Already supported: @@ -37,9 +37,20 @@ Usage ### In your PHP project +To use the parser as is, you just create an instance of a provided flavor and call the `parse()`- +or `parseParagraph()`-method: + + // default markdown and parse full text $parser = new \cebe\markdown\Markdown(); $parser->parse($markdown); + // use github + $parser = new \cebe\markdown\GithubMarkdown(); + $parser->parse($markdown); + + // parse only inline elements (useful for one-line descriptions) + $parser = new \cebe\markdown\GithubMarkdown(); + $parser->parseParagraph($markdown); ### The command line script @@ -52,10 +63,136 @@ or convert the original markdown description to html using the unix pipe: curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html -Extending ---------- +Extending the language +---------------------- -TBD +Markdown consists of two types of language elements, I'll call them block and inline elements simlar to what you have in +HTML with `
`). +Inline elements are elements that are added inside of block elements i.e. inside of text. + +This markdown parser allows you to extend the markdown language by changing existing elements behavior and also adding +new block and inline elements. You do this by extending from the parser class and adding/overriding class methods and +properties. For the different element types there are different ways to extend them as you will see in the following sections. + +### Adding block elements + +The markdown is parsed line by line to identify each non-empty line as one of the block element types. +This job is performed by the `indentifyLine()` method which takes the array of lines and the number of the current line +to identify as an argument. This method returns the name of the identified block element which will then be used to parse it. +In the following example we will implement support for [fenced code blocks][] which are part of the github flavored markdown. + +[fenced code blocks]: https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks "Fenced code block feature of github flavored markdown" + + 'fencedCode', + 'content' => [], + ]; + $line = rtrim($lines[$current]); + + // detect language and fence length (can be more than 3 backticks) + $fence = substr($line, 0, $pos = strrpos($line, '`') + 1); + $language = substr($line, $pos); + if (!empty($language)) { + $block['language'] = $language; + } + + // consume all lines until ``` + for($i = $current + 1, $count = count($lines); $i < $count; $i++) { + if (rtrim($line = $lines[$i]) !== $fence) { + $block['content'][] = $line; + } else { + // stop consuming when code block is over + break; + } + } + return [$block, $i]; + } + +2. "rendering" the element. After all blocks have been consumed, they are beeing rendered using the `render{blockName}()` + method: + + protected function renderFencedCode($block) + { + $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : ''; + return "
" . htmlspecialchars(implode("\n", $block['content']) . "\n", ENT_NOQUOTES, 'UTF-8') . '
';
+ }
+
+ You may also add code highlighting here. In general it would also be possible to render ouput in a different language than
+ HTML for example LaTeX.
+
+
+### Adding inline elements
+
+Adding inline elements is different from block elements as they are directly parsed in the text where they occur.
+An inline element is identified by a marker that marks the beginning of an inline element (e.g. `[` will mark a possible
+beginning of a link or `` ` `` will mark inline code).
+
+Inline markers are declared in the `inlineMarkers()`-method which returns a map from marker to parser method. That method
+will then be called when a marker is found in the text. As an argument it takes the text starting at the position of the marker.
+The parser method will return an array containing the text to append to the parsed markup and an offset of text it has
+parsed from the input markdown. All text up to this offset will be removed from the markdown before the next marker will be searched.
+
+As an example, we will add support for the [strikethrough][] feature of github flavored markdown:
+
+[strikethrough]: https://help.github.com/articles/github-flavored-markdown#strikethrough "Strikethrough feature of github flavored markdown"
+
+ 'parseStrike',
+ ];
+ // merge new markers with existing ones from parent class
+ return array_merge(parent::inlineMarkers(), $markers);
+ }
+
+ protected function parseStrike($markdown)
+ {
+ // check whether the marker really represents a strikethrough (i.e. there is a closing ~~)
+ if (preg_match('/^~~(.+?)~~/', $markdown, $matches)) {
+ return [
+ // return the parsed tag with its content and call `parseInline()` to allow
+ // other inline markdown elements inside this tag
+ '