Version 1
[yaffs-website] / vendor / cebe / markdown / README.md
1 A super fast, highly extensible markdown parser for PHP
2 =======================================================
3
4 [![Latest Stable Version](https://poser.pugx.org/cebe/markdown/v/stable.png)](https://packagist.org/packages/cebe/markdown)
5 [![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png)](https://packagist.org/packages/cebe/markdown)
6 [![Build Status](https://secure.travis-ci.org/cebe/markdown.png)](http://travis-ci.org/cebe/markdown)
7 [![Tested against HHVM](http://hhvm.h4cc.de/badge/cebe/markdown.png)](http://hhvm.h4cc.de/package/cebe/markdown)
8 [![Code Coverage](https://scrutinizer-ci.com/g/cebe/markdown/badges/coverage.png?s=db6af342d55bea649307ef311fbd536abb9bab76)](https://scrutinizer-ci.com/g/cebe/markdown/)
9 [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/cebe/markdown/badges/quality-score.png?s=17448ca4d140429fd687c58ff747baeb6568d528)](https://scrutinizer-ci.com/g/cebe/markdown/)
10
11 What is this? <a name="what"></a>
12 -------------
13
14 A set of [PHP][] classes, each representing a [Markdown][] flavor, and a command line tool
15 for converting markdown files to HTML files.
16
17 The implementation focus is to be **fast** (see [benchmark][]) and **extensible**.
18 Parsing Markdown to HTML is as simple as calling a single method (see [Usage](#usage)) providing a solid implementation
19 that gives most expected results even in non-trivial edge cases.
20
21 Extending the Markdown language with new elements is as simple as adding a new method to the class that converts the
22 markdown text to the expected output in HTML. This is possible without dealing with complex and error prone regular expressions.
23 It is also possible to hook into the markdown structure and add elements or read meta information using the internal representation
24 of the Markdown text as an abstract syntax tree (see [Extending the language](#extend)).
25
26 Currently the following markdown flavors are supported:
27
28 - **Traditional Markdown** according to <http://daringfireball.net/projects/markdown/syntax> ([try it!](http://markdown.cebe.cc/try?flavor=default)).
29 - **Github flavored Markdown** according to <https://help.github.com/articles/github-flavored-markdown> ([try it!](http://markdown.cebe.cc/try?flavor=gfm)).
30 - **Markdown Extra** according to <http://michelf.ca/projects/php-markdown/extra/> (currently not fully supported WIP see [#25][], [try it!](http://markdown.cebe.cc/try?flavor=extra))
31 - Any mixed Markdown flavor you like because of its highly extensible structure (See documentation below).
32
33 [#25]: https://github.com/cebe/markdown/issues/25 "issue #25"
34
35 Future plans are to support:
36
37 - Smarty Pants <http://daringfireball.net/projects/smartypants/>
38 - ... (Feel free to [suggest](https://github.com/cebe/markdown/issues/new) further additions!)
39
40 ### Who is using it?
41
42 - It powers the [API-docs and the definitive guide](http://www.yiiframework.com/doc-2.0/) for the [Yii Framework][] [2.0](https://github.com/yiisoft/yii2).
43
44 [Yii Framework]: http://www.yiiframework.com/ "The Yii PHP Framework"
45
46
47 Installation <a name="installation"></a>
48 ------------
49
50 [PHP 5.4 or higher](http://www.php.net/downloads.php) is required to use it.
51 It will also run on facebook's [hhvm](http://hhvm.com/).
52
53 Installation is recommended to be done via [composer][] by running:
54
55         composer require cebe/markdown "~1.0.1"
56
57 Alternatively you can add the following to the `require` section in your `composer.json` manually:
58
59 ```json
60 "cebe/markdown": "~1.0.1"
61 ```
62
63 Run `composer update` afterwards.
64
65
66 Usage <a name="usage"></a>
67 -----
68
69 ### In your PHP project
70
71 To parse your markdown you need only two lines of code. The first one is to choose the markdown flavor as
72 one of the following:
73
74 - Traditional Markdown: `$parser = new \cebe\markdown\Markdown();`
75 - Github Flavored Markdown: `$parser = new \cebe\markdown\GithubMarkdown();`
76 - Markdown Extra: `$parser = new \cebe\markdown\MarkdownExtra();`
77
78 The next step is to call the `parse()`-method for parsing the text using the full markdown language
79 or calling the `parseParagraph()`-method to parse only inline elements.
80
81 Here are some examples:
82
83 ```php
84 // traditional markdown and parse full text
85 $parser = new \cebe\markdown\Markdown();
86 $parser->parse($markdown);
87
88 // use github markdown
89 $parser = new \cebe\markdown\GithubMarkdown();
90 $parser->parse($markdown);
91
92 // use markdown extra
93 $parser = new \cebe\markdown\MarkdownExtra();
94 $parser->parse($markdown);
95
96 // parse only inline elements (useful for one-line descriptions)
97 $parser = new \cebe\markdown\GithubMarkdown();
98 $parser->parseParagraph($markdown);
99 ```
100
101 You may optionally set one of the following options on the parser object:
102
103 For all Markdown Flavors:
104
105 - `$parser->html5 = true` to enable HTML5 output instead of HTML4.
106 - `$parser->keepListStartNumber = true` to enable keeping the numbers of ordered lists as specified in the markdown.
107   The default behavior is to always start from 1 and increment by one regardless of the number in markdown.
108
109 For GithubMarkdown:
110
111 - `$parser->enableNewlines = true` to convert all newlines to `<br/>`-tags. By default only newlines with two preceding spaces are converted to `<br/>`-tags. 
112
113 It is recommended to use UTF-8 encoding for the input strings. Other encodings are currently not tested.
114
115 ### The command line script
116
117 You can use it to render this readme:
118
119     bin/markdown README.md > README.html
120
121 Using github flavored markdown:
122
123     bin/markdown --flavor=gfm README.md > README.html
124
125 or convert the original markdown description to html using the unix pipe:
126
127     curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html
128
129 Here is the full Help output you will see when running `bin/markdown --help`:
130
131     PHP Markdown to HTML converter
132     ------------------------------
133     
134     by Carsten Brandt <mail@cebe.cc>
135     
136     Usage:
137         bin/markdown [--flavor=<flavor>] [--full] [file.md]
138     
139         --flavor  specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used.
140                   Available flavors:
141     
142                   gfm   - Github flavored markdown [2]
143                   extra - Markdown Extra [3]
144
145         --full    ouput a full HTML page with head and body. If not given, only the parsed markdown will be output.
146
147         --help    shows this usage information.
148
149         If no file is specified input will be read from STDIN.
150
151     Examples:
152
153         Render a file with original markdown:
154
155             bin/markdown README.md > README.html
156
157         Render a file using gihtub flavored markdown:
158
159             bin/markdown --flavor=gfm README.md > README.html
160
161         Convert the original markdown description to html using STDIN:
162
163             curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html
164
165     
166     [1] http://daringfireball.net/projects/markdown/syntax
167     [2] https://help.github.com/articles/github-flavored-markdown
168     [3] http://michelf.ca/projects/php-markdown/extra/
169
170
171 Extensions
172 ----------
173
174 Here are some extensions to this library:
175
176 - [Bogardo/markdown-codepen](https://github.com/Bogardo/markdown-codepen) - shortcode to embed codepens from http://codepen.io/ in markdown.
177 - [kartik-v/yii2-markdown](https://github.com/kartik-v/yii2-markdown) - Advanced Markdown editing and conversion utilities for Yii Framework 2.0.
178 - [cebe/markdown-latex](https://github.com/cebe/markdown-latex) - Convert Markdown to LaTeX and PDF
179 - ... [add yours!](https://github.com/cebe/markdown/edit/master/README.md#L98)
180
181
182 Extending the language <a name="extend"></a>
183 ----------------------
184
185 Markdown consists of two types of language elements, I'll call them block and inline elements simlar to what you have in
186 HTML with `<div>` and `<span>`. Block elements are normally spreads over several lines and are separated by blank lines.
187 The most basic block element is a paragraph (`<p>`).
188 Inline elements are elements that are added inside of block elements i.e. inside of text.
189
190 This markdown parser allows you to extend the markdown language by changing existing elements behavior and also adding
191 new block and inline elements. You do this by extending from the parser class and adding/overriding class methods and
192 properties. For the different element types there are different ways to extend them as you will see in the following sections.
193
194 ### Adding block elements
195
196 The markdown is parsed line by line to identify each non-empty line as one of the block element types.
197 To identify a line as the beginning of a block element it calls all protected class methods who's name begins with `identify`.
198 An identify function returns true if it has identified the block element it is responsible for or false if not.
199 In the following example we will implement support for [fenced code blocks][] which are part of the github flavored markdown.
200
201 [fenced code blocks]: https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks
202                       "Fenced code block feature of github flavored markdown"
203
204 ```php
205 <?php
206
207 class MyMarkdown extends \cebe\markdown\Markdown
208 {
209         protected function identifyLine($line, $lines, $current)
210         {
211                 // if a line starts with at least 3 backticks it is identified as a fenced code block
212                 if (strncmp($line, '```', 3) === 0) {
213                         return 'fencedCode';
214                 }
215                 return parent::identifyLine($lines, $current);
216         }
217
218         // ...
219 }
220 ```
221
222 In the above, `$line` is a string containing the content of the current line and is equal to `$lines[$current]`.
223 You may use `$lines` and `$current` to check other lines than the current line. In most cases you can ignore these parameters.
224
225 Parsing of a block element is done in two steps:
226
227 1. "consuming" all the lines belonging to it. In most cases this is iterating over the lines starting from the identified
228    line until a blank line occurs. This step is implemented by a method named `consume{blockName}()` where `{blockName}`
229    is the same name as used for the identify function above. The consume method also takes the lines array
230    and the number of the current line. It will return two arguments: an array representing the block element in the abstract syntax tree
231    of the markdown document and the line number to parse next. In the abstract syntax array the first element refers to the name of
232    the element, all other array elements can be freely defined by yourself.
233    In our example we will implement it like this:
234
235    ```php
236         protected function consumeFencedCode($lines, $current)
237         {
238                 // create block array
239                 $block = [
240                         'fencedCode',
241                         'content' => [],
242                 ];
243                 $line = rtrim($lines[$current]);
244
245                 // detect language and fence length (can be more than 3 backticks)
246                 $fence = substr($line, 0, $pos = strrpos($line, '`') + 1);
247                 $language = substr($line, $pos);
248                 if (!empty($language)) {
249                         $block['language'] = $language;
250                 }
251
252                 // consume all lines until ```
253                 for($i = $current + 1, $count = count($lines); $i < $count; $i++) {
254                         if (rtrim($line = $lines[$i]) !== $fence) {
255                                 $block['content'][] = $line;
256                         } else {
257                                 // stop consuming when code block is over
258                                 break;
259                         }
260                 }
261                 return [$block, $i];
262         }
263         ```
264
265 2. "rendering" the element. After all blocks have been consumed, they are being rendered using the
266    `render{elementName}()`-method where `elementName` refers to the name of the element in the abstract syntax tree:
267
268    ```php
269         protected function renderFencedCode($block)
270         {
271                 $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : '';
272                 return "<pre><code$class>" . htmlspecialchars(implode("\n", $block['content']) . "\n", ENT_NOQUOTES, 'UTF-8') . '</code></pre>';
273         }
274    ```
275
276    You may also add code highlighting here. In general it would also be possible to render ouput in a different language than
277    HTML for example LaTeX.
278
279
280 ### Adding inline elements
281
282 Adding inline elements is different from block elements as they are parsed using markers in the text.
283 An inline element is identified by a marker that marks the beginning of an inline element (e.g. `[` will mark a possible
284 beginning of a link or `` ` `` will mark inline code).
285
286 Parsing methods for inline elements are also protected and identified by the prefix `parse`. Additionally a `@marker` annotation
287 in PHPDoc is needed to register the parse function for one or multiple markers.
288 The 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.
289 The parser method will return an array containing the element of the abstract sytnax tree and an offset of text it has
290 parsed from the input markdown. All text up to this offset will be removed from the markdown before the next marker will be searched.
291
292 As an example, we will add support for the [strikethrough][] feature of github flavored markdown:
293
294 [strikethrough]: https://help.github.com/articles/github-flavored-markdown#strikethrough "Strikethrough feature of github flavored markdown"
295
296 ```php
297 <?php
298
299 class MyMarkdown extends \cebe\markdown\Markdown
300 {
301         /**
302          * @marker ~~
303          */
304         protected function parseStrike($markdown)
305         {
306                 // check whether the marker really represents a strikethrough (i.e. there is a closing ~~)
307                 if (preg_match('/^~~(.+?)~~/', $markdown, $matches)) {
308                         return [
309                             // return the parsed tag as an element of the abstract syntax tree and call `parseInline()` to allow
310                             // other inline markdown elements inside this tag
311                                 ['strike', $this->parseInline($matches[1])],
312                                 // return the offset of the parsed text
313                                 strlen($matches[0])
314                         ];
315                 }
316                 // in case we did not find a closing ~~ we just return the marker and skip 2 characters
317                 return [['text', '~~'], 2];
318         }
319
320         // rendering is the same as for block elements, we turn the abstract syntax array into a string.
321         protected function renderStrike($element)
322         {
323                 return '<del>' . $this->renderAbsy($element[1]) . '</del>';
324         }
325 }
326 ```
327
328 ### Composing your own Markdown flavor
329
330 TBD
331
332
333 Acknowledgements <a name="ack"></a>
334 ----------------
335
336 I'd like to thank [@erusev][] for creating [Parsedown][] which heavily influenced this work and provided
337 the idea of the line based parsing approach.
338
339 [@erusev]: https://github.com/erusev "Emanuil Rusev"
340
341 FAQ <a name="faq"></a>
342 ---
343
344 ### Why another markdown parser?
345
346 While reviewing PHP markdown parsers for choosing one to use bundled with the [Yii framework 2.0][]
347 I found that most of the implementations use regex to replace patterns instead
348 of doing real parsing. This way extending them with new language elements is quite hard
349 as you have to come up with a complex regex, that matches your addition but does not mess
350 with other elements. Such additions are very common as you see on github which supports referencing
351 issues, users and commits in the comments.
352 A [real parser][] should use context aware methods that walk trough the text and
353 parse the tokens as they find them. The only implentation that I have found that uses
354 this approach is [Parsedown][] which also shows that this implementation is [much faster][benchmark]
355 than the regex way. Parsedown however is an implementation that focuses on speed and implements
356 its own flavor (mainly github flavored markdown) in one class and at the time of this writing was
357 not easily extensible.
358
359 Given the situation above I decided to start my own implementation using the parsing approach
360 from Parsedown and making it extensible creating a class for each markdown flavor that extend each
361 other in the way that also the markdown languages extend each other.
362 This allows you to choose between markdown language flavors and also provides a way to compose your
363 own flavor picking the best things from all.
364 I chose this approach as it is easier to implement and also more intuitive approach compared
365 to using callbacks to inject functionallity into the parser.
366
367
368 ### Where do I report bugs or rendering issues?
369
370 Just [open an issue][] on github, post your markdown code and describe the problem. You may also attach screenshots of the rendered HTML result to describe your problem.
371
372
373 ### How can I contribute to this library?
374
375 Check the [CONTRIBUTING.md](CONTRIBUTING.md) file for more info.
376
377
378 ### Am I free to use this?
379
380 This library is open source and licensed under the [MIT License][]. This means that you can do whatever you want
381 with it as long as you mention my name and include the [license file][license]. Check the [license][] for details.
382
383 [MIT License]: http://opensource.org/licenses/MIT
384
385
386 Contact
387 -------
388
389 Feel free to contact me using [email](mailto:mail@cebe.cc) or [twitter](https://twitter.com/cebe_cc).
390
391
392 [PHP]: http://php.net/ "PHP is a popular general-purpose scripting language that is especially suited to web development."
393 [Markdown]: http://en.wikipedia.org/wiki/Markdown "Markdown on Wikipedia"
394 [composer]: https://getcomposer.org/ "The PHP package manager"
395 [Parsedown]: http://parsedown.org/ "The Parsedown PHP Markdown parser"
396 [benchmark]: https://github.com/kzykhys/Markbench#readme "kzykhys/Markbench on github"
397 [Yii framework 2.0]: https://github.com/yiisoft/yii2
398 [real parser]: http://en.wikipedia.org/wiki/Parsing#Types_of_parser
399 [open an issue]: https://github.com/cebe/markdown/issues/new
400 [license]: https://github.com/cebe/markdown/blob/master/LICENSE