From 3c541b580b56fda52ca4200fc2d37582cb7f7108 Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Mon, 15 Oct 2012 12:24:11 +0200 Subject: [PATCH] Removed hard dependency on MarkdownParser code, now uses `dflydev/markdown` library Refactored way how parsers are initialized, and allow to select parser while rendering Interface `MarkdownParserInterface` method name was changed from `#transform($text)` to `#transformMarkdown($text)` --- .../Compiler/ParsersCompilerPass.php | 37 + DependencyInjection/KnpMarkdownExtension.php | 19 +- Helper/MarkdownHelper.php | 52 +- KnpMarkdownBundle.php | 10 +- MarkdownParserInterface.php | 3 +- Parser/MarkdownParser.php | 100 +- Parser/Preset/Light.php | 5 +- Parser/Preset/Medium.php | 5 +- Parser/Preset/Min.php | 2 - Parser/SundownParser.php | 4 +- README.markdown | 95 +- Resources/config/helper.xml | 23 +- Resources/config/parser.xml | 25 +- Resources/config/twig.xml | 2 - Tests/FeatureTest.php | 11 +- Tests/PresetTest.php | 3 - Twig/Extension/MarkdownTwigExtension.php | 4 +- composer.json | 9 +- vendor/parser/LICENSE | 40 - vendor/parser/MarkdownExtraParser.php | 1321 -------------- vendor/parser/MarkdownParser.php | 1528 ----------------- vendor/parser/README.markdown | 179 -- 22 files changed, 257 insertions(+), 3220 deletions(-) create mode 100644 DependencyInjection/Compiler/ParsersCompilerPass.php delete mode 100644 vendor/parser/LICENSE delete mode 100644 vendor/parser/MarkdownExtraParser.php delete mode 100644 vendor/parser/MarkdownParser.php delete mode 100644 vendor/parser/README.markdown diff --git a/DependencyInjection/Compiler/ParsersCompilerPass.php b/DependencyInjection/Compiler/ParsersCompilerPass.php new file mode 100644 index 0000000..4e0c211 --- /dev/null +++ b/DependencyInjection/Compiler/ParsersCompilerPass.php @@ -0,0 +1,37 @@ +hasDefinition('templating.helper.markdown')) { + return; + } + + if (!$container->hasDefinition('markdown.parser')) { + return; + } + + $defaultParserTag = $container->getDefinition('markdown.parser')->getTag('markdown.parser'); + + $definition = $container->getDefinition('templating.helper.markdown'); + + foreach ($container->findTaggedServiceIds('markdown.parser') as $id => $tags) { + if ($defaultParserTag == $id) { + $definition->addMethodCall('addParser', array(new Reference($id), 'default')); + continue; + } + + foreach ($tags as $attributes) { + $alias = empty($attributes['alias']) ? $id : $attributes['alias']; + $definition->addMethodCall('addParser', array(new Reference($id), $alias)); + } + } + } +} diff --git a/DependencyInjection/KnpMarkdownExtension.php b/DependencyInjection/KnpMarkdownExtension.php index 62e2feb..c0c3e28 100644 --- a/DependencyInjection/KnpMarkdownExtension.php +++ b/DependencyInjection/KnpMarkdownExtension.php @@ -2,20 +2,21 @@ namespace Knp\Bundle\MarkdownBundle\DependencyInjection; -use Symfony\Component\Config\Definition\Processor; -use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; class KnpMarkdownExtension extends Extension { /** * Handles the knp_markdown configuration. * - * @param array $configs The configurations being loaded + * @param array $configs The configurations being loaded * @param ContainerBuilder $container + * + * @throws InvalidConfigurationException When Sundown parser was selected, but extension is not available */ public function load(array $configs , ContainerBuilder $container) { @@ -28,12 +29,12 @@ class KnpMarkdownExtension extends Extension $loader->load('helper.xml'); $loader->load('twig.xml'); + if ($config['parser']['service'] == 'markdown.parser.sundown' && !class_exists('Sundown\Markdown')) { + throw new InvalidConfigurationException('Sundown parser selected, but required extension is not installed or configured.'); + } + $container->setParameter('markdown.sundown.extensions', $config['sundown']['extensions']); $container->setParameter('markdown.sundown.render_flags', $config['sundown']['render_flags']); $container->setAlias('markdown.parser', $config['parser']['service']); - - if ($config['parser']['service'] == 'markdown.parser.sundown' && !class_exists('Sundown\Markdown')) { - throw new InvalidConfigurationException('Sundown extension not installed or configured.'); - } } } diff --git a/Helper/MarkdownHelper.php b/Helper/MarkdownHelper.php index 6b0f505..e4d3718 100644 --- a/Helper/MarkdownHelper.php +++ b/Helper/MarkdownHelper.php @@ -8,14 +8,43 @@ use Knp\Bundle\MarkdownBundle\MarkdownParserInterface; class MarkdownHelper implements HelperInterface { /** - * @var MarkdownParserInterface + * @var MarkdownParserInterface[] */ - protected $parser; - protected $charset = 'UTF-8'; + private $parsers = array(); + private $charset = 'UTF-8'; - public function __construct(MarkdownParserInterface $parser) + /** + * @param MarkdownParserInterface $parser + * @param string $alias + */ + public function addParser(MarkdownParserInterface $parser, $alias) { - $this->parser = $parser; + $this->parsers[$alias] = $parser; + } + + /** + * Transforms markdown syntax to HTML + * + * @param string $markdownText The markdown syntax text + * @param null|string $parserName + * + * @return string The HTML code + * + * @throws \RuntimeException + */ + public function transform($markdownText, $parserName = null) + { + if (null === $parserName) { + $parserName = 'default'; + } + + if (!isset($this->parsers[$parserName])) { + throw new \RuntimeException(sprintf('Unknown parser selected ("%s"), available are: %s', $parserName, implode(', ', array_keys($this->parsers)))); + } + + $parser = $this->parsers[$parserName]; + + return $parser->transformMarkdown($markdownText); } /** @@ -38,18 +67,11 @@ class MarkdownHelper implements HelperInterface return $this->charset; } + /** + * {@inheritDoc} + */ public function getName() { return 'markdown'; } - - /** - * Transforms markdown syntax to HTML - * @param string $markdownText The markdown syntax text - * @return string The HTML code - */ - public function transform($markdownText) - { - return $this->parser->transform($markdownText); - } } diff --git a/KnpMarkdownBundle.php b/KnpMarkdownBundle.php index 98544e5..2b18c89 100644 --- a/KnpMarkdownBundle.php +++ b/KnpMarkdownBundle.php @@ -2,8 +2,14 @@ namespace Knp\Bundle\MarkdownBundle; -use Symfony\Component\HttpKernel\Bundle\Bundle as BaseBundle; +use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Knp\Bundle\MarkdownBundle\DependencyInjection\Compiler\ParsersCompilerPass; -class KnpMarkdownBundle extends BaseBundle +class KnpMarkdownBundle extends Bundle { + public function build(ContainerBuilder $container) + { + $container->addCompilerPass(new ParsersCompilerPass()); + } } diff --git a/MarkdownParserInterface.php b/MarkdownParserInterface.php index 6db18ad..1cfe2d1 100644 --- a/MarkdownParserInterface.php +++ b/MarkdownParserInterface.php @@ -8,7 +8,8 @@ interface MarkdownParserInterface * Converts text to html using markdown rules * * @param string $text plain text + * * @return string rendered html */ - function transform($text); + function transformMarkdown($text); } diff --git a/Parser/MarkdownParser.php b/Parser/MarkdownParser.php index 9bc63cd..a09e2fa 100644 --- a/Parser/MarkdownParser.php +++ b/Parser/MarkdownParser.php @@ -4,9 +4,7 @@ namespace Knp\Bundle\MarkdownBundle\Parser; use Knp\Bundle\MarkdownBundle\MarkdownParserInterface; -if(!class_exists('\MarkdownExtraParser')) { - require_once(realpath(__DIR__.'/..').'/vendor/parser/MarkdownExtraParser.php'); -} +use dflydev\markdown\MarkdownExtraParser; /** * MarkdownParser @@ -14,12 +12,12 @@ if(!class_exists('\MarkdownExtraParser')) { * This class extends the original Markdown parser. * It allows to disable unwanted features to increase performances. */ -class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInterface +class MarkdownParser extends MarkdownExtraParser implements MarkdownParserInterface { - /** - * @var array enabled features - * use the constructor to disable some of them + * Use the constructor to disable some of them + * + * @var array Enabled features */ protected $features = array( 'header' => true, @@ -90,20 +88,32 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter if (!$this->features['reference_link']) { unset($this->document_gamut['stripLinkDefinitions']); } - if(!$this->features['block_quote']) { + if (!$this->features['block_quote']) { unset($this->block_gamut['doBlockQuotes']); } - if(!$this->features['code_block']) { + if (!$this->features['code_block']) { unset($this->block_gamut['doCodeBlocks']); } - if(!$this->features['auto_link']) { + if (!$this->features['auto_link']) { unset($this->span_gamut['doAutoLinks']); } - if(!$this->features['entities'] && !$this->features['no_html']) { + if (!$this->features['entities'] && !$this->features['no_html']) { $this->no_entities = true; } } + /** + * {@inheritDoc} + */ + public function transformMarkdown($text) + { + if ($this->features['no_html']) { + $text = htmlspecialchars($text, ENT_NOQUOTES); + } + + return parent::transformMarkdown($text); + } + /** * MarkdownExtraParser overwritten methods */ @@ -111,11 +121,12 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter /** * Simplify detab */ - protected function detab($text) + public function detab($text) { return str_replace("\t", str_repeat(' ', $this->tab_width), $text); } - protected function _initDetab() + + public function _initDetab() { return; } @@ -123,7 +134,7 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter /** * Disable unless html_block */ - protected function hashHTMLBlocks($text) + public function hashHTMLBlocks($text) { if (!$this->features['html_block']) { return $text; @@ -135,12 +146,10 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter /** * Disable mailto unless auto_mailto */ - protected function doAutoLinks($text) + public function doAutoLinks($text) { - if(!$this->features['auto_mailto']) - { - return preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', - array(&$this, '_doAutoLinks_url_callback'), $text); + if (!$this->features['auto_mailto']) { + return preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', array(&$this, '_doAutoLinks_url_callback'), $text); } return parent::doAutoLinks($text); @@ -149,13 +158,14 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter /** * Conditional features: reference_link, inline_link, */ - protected function doAnchors($text) + public function doAnchors($text) { # # Turn Markdown link shortcuts into XHTML tags. # - if ($this->in_anchor) + if ($this->in_anchor) { return $text; + } $this->in_anchor = true; # @@ -163,16 +173,16 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter # if ($this->features['reference_link']) { $text = preg_replace_callback('{ - ( # wrap whole match in $1 + ( # wrap whole match in $1 \[ ('.$this->nested_brackets_re.') # link text = $2 \] - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces \[ - (.*?) # id = $3 + (.*?) # id = $3 \] ) }xs', @@ -184,24 +194,24 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter # if ($this->features['inline_link']) { $text = preg_replace_callback('{ - ( # wrap whole match in $1 + ( # wrap whole match in $1 \[ ('.$this->nested_brackets_re.') # link text = $2 \] - \( # literal paren + \( # literal parent [ \n]* (?: - <(.+?)> # href = $3 + <(.+?)> # href = $3 | ('.$this->nested_url_parenthesis_re.') # href = $4 ) [ \n]* - ( # $5 - ([\'"]) # quote char = $6 - (.*?) # Title = $7 - \6 # matching quote - [ \n]* # ignore any spaces/tabs between closing quote and ) - )? # title is optional + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # Title = $7 + \6 # matching quote + [ \n]* # ignore any spaces/tabs between closing quote and ) + )? # title is optional \) ) }xs', @@ -215,9 +225,9 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter # if ($this->features['shortcut_link']) { $text = preg_replace_callback('{ - ( # wrap whole match in $1 + ( # wrap whole match in $1 \[ - ([^\[\]]+) # link text = $2; can\'t contain [ or ] + ([^\[\]]+) # link text = $2; can\'t contain [ or ] \] ) }xs', @@ -225,18 +235,11 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter } $this->in_anchor = false; + return $text; } - public function transform($text) - { - if ($this->features['no_html']) { - $text = htmlspecialchars($text, ENT_NOQUOTES); - } - return parent::transform($text); - } - - protected function _doCodeBlocks_callback($matches) + public function _doCodeBlocks_callback($matches) { $codeblock = $matches[1]; @@ -247,12 +250,12 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter # trim leading newlines and trailing newlines $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock); - $codeblock = "
$codeblock\n
"; + return "\n\n".$this->hashBlock($codeblock)."\n\n"; } - protected function makeCodeSpan($code) + public function makeCodeSpan($code) { if (!$this->features['no_html']) { $code = htmlspecialchars(trim($code), ENT_NOQUOTES); @@ -263,7 +266,7 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter return $this->hashPart("$code"); } - protected function _doFencedCodeBlocks_callback($matches) + public function _doFencedCodeBlocks_callback($matches) { $codeblock = $matches[2]; if (!$this->features['no_html']) { @@ -272,6 +275,7 @@ class MarkdownParser extends \MarkdownExtraParser implements MarkdownParserInter $codeblock = preg_replace_callback('/^\n+/', array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); $codeblock = "
$codeblock
"; + return "\n\n".$this->hashBlock($codeblock)."\n\n"; } } diff --git a/Parser/Preset/Light.php b/Parser/Preset/Light.php index f25e177..603f920 100644 --- a/Parser/Preset/Light.php +++ b/Parser/Preset/Light.php @@ -9,7 +9,9 @@ use Knp\Bundle\MarkdownBundle\Parser\MarkdownParser; */ class Light extends MarkdownParser { - + /** + * @var array Enabled features + */ protected $features = array( 'header' => true, 'list' => true, @@ -30,5 +32,4 @@ class Light extends MarkdownParser 'entities' => false, 'no_html' => false, ); - } diff --git a/Parser/Preset/Medium.php b/Parser/Preset/Medium.php index b569113..d47ba7a 100644 --- a/Parser/Preset/Medium.php +++ b/Parser/Preset/Medium.php @@ -9,7 +9,9 @@ use Knp\Bundle\MarkdownBundle\Parser\MarkdownParser; */ class Medium extends MarkdownParser { - + /** + * @var array Enabled features + */ protected $features = array( 'header' => true, 'list' => true, @@ -30,5 +32,4 @@ class Medium extends MarkdownParser 'entities' => false, 'no_html' => false, ); - } diff --git a/Parser/Preset/Min.php b/Parser/Preset/Min.php index 5489a9d..2a4646b 100644 --- a/Parser/Preset/Min.php +++ b/Parser/Preset/Min.php @@ -9,7 +9,6 @@ use Knp\Bundle\MarkdownBundle\Parser\MarkdownParser; */ class Min extends MarkdownParser { - public function __construct(array $features = array()) { foreach ($this->features as $name => $enabled) { @@ -18,6 +17,5 @@ class Min extends MarkdownParser return parent::__construct($features); } - } diff --git a/Parser/SundownParser.php b/Parser/SundownParser.php index a512328..572bc7d 100644 --- a/Parser/SundownParser.php +++ b/Parser/SundownParser.php @@ -23,8 +23,8 @@ class SundownParser implements MarkdownParserInterface /** * {@inheritdoc} */ - public function transform($text) + public function transformMarkdown($text) { return $this->parser->render($text); } -} \ No newline at end of file +} diff --git a/README.markdown b/README.markdown index bf51c5c..ac6a25e 100644 --- a/README.markdown +++ b/README.markdown @@ -1,52 +1,83 @@ -Provide markdown conversion to your Symfony2 projects. - -This implementation is based on Michel Fortin work. -We added PHP5 sugar, feature selection, and unit tests. +Provide markdown conversion (based on Michel Fortin work) to your Symfony2 projects. [![Build Status](https://secure.travis-ci.org/KnpLabs/KnpMarkdownBundle.png)](http://travis-ci.org/KnpLabs/KnpMarkdownBundle) ## INSTALLATION -Add the following entry to ``deps`` the run ``php bin/vendors install``. +Symfony 2.0) Add the following entry to ``deps`` the run ``php bin/vendors install``. - [KnpMarkdownBundle] - git=http://github.com/KnpLabs/KnpMarkdownBundle.git - target=/bundles/Knp/Bundle/MarkdownBundle +``` +[KnpMarkdownBundle] + git=https://github.com/KnpLabs/KnpMarkdownBundle + target=/bundles/Knp/Bundle/MarkdownBundle -Register the bundle in ``app/AppKernel.php`` +[dflydev-markdown] + git=https://github.com/dflydev/dflydev-markdown + target=dflydev-markdown +``` - $bundles = array( - // ... - new Knp\Bundle\MarkdownBundle\KnpMarkdownBundle(), - ); +And register namespace in ``app/autoload.php`` -Register namespace in ``app/autoload.php`` +```php +$loader->registerNamespaces(array( + // ... + 'dflydev' => __DIR__.'/../vendor/dflydev-markdown/src' + 'Knp' => __DIR__.'/../vendor/bundles', +)); +``` - $loader->registerNamespaces(array( - // ... - 'Knp' => __DIR__.'/../vendor/bundles', - )); +Symfony 2.1) Add HWIOAuthBundle to your `composer.json` + +```yaml +{ + "require": { + "knplabs/knp-markdown-bundle": "1.2.*@dev" + } +} +``` + +Symfony 2.0 & 2.1) Register the bundle in ``app/AppKernel.php`` + +```php +$bundles = array( + // ... + new Knp\Bundle\MarkdownBundle\KnpMarkdownBundle(), +); +``` ## USAGE - // Use the service - $html = $this->container->get('markdown.parser')->transform($text); +```php +// Use the service +$html = $this->container->get('markdown.parser')->transformMarkdown($text); - // Use the helper - echo $view['markdown']->transform($text); +// Use the helper with default parser +echo $view['markdown']->transform($text); + +// Use the helper and a select specific parser +echo $view['markdown']->transform($text, $parserName); +``` If you have enabled the Twig markdown filter, you can use the following in your Twig templates: - {{ my_data | markdown }} +```twig +{# Use default parser #} +{{ my_data|markdown }} + +{# Or select specific parser #} +{{ my_data|markdown('parserName') }} +``` ## Change the parser implementation -Create a service implementing Knp\Bundle\MarkdownBundle\MarkdownParserInterface, +Create a service implementing `Knp\Bundle\MarkdownBundle\MarkdownParserInterface`, then configure the bundle to use it: - knp_markdown: - parser: - service: my.markdown.parser +```yaml +knp_markdown: + parser: + service: my.markdown.parser +``` Alternatively if you are using the ``markdown.parser.sundown`` there are options for enabling sundown extensions and render flags, see the @@ -58,11 +89,11 @@ This bundle comes with 5 parser services, 4 based on the same algorithm but providing different levels of compliance to the markdown specification, and one which is uses the php sundown extension: -- markdown.parser.max // fully compliant = slower (default implementation) -- markdown.parser.medium // expensive and uncommon features dropped -- markdown.parser.light // expensive features dropped -- markdown.parser.min // most features dropped = faster -- markdown.parser.sundown // faster and fully compliant (recommended) + - markdown.parser.max // fully compliant = slower (default implementation) + - markdown.parser.medium // expensive and uncommon features dropped + - markdown.parser.light // expensive features dropped + - markdown.parser.min // most features dropped = faster + - markdown.parser.sundown // faster and fully compliant (recommended) ``markdown.parser.sundown`` requires [php sundown extension](https://github.com/chobie/php-sundown). diff --git a/Resources/config/helper.xml b/Resources/config/helper.xml index b910745..cb6a54e 100644 --- a/Resources/config/helper.xml +++ b/Resources/config/helper.xml @@ -1,21 +1,16 @@ - - + + Knp\Bundle\MarkdownBundle\Helper\MarkdownHelper + - Knp\Bundle\MarkdownBundle\Helper\MarkdownHelper - - - - - - - - - - - + + + + + + diff --git a/Resources/config/parser.xml b/Resources/config/parser.xml index 164b92a..83762ad 100644 --- a/Resources/config/parser.xml +++ b/Resources/config/parser.xml @@ -1,21 +1,29 @@ - - - - - + + + + + + + + + + + + - - + + + - + %markdown.sundown.extensions% @@ -23,5 +31,4 @@ %markdown.sundown.render_flags% - diff --git a/Resources/config/twig.xml b/Resources/config/twig.xml index 7605640..339f795 100644 --- a/Resources/config/twig.xml +++ b/Resources/config/twig.xml @@ -1,5 +1,4 @@ - @@ -10,5 +9,4 @@ - diff --git a/Tests/FeatureTest.php b/Tests/FeatureTest.php index 69c1c41..23726eb 100644 --- a/Tests/FeatureTest.php +++ b/Tests/FeatureTest.php @@ -6,7 +6,6 @@ use Knp\Bundle\MarkdownBundle\Parser\MarkdownParser as Parser; class FeatureTest extends \PHPUnit_Framework_TestCase { - public function testParser() { $parser = new Parser(); @@ -131,7 +130,7 @@ EOF; sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

- +

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.

@@ -156,11 +155,11 @@ EOF; $html = <<

Ceci est le premier niveau de citation.

- +

Ceci est un bloc de citation imbriqué.

- +

Retour au premier niveau.

@@ -188,12 +187,12 @@ EOF; $html = <<

This is a header.

- +
  1. This is the first list item.
  2. This is the second list item.
- +

Here's some example code:

return shell_exec("echo \$input | \$markdown_script");
diff --git a/Tests/PresetTest.php b/Tests/PresetTest.php
index 8628904..cc7aaf0 100644
--- a/Tests/PresetTest.php
+++ b/Tests/PresetTest.php
@@ -2,13 +2,10 @@
 
 namespace Knp\Bundle\MarkdownBundle\Tests;
 
-use Knp\Bundle\MarkdownBundle\Parser\MarkdownParser as Parser;
-
 use Knp\Bundle\MarkdownBundle\Parser\Preset as Preset;
 
 class PresetTest extends \PHPUnit_Framework_TestCase
 {
-
     public function testMax()
     {
         $parser = new Preset\Max();
diff --git a/Twig/Extension/MarkdownTwigExtension.php b/Twig/Extension/MarkdownTwigExtension.php
index 51bd629..859fde9 100644
--- a/Twig/Extension/MarkdownTwigExtension.php
+++ b/Twig/Extension/MarkdownTwigExtension.php
@@ -20,9 +20,9 @@ class MarkdownTwigExtension extends \Twig_Extension
         );
     }
 
-    public function markdown($txt)
+    public function markdown($text, $parser = null)
     {
-        return $this->helper->transform($txt);
+        return $this->helper->transform($text, $parser);
     }
 
     public function getName()
diff --git a/composer.json b/composer.json
index de2f316..b2a9e3d 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,8 @@
 
     "require": {
         "php":                      ">=5.3.3",
-        "symfony/framework-bundle": ">=2.0,<2.3-dev"
+        "symfony/framework-bundle": ">=2.0,<2.3-dev",
+        "dflydev/markdown":         "1.0.*@dev"
     },
 
     "suggest": {
@@ -27,6 +28,12 @@
         "ext-sundown": "to use optional support for php-sundown extension instead of php implementation"
     },
 
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.2.x-dev"
+        }
+    },
+
     "autoload": {
         "psr-0": {
             "Knp\\Bundle\\MarkdownBundle": ""
diff --git a/vendor/parser/LICENSE b/vendor/parser/LICENSE
deleted file mode 100644
index 03b35ea..0000000
--- a/vendor/parser/LICENSE
+++ /dev/null
@@ -1,40 +0,0 @@
-PHP Markdown
-Copyright (c) 2010 knplabs
-
-
-Based on Markdown
-Copyright (c) 2004-2009 Michel Fortin
-
-All rights reserved.
-
-Based on Markdown
-Copyright (c) 2003-2006 John Gruber   
-   
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright notice,
-  this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-
-* Neither the name "Markdown" nor the names of its contributors may
-  be used to endorse or promote products derived from this software
-  without specific prior written permission.
-
-This software is provided by the copyright holders and contributors "as
-is" and any express or implied warranties, including, but not limited
-to, the implied warranties of merchantability and fitness for a
-particular purpose are disclaimed. In no event shall the copyright owner
-or contributors be liable for any direct, indirect, incidental, special,
-exemplary, or consequential damages (including, but not limited to,
-procurement of substitute goods or services; loss of use, data, or
-profits; or business interruption) however caused and on any theory of
-liability, whether in contract, strict liability, or tort (including
-negligence or otherwise) arising in any way out of the use of this
-software, even if advised of the possibility of such damage.
diff --git a/vendor/parser/MarkdownExtraParser.php b/vendor/parser/MarkdownExtraParser.php
deleted file mode 100644
index e6f1b67..0000000
--- a/vendor/parser/MarkdownExtraParser.php
+++ /dev/null
@@ -1,1321 +0,0 @@
-escape_chars .= ':|';
-
-        # Insert extra document, block, and span transformations.
-        # Parent constructor will do the sorting.
-        $this->document_gamut += array(
-            "doFencedCodeBlocks" => 5,
-            "stripFootnotes" => 15,
-            "stripAbbreviations" => 25,
-            "appendFootnotes" => 50,
-        );
-        $this->block_gamut += array(
-            "doFencedCodeBlocks" => 5,
-            "doTables" => 15,
-            "doDefLists" => 45,
-        );
-        $this->span_gamut += array(
-            "doFootnotes" => 5,
-            "doAbbreviations" => 70,
-        );
-
-        parent::__construct();
-    }
-
-    protected function setup()
-    {
-        #
-        # Setting up Extra-specific variables.
-        #
-        parent::setup();
-
-        $this->footnotes = array();
-        $this->footnotes_ordered = array();
-        $this->abbr_desciptions = array();
-        $this->abbr_word_re = '';
-        $this->footnote_counter = 1;
-
-        foreach ($this->predef_abbr as $abbr_word => $abbr_desc)
-        {
-            if ($this->abbr_word_re)
-                $this->abbr_word_re .= '|';
-            $this->abbr_word_re .= preg_quote($abbr_word);
-            $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
-        }
-    }
-
-    protected function teardown()
-    {
-        #
-        # Clearing Extra-specific variables.
-        #
-        $this->footnotes = array();
-        $this->footnotes_ordered = array();
-        $this->abbr_desciptions = array();
-        $this->abbr_word_re = '';
-
-        parent::teardown();
-    }
-
-    ### HTML Block Parser ###
-    # Tags that are always treated as block tags:
-
-    var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
-
-    # Tags treated as block tags only if the opening tag is alone on it's line:
-    var $context_block_tags_re = 'script|noscript|math|ins|del';
-
-    # Tags where markdown="1" default to span mode:
-    var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
-
-    # Tags which must not have their contents modified, no matter where
-    # they appear:
-    var $clean_tags_re = 'script|math';
-
-    # Tags that do not need to be closed.
-    var $auto_close_tags_re = 'hr|img';
-
-    protected function hashHTMLBlocks($text)
-    {
-        #
-        # Hashify HTML Blocks and "clean tags".
-        #
-        # We only want to do this for block-level HTML tags, such as headers,
-        # lists, and tables. That's because we still want to wrap 

s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded. - # - # This works by calling _HashHTMLBlocks_InMarkdown, which then calls - # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" - # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back - # _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag. - # These two functions are calling each other. It's recursive! - # - # - # Call the HTML-in-Markdown hasher. - # - list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text); - - return $text; - } - - protected function _hashHTMLBlocks_inMarkdown($text, $indent = 0, $enclosing_tag_re = '', $span = false) - { - # - # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags. - # - # * $indent is the number of space to be ignored when checking for code - # blocks. This is important because if we don't take the indent into - # account, something like this (which looks right) won't work as expected: - # - #

- #
- # Hello World. <-- Is this a Markdown code block or text? - #
<-- Is this a Markdown code block or a real tag? - #
- # - # If you don't like this, just don't indent the tag on which - # you apply the markdown="1" attribute. - # - # * If $enclosing_tag_re is not empty, stops at the first unmatched closing - # tag with that name. Nested tags supported. - # - # * If $span is true, text inside must treated as span. So any double - # newline will be replaced by a single newline so that it does not create - # paragraphs. - # - # Returns an array of that form: ( processed text , remaining text ) - # - if ($text === '') - return array('', ''); - - # Regex to check for the presense of newlines around a block tag. - $newline_before_re = '/(?:^\n?|\n\n)*$/'; - $newline_after_re = - '{ - ^ # Start of text following the tag. - (?>[ ]*)? # Optional comment. - [ ]*\n # Must be followed by newline. - }xs'; - - # Regex to match any tag. - $block_tag_re = - '{ - ( # $2: Capture hole tag. - # Tag name. - '.$this->block_tags_re.' | - '.$this->context_block_tags_re.' | - '.$this->clean_tags_re.' | - (?!\s)'.$enclosing_tag_re.' - ) - (?: - (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. - (?> - ".*?" | # Double quotes (can contain `>`) - \'.*?\' | # Single quotes (can contain `>`) - .+? # Anything but quotes and `>`. - )*? - )? - > # End of tag. - | - # HTML Comment - | - <\?.*?\?> | <%.*?%> # Processing instruction - | - # CData Block - | - # Code span marker - `+ - '.(!$span ? ' # If not in span. - | - # Indented code block - (?: ^[ ]*\n | ^ | \n[ ]*\n ) - [ ]{'.($indent + 4).'}[^\n]* \n - (?> - (?: [ ]{'.($indent + 4).'}[^\n]* | [ ]* ) \n - )* - | - # Fenced code block marker - (?> ^ | \n ) - [ ]{'.($indent).'}~~~+[ ]*\n - ' : '' ).' # End (if not is span). - ) - }xs'; - - - $depth = 0; # Current depth inside the tag tree. - $parsed = ""; # Parsed text that will be returned. - # - # Loop through every tag until we find the closing tag of the parent - # or loop until reaching the end of text if no parent tag specified. - # - do - { - # - # Split the text using the first $tag_match pattern found. - # Text before pattern will be first in the array, text after - # pattern will be at the end, and between will be any catches made - # by the pattern. - # - $parts = preg_split($block_tag_re, $text, 2, - PREG_SPLIT_DELIM_CAPTURE); - - # If in Markdown span mode, add a empty-string span-level hash - # after each newline to prevent triggering any block element. - if ($span) - { - $void = $this->hashPart("", ':'); - $newline = "$void\n"; - $parts[0] = $void.str_replace("\n", $newline, $parts[0]).$void; - } - - $parsed .= $parts[0]; # Text before current tag. - # If end of $text has been reached. Stop loop. - if (count($parts) < 3) - { - $text = ""; - break; - } - - $tag = $parts[1]; # Tag to handle. - $text = $parts[2]; # Remaining text after current tag. - $tag_re = preg_quote($tag); # For use in a regular expression. - # - # Check for: Code span marker - # - if ($tag{0} == "`") - { - # Find corresponding end marker. - $tag_re = preg_quote($tag); - if (preg_match('{^(?>.+?|\n(?!\n))*?(?.*\n)+?'.$tag_re.' *\n}', $text, - $matches)) - { - # End marker found: pass text unchanged until marker. - $parsed .= $tag.$matches[0]; - $text = substr($text, strlen($matches[0])); - } - else - { - # No end marker: just skip it. - $parsed .= $tag; - } - } - # - # Check for: Opening Block level tag or - # Opening Context Block tag (like ins and del) - # used as a block tag (tag is alone on it's line). - # - else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) || - ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) && - preg_match($newline_before_re, $parsed) && - preg_match($newline_after_re, $text) ) - ) - { - # Need to parse tag and following text using the HTML parser. - list($block_text, $text) = - $this->_hashHTMLBlocks_inHTML($tag.$text, "hashBlock", true); - - # Make sure it stays outside of any paragraph by adding newlines. - $parsed .= "\n\n$block_text\n\n"; - } - # - # Check for: Clean tag (like script, math) - # HTML Comments, processing instructions. - # - else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) || - $tag{1} == '!' || $tag{1} == '?') - { - # Need to parse tag and following text using the HTML parser. - # (don't check for markdown attribute) - list($block_text, $text) = - $this->_hashHTMLBlocks_inHTML($tag.$text, "hashClean", false); - - $parsed .= $block_text; - } - # - # Check for: Tag with same name as enclosing tag. - # - else if ($enclosing_tag_re !== '' && - # Same name as enclosing tag. - preg_match('{^= 0); - - return array($parsed, $text); - } - - protected function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) - { - # - # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags. - # - # * Calls $hash_method to convert any blocks. - # * Stops when the first opening tag closes. - # * $md_attr indicate if the use of the `markdown="1"` attribute is allowed. - # (it is not inside clean tags) - # - # Returns an array of that form: ( processed text , remaining text ) - # - if ($text === '') - return array('', ''); - - # Regex to match `markdown` attribute inside of a tag. - $markdown_attr_re = ' - { - \s* # Eat whitespace before the `markdown` attribute - markdown - \s*=\s* - (?> - (["\']) # $1: quote delimiter - (.*?) # $2: attribute value - \1 # matching delimiter - | - ([^\s>]*) # $3: unquoted attribute value - ) - () # $4: make $3 always defined (avoid warnings) - }xs'; - - # Regex to match any tag. - $tag_re = '{ - ( # $2: Capture hole tag. - - ".*?" | # Double quotes (can contain `>`) - \'.*?\' | # Single quotes (can contain `>`) - .+? # Anything but quotes and `>`. - )*? - )? - > # End of tag. - | - # HTML Comment - | - <\?.*?\?> | <%.*?%> # Processing instruction - | - # CData Block - ) - }xs'; - - $original_text = $text; # Save original text in case of faliure. - - $depth = 0; # Current depth inside the tag tree. - $block_text = ""; # Temporary text holder for current text. - $parsed = ""; # Parsed text that will be returned. - # - # Get the name of the starting tag. - # (This pattern makes $base_tag_name_re safe without quoting.) - # - if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) - $base_tag_name_re = $matches[1]; - - # - # Loop through every tag until we find the corresponding closing tag. - # - do - { - # - # Split the text using the first $tag_match pattern found. - # Text before pattern will be first in the array, text after - # pattern will be at the end, and between will be any catches made - # by the pattern. - # - $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); - - if (count($parts) < 3) - { - # - # End of $text reached with unbalenced tag(s). - # In that case, we return original text unchanged and pass the - # first character as filtered to prevent an infinite loop in the - # parent function. - # - return array($original_text{0}, substr($original_text, 1)); - } - - $block_text .= $parts[0]; # Text before current tag. - $tag = $parts[1]; # Tag to handle. - $text = $parts[2]; # Remaining text after current tag. - # - # Check for: Auto-close tag (like
) - # Comments and Processing Instructions. - # - if (preg_match('{^auto_close_tags_re.')\b}', $tag) || - $tag{1} == '!' || $tag{1} == '?') - { - # Just add the tag to the block as if it was text. - $block_text .= $tag; - } - else - { - # - # Increase/decrease nested tag count. Only do so if - # the tag's name match base tag's. - # - if (preg_match('{^mode = $attr_m[2].$attr_m[3]; - $span_mode = $this->mode == 'span' || $this->mode != 'block' && - preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag); - - # Calculate indent before tag. - if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) - { - $strlen = $this->utf8_strlen; - $indent = $strlen($matches[1], 'UTF-8'); - } - else - { - $indent = 0; - } - - # End preceding block with this tag. - $block_text .= $tag; - $parsed .= $this->$hash_method($block_text); - - # Get enclosing tag name for the ParseMarkdown function. - # (This pattern makes $tag_name_re safe without quoting.) - preg_match('/^<([\w:$]*)\b/', $tag, $matches); - $tag_name_re = $matches[1]; - - # Parse the content using the HTML-in-Markdown parser. - list ($block_text, $text) - = $this->_hashHTMLBlocks_inMarkdown($text, $indent, - $tag_name_re, $span_mode); - - # Outdent markdown text. - if ($indent > 0) - { - $block_text = preg_replace("/^[ ]{1,$indent}/m", "", - $block_text); - } - - # Append tag content to parsed text. - if (!$span_mode) - $parsed .= "\n\n$block_text\n\n"; - else - $parsed .= "$block_text"; - - # Start over a new block. - $block_text = ""; - } - else - $block_text .= $tag; - } - } while ($depth > 0); - - # - # Hash last block text that wasn't processed inside the loop. - # - $parsed .= $this->$hash_method($block_text); - - return array($parsed, $text); - } - - protected function hashClean($text) - { - # - # Called whenever a tag must be hashed when a protected function insert a "clean" tag - # in $text, it pass through this protected function and is automaticaly escaped, - # blocking invalid nested overlap. - # - return $this->hashPart($text, 'C'); - } - - protected function doHeaders($text) - { - # - # Redefined to add id attribute support. - # - # Setext-style headers: - # Header 1 {#header1} - # ======== - # - # Header 2 {#header2} - # -------- - # - $text = preg_replace_callback( - '{ - (^.+?) # $1: Header text - (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute - [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer - }mx', - array(&$this, '_doHeaders_callback_setext'), $text); - - # atx-style headers: - # # Header 1 {#header1} - # ## Header 2 {#header2} - # ## Header 2 with closing hashes ## {#header3} - # ... - # ###### Header 6 {#header2} - # - $text = preg_replace_callback('{ - ^(\#{1,6}) # $1 = string of #\'s - [ ]* - (.+?) # $2 = Header text - [ ]* - \#* # optional closing #\'s (not counted) - (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute - [ ]* - \n+ - }xm', - array(&$this, '_doHeaders_callback_atx'), $text); - - return $text; - } - - protected function _doHeaders_attr($attr) - { - if (empty($attr)) - return ""; - return " id=\"$attr\""; - } - - protected function _doHeaders_callback_setext($matches) - { - if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) - return $matches[0]; - $level = $matches[3]{0} == '=' ? 1 : 2; - $attr = $this->_doHeaders_attr($id = & $matches[2]); - $block = "".$this->runSpanGamut($matches[1]).""; - return "\n".$this->hashBlock($block)."\n\n"; - } - - protected function _doHeaders_callback_atx($matches) - { - $level = strlen($matches[1]); - $attr = $this->_doHeaders_attr($id = & $matches[3]); - $block = "".$this->runSpanGamut($matches[2]).""; - return "\n".$this->hashBlock($block)."\n\n"; - } - - protected function doTables($text) - { - # - # Form HTML tables. - # - $less_than_tab = $this->tab_width - 1; - # - # Find tables with leading pipe. - # - # | Header 1 | Header 2 - # | -------- | -------- - # | Cell 1 | Cell 2 - # | Cell 3 | Cell 4 - # - $text = preg_replace_callback(' - { - ^ # Start of a line - [ ]{0,'.$less_than_tab.'} # Allowed whitespace. - [|] # Optional leading pipe (present) - (.+) \n # $1: Header row (at least one pipe) - - [ ]{0,'.$less_than_tab.'} # Allowed whitespace. - [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline - - ( # $3: Cells - (?> - [ ]* # Allowed whitespace. - [|] .* \n # Row content. - )* - ) - (?=\n|\Z) # Stop at final double newline. - }xm', - array(&$this, '_doTable_leadingPipe_callback'), $text); - - # - # Find tables without leading pipe. - # - # Header 1 | Header 2 - # -------- | -------- - # Cell 1 | Cell 2 - # Cell 3 | Cell 4 - # - $text = preg_replace_callback(' - { - ^ # Start of a line - [ ]{0,'.$less_than_tab.'} # Allowed whitespace. - (\S.*[|].*) \n # $1: Header row (at least one pipe) - - [ ]{0,'.$less_than_tab.'} # Allowed whitespace. - ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline - - ( # $3: Cells - (?> - .* [|] .* \n # Row content - )* - ) - (?=\n|\Z) # Stop at final double newline. - }xm', - array(&$this, '_DoTable_callback'), $text); - - return $text; - } - - protected function _doTable_leadingPipe_callback($matches) - { - $head = $matches[1]; - $underline = $matches[2]; - $content = $matches[3]; - - # Remove leading pipe for each row. - $content = preg_replace('/^ *[|]/m', '', $content); - - return $this->_doTable_callback(array($matches[0], $head, $underline, $content)); - } - - protected function _doTable_callback($matches) - { - $head = $matches[1]; - $underline = $matches[2]; - $content = $matches[3]; - - # Remove any tailing pipes for each line. - $head = preg_replace('/[|] *$/m', '', $head); - $underline = preg_replace('/[|] *$/m', '', $underline); - $content = preg_replace('/[|] *$/m', '', $content); - - # Reading alignement from header underline. - $separators = preg_split('/ *[|] */', $underline); - foreach ($separators as $n => $s) - { - if (preg_match('/^ *-+: *$/', $s)) - $attr[$n] = ' align="right"'; - else if (preg_match('/^ *:-+: *$/', $s) - - )$attr[$n] = ' align="center"'; - else if (preg_match('/^ *:-+ *$/', $s)) - $attr[$n] = ' align="left"'; - else - $attr[$n] = ''; - } - - # Parsing span elements, including code spans, character escapes, - # and inline HTML tags, so that pipes inside those gets ignored. - $head = $this->parseSpan($head); - $headers = preg_split('/ *[|] */', $head); - $col_count = count($headers); - - # Write column headers. - $text = "\n"; - $text .= "\n"; - $text .= "\n"; - foreach ($headers as $n => $header) - $text .= " ".$this->runSpanGamut(trim($header))."\n"; - $text .= "\n"; - $text .= "\n"; - - # Split content by row. - $rows = explode("\n", trim($content, "\n")); - - $text .= "\n"; - foreach ($rows as $row) - { - # Parsing span elements, including code spans, character escapes, - # and inline HTML tags, so that pipes inside those gets ignored. - $row = $this->parseSpan($row); - - # Split row by cell. - $row_cells = preg_split('/ *[|] */', $row, $col_count); - $row_cells = array_pad($row_cells, $col_count, ''); - - $text .= "\n"; - foreach ($row_cells as $n => $cell) - $text .= " ".$this->runSpanGamut(trim($cell))."\n"; - $text .= "\n"; - } - $text .= "\n"; - $text .= "
"; - - return $this->hashBlock($text)."\n"; - } - - protected function doDefLists($text) - { - # - # Form HTML definition lists. - # - $less_than_tab = $this->tab_width - 1; - - # Re-usable pattern to match any entire dl list: - $whole_list_re = '(?> - ( # $1 = whole list - ( # $2 - [ ]{0,'.$less_than_tab.'} - ((?>.*\S.*\n)+) # $3 = defined term - \n? - [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition - ) - (?s:.+?) - ( # $4 - \z - | - \n{2,} - (?=\S) - (?! # Negative lookahead for another term - [ ]{0,'.$less_than_tab.'} - (?: \S.*\n )+? # defined term - \n? - [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition - ) - (?! # Negative lookahead for another definition - [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition - ) - ) - ) - )'; // mx - - $text = preg_replace_callback('{ - (?>\A\n?|(?<=\n\n)) - '.$whole_list_re.' - }mx', - array(&$this, '_doDefLists_callback'), $text); - - return $text; - } - - protected function _doDefLists_callback($matches) - { - # Re-usable patterns to match list item bullets and number markers: - $list = $matches[1]; - - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $result = trim($this->processDefListItems($list)); - $result = "
\n".$result."\n
"; - return $this->hashBlock($result)."\n\n"; - } - - protected function processDefListItems($list_str) - { - # - # Process the contents of a single definition list, splitting it - # into individual term and definition list items. - # - $less_than_tab = $this->tab_width - 1; - - # trim trailing blank lines: - $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); - - # Process definition terms. - $list_str = preg_replace_callback('{ - (?>\A\n?|\n\n+) # leading line - ( # definition terms = $1 - [ ]{0,'.$less_than_tab.'} # leading whitespace - (?![:][ ]|[ ]) # negative lookahead for a definition - # mark (colon) or more whitespace. - (?> \S.* \n)+? # actual term (not whitespace). - ) - (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed - # with a definition mark. - }xm', - array(&$this, '_processDefListItems_callback_dt'), $list_str); - - # Process actual definitions. - $list_str = preg_replace_callback('{ - \n(\n+)? # leading line = $1 - ( # marker space = $2 - [ ]{0,'.$less_than_tab.'} # whitespace before colon - [:][ ]+ # definition mark (colon) - ) - ((?s:.+?)) # definition text = $3 - (?= \n+ # stop at next definition mark, - (?: # next term or end of text - [ ]{0,'.$less_than_tab.'} [:][ ] | -
| \z - ) - ) - }xm', - array(&$this, '_processDefListItems_callback_dd'), $list_str); - - return $list_str; - } - - protected function _processDefListItems_callback_dt($matches) - { - $terms = explode("\n", trim($matches[1])); - $text = ''; - foreach ($terms as $term) - { - $term = $this->runSpanGamut(trim($term)); - $text .= "\n
".$term."
"; - } - return $text."\n"; - } - - protected function _processDefListItems_callback_dd($matches) - { - $leading_line = $matches[1]; - $marker_space = $matches[2]; - $def = $matches[3]; - - if ($leading_line || preg_match('/\n{2,}/', $def)) - { - # Replace marker with the appropriate whitespace indentation - $def = str_repeat(' ', strlen($marker_space)).$def; - $def = $this->runBlockGamut($this->outdent($def."\n\n")); - $def = "\n".$def."\n"; - } - else - { - $def = rtrim($def); - $def = $this->runSpanGamut($this->outdent($def)); - } - - return "\n
".$def."
\n"; - } - - protected function doFencedCodeBlocks($text) - { - # - # Adding the fenced code block syntax to regular Markdown: - # - # ~~~ - # Code block - # ~~~ - # - $less_than_tab = $this->tab_width; - - $text = preg_replace_callback('{ - (?:\n|\A) - # 1: Opening marker - ( - ~{3,} # Marker: three tilde or more. - ) - [ ]* \n # Whitespace and newline following marker. - - # 2: Content - ( - (?> - (?!\1 [ ]* \n) # Not a closing marker. - .*\n+ - )+ - ) - - # Closing marker. - \1 [ ]* \n - }xm', - array(&$this, '_doFencedCodeBlocks_callback'), $text); - - return $text; - } - - protected function _doFencedCodeBlocks_callback($matches) - { - $codeblock = $matches[2]; - $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); - $codeblock = preg_replace_callback('/^\n+/', - array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); - $codeblock = "
$codeblock
"; - return "\n\n".$this->hashBlock($codeblock)."\n\n"; - } - - protected function _doFencedCodeBlocks_newlines($matches) - { - return str_repeat("empty_element_suffix", - strlen($matches[0])); - } - - # - # Redefining emphasis markers so that emphasis by underscore does not - # work in the middle of a word. - # - - var $em_relist = array( - '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? tags - # - # Strip leading and trailing lines: - $text = preg_replace('/\A\n+|\n+\z/', '', $text); - - $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); - - # - # Wrap

tags and unhashify HTML blocks - # - foreach ($grafs as $key => $value) - { - $value = trim($this->runSpanGamut($value)); - - # Check if this should be enclosed in a paragraph. - # Clean tag hashes & block tag hashes are left alone. - - if (!preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value)) - { - $value = '

'.$value.'

'; - } - - $grafs[$key] = $value; - } - - # Join grafs in one text, then unhash HTML tags. - $text = implode("\n\n", $grafs); - - # Finish by removing any tag hashes still present in $text. - $text = $this->unhash($text); - - return $text; - } - - ### Footnotes - - protected function stripFootnotes($text) - { - # - # Strips link definitions from text, stores the URLs and titles in - # hash references. - # - $less_than_tab = $this->tab_width - 1; - - # Link defs are in the form: [^id]: url "optional title" - $text = preg_replace_callback('{ - ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1 - [ ]* - \n? # maybe *one* newline - ( # text = $2 (no blank lines allowed) - (?: - .+ # actual text - | - \n # newlines but - (?!\[\^.+?\]:\s)# negative lookahead for footnote marker. - (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed - # by non-indented content - )* - ) - }xm', - array(&$this, '_stripFootnotes_callback'), - $text); - return $text; - } - - protected function _stripFootnotes_callback($matches) - { - $note_id = $this->fn_id_prefix.$matches[1]; - $this->footnotes[$note_id] = $this->outdent($matches[2]); - return ''; # String that will replace the block - } - - protected function doFootnotes($text) - { - # - # Replace footnote references in $text [^id] with a special text-token - # which will be replaced by the actual footnote marker in appendFootnotes. - # - if (!$this->in_anchor) - { - $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text); - } - return $text; - } - - protected function appendFootnotes($text) - { - # - # Append footnote list to text. - # - $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', - array(&$this, '_appendFootnotes_callback'), $text); - - if (!empty($this->footnotes_ordered)) - { - $text .= "\n\n"; - $text .= "
"; - } - return $text; - } - - protected function _appendFootnotes_callback($matches) - { - $node_id = $this->fn_id_prefix.$matches[1]; - - # Create footnote marker only if it has a corresponding footnote *and* - # the footnote hasn't been used by another marker. - if (isset($this->footnotes[$node_id])) - { - # Transfert footnote content to the ordered list. - $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id]; - unset($this->footnotes[$node_id]); - - $num = $this->footnote_counter++; - $attr = " rel=\"footnote\""; - if ($this->fn_link_class != "") - { - $class = $this->fn_link_class; - $class = $this->encodeAttribute($class); - $attr .= " class=\"$class\""; - } - if ($this->fn_link_title != "") - { - $title = $this->fn_link_title; - $title = $this->encodeAttribute($title); - $attr .= " title=\"$title\""; - } - - $attr = str_replace("%%", $num, $attr); - $node_id = $this->encodeAttribute($node_id); - - return - "". - "$num". - ""; - } - - return "[^".$matches[1]."]"; - } - - ### Abbreviations ### - - protected function stripAbbreviations($text) - { - # - # Strips abbreviations from text, stores titles in hash references. - # - $less_than_tab = $this->tab_width - 1; - - # Link defs are in the form: [id]*: url "optional title" - $text = preg_replace_callback('{ - ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1 - (.*) # text = $2 (no blank lines allowed) - }xm', - array(&$this, '_stripAbbreviations_callback'), - $text); - return $text; - } - - protected function _stripAbbreviations_callback($matches) - { - $abbr_word = $matches[1]; - $abbr_desc = $matches[2]; - if ($this->abbr_word_re) - $this->abbr_word_re .= '|'; - $this->abbr_word_re .= preg_quote($abbr_word); - $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); - return ''; # String that will replace the block - } - - protected function doAbbreviations($text) - { - # - # Find defined abbreviations in text and wrap them in elements. - # - if ($this->abbr_word_re) - { - // cannot use the /x modifier because abbr_word_re may - // contain significant spaces: - $text = preg_replace_callback('{'. - '(?abbr_word_re.')'. - '(?![\w\x1A])'. - '}', - array(&$this, '_doAbbreviations_callback'), $text); - } - return $text; - } - - protected function _doAbbreviations_callback($matches) - { - $abbr = $matches[0]; - if (isset($this->abbr_desciptions[$abbr])) - { - $desc = $this->abbr_desciptions[$abbr]; - if (empty($desc)) - { - return $this->hashPart("$abbr"); - } - else - { - $desc = $this->encodeAttribute($desc); - return $this->hashPart("$abbr"); - } - } - else - { - return $matches[0]; - } - } - -} - -/* - * HP Markdown Extra - * ================= - * escription - * ---------- - * his is a PHP port of the original Markdown formatter written in Perl - * y John Gruber. This special "Extra" version of PHP Markdown features - * urther enhancements to the syntax for making additional constructs - * uch as tables and definition list. - * arkdown is a text-to-HTML filter; it translates an easy-to-read / - * asy-to-write structured text format into HTML. Markdown's text format - * s most similar to that of plain text email, and supports features such - * s headers, *emphasis*, code blocks, blockquotes, and links. - * arkdown's syntax is designed not as a generic markup language, but - * pecifically to serve as a front-end to (X)HTML. You can use span-level - * TML tags anywhere in a Markdown document, and you can use block level - * TML tags (like
and as well). - * or more information about Markdown's syntax, see: - * http://daringfireball.net/projects/markdown/> - * ugs - * --- - * o file bug reports please send email to: - * michel.fortin@michelf.com> - * lease include with your report: (1) the example input; (2) the output you - * xpected; (3) the output Markdown actually produced. - * ersion History - * -------------- - * ee the readme file for detailed release notes for this version. - * opyright and License - * -------------------- - * HP Markdown & Extra - * opyright (c) 2004-2009 Michel Fortin - * http://michelf.com/> - * ll rights reserved. - * ased on Markdown - * opyright (c) 2003-2006 John Gruber - * http://daringfireball.net/> - * ll rights reserved. - * edistribution and use in source and binary forms, with or without - * odification, are permitted provided that the following conditions are - * et: - * Redistributions of source code must retain the above copyright notice, - * his list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * otice, this list of conditions and the following disclaimer in the - * ocumentation and/or other materials provided with the distribution. - * Neither the name "Markdown" nor the names of its contributors may - * e used to endorse or promote products derived from this software - * ithout specific prior written permission. - * his software is provided by the copyright holders and contributors "as - * s" and any express or implied warranties, including, but not limited - * o, the implied warranties of merchantability and fitness for a - * articular purpose are disclaimed. In no event shall the copyright owner - * r contributors be liable for any direct, indirect, incidental, special, - * xemplary, or consequential damages (including, but not limited to, - * rocurement of substitute goods or services; loss of use, data, or - * rofits; or business interruption) however caused and on any theory of - * iability, whether in contract, strict liability, or tort (including - * egligence or otherwise) arising in any way out of the use of this - * oftware, even if advised of the possibility of such damage. - */ -?> diff --git a/vendor/parser/MarkdownParser.php b/vendor/parser/MarkdownParser.php deleted file mode 100644 index cac655e..0000000 --- a/vendor/parser/MarkdownParser.php +++ /dev/null @@ -1,1528 +0,0 @@ -#+-.!'; - protected $escape_chars_re; - - # Change to ">" for HTML output. - protected $empty_element_suffix = ' />'; - protected $tab_width = 4; - - # Change to `true` to disallow markup or entities. - protected $no_markup = false; - protected $no_entities = false; - - # Predefined urls and titles for reference links and images. - protected $predef_urls = array(); - protected $predef_titles = array(); - - # Internal hashes used during transformation. - protected $urls = array(); - protected $titles = array(); - protected $html_hashes = array(); - - # Status flag to avoid invalid nesting. - protected $in_anchor = false; - protected $document_gamut = array( - # Strip link definitions, store in hashes. - "stripLinkDefinitions" => 20, - "runBasicBlockGamut" => 30, - ); - protected $block_gamut = array( - # - # These are all the transformations that form block-level - # tags like paragraphs, headers, and list items. - # - "doHeaders" => 10, - "doHorizontalRules" => 20, - "doLists" => 40, - "doCodeBlocks" => 50, - "doBlockQuotes" => 60, - ); - protected $list_level = 0; - protected $span_gamut = array( - # - # These are all the transformations that occur *within* block-level - # tags like paragraphs, headers, and list items. - # - # Process character escapes, code spans, and inline HTML - # in one shot. - "parseSpan" => -30, - # Process anchor and image tags. Images must come first, - # because ![foo][f] looks like an anchor. - "doImages" => 10, - "doAnchors" => 20, - # Make links out of things like `` - # Must come after doAnchors, because you can use < and > - # delimiters in inline links like [this](). - "doAutoLinks" => 30, - "encodeAmpsAndAngles" => 40, - "doItalicsAndBold" => 50, - "doHardBreaks" => 60, - ); - protected $em_relist = array( - '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(?_initDetab(); - $this->prepareItalicsAndBold(); - - $this->nested_brackets_re = - str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). - str_repeat('\])*', $this->nested_brackets_depth); - - $this->nested_url_parenthesis_re = - str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). - str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); - - $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; - - # Sort document, block, and span gamut in ascendent priority order. - asort($this->document_gamut); - asort($this->block_gamut); - asort($this->span_gamut); - } - - public function transform($text) - { - # - # Main function. Performs some preprocessing on the input text - # and pass it through the document gamut. - # - $this->setup(); - - # Remove UTF-8 BOM and marker character in input, if present. - $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); - - # Standardize line endings: - # DOS to Unix and Mac to Unix - $text = preg_replace('{\r\n?}', "\n", $text); - - # Make sure $text ends with a couple of newlines: - $text .= "\n\n"; - - # Convert all tabs to spaces. - $text = $this->detab($text); - - # Turn block-level HTML blocks into hash entries - $text = $this->hashHTMLBlocks($text); - - # Strip any lines consisting only of spaces and tabs. - # This makes subsequent regexen easier to write, because we can - # match consecutive blank lines with /\n+/ instead of something - # contorted like /[ ]*\n+/ . - $text = preg_replace('/^[ ]+$/m', '', $text); - - # Run document gamut methods. - foreach ($this->document_gamut as $method => $priority) - { - $text = $this->$method($text); - } - - // Remove all white spaces on blank lines - $text = preg_replace("/\n\s+\n/", "\n\n", $text); - - $this->teardown(); - - return $text."\n"; - } - - protected function setup() - { - # - # Called before the transformation process starts to setup parser - # states. - # - # Clear global hashes. - $this->urls = $this->predef_urls; - $this->titles = $this->predef_titles; - $this->html_hashes = array(); - - $in_anchor = false; - } - - protected function teardown() - { - # - # Called after the transformation process to clear any variable - # which may be taking up memory unnecessarly. - # - $this->urls = array(); - $this->titles = array(); - $this->html_hashes = array(); - } - - protected function stripLinkDefinitions($text) - { - # - # Strips link definitions from text, stores the URLs and titles in - # hash references. - # - $less_than_tab = $this->tab_width - 1; - - # Link defs are in the form: ^[id]: url "optional title" - $text = preg_replace_callback('{ - ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 - [ ]* - \n? # maybe *one* newline - [ ]* - (?: - <(.+?)> # url = $2 - | - (\S+?) # url = $3 - ) - [ ]* - \n? # maybe one newline - [ ]* - (?: - (?<=\s) # lookbehind for whitespace - ["(] - (.*?) # title = $4 - [")] - [ ]* - )? # title is optional - (?:\n+|\Z) - }xm', - array(&$this, '_stripLinkDefinitions_callback'), - $text); - return $text; - } - - protected function _stripLinkDefinitions_callback($matches) - { - $link_id = strtolower($matches[1]); - $url = $matches[2] == '' ? $matches[3] : $matches[2]; - $this->urls[$link_id] = $url; - $this->titles[$link_id] = & $matches[4]; - return ''; # String that will replace the block - } - - protected function hashHTMLBlocks($text) - { - if ($this->no_markup) - return $text; - - $less_than_tab = $this->tab_width - 1; - - # Hashify HTML blocks: - # We only want to do this for block-level HTML tags, such as headers, - # lists, and tables. That's because we still want to wrap

s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded: - # - # * List "a" is made of tags which can be both inline or block-level. - # These will be treated block-level when the start tag is alone on - # its line, otherwise they're not matched here and will be taken as - # inline later. - # * List "b" is made of tags which are always block-level; - # - $block_tags_a_re = 'ins|del'; - $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'. - 'script|noscript|form|fieldset|iframe|math'; - - # Regular expression for the content of a block tag. - $nested_tags_level = 4; - $attr = ' - (?> # optional tag attributes - \s # starts with whitespace - (?> - [^>"/]+ # text outside quotes - | - /+(?!>) # slash not followed by ">" - | - "[^"]*" # text inside double quotes (tolerate ">") - | - \'[^\']*\' # text inside single quotes (tolerate ">") - )* - )? - '; - $content = - str_repeat(' - (?> - [^<]+ # content without tag - | - <\2 # nested opening tag - '.$attr.' # attributes - (?> - /> - | - >', $nested_tags_level).# end of opening tag - '.*?'.# last level nested tag content - str_repeat(' - # closing nested tag - ) - | - <(?!/\2\s*> # other tags with a different name - ) - )*', - $nested_tags_level); - $content2 = str_replace('\2', '\3', $content); - - # First, look for nested blocks, e.g.: - #

- #
- # tags for inner block must be indented. - #
- #
- # - # The outermost tags must start at the left margin for this to match, and - # the inner nested divs must be indented. - # We need to do this before the next, more liberal match, because the next - # match will start at the first `
` and stop at the first `
`. - $text = preg_replace_callback('{(?> - (?> - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - - # Match from `\n` to `\n`, handling nested tags - # in between. - - [ ]{0,'.$less_than_tab.'} - <('.$block_tags_b_re.')# start tag = $2 - '.$attr.'> # attributes followed by > and \n - '.$content.' # content, support nesting - # the matching end tag - [ ]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - - | # Special version for tags of group a. - - [ ]{0,'.$less_than_tab.'} - <('.$block_tags_a_re.')# start tag = $3 - '.$attr.'>[ ]*\n # attributes followed by > - '.$content2.' # content, support nesting - # the matching end tag - [ ]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - - | # Special case just for
. It was easier to make a special - # case than to make the other regex more complicated. - - [ ]{0,'.$less_than_tab.'} - <(hr) # start tag = $2 - '.$attr.' # attributes - /?> # the matching end tag - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - | # Special case for standalone HTML comments: - - [ ]{0,'.$less_than_tab.'} - (?s: - - ) - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - | # PHP and ASP-style processor instructions ( - ) - [ ]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - - ) - )}Sxmi', - array(&$this, '_hashHTMLBlocks_callback'), - $text); - - return $text; - } - - protected function _hashHTMLBlocks_callback($matches) - { - $text = $matches[1]; - $key = $this->hashBlock($text); - return "\n\n$key\n\n"; - } - - protected function hashPart($text, $boundary = 'X') - { - # - # Called whenever a tag must be hashed when a function insert an atomic - # element in the text stream. Passing $text to through this function gives - # a unique text-token which will be reverted back when calling unhash. - # - # The $boundary argument specify what character should be used to surround - # the token. By convension, "B" is used for block elements that needs not - # to be wrapped into paragraph tags at the end, ":" is used for elements - # that are word separators and "X" is used in the general case. - # - # Swap back any tag hash found in $text so we do not have to `unhash` - # multiple times at the end. - $text = $this->unhash($text); - - # Then hash the block. - static $i = 0; - $key = $boundary."\x1A".++$i.$boundary; - $this->html_hashes[$key] = $text; - return $key; # String that will replace the tag. - } - - protected function hashBlock($text) - { - # - # Shortcut function for hashPart with block-level boundaries. - # - return $this->hashPart($text, 'B'); - } - - protected function runBlockGamut($text) - { - # - # Run block gamut tranformations. - # - # We need to escape raw HTML in Markdown source before doing anything - # else. This need to be done for each block, and not only at the - # begining in the Markdown function since hashed blocks can be part of - # list items and could have been indented. Indented blocks would have - # been seen as a code block in a previous pass of hashHTMLBlocks. - $text = $this->hashHTMLBlocks($text); - - return $this->runBasicBlockGamut($text); - } - - protected function runBasicBlockGamut($text) - { - # - # Run block gamut tranformations, without hashing HTML blocks. This is - # useful when HTML blocks are known to be already hashed, like in the first - # whole-document pass. - # - foreach ($this->block_gamut as $method => $priority) - { - $text = $this->$method($text); - } - - # Finally form paragraph and restore hashed blocks. - $text = $this->formParagraphs($text); - - return $text; - } - - protected function doHorizontalRules($text) - { - # Do Horizontal Rules: - return preg_replace( - '{ - ^[ ]{0,3} # Leading space - ([-*_]) # $1: First marker - (?> # Repeated marker group - [ ]{0,2} # Zero, one, or two spaces. - \1 # Marker character - ){2,} # Group repeated at least twice - [ ]* # Tailing spaces - $ # End of line. - }mx', - "\n".$this->hashBlock("empty_element_suffix")."\n", - $text); - } - - protected function runSpanGamut($text) - { - # - # Run span gamut tranformations. - # - foreach ($this->span_gamut as $method => $priority) - { - $text = $this->$method($text); - } - - return $text; - } - - protected function doHardBreaks($text) - { - # Do hard breaks: - return preg_replace_callback('/ {2,}\n/', - array(&$this, '_doHardBreaks_callback'), $text); - } - - protected function _doHardBreaks_callback($matches) - { - return $this->hashPart("empty_element_suffix\n"); - } - - protected function doAnchors($text) - { - # - # Turn Markdown link shortcuts into XHTML tags. - # - if ($this->in_anchor) - return $text; - $this->in_anchor = true; - - # - # First, handle reference-style links: [link text] [id] - # - $text = preg_replace_callback('{ - ( # wrap whole match in $1 - \[ - ('.$this->nested_brackets_re.') # link text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - ) - }xs', - array(&$this, '_doAnchors_reference_callback'), $text); - - # - # Next, inline-style links: [link text](url "optional title") - # - $text = preg_replace_callback('{ - ( # wrap whole match in $1 - \[ - ('.$this->nested_brackets_re.') # link text = $2 - \] - \( # literal paren - [ \n]* - (?: - <(.+?)> # href = $3 - | - ('.$this->nested_url_parenthesis_re.') # href = $4 - ) - [ \n]* - ( # $5 - ([\'"]) # quote char = $6 - (.*?) # Title = $7 - \6 # matching quote - [ \n]* # ignore any spaces/tabs between closing quote and ) - )? # title is optional - \) - ) - }xs', - array(&$this, '_doAnchors_inline_callback'), $text); - - # - # Last, handle reference-style shortcuts: [link text] - # These must come last in case you've also got [link text][1] - # or [link text](/foo) - # - $text = preg_replace_callback('{ - ( # wrap whole match in $1 - \[ - ([^\[\]]+) # link text = $2; can\'t contain [ or ] - \] - ) - }xs', - array(&$this, '_doAnchors_reference_callback'), $text); - - $this->in_anchor = false; - return $text; - } - - protected function _doAnchors_reference_callback($matches) - { - $whole_match = $matches[1]; - $link_text = $matches[2]; - $link_id = & $matches[3]; - - if ($link_id == "") - { - # for shortcut links like [this][] or [this]. - $link_id = $link_text; - } - - # lower-case and turn embedded newlines into spaces - $link_id = strtolower($link_id); - $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); - - if (isset($this->urls[$link_id])) - { - $url = $this->urls[$link_id]; - $url = $this->encodeAttribute($url); - - $result = "titles[$link_id])) - { - $title = $this->titles[$link_id]; - $title = $this->encodeAttribute($title); - $result .= " title=\"$title\""; - } - - $link_text = $this->runSpanGamut($link_text); - $result .= ">$link_text"; - $result = $this->hashPart($result); - } - else - { - $result = $whole_match; - } - return $result; - } - - protected function _doAnchors_inline_callback($matches) - { - $whole_match = $matches[1]; - $link_text = $this->runSpanGamut($matches[2]); - $url = $matches[3] == '' ? $matches[4] : $matches[3]; - $title = & $matches[7]; - - $url = $this->encodeAttribute($url); - - $result = "encodeAttribute($title); - $result .= " title=\"$title\""; - } - - $link_text = $this->runSpanGamut($link_text); - $result .= ">$link_text"; - - return $this->hashPart($result); - } - - protected function doImages($text) - { - # - # Turn Markdown image shortcuts into tags. - # - # - # First, handle reference-style labeled images: ![alt text][id] - # - $text = preg_replace_callback('{ - ( # wrap whole match in $1 - !\[ - ('.$this->nested_brackets_re.') # alt text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - - ) - }xs', - array(&$this, '_doImages_reference_callback'), $text); - - # - # Next, handle inline images: ![alt text](url "optional title") - # Don't forget: encode * and _ - # - $text = preg_replace_callback('{ - ( # wrap whole match in $1 - !\[ - ('.$this->nested_brackets_re.') # alt text = $2 - \] - \s? # One optional whitespace character - \( # literal paren - [ \n]* - (?: - <(\S*)> # src url = $3 - | - ('.$this->nested_url_parenthesis_re.') # src url = $4 - ) - [ \n]* - ( # $5 - ([\'"]) # quote char = $6 - (.*?) # title = $7 - \6 # matching quote - [ \n]* - )? # title is optional - \) - ) - }xs', - array(&$this, '_doImages_inline_callback'), $text); - - return $text; - } - - protected function _doImages_reference_callback($matches) - { - $whole_match = $matches[1]; - $alt_text = $matches[2]; - $link_id = strtolower($matches[3]); - - if ($link_id == "") - { - $link_id = strtolower($alt_text); # for shortcut links like ![this][]. - } - - $alt_text = $this->encodeAttribute($alt_text); - if (isset($this->urls[$link_id])) - { - $url = $this->encodeAttribute($this->urls[$link_id]); - $result = "\"$alt_text\"";titles[$link_id])) - { - $title = $this->titles[$link_id]; - $title = $this->encodeAttribute($title); - $result .= " title=\"$title\""; - } - $result .= $this->empty_element_suffix; - $result = $this->hashPart($result); - } - else - { - # If there's no such link ID, leave intact: - $result = $whole_match; - } - - return $result; - } - - protected function _doImages_inline_callback($matches) - { - $whole_match = $matches[1]; - $alt_text = $matches[2]; - $url = $matches[3] == '' ? $matches[4] : $matches[3]; - $title = & $matches[7]; - - $alt_text = $this->encodeAttribute($alt_text); - $url = $this->encodeAttribute($url); - $result = "\"$alt_text\"";encodeAttribute($title); - $result .= " title=\"$title\""; # $title already quoted - } - $result .= $this->empty_element_suffix; - - return $this->hashPart($result); - } - - protected function doHeaders($text) - { - # Setext-style headers: - # Header 1 - # ======== - # - # Header 2 - # -------- - # - $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', - array(&$this, '_doHeaders_callback_setext'), $text); - - # atx-style headers: - # # Header 1 - # ## Header 2 - # ## Header 2 with closing hashes ## - # ... - # ###### Header 6 - # - $text = preg_replace_callback('{ - ^(\#{1,6}) # $1 = string of #\'s - [ ]* - (.+?) # $2 = Header text - [ ]* - \#* # optional closing #\'s (not counted) - \n+ - }xm', - array(&$this, '_doHeaders_callback_atx'), $text); - - return $text; - } - - protected function _doHeaders_callback_setext($matches) - { - # Terrible hack to check we haven't found an empty list item. - if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) - return $matches[0]; - - $level = $matches[2]{0} == '=' ? 1 : 2; - $block = "".$this->runSpanGamut($matches[1]).""; - return "\n".$this->hashBlock($block)."\n\n"; - } - - protected function _doHeaders_callback_atx($matches) - { - $level = strlen($matches[1]); - $block = "".$this->runSpanGamut($matches[2]).""; - return "\n".$this->hashBlock($block)."\n\n"; - } - - protected function doLists($text) - { - # - # Form HTML ordered (numbered) and unordered (bulleted) lists. - # - $less_than_tab = $this->tab_width - 1; - - # Re-usable patterns to match list item bullets and number markers: - $marker_ul_re = '[*+-]'; - $marker_ol_re = '\d+[.]'; - $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; - - $markers_relist = array( - $marker_ul_re => $marker_ol_re, - $marker_ol_re => $marker_ul_re, - ); - - foreach ($markers_relist as $marker_re => $other_marker_re) - { - # Re-usable pattern to match any entirel ul or ol list: - $whole_list_re = ' - ( # $1 = whole list - ( # $2 - ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces - ('.$marker_re.') # $4 = first list item marker - [ ]+ - ) - (?s:.+?) - ( # $5 - \z - | - \n{2,} - (?=\S) - (?! # Negative lookahead for another list item marker - [ ]* - '.$marker_re.'[ ]+ - ) - | - (?= # Lookahead for another kind of list - \n - \3 # Must have the same indentation - '.$other_marker_re.'[ ]+ - ) - ) - ) - '; // mx - # We use a different prefix before nested lists than top-level lists. - # See extended comment in _ProcessListItems(). - - if ($this->list_level) - { - $text = preg_replace_callback('{ - ^ - '.$whole_list_re.' - }mx', - array(&$this, '_doLists_callback'), $text); - } - else - { - $text = preg_replace_callback('{ - (?:(?<=\n)\n|\A\n?) # Must eat the newline - '.$whole_list_re.' - }mx', - array(&$this, '_doLists_callback'), $text); - } - } - - return $text; - } - - protected function _doLists_callback($matches) - { - # Re-usable patterns to match list item bullets and number markers: - $marker_ul_re = '[*+-]'; - $marker_ol_re = '\d+[.]'; - $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; - - $list = $matches[1]; - $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol"; - - $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re ); - - $list .= "\n"; - $result = $this->processListItems($list, $marker_any_re); - - $result = $this->hashBlock("<$list_type>\n".$result.""); - return "\n".$result."\n\n"; - } - - protected function processListItems($list_str, $marker_any_re) - { - # - # Process the contents of a single ordered or unordered list, splitting it - # into individual list items. - # - # The $this->list_level global keeps track of when we're inside a list. - # Each time we enter a list, we increment it; when we leave a list, - # we decrement. If it's zero, we're not in a list anymore. - # - # We do this because when we're not inside a list, we want to treat - # something like this: - # - # I recommend upgrading to version - # 8. Oops, now this line is treated - # as a sub-list. - # - # As a single paragraph, despite the fact that the second line starts - # with a digit-period-space sequence. - # - # Whereas when we're inside a list (or sub-list), that line will be - # treated as the start of a sub-list. What a kludge, huh? This is - # an aspect of Markdown's syntax that's hard to parse perfectly - # without resorting to mind-reading. Perhaps the solution is to - # change the syntax rules such that sub-lists must start with a - # starting cardinal number; e.g. "1." or "a.". - - $this->list_level++; - - # trim trailing blank lines: - $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); - - $list_str = preg_replace_callback('{ - (\n)? # leading line = $1 - (^[ ]*) # leading whitespace = $2 - ('.$marker_any_re.' # list marker and space = $3 - (?:[ ]+|(?=\n)) # space only required if item is not empty - ) - ((?s:.*?)) # list item text = $4 - (?:(\n+(?=\n))|\n) # tailing blank line = $5 - (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n)))) - }xm', - array(&$this, '_processListItems_callback'), $list_str); - - $this->list_level--; - return $list_str; - } - - protected function _processListItems_callback($matches) - { - $item = $matches[4]; - $leading_line = & $matches[1]; - $leading_space = & $matches[2]; - $marker_space = $matches[3]; - $tailing_blank_line = & $matches[5]; - - if ($leading_line || $tailing_blank_line || - preg_match('/\n{2,}/', $item)) - { - # Replace marker with the appropriate whitespace indentation - $item = $leading_space.str_repeat(' ', strlen($marker_space)).$item; - $item = $this->runBlockGamut($this->outdent($item)."\n"); - } - else - { - # Recursion for sub-lists: - $item = $this->doLists($this->outdent($item)); - $item = preg_replace('/\n+$/', '', $item); - $item = $this->runSpanGamut($item); - } - - return "
  • ".$item."
  • \n"; - } - - protected function doCodeBlocks($text) - { - # - # Process Markdown `
    ` blocks.
    -        #
    -        $text = preg_replace_callback('{
    -				(?:\n\n|\A\n?)
    -				(	            # $1 = the code block -- one or more lines, starting with a space/tab
    -				  (?>
    -					[ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
    -					.*\n+
    -				  )+
    -				)
    -				((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    -			}xm',
    -        array(&$this, '_doCodeBlocks_callback'), $text);
    -
    -        return $text;
    -    }
    -
    -    protected function _doCodeBlocks_callback($matches)
    -    {
    -        $codeblock = $matches[1];
    -
    -        $codeblock = $this->outdent($codeblock);
    -        $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
    -
    -        # trim leading newlines and trailing newlines
    -        $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
    -
    -        $codeblock = "
    $codeblock\n
    "; - return "\n\n".$this->hashBlock($codeblock)."\n\n"; - } - - protected function makeCodeSpan($code) - { - # - # Create a code span markup for $code. Called from handleSpanToken. - # - $code = htmlspecialchars(trim($code), ENT_NOQUOTES); - return $this->hashPart("$code"); - } - - protected function prepareItalicsAndBold() - { - # - # Prepare regular expressions for searching emphasis tokens in any - # context. - # - foreach ($this->em_relist as $em => $em_re) - { - foreach ($this->strong_relist as $strong => $strong_re) - { - # Construct list of allowed token expressions. - $token_relist = array(); - if (isset($this->em_strong_relist[$em.$strong])) - { - $token_relist[] = $this->em_strong_relist[$em.$strong]; - } - $token_relist[] = $em_re; - $token_relist[] = $strong_re; - - # Construct master expression from list. - $token_re = '{('.implode('|', $token_relist).')}'; - $this->em_strong_prepared_relist[$em.$strong] = $token_re; - } - } - } - - protected function doItalicsAndBold($text) - { - $token_stack = array(''); - $text_stack = array(''); - $em = ''; - $strong = ''; - $tree_char_em = false; - - while (1) - { - # - # Get prepared regular expression for seraching emphasis tokens - # in current context. - # - $token_re = $this->em_strong_prepared_relist["$em$strong"]; - - # - # Each loop iteration search for the next emphasis token. - # Each token is then passed to handleSpanToken. - # - $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); - $text_stack[0] .= $parts[0]; - $token = & $parts[1]; - $text = & $parts[2]; - - if (empty($token)) - { - # Reached end of text span: empty stack without emitting. - # any more emphasis. - while ($token_stack[0]) - { - $text_stack[1] .= array_shift($token_stack); - $text_stack[0] .= array_shift($text_stack); - } - break; - } - - $token_len = strlen($token); - if ($tree_char_em) - { - # Reached closing marker while inside a three-char emphasis. - if ($token_len == 3) - { - # Three-char closing marker, close em and strong. - array_shift($token_stack); - $span = array_shift($text_stack); - $span = $this->runSpanGamut($span); - $span = "$span"; - $text_stack[0] .= $this->hashPart($span); - $em = ''; - $strong = ''; - } - else - { - # Other closing marker: close one em or strong and - # change current token state to match the other - $token_stack[0] = str_repeat($token{0}, 3 - $token_len); - $tag = $token_len == 2 ? "strong" : "em"; - $span = $text_stack[0]; - $span = $this->runSpanGamut($span); - $span = "<$tag>$span"; - $text_stack[0] = $this->hashPart($span); - $$tag = ''; # $$tag stands for $em or $strong - } - $tree_char_em = false; - } - else if ($token_len == 3) - { - if ($em) - { - # Reached closing marker for both em and strong. - # Closing strong marker: - for ($i = 0; $i < 2; ++$i) - { - $shifted_token = array_shift($token_stack); - $tag = strlen($shifted_token) == 2 ? "strong" : "em"; - $span = array_shift($text_stack); - $span = $this->runSpanGamut($span); - $span = "<$tag>$span"; - $text_stack[0] .= $this->hashPart($span); - $$tag = ''; # $$tag stands for $em or $strong - } - } - else - { - # Reached opening three-char emphasis marker. Push on token - # stack; will be handled by the special condition above. - $em = $token{0}; - $strong = "$em$em"; - array_unshift($token_stack, $token); - array_unshift($text_stack, ''); - $tree_char_em = true; - } - } - else if ($token_len == 2) - { - if ($strong) - { - # Unwind any dangling emphasis marker: - if (strlen($token_stack[0]) == 1) - { - $text_stack[1] .= array_shift($token_stack); - $text_stack[0] .= array_shift($text_stack); - } - # Closing strong marker: - array_shift($token_stack); - $span = array_shift($text_stack); - $span = $this->runSpanGamut($span); - $span = "$span"; - $text_stack[0] .= $this->hashPart($span); - $strong = ''; - } - else - { - array_unshift($token_stack, $token); - array_unshift($text_stack, ''); - $strong = $token; - } - } - else - { - # Here $token_len == 1 - if ($em) - { - if (strlen($token_stack[0]) == 1) - { - # Closing emphasis marker: - array_shift($token_stack); - $span = array_shift($text_stack); - $span = $this->runSpanGamut($span); - $span = "$span"; - $text_stack[0] .= $this->hashPart($span); - $em = ''; - } - else - { - $text_stack[0] .= $token; - } - } - else - { - array_unshift($token_stack, $token); - array_unshift($text_stack, ''); - $em = $token; - } - } - } - return $text_stack[0]; - } - - protected function doBlockQuotes($text) - { - $text = preg_replace_callback('/ - ( # Wrap whole match in $1 - (?> - ^[ ]*>[ ]? # ">" at the start of a line - .+\n # rest of the first line - (.+\n)* # subsequent consecutive lines - \n* # blanks - )+ - ) - /xm', - array(&$this, '_doBlockQuotes_callback'), $text); - - return $text; - } - - protected function _doBlockQuotes_callback($matches) - { - $bq = $matches[1]; - # trim one level of quoting - trim whitespace-only lines - $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq); - $bq = $this->runBlockGamut($bq); # recurse - - $bq = preg_replace('/^/m', " ", $bq); - # These leading spaces cause problem with
     content,
    -        # so we need to fix that:
    -        $bq = preg_replace_callback('{(\s*
    .+?
    )}sx', - array(&$this, '_doBlockQuotes_callback2'), $bq); - - return "\n".$this->hashBlock("
    \n$bq\n
    ")."\n\n"; - } - - protected function _doBlockQuotes_callback2($matches) - { - $pre = $matches[1]; - $pre = preg_replace('/^ /m', '', $pre); - return $pre; - } - - protected function formParagraphs($text) - { - # - # Params: - # $text - string to process with html

    tags - # - # Strip leading and trailing lines: - $text = preg_replace('/\A\n+|\n+\z/', '', $text); - - $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); - - # - # Wrap

    tags and unhashify HTML blocks - # - foreach ($grafs as $key => $value) - { - if (!preg_match('/^B\x1A[0-9]+B$/', $value)) - { - # Is a paragraph. - $value = $this->runSpanGamut($value); - $value = preg_replace('/^([ ]*)/', "

    ", $value); - $value .= "

    "; - $grafs[$key] = $this->unhash($value); - } - else - { - # Is a block. - # Modify elements of @grafs in-place... - $graf = $value; - $block = $this->html_hashes[$graf]; - $graf = $block; - $grafs[$key] = $graf; - } - } - - return implode("\n\n", $grafs); - } - - protected function encodeAttribute($text) - { - # - # Encode text for a double-quoted HTML attribute. This function - # is *not* suitable for attributes enclosed in single quotes. - # - $text = $this->encodeAmpsAndAngles($text); - $text = str_replace('"', '"', $text); - return $text; - } - - protected function encodeAmpsAndAngles($text) - { - # - # Smart processing for ampersands and angle brackets that need to - # be encoded. Valid character entities are left alone unless the - # no-entities mode is set. - # - if ($this->no_entities) - { - $text = str_replace('&', '&', $text); - } - else - { - # Ampersand-encoding based entirely on Nat Irons's Amputator - # MT plugin: - $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', - '&', $text); - ; - } - # Encode remaining <'s - $text = str_replace('<', '<', $text); - - return $text; - } - - protected function doAutoLinks($text) - { - $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', - array(&$this, '_doAutoLinks_url_callback'), $text); - - # Email addresses: - $text = preg_replace_callback('{ - < - (?:mailto:)? - ( - (?: - [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+ - | - ".*?" - ) - \@ - (?: - [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+ - | - \[[\d.a-fA-F:]+\] # IPv4 & IPv6 - ) - ) - > - }xi', - array(&$this, '_doAutoLinks_email_callback'), $text); - - return $text; - } - - protected function _doAutoLinks_url_callback($matches) - { - $url = $this->encodeAttribute($matches[1]); - $link = "$url"; - return $this->hashPart($link); - } - - protected function _doAutoLinks_email_callback($matches) - { - $address = $matches[1]; - $link = $this->encodeEmailAddress($address); - return $this->hashPart($link); - } - - protected function encodeEmailAddress($addr) - { - # - # Input: an email address, e.g. "foo@example.com" - # - # Output: the email address as a mailto link, with each character - # of the address encoded as either a decimal or hex entity, in - # the hopes of foiling most address harvesting spam bots. E.g.: - # - #

    foo@exampl - # e.com

    - # - # Based by a filter by Matthew Wickline, posted to BBEdit-Talk. - # With some optimizations by Milian Wolff. - # - $addr = "mailto:".$addr; - $chars = preg_split('/(? $char) - { - $ord = ord($char); - # Ignore non-ascii chars. - if ($ord < 128) - { - $r = ($seed * (1 + $key)) % 100; # Pseudo-random function. - # roughly 10% raw, 45% hex, 45% dec - # '@' *must* be encoded. I insist. - if ($r > 90 && $char != '@') /* do nothing - */; - else if ($r < 45) - $chars[$key] = '&#x'.dechex($ord).';'; - else - $chars[$key] = '&#'.$ord.';'; - } - } - - $addr = implode('', $chars); - $text = implode('', array_slice($chars, 7)); # text without `mailto:` - $addr = "$text"; - - return $addr; - } - - protected function parseSpan($str) - { - # - # Take the string $str and parse it into tokens, hashing embeded HTML, - # escaped characters and handling code spans. - # - $output = ''; - - $span_re = '{ - ( - \\\\'.$this->escape_chars_re.' - | - (?no_markup ? '' : ' - | - # comment - | - <\?.*?\?> | <%.*?%> # processing instruction - | - <[/!$]?[-a-zA-Z0-9:_]+ # regular tags - (?> - \s - (?>[^"\'>]+|"[^"]*"|\'[^\']*\')* - )? - > - ').' - ) - }xs'; - - while (1) - { - # - # Each loop iteration seach for either the next tag, the next - # openning code span marker, or the next escaped character. - # Each token is then passed to handleSpanToken. - # - $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE); - - # Create token from text preceding tag. - if ($parts[0] != '') - { - $output .= $parts[0]; - } - - # Check if we reach the end. - if (isset($parts[1])) - { - $output .= $this->handleSpanToken($parts[1], $parts[2]); - $str = $parts[2]; - } - else - { - break; - } - } - - return $output; - } - - protected function handleSpanToken($token, &$str) - { - # - # Handle $token provided by parseSpan by determining its nature and - # returning the corresponding value that should replace it. - # - switch ($token{0}) - { - case "\\": - return $this->hashPart("&#".ord($token{1}).";"); - case "`": - # Search for end marker in remaining text. - if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', - $str, $matches)) - { - $str = $matches[2]; - $codespan = $this->makeCodeSpan($matches[1]); - return $this->hashPart($codespan); - } - return $token; // return as text since no ending marker found. - default: - return $this->hashPart($token); - } - } - - protected function outdent($text) - { - # - # Remove one level of line-leading tabs or spaces - # - return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text); - } - - protected function detab($text) - { - # - # Replace tabs with the appropriate amount of space. - # - # For each line we separate the line in blocks delemited by - # tab characters. Then we reconstruct every line by adding the - # appropriate number of space between each blocks. - - $text = preg_replace_callback('/^.*\t.*$/m', - array(&$this, '_detab_callback'), $text); - - return $text; - } - - protected function _detab_callback($matches) - { - $line = $matches[0]; - $strlen = $this->utf8_strlen; # strlen function for UTF-8. - # Split in blocks. - $blocks = explode("\t", $line); - # Add each blocks to the line. - $line = $blocks[0]; - unset($blocks[0]); # Do not add first block twice. - foreach ($blocks as $block) - { - # Calculate amount of space, insert spaces, insert block. - $amount = $this->tab_width - - $strlen($line, 'UTF-8') % $this->tab_width; - $line .= str_repeat(" ", $amount).$block; - } - return $line; - } - - protected function _initDetab() - { - # - # Check for the availability of the function in the `utf8_strlen` property - # (initially `mb_strlen`). If the function is not available, create a - # function that will loosely count the number of UTF-8 characters with a - # regular expression. - # - if (function_exists($this->utf8_strlen)) - return; - $this->utf8_strlen = create_function('$text', 'return preg_match_all( - "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/", - $text, $m);'); - } - - protected function unhash($text) - { - if(false === strpos($text, "\x1A")) - { - return $text; - } - - # - # Swap back in all the tags hashed by _HashHTMLBlocks. - # - return preg_replace_callback('/(\w)\x1A[0-9]+\1/', - array(&$this, '_unhash_callback'), $text); - } - - protected function _unhash_callback($matches) - { - return $this->html_hashes[$matches[0]]; - } - -} \ No newline at end of file diff --git a/vendor/parser/README.markdown b/vendor/parser/README.markdown deleted file mode 100644 index eeca476..0000000 --- a/vendor/parser/README.markdown +++ /dev/null @@ -1,179 +0,0 @@ -PHP Markdown -============ - -Version 1.0.1m - Sat 21 Jun 2008 - -by Michel Fortin - - -based on work by John Gruber - - - -Introduction ------------- - -Markdown is a text-to-HTML conversion tool for web writers. Markdown -allows you to write using an easy-to-read, easy-to-write plain text -format, then convert it to structurally valid XHTML (or HTML). - -"Markdown" is two things: a plain text markup syntax, and a software -tool, written in Perl, that converts the plain text markup to HTML. -PHP Markdown is a port to PHP of the original Markdown program by -John Gruber. - -PHP Markdown can work as a plug-in for WordPress and bBlog, as a -modifier for the Smarty templating engine, or as a remplacement for -textile formatting in any software that support textile. - -Full documentation of Markdown's syntax is available on John's -Markdown page: - - -Installation and Requirement ----------------------------- - -PHP Markdown requires PHP version 4.0.5 or later. - - -### WordPress ### - -PHP Markdown works with [WordPress][wp], version 1.2 or later. - - [wp]: http://wordpress.org/ - -1. To use PHP Markdown with WordPress, place the "makrdown.php" file - in the "plugins" folder. This folder is located inside - "wp-content" at the root of your site: - - (site home)/wp-content/plugins/ - -2. Activate the plugin with the administrative interface of - WordPress. In the "Plugins" section you will now find Markdown. - To activate the plugin, click on the "Activate" button on the - same line than Markdown. Your entries will now be formatted by - PHP Markdown. - -3. To post Markdown content, you'll first have to disable the - "visual" editor in the User section of WordPress. - -You can configure PHP Markdown to not apply to the comments on your -WordPress weblog. See the "Configuration" section below. - -It is not possible at this time to apply a different set of -filters to different entries. All your entries will be formated by -PHP Markdown. This is a limitation of WordPress. If your old entries -are written in HTML (as opposed to another formatting syntax, like -Textile), they'll probably stay fine after installing Markdown. - - -### bBlog ### - -PHP Markdown also works with [bBlog][bb]. - - [bb]: http://www.bblog.com/ - -To use PHP Markdown with bBlog, rename "markdown.php" to -"modifier.markdown.php" and place the file in the "bBlog_plugins" -folder. This folder is located inside the "bblog" directory of -your site, like this: - - (site home)/bblog/bBlog_plugins/modifier.markdown.php - -Select "Markdown" as the "Entry Modifier" when you post a new -entry. This setting will only apply to the entry you are editing. - - -### Replacing Textile in TextPattern ### - -[TextPattern][tp] use [Textile][tx] to format your text. You can -replace Textile by Markdown in TextPattern without having to change -any code by using the *Texitle Compatibility Mode*. This may work -with other software that expect Textile too. - - [tx]: http://www.textism.com/tools/textile/ - [tp]: http://www.textpattern.com/ - -1. Rename the "markdown.php" file to "classTextile.php". This will - make PHP Markdown behave as if it was the actual Textile parser. - -2. Replace the "classTextile.php" file TextPattern installed in your - web directory. It can be found in the "lib" directory: - - (site home)/textpattern/lib/ - -Contrary to Textile, Markdown does not convert quotes to curly ones -and does not convert multiple hyphens (`--` and `---`) into en- and -em-dashes. If you use PHP Markdown in Textile Compatibility Mode, you -can solve this problem by installing the "smartypants.php" file from -[PHP SmartyPants][psp] beside the "classTextile.php" file. The Textile -Compatibility Mode function will use SmartyPants automatically without -further modification. - - [psp]: http://michelf.com/projects/php-smartypants/ - - -### Updating Markdown in Other Programs ### - -Many web applications now ship with PHP Markdown, or have plugins to -perform the conversion to HTML. You can update PHP Markdown in many of -these programs by swapping the old "markdown.php" file for the new one. - -Here is a short non-exhaustive list of some programs and where they -hide the "markdown.php" file. - -| Program | Path to Markdown -| ------- | ---------------- -| [Pivot][] | `(site home)/pivot/includes/markdown/markdown.php` - -If you're unsure if you can do this with your application, ask the -developer, or wait for the developer to update his application or -plugin with the new version of PHP Markdown. - - [Pivot]: http://pivotlog.net/ - - -### In Your Own Programs ### - -You can use PHP Markdown easily in your current PHP program. Simply -include the file and then call the Markdown function on the text you -want to convert: - - include_once "markdown.php"; - $my_html = Markdown($my_text); - -If you wish to use PHP Markdown with another text filter function -built to parse HTML, you should filter the text *after* the Markdown -function call. This is an example with [PHP SmartyPants][psp]: - - $my_html = SmartyPants(Markdown($my_text)); - - -### With Smarty ### - -If your program use the [Smarty][sm] template engine, PHP Markdown -can now be used as a modifier for your templates. Rename "markdown.php" -to "modifier.markdown.php" and put it in your smarty plugins folder. - - [sm]: http://smarty.php.net/ - -If you are using MovableType 3.1 or later, the Smarty plugin folder is -located at `(MT CGI root)/php/extlib/smarty/plugins`. This will allow -Markdown to work on dynamic pages. - - -Configuration -------------- - -By default, PHP Markdown produces XHTML output for tags with empty -elements. E.g.: - -
    - -Markdown can be configured to produce HTML-style tags; e.g.: - -
    - -To do this, you must edit the "MARKDOWN_EMPTY_ELEMENT_SUFFIX" -definition below the "Global default settings" header at the start of -the "markdown.php" file. \ No newline at end of file