better markmin, thanks Vladyslav
This commit is contained in:
@@ -1 +1 @@
|
||||
Version 2.00.0 (2012-07-11 22:40:45) dev
|
||||
Version 2.00.0 (2012-07-11 23:13:56) dev
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
||||
'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!',
|
||||
'About': 'About',
|
||||
'About': 'about',
|
||||
'About application': 'About application',
|
||||
'Additional code for your application': 'Additional code for your application',
|
||||
'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel',
|
||||
@@ -24,6 +24,7 @@
|
||||
'Application name:': 'Application name:',
|
||||
'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?',
|
||||
'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?',
|
||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||
'Are you sure you want to uninstall application "%s"': 'Are you sure you want to uninstall application "%s"',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?',
|
||||
'Are you sure you want to upgrade web2py now?': 'Are you sure you want to upgrade web2py now?',
|
||||
@@ -31,20 +32,30 @@
|
||||
'Cannot be empty': 'Cannot be empty',
|
||||
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.',
|
||||
'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:',
|
||||
'Change admin password': 'change admin password',
|
||||
'Check for upgrades': 'check for upgrades',
|
||||
'Check to delete': 'Check to delete',
|
||||
'Checking for upgrades...': 'Checking for upgrades...',
|
||||
'Clean': 'clean',
|
||||
'Compile': 'compile',
|
||||
'Controllers': 'Controllers',
|
||||
'Create': 'create',
|
||||
'Create new simple application': 'Create new simple application',
|
||||
'Current request': 'Current request',
|
||||
'Current response': 'Current response',
|
||||
'Current session': 'Current session',
|
||||
'DESIGN': 'DESIGN',
|
||||
'Date and Time': 'Date and Time',
|
||||
'Debug': 'Debug',
|
||||
'Delete': 'Delete',
|
||||
'Delete:': 'Delete:',
|
||||
'Deploy': 'deploy',
|
||||
'Deploy on Google App Engine': 'Deploy on Google App Engine',
|
||||
'Deploy to OpenShift': 'Deploy to OpenShift',
|
||||
'Design for': 'Design for',
|
||||
'Disable': 'Disable',
|
||||
'EDIT': 'EDIT',
|
||||
'Edit': 'edit',
|
||||
'Edit application': 'Edit application',
|
||||
'Edit current record': 'Edit current record',
|
||||
'Editing Language file': 'Editing Language file',
|
||||
@@ -52,11 +63,15 @@
|
||||
'Editing file "%s"': 'Editing file "%s"',
|
||||
'Enterprise Web Framework': 'Enterprise Web Framework',
|
||||
'Error logs for "%(app)s"': 'Error logs for "%(app)s"',
|
||||
'Errors': 'errors',
|
||||
'Exception instance attributes': 'Exception instance attributes',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
||||
'Get from URL:': 'Get from URL:',
|
||||
'Hello World': 'Здравей, свят',
|
||||
'Help': 'help',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'Import/Export': 'Import/Export',
|
||||
'Install': 'install',
|
||||
'Installed applications': 'Installed applications',
|
||||
'Internal State': 'Internal State',
|
||||
'Invalid Query': 'Невалидна заявка',
|
||||
@@ -67,6 +82,7 @@
|
||||
'License for': 'License for',
|
||||
'Login': 'Login',
|
||||
'Login to the Administrative Interface': 'Login to the Administrative Interface',
|
||||
'Logout': 'logout',
|
||||
'Models': 'Models',
|
||||
'Modules': 'Modules',
|
||||
'NO': 'NO',
|
||||
@@ -75,17 +91,25 @@
|
||||
'New simple application': 'New simple application',
|
||||
'No databases in this application': 'No databases in this application',
|
||||
'Original/Translation': 'Original/Translation',
|
||||
'Overwrite installed app': 'overwrite installed app',
|
||||
'PAM authenticated user, cannot change password here': 'PAM authenticated user, cannot change password here',
|
||||
'Pack all': 'pack all',
|
||||
'Pack compiled': 'pack compiled',
|
||||
'Peeking at file': 'Peeking at file',
|
||||
'Plugin "%s" in application': 'Plugin "%s" in application',
|
||||
'Plugins': 'Plugins',
|
||||
'Powered by': 'Powered by',
|
||||
'Query:': 'Query:',
|
||||
'Reload routes': 'Reload routes',
|
||||
'Remove compiled': 'remove compiled',
|
||||
'Resolve Conflict file': 'Resolve Conflict file',
|
||||
'Rows in table': 'Rows in table',
|
||||
'Rows selected': 'Rows selected',
|
||||
'Running on %s': 'Running on %s',
|
||||
'Saved file hash:': 'Saved file hash:',
|
||||
'Searching:': 'Searching:',
|
||||
'Site': 'site',
|
||||
'Start wizard': 'start wizard',
|
||||
'Static files': 'Static files',
|
||||
'Sure you want to delete this object?': 'Сигурен ли си, че искаш да изтриеш този обект?',
|
||||
'TM': 'TM',
|
||||
@@ -110,9 +134,11 @@
|
||||
'Unable to download': 'Unable to download',
|
||||
'Unable to download app because:': 'Unable to download app because:',
|
||||
'Unable to download because': 'Unable to download because',
|
||||
'Uninstall': 'uninstall',
|
||||
'Update:': 'Update:',
|
||||
'Upload & install packed application': 'Upload & install packed application',
|
||||
'Upload a package:': 'Upload a package:',
|
||||
'Upload and install packed application': 'Upload and install packed application',
|
||||
'Upload existing application': 'Upload existing application',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.',
|
||||
'Use an url:': 'Use an url:',
|
||||
@@ -120,7 +146,6 @@
|
||||
'Views': 'Views',
|
||||
'Welcome to web2py': 'Добре дошъл в web2py',
|
||||
'YES': 'YES',
|
||||
'About': 'about',
|
||||
'additional code for your application': 'additional code for your application',
|
||||
'admin disabled because no admin password': 'admin disabled because no admin password',
|
||||
'admin disabled because not supported on google app engine': 'admin disabled because not supported on google apps engine',
|
||||
@@ -139,19 +164,14 @@
|
||||
'cache, errors and sessions cleaned': 'cache, errors and sessions cleaned',
|
||||
'cannot create file': 'cannot create file',
|
||||
'cannot upload file "%(filename)s"': 'cannot upload file "%(filename)s"',
|
||||
'Change admin password': 'change admin password',
|
||||
'check all': 'check all',
|
||||
'Check for upgrades': 'check for upgrades',
|
||||
'Clean': 'clean',
|
||||
'click here for online examples': 'щракни тук за онлайн примери',
|
||||
'click here for the administrative interface': 'щракни тук за административния интерфейс',
|
||||
'click to check for upgrades': 'click to check for upgrades',
|
||||
'code': 'code',
|
||||
'collapse/expand all': 'collapse/expand all',
|
||||
'Compile': 'compile',
|
||||
'compiled application removed': 'compiled application removed',
|
||||
'controllers': 'controllers',
|
||||
'Create': 'create',
|
||||
'create file with filename:': 'create file with filename:',
|
||||
'create new application:': 'create new application:',
|
||||
'created by': 'created by',
|
||||
@@ -167,16 +187,13 @@
|
||||
'delete': 'delete',
|
||||
'delete all checked': 'delete all checked',
|
||||
'delete plugin': 'delete plugin',
|
||||
'Deploy': 'deploy',
|
||||
'design': 'дизайн',
|
||||
'direction: ltr': 'direction: ltr',
|
||||
'done!': 'готово!',
|
||||
'download layouts': 'download layouts',
|
||||
'download plugins': 'download plugins',
|
||||
'Edit': 'edit',
|
||||
'edit controller': 'edit controller',
|
||||
'edit views:': 'edit views:',
|
||||
'Errors': 'errors',
|
||||
'export as csv file': 'export as csv file',
|
||||
'exposes': 'exposes',
|
||||
'extends': 'extends',
|
||||
@@ -193,12 +210,10 @@
|
||||
'file saved on %s': 'file saved on %s',
|
||||
'files': 'files',
|
||||
'filter': 'filter',
|
||||
'Help': 'help',
|
||||
'htmledit': 'htmledit',
|
||||
'includes': 'includes',
|
||||
'insert new': 'insert new',
|
||||
'insert new %s': 'insert new %s',
|
||||
'Install': 'install',
|
||||
'internal error': 'internal error',
|
||||
'invalid password': 'invalid password',
|
||||
'invalid request': 'невалидна заявка',
|
||||
@@ -208,7 +223,6 @@
|
||||
'languages updated': 'languages updated',
|
||||
'loading...': 'loading...',
|
||||
'login': 'login',
|
||||
'Logout': 'logout',
|
||||
'merge': 'merge',
|
||||
'models': 'models',
|
||||
'modules': 'modules',
|
||||
@@ -220,9 +234,6 @@
|
||||
'or import from csv file': 'or import from csv file',
|
||||
'or provide app url:': 'or provide app url:',
|
||||
'or provide application url:': 'or provide application url:',
|
||||
'Overwrite installed app': 'overwrite installed app',
|
||||
'Pack all': 'pack all',
|
||||
'Pack compiled': 'pack compiled',
|
||||
'pack plugin': 'pack plugin',
|
||||
'password changed': 'password changed',
|
||||
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted',
|
||||
@@ -231,16 +242,13 @@
|
||||
'record': 'record',
|
||||
'record does not exist': 'записът не съществува',
|
||||
'record id': 'record id',
|
||||
'Remove compiled': 'remove compiled',
|
||||
'restore': 'restore',
|
||||
'revert': 'revert',
|
||||
'save': 'save',
|
||||
'selected': 'selected',
|
||||
'session expired': 'session expired',
|
||||
'shell': 'shell',
|
||||
'Site': 'site',
|
||||
'some files could not be removed': 'some files could not be removed',
|
||||
'Start wizard': 'start wizard',
|
||||
'state': 'състояние',
|
||||
'static': 'static',
|
||||
'submit': 'submit',
|
||||
@@ -261,7 +269,6 @@
|
||||
'unable to uninstall "%s"': 'unable to uninstall "%s"',
|
||||
'unable to upgrade because "%s"': 'unable to upgrade because "%s"',
|
||||
'uncheck all': 'uncheck all',
|
||||
'Uninstall': 'uninstall',
|
||||
'update': 'update',
|
||||
'update all languages': 'update all languages',
|
||||
'upgrade web2py now': 'upgrade web2py now',
|
||||
@@ -277,5 +284,3 @@
|
||||
'web2py is up to date': 'web2py is up to date',
|
||||
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<html><body><h1>Markmin markup language</h1><h2>About</h2><p>This is a new markup language that we call markmin designed to produce high quality scientific papers and books and also put them online. We provide serializers for html, latex and pdf. It is implemented in the <code class="">markmin2html</code> function in the <code class="">markmin2html.py</code>.</p><p>Example of usage:</p><pre><code class="">>>> m = "Hello **world** [[link http://web2py.com]]"
|
||||
>>> from markmin2html import markmin2html
|
||||
>>> print markmin2html(m)
|
||||
>>> from markmin2latex import markmin2latex
|
||||
>>> print markmin2latex(m)
|
||||
>>> from markmin2pdf import markmin2pdf # requires pdflatex
|
||||
>>> print markmin2pdf(m)</code></pre><h2>Why?</h2><p>We wanted a markup language with the following requirements:</p><ul><li>less than 100 lines of functional code</li><li>easy to read</li><li>secure</li><li>support table, ul, ol, code</li><li>support html5 video and audio elements (html serialization only)</li><li>can align images and resize them</li><li>can specify class for tables and code elements</li><li>can add anchors</li><li>does not use _ for markup (since it creates odd behavior)</li><li>automatically links urls</li><li>fast</li><li>easy to extend</li><li>supports latex and pdf including references</li><li>allows to describe the markup in the markup (this document is generated from markmin syntax)</li></ul><p>(results depend on text but in average for text ~100K markmin is 30% faster than markdown, for text ~10K it is 10x faster)</p><p>The <a href="http://www.lulu.com/product/paperback/web2py-%283rd-edition%29/12822827">web2py book</a> published by lulu, for example, was entirely generated with markmin2pdf from the online <a href="http://www.web2py.com/book">web2py wiki</a></p><h2>Download</h2><ul><li>http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2html.py</li><li>http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2latex.py</li><li>http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2pdf.py</li></ul><p>markmin2html.py and markmin2latex.py are single files and have no web2py dependence. Their license is BSD.</p><h2>Examples</h2><h3>Bold, italic, code and links</h3><table class=""><tr><td><b>SOURCE</b> </td><td><b>OUTPUT</b></td></tr><tr><td><code class=""># title</code> </td><td><b>title</b></td></tr><tr><td><code class="">## section</code> </td><td><b>section</b></td></tr><tr><td><code class="">### subsection</code> </td><td><b>subsection</b></td></tr><tr><td><code class="">**bold**</code> </td><td><b>bold</b></td></tr><tr><td><code class="">''italic''</code> </td><td><i>italic</i></td></tr><tr><td><code class="">``verbatim``</code> </td><td><code class="">verbatim</code></td></tr><tr><td><code class="">http://google.com</code> </td><td>http://google.com</td></tr><tr><td><code class="">[[click me #myanchor]]</code></td><td><a href="#myanchor">click me</a></td></tr></table>
|
||||
<h3>More on links</h3><p>The format is always <code class="">[[title link]]</code>. Notice you can nest bold, italic and code inside the link title.</p><h3>Anchors <span id="myanchor"><span></h3><p>You can place an anchor anywhere in the text using the syntax <code class="">[[name]]</code> where <i>name</i> is the name of the anchor.
|
||||
You can then link the anchor with <a href="#myanchor">link</a>, i.e. <code class="">[[link #myanchor]]</code>.</p><h3>Images</h3><p><img src="http://www.web2py.com/examples/static/web2py_logo.png" alt="some image" align="right" width="200px" />
|
||||
This paragraph has an image aligned to the right with a width of 200px. Its is placed using the code</p><p><code class="">[[some image http://www.web2py.com/examples/static/web2py_logo.png right 200px]]</code>.</p><h3>Unordered Lists</h3><pre><code class="">- Dog
|
||||
<html><body><h1>Markmin markup language</h1><h2>About</h2><p>This is a new markup language that we call markmin designed to produce high quality scientific papers and books and also put them online. We provide serializers for html, latex and pdf. It is implemented in the <code class="">markmin2html</code> function in the <code class="">markmin2html.py</code>.</p><p>Example of usage:</p><pre><code class="">m = "Hello **world** [[link http://web2py.com]]"
|
||||
from markmin2html import markmin2html
|
||||
print markmin2html(m)
|
||||
from markmin2latex import markmin2latex
|
||||
print markmin2latex(m)
|
||||
from markmin2pdf import markmin2pdf # requires pdflatex
|
||||
print markmin2pdf(m)</code></pre><h2>Why?</h2><p>We wanted a markup language with the following requirements:</p><ul><li>less than 200 lines of functional code</li><li>easy to read</li><li>secure</li><li>support table, ul, ol, code</li><li>support html5 video and audio elements (html serialization only)</li><li>can align images and resize them</li><li>can specify class for tables and code elements</li><li>can add anchors</li><li>does not use _ for markup (since it creates odd behavior)</li><li>automatically links urls</li><li>fast</li><li>easy to extend</li><li>supports latex and pdf including references</li><li>allows to describe the markup in the markup (this document is generated from markmin syntax)</li></ul><p>(results depend on text but in average for text ~100K markmin is 30% faster than markdown, for text ~10K it is 10x faster)</p><p>The <a href="http://www.lulu.com/product/paperback/web2py-%283rd-edition%29/12822827">web2py book</a> published by lulu, for example, was entirely generated with markmin2pdf from the online <a href="http://www.web2py.com/book">web2py wiki</a></p><h2>Download</h2><ul><li><a href="http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2html.py">http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2html.py</a></li><li><a href="http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2latex.py">http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2latex.py</a></li><li><a href="http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2pdf.py">http://web2py.googlecode.com/hg/gluon/contrib/markmin/markmin2pdf.py</a></li></ul><p>markmin2html.py and markmin2latex.py are single files and have no web2py dependence. Their license is BSD.</p><h2>Examples</h2><h3>Bold, italic, code and links</h3><table class=""><tr><td><strong>SOURCE</strong> </td><td><strong>OUTPUT</strong></td></tr><tr><td><code class=""># title</code> </td><td><strong>title</strong></td></tr><tr><td><code class="">## section</code> </td><td><strong>section</strong></td></tr><tr><td><code class="">### subsection</code> </td><td><strong>subsection</strong></td></tr><tr><td><code class="">**bold**</code> </td><td><strong>bold</strong></td></tr><tr><td><code class="">''italic''</code> </td><td><em>italic</em></td></tr><tr><td><code class="">~~strikeout~~</code> </td><td><del>strikeout</del></td></tr><tr><td><code class="">``verbatim``</code> </td><td><code class="">verbatim</code></td></tr><tr><td><code class="">``color with **bold**``:red</code> </td><td><span style="color: red">color with <strong>bold</strong></span></td></tr><tr><td><code class="">``many colors``:color[blue:#ffff00]</code> </td><td><span style="color: blue;background-color: #ffff00;">many colors</span></td></tr><tr><td><code class="">http://google.com</code> </td><td><a href="http://google.com">http://google.com</a></td></tr><tr><td><code class="">[[**click** me #myanchor]]</code> </td><td><a href="#myanchor"><strong>click</strong> me</a></td></tr><tr><td><code class="">[[click me [extra info] #myanchor popup]]</code></td><td><a href="#myanchor" title="extra info" target="_blank">click me</a></td></tr></table><h3>More on links</h3><p>The format is always <code class="">[[title link]]</code> or <code class="">[[title [extra] link]]</code>. Notice you can nest bold, italic, strikeout and code inside the link <code class="">title</code>.</p><h3>Anchors <span id="myanchor"></span></h3><p>You can place an anchor anywhere in the text using the syntax <code class="">[[name]]</code> where <em>name</em> is the name of the anchor.
|
||||
You can then link the anchor with <a href="#myanchor">link</a>, i.e. <code class="">[[link #myanchor]]</code> or <a href="#myanchor" title="extra info">link with an extra info</a>, i.e.
|
||||
<code class="">[[link with an extra info [extra info] #myanchor]]</code>.</p><h3>Images</h3><p><img src="http://www.web2py.com/examples/static/web2py_logo.png" alt="alt-string for the image" title="the image title" style="float:right" width="200px" />
|
||||
This paragraph has an image aligned to the right with a width of 200px. Its is placed using the code</p><p><code class="">[[alt-string for the image [the image title] http://www.web2py.com/examples/static/web2py_logo.png right 200px]]</code>.</p><h3>Unordered Lists</h3><pre><code class="">- Dog
|
||||
- Cat
|
||||
- Mouse</code></pre><p>is rendered as</p><ul><li>Dog</li><li>Cat</li><li>Mouse</li></ul><p>Two new lines between items break the list in two lists.</p><h3>Ordered Lists</h3><pre><code class="">+ Dog
|
||||
+ Cat
|
||||
@@ -19,17 +19,34 @@ This paragraph has an image aligned to the right with a width of 200px. Its is p
|
||||
X | 0 | 0
|
||||
-----:abc</code></pre>
|
||||
is a table and is rendered as
|
||||
<table class="abc"><tr><td><b>A</b></td><td><b>B</b></td><td><b>C</b></td></tr><tr><td>0</td><td>0</td><td>X</td></tr><tr><td>0</td><td>X</td><td>0</td></tr><tr><td>X</td><td>0</td><td>0</td></tr></table>Four or more dashes delimit the table and | separates the columns.
|
||||
The <code class="">:abc</code> at the end sets the class for the table and it is optional.</p><h3>Blockquote</h3><p>A table with a single cell is rendered as a blockquote:</p><blockquote class="">Hello world</blockquote>
|
||||
<h3>Code, <code class=""><code></code>, escaping and extra stuff</h3><pre><code class="python">def test():
|
||||
return "this is Python code"</code></pre><p>Optionally a ` inside a <code class="">``...``</code> block can be inserted escaped with !`!.
|
||||
The <code class="">:python</code> after the markup is also optional. If present, by default, it is used to set the class of the <code> block.
|
||||
The behavior can be overridden by passing an argument <code class="">extra</code> to the <code class="">render</code> function. For example:</p><pre><code class="python">>>> markmin2html("``aaa``:custom",
|
||||
extra=dict(custom=lambda text: 'x'+text+'x'))</code></pre><p>generates</p><code class="python">'xaaax'</code><p>(the <code class="">``...``:custom</code> block is rendered by the <code class="">custom=lambda</code> function passed to <code class="">render</code>).</p><h3>Html5 support</h3><p>Markmin also supports the <video> and <audio> html5 tags using the notation:
|
||||
<pre><code class="">[[title link video]]
|
||||
[[title link audio]]</code></pre></p><h3>Latex</h3><p>Formulas can be embedded into HTML with <code class="">$</code><code class="">$</code>formula<code class="">$</code><code class="">$</code>.
|
||||
You can use Google charts to render the formula:</p><pre><code class="">>>> LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" align="center"/>'
|
||||
>>> markmin2html(text,{'latex':lambda code: LATEX % code.replace('"','"')})</code></pre><h3>Citations and References</h3><p>Citations are treated as internal links in html and proper citations in latex if there is a final section called "References". Items like</p><pre><code class="">- [[key]] value</code></pre><p>in the References will be translated into Latex</p><pre><code class="">\bibitem{key} value</code></pre><p>Here is an example of usage:</p><pre><code class="">As shown in Ref.``mdipierro``:cite
|
||||
<table class="abc"><tr><td><strong>A</strong></td><td><strong>B</strong></td><td><strong>C</strong></td></tr><tr><td>0</td><td>0</td><td>X</td></tr><tr><td>0</td><td>X</td><td>0</td></tr><tr><td>X</td><td>0</td><td>0</td></tr></table>
|
||||
Four or more dashes delimit the table and | separates the columns.
|
||||
The <code class="">:abc</code> at the end sets the class for the table and it is optional.</p><h3>Blockquote</h3><p>A table with a single cell is rendered as a blockquote:</p><blockquote class="">Hello world</blockquote><h3>Code, <code class=""><code></code>, escaping and extra stuff</h3><pre><code class="python">def test():
|
||||
return "this is Python code"</code></pre><p>Optionally a ` inside a <code class="">``...``</code> block can be inserted escaped with !`!.</p><p><strong>NOTE:</strong> You can escape markmin constructions ('',``,**,~~,[,{,]},$,@) with '\' character:
|
||||
so \`\` can replace !`!`! escape string</p><p>The <code class="">:python</code> after the markup is also optional. If present, by default, it is used to set the class of the <code> block.
|
||||
The behavior can be overridden by passing an argument <code class="">extra</code> to the <code class="">render</code> function. For example:</p><pre><code class="python">markmin2html("``aaa``:custom",
|
||||
extra=dict(custom=lambda text: 'x'+text+'x'))</code></pre><p>generates</p><code class="python">'xaaax'</code><p>(the <code class="">``...``:custom</code> block is rendered by the <code class="">custom=lambda</code> function passed to <code class="">render</code>).</p><h3>Html5 support</h3><p>Markmin also supports the <video> and <audio> html5 tags using the notation:
|
||||
<pre><code class="">[[message link video]]
|
||||
[[message link audio]]
|
||||
|
||||
[[message [title] link video]]
|
||||
[[message [title] link audio]]</code></pre>
|
||||
where <code class="">message</code> will be shown in brousers without HTML5 video/audio tags support.</p><h3>Latex and other extensions</h3><p>Formulas can be embedded into HTML with <em>$$<code class="">formula</code>$$</em>.
|
||||
You can use Google charts to render the formula:</p><pre><code class="">LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
||||
markmin2html(text,{'latex':lambda code: LATEX % code.replace('"','\"')})</code></pre><h3>Code with syntax highlighting</h3><p>This requires a syntax highlighting tool, such as the web2py CODE helper.</p><p><pre><code class="">extra={'code_cpp':lambda text: CODE(text,language='cpp').xml(),
|
||||
'code_java':lambda text: CODE(text,language='java').xml(),
|
||||
'code_python':lambda text: CODE(text,language='python').xml(),
|
||||
'code_html':lambda text: CODE(text,language='html').xml()}</code></pre>
|
||||
or simple:
|
||||
<pre><code class="">extra={'code':lambda text,lang='': CODE(text,language=lang).xml()}</code></pre>
|
||||
<pre><code class="">markmin2html(text,extra=extra)</code></pre></p><p>Code can now be marked up as in this example:
|
||||
<pre><code class="">``
|
||||
<html><body>example</body></html>
|
||||
``:code_html</code></pre>
|
||||
OR
|
||||
<pre><code class="">``
|
||||
<html><body>example</body></html>
|
||||
``:code[html]</code></pre></p><h3>Citations and References</h3><p>Citations are treated as internal links in html and proper citations in latex if there is a final section called "References". Items like</p><pre><code class="">- [[key]] value</code></pre><p>in the References will be translated into Latex</p><pre><code class="">\bibitem{key} value</code></pre><p>Here is an example of usage:</p><pre><code class="">As shown in Ref.``mdipierro``:cite
|
||||
|
||||
## References
|
||||
- [[mdipierro]] web2py Manual, 3rd Edition, lulu.com</code></pre><h3>Caveats</h3><p><code class=""><ul/></code>, <code class=""><ol/></code>, <code class=""><code/></code>, <code class=""><table/></code>, <code class=""><blockquote/></code>, <code class=""><h1/></code>, ..., <code class=""><h6/></code> do not have <code class=""><p>...</p></code> around them.</p></body></html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# created my Massimo Di Pierro
|
||||
#!/usr/bin/env python
|
||||
# created by Massimo Di Pierro
|
||||
# improved by Vladyslav Kozlovskyy
|
||||
# license MIT/BSD/GPL
|
||||
import re
|
||||
import cgi
|
||||
@@ -20,7 +21,7 @@ MathJax.Hub.Config({
|
||||
</script>
|
||||
"""
|
||||
|
||||
__all__ = ['render', 'markmin2html']
|
||||
__all__ = ['render', 'markmin2html', 'markmin_escape']
|
||||
|
||||
__doc__ = """
|
||||
# Markmin markup language
|
||||
@@ -44,7 +45,7 @@ print markmin2pdf(m)
|
||||
## Why?
|
||||
|
||||
We wanted a markup language with the following requirements:
|
||||
- less than 100 lines of functional code
|
||||
- less than 200 lines of functional code
|
||||
- easy to read
|
||||
- secure
|
||||
- support table, ul, ol, code
|
||||
@@ -75,33 +76,38 @@ markmin2html.py and markmin2latex.py are single files and have no web2py depende
|
||||
|
||||
### Bold, italic, code and links
|
||||
|
||||
--------------------------------------------------
|
||||
**SOURCE** | **OUTPUT**
|
||||
``# title`` | **title**
|
||||
``## section`` | **section**
|
||||
``### subsection`` | **subsection**
|
||||
``**bold**`` | **bold**
|
||||
``''italic''`` | ''italic''
|
||||
``!`!`verbatim`!`!`` | ``verbatim``
|
||||
``http://google.com`` | http://google.com
|
||||
``[[click me #myanchor]]`` | [[click me #myanchor]]
|
||||
---------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
**SOURCE** | **OUTPUT**
|
||||
``# title`` | **title**
|
||||
``## section`` | **section**
|
||||
``### subsection`` | **subsection**
|
||||
``**bold**`` | **bold**
|
||||
``''italic''`` | ''italic''
|
||||
``~~strikeout~~`` | ~~strikeout~~
|
||||
``!`!`verbatim`!`!`` | ``verbatim``
|
||||
``\`\`color with **bold**\`\`:red`` | ``color with **bold**``:red
|
||||
``\`\`many colors\`\`:color[blue:#ffff00]`` | ``many colors``:color[blue:#ffff00]
|
||||
``http://google.com`` | http://google.com
|
||||
``[[**click** me #myanchor]]`` | [[**click** me #myanchor]]
|
||||
``[[click me [extra info] #myanchor popup]]`` | [[click me [extra info] #myanchor popup]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
### More on links
|
||||
|
||||
The format is always ``[[title link]]``. Notice you can nest bold, italic and code inside the link title.
|
||||
The format is always ``[[title link]]`` or ``[[title [extra] link]]``. Notice you can nest bold, italic, strikeout and code inside the link ``title``.
|
||||
|
||||
### Anchors [[myanchor]]
|
||||
|
||||
You can place an anchor anywhere in the text using the syntax ``[[name]]`` where ''name'' is the name of the anchor.
|
||||
You can then link the anchor with [[link #myanchor]], i.e. ``[[link #myanchor]]``.
|
||||
You can then link the anchor with [[link #myanchor]], i.e. ``[[link #myanchor]]`` or [[link with an extra info [extra info] #myanchor]], i.e.
|
||||
``[[link with an extra info [extra info] #myanchor]]``.
|
||||
|
||||
### Images
|
||||
|
||||
[[some image http://www.web2py.com/examples/static/web2py_logo.png right 200px]]
|
||||
[[alt-string for the image [the image title] http://www.web2py.com/examples/static/web2py_logo.png right 200px]]
|
||||
This paragraph has an image aligned to the right with a width of 200px. Its is placed using the code
|
||||
|
||||
``[[some image http://www.web2py.com/examples/static/web2py_logo.png right 200px]]``.
|
||||
``[[alt-string for the image [the image title] http://www.web2py.com/examples/static/web2py_logo.png right 200px]]``.
|
||||
|
||||
### Unordered Lists
|
||||
|
||||
@@ -169,6 +175,10 @@ def test():
|
||||
``:python
|
||||
|
||||
Optionally a ` inside a ``!`!`...`!`!`` block can be inserted escaped with !`!.
|
||||
|
||||
**NOTE:** You can escape markmin constructions (\\'\\',\`\`,\*\*,\~\~,\[,\{,\]\},\$,\@) with '\\\\' character:
|
||||
so \\\\`\\\\` can replace !`!`! escape string
|
||||
|
||||
The ``:python`` after the markup is also optional. If present, by default, it is used to set the class of the <code> block.
|
||||
The behavior can be overridden by passing an argument ``extra`` to the ``render`` function. For example:
|
||||
|
||||
@@ -183,23 +193,26 @@ generates
|
||||
|
||||
(the ``!`!`...`!`!:custom`` block is rendered by the ``custom=lambda`` function passed to ``render``).
|
||||
|
||||
|
||||
### Html5 support
|
||||
|
||||
Markmin also supports the <video> and <audio> html5 tags using the notation:
|
||||
``
|
||||
[[title link video]]
|
||||
[[title link audio]]
|
||||
[[message link video]]
|
||||
[[message link audio]]
|
||||
|
||||
[[message [title] link video]]
|
||||
[[message [title] link audio]]
|
||||
``
|
||||
where ``message`` will be shown in brousers without HTML5 video/audio tags support.
|
||||
|
||||
### Latex and other extensions
|
||||
|
||||
Formulas can be embedded into HTML with ``$````$``formula``$````$``.
|
||||
Formulas can be embedded into HTML with ''\$\$``formula``\$\$''.
|
||||
You can use Google charts to render the formula:
|
||||
|
||||
``
|
||||
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
||||
markmin2html(text,{'latex':lambda code: LATEX % code.replace('"','\"')})
|
||||
markmin2html(text,{'latex':lambda code: LATEX % code.replace('"','\\\\"')})
|
||||
``
|
||||
|
||||
### Code with syntax highlighting
|
||||
@@ -211,16 +224,27 @@ extra={'code_cpp':lambda text: CODE(text,language='cpp').xml(),
|
||||
'code_java':lambda text: CODE(text,language='java').xml(),
|
||||
'code_python':lambda text: CODE(text,language='python').xml(),
|
||||
'code_html':lambda text: CODE(text,language='html').xml()}
|
||||
``
|
||||
or simple:
|
||||
``
|
||||
extra={'code':lambda text,lang='': CODE(text,language=lang).xml()}
|
||||
``
|
||||
``
|
||||
markmin2html(text,extra=extra)
|
||||
``
|
||||
|
||||
Code can now be marked up as in this example:
|
||||
|
||||
``
|
||||
!`!`
|
||||
<html><body>example</body></html>
|
||||
!`!`:code_html
|
||||
``
|
||||
OR
|
||||
``
|
||||
!`!`
|
||||
<html><body>example</body></html>
|
||||
!`!`:code[html]
|
||||
``
|
||||
|
||||
### Citations and References
|
||||
|
||||
@@ -249,17 +273,26 @@ As shown in Ref.!`!`mdipierro`!`!:cite
|
||||
``<ul/>``, ``<ol/>``, ``<code/>``, ``<table/>``, ``<blockquote/>``, ``<h1/>``, ..., ``<h6/>`` do not have ``<p>...</p>`` around them.
|
||||
|
||||
"""
|
||||
html_colors=['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
|
||||
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
|
||||
'silver', 'teal', 'white', 'yellow']
|
||||
|
||||
META = 'META'
|
||||
LINK = 'LINK'
|
||||
DISABLED_META = META[::-1]
|
||||
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
||||
regex_URL=re.compile(r'(?P<b>(?<!\\)(?:\\\\)*)@\{(?P<f>\w+)/(?P<args>.+?)\}')
|
||||
regex_env=re.compile(r'(?P<b>(?<!\\)(?:\\\\)*)@\{(?P<a>\w+?)\}')
|
||||
regex_expand_meta = re.compile('('+META+'|'+DISABLED_META+')')
|
||||
regex_newlines = re.compile(r'(\n\r)|(\r\n)')
|
||||
regex_dd=re.compile(r'\$\$(?P<latex>.*?)\$\$')
|
||||
regex_code = re.compile(r'('+META+r')|(``(?P<t>.*?)``(:(?P<c>\w+))?)',re.S)
|
||||
regex_code = re.compile('('+META+'|'+DISABLED_META+r')|((?P<b>(?<!\\)(?:\\\\)*)``(?P<t>.*?(?<!\\)(?:\\\\)*)``(?:(?<!\\):(?P<c>\w+)(?:(?<!\\)\[(?P<p>\S+?)(?<!\\)\])?)?)',re.S)
|
||||
regex_maps = [
|
||||
(re.compile(r'[ \t\r]+\n'),'\n'),
|
||||
(re.compile(r'[ \t\r]+\n'),'\n'),
|
||||
(re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*'),'<strong>\g<t></strong>'),
|
||||
(re.compile("''(?P<t>[^\s']+( +[^\s']+)*)''"),'<em>\g<t></em>'),
|
||||
(re.compile(r'(?P<b1>(?<!\\)(?:\\\\)*)\*\*(?P<t>[^\s*]+( +[^\s*]+)*)(?P<b2>(?<!\\)(?:\\\\)*)\*\*'),'\g<b1><strong>\g<t>\g<b2></strong>'),
|
||||
(re.compile(r'(?P<b1>(?<!\\)(?:\\\\)*)~~(?P<t>[^\s*]+( +[^\s*]+)*)(?P<b2>(?<!\\)(?:\\\\)*)~~'),'\g<b1><del>\g<t>\g<b2></del>'),
|
||||
(re.compile(r"(?P<b1>(?<!\\)(?:\\\\)*)''(?P<t>[^\s']+(?: +[^\s']+)*)(?P<b2>(?<!\\)(?:\\\\)*)''"),'\g<b1><em>\g<t>\g<b2></em>'),
|
||||
(re.compile(r'^#{6} (?P<t>[^\n]+)',re.M),'\n\n<<h6>\g<t></h6>\n'),
|
||||
(re.compile(r'^#{5} (?P<t>[^\n]+)',re.M),'\n\n<<h5>\g<t></h5>\n'),
|
||||
(re.compile(r'^#{4} (?P<t>[^\n]+)',re.M),'\n\n<<h4>\g<t></h4>\n'),
|
||||
@@ -273,25 +306,29 @@ regex_maps = [
|
||||
(re.compile(r'<<'),'\n\n<<'),
|
||||
(re.compile(r'\n\s+\n'),'\n\n')]
|
||||
regex_table = re.compile(r'^\-{4,}\n(?P<t>.*?)\n\-{4,}(:(?P<c>\w+))?\n',re.M|re.S)
|
||||
regex_anchor = re.compile(r'\[\[(?P<t>\S+)\]\]')
|
||||
regex_image_center_width = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +center +(?P<w>\d+px)\]\]')
|
||||
regex_image_width = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right) +(?P<w>\d+px)\]\]')
|
||||
regex_image_center = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +center\]\]')
|
||||
regex_image = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right)\]\]')
|
||||
regex_video = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +video\]\]')
|
||||
regex_audio = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +audio\]\]')
|
||||
regex_link = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+)\]\]')
|
||||
regex_link_popup = re.compile(r'\[\[(?P<t>[^\]]*?) +(?P<k>\S+) popup\]\]')
|
||||
regex_link_no_anchor = re.compile(r'\[\[ +(?P<k>\S+)\]\]')
|
||||
regex_qr = re.compile(r'(?<!["\w>/=])qr:(?P<k>\w+://[\w.\-+?&%/:]+)',re.M)
|
||||
regex_embed = re.compile(r'(?<!["\w>/=])embed:(?P<k>\w+://[\w.\-+?&%/:]+)', re.M)
|
||||
regex_iframe = re.compile(r'(?<!["\w>/=])iframe:(?P<k>\w+://[\w.\-+?&%/:]+)', re.M)
|
||||
regex_auto_image = re.compile(r'(?<!["\w>/=])(?P<k>\w+://\S+\.(jpeg|JPEG|jpg|JPG|gif|GIF|png|PNG)(\?\S+)?)',re.M)
|
||||
regex_auto_video = re.compile(r'(?<!["\w>/=])(?P<k>\w+://\S+\.(mp4|MP4|mpeg|MPEG|mov|MOV)(\?\S+)?)',re.M)
|
||||
regex_auto_audio = re.compile(r'(?<!["\w>/=])(?P<k>\w+://\S+\.(mp3|MP3|wav|WAV)(\?\S+)?)',re.M)
|
||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://\S+)',re.M)
|
||||
regex_qr = re.compile(r'(?<!["\w>/=])qr:(?P<k>\w+://[\w\d\-+?&%/:.]+)',re.M)
|
||||
regex_embed = re.compile(r'(?<!["\w>/=])embed:(?P<k>\w+://[\w\d\-+_=?%&/:.]+)', re.M)
|
||||
regex_iframe = re.compile(r'(?<!["\w>/=])iframe:(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
||||
regex_auto_image = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(jpeg|JPEG|jpg|JPG|gif|GIF|png|PNG)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
|
||||
regex_auto_video = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(mp4|MP4|mpeg|MPEG|mov|MOV)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
|
||||
regex_auto_audio = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(mp3|MP3|wav|WAV)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
|
||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
|
||||
|
||||
def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='google'):
|
||||
regex_link=re.compile(r'('+LINK+r')|(?P<b>(?<!\\)(?:\\\\)*)\[\[(?P<s>.*?)(?<!\\)\]\]')
|
||||
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+(?<!\\)\[(?P<a>.+?(?<!\\)(?:\\\\)*)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
|
||||
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+(?<!\\)\[(?P<a>.+?(?<!\\)(?:\\\\)*)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$')
|
||||
|
||||
regex_backslash = re.compile(r"(\\+)(['`:*~\\[\]{}@\$])")
|
||||
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$])")
|
||||
|
||||
def markmin_escape(text):
|
||||
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
|
||||
return regex_markmin_escape.sub(lambda m: '\\'+m.group(0).replace('\\','\\\\'), text)
|
||||
|
||||
def remove_backslashes(text):
|
||||
return regex_backslash.sub(lambda m: m.group(0)[m.group(0).find('\\')+1:].replace('\\\\','\\') , text)
|
||||
|
||||
def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='google',auto=True):
|
||||
"""
|
||||
Arguments:
|
||||
- text is the text to be processed
|
||||
@@ -301,7 +338,8 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
|
||||
allowed = dict(code=('python','cpp','java'))
|
||||
- sep can be 'p' to separate text in <p>...</p>
|
||||
or can be 'br' to separate text using <br />
|
||||
|
||||
- auto is a True/False value (default is True) -
|
||||
enables auto links processing for iframe,embed,qr,url,image,video,audio
|
||||
|
||||
>>> render('this is\\n# a section\\nparagraph')
|
||||
'<p>this is</p><h1>a section</h1><p>paragraph</p>'
|
||||
@@ -338,67 +376,211 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
|
||||
'<p><a href="http://example.com">this is a link</a></p>'
|
||||
|
||||
>>> render('[[this is an image http://example.com left]]')
|
||||
'<p><img src="http://example.com" alt="this is an image" align="left" /></p>'
|
||||
>>> render('[[this is an image http://example.com left 200px]]')
|
||||
'<p><img src="http://example.com" alt="this is an image" align="left" width="200px" /></p>'
|
||||
'<p><img src="http://example.com" alt="this is an image" style="float:left" /></p>'
|
||||
|
||||
>>> render('[[this is an image http://example.com video]]')
|
||||
'<p><video controls="controls"><source src="http://example.com" /></video></p>'
|
||||
>>> render('[[this is an image http://example.com audio]]')
|
||||
'<p><audio controls="controls"><source src="http://example.com" /></audio></p>'
|
||||
>>> render('[[this is an image http://example.com left 200px]]')
|
||||
'<p><img src="http://example.com" alt="this is an image" style="float:left" width="200px" /></p>'
|
||||
|
||||
>>> render("[[Your browser doesn't support <video> HTML5 tag http://example.com video]]")
|
||||
'<p><video controls="controls"><source src="http://example.com" />Your browser doesn\\'t support <video> HTML5 tag</video></p>'
|
||||
|
||||
>>> render("[[Your browser doesn't support <audio> HTML5 tag http://example.com audio]]")
|
||||
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support <audio> HTML5 tag</audio></p>'
|
||||
|
||||
>>> render('[[this is a **link** http://example.com]]')
|
||||
'<p><a href="http://example.com">this is a <strong>link</strong></a></p>'
|
||||
|
||||
>>> render("``aaa``:custom",extra=dict(custom=lambda text: 'x'+text+'x'))
|
||||
>>> render("``aaa``:custom", extra=dict(custom=lambda text: 'x'+text+'x'))
|
||||
'xaaax'
|
||||
|
||||
|
||||
>>> print render(r"$$\int_a^b sin(x)dx$$")
|
||||
<img src="http://chart.apis.google.com/chart?cht=tx&chl=\\int_a^b sin(x)dx" />
|
||||
|
||||
>>> markmin2html(r"use backslash: \[\[[[mess\[[ag\]]e link]]\]]")
|
||||
'<p>use backslash: [[<a href="link">mess[[ag]]e</a>]]</p>'
|
||||
|
||||
>>> markmin2html("backslash instead of exclamation sign: \``probe``")
|
||||
'<p>backslash instead of exclamation sign: ``probe``</p>'
|
||||
|
||||
>>> render(r"simple image: [[\[[this is an image\]] http://example.com IMG]]!!!")
|
||||
'<p>simple image: <img src="http://example.com" alt="[[this is an image]]" />!!!</p>'
|
||||
|
||||
>>> render(r"simple link no anchor with popup: [[ http://example.com popup]]")
|
||||
'<p>simple link no anchor with popup: <a href="http://example.com" target="_blank">http://example.com</a></p>'
|
||||
|
||||
>>> render("auto-url: http://example.com")
|
||||
'<p>auto-url: <a href="http://example.com">http://example.com</a></p>'
|
||||
|
||||
>>> render("auto-image: (http://example.com/image.jpeg)")
|
||||
'<p>auto-image: (<img src="http://example.com/image.jpeg" controls />)</p>'
|
||||
|
||||
>>> render("title1: [[test message [simple \[test\] title] http://example.com ]] test")
|
||||
'<p>title1: <a href="http://example.com" title="simple [test] title">test message</a> test</p>'
|
||||
|
||||
>>> render("title2: \[\[[[test message [simple title] http://example.com popup]]\]]")
|
||||
'<p>title2: [[<a href="http://example.com" title="simple title" target="_blank">test message</a>]]</p>'
|
||||
|
||||
>>> render("title3: [[ [link w/o anchor but with title] http://www.example.com ]]")
|
||||
'<p>title3: <a href="http://www.example.com" title="link w/o anchor but with title">http://www.example.com</a></p>'
|
||||
|
||||
>>> render("title4: [[ [simple title] http://www.example.com popup]]")
|
||||
'<p>title4: <a href="http://www.example.com" title="simple title" target="_blank">http://www.example.com</a></p>'
|
||||
|
||||
>>> render("title5: [[test message [simple title] http://example.com IMG]]")
|
||||
'<p>title5: <img src="http://example.com" alt="test message" title="simple title" /></p>'
|
||||
|
||||
>>> render("title6: [[[test message w/o title] http://example.com IMG]]")
|
||||
'<p>title6: <img src="http://example.com" alt="[test message w/o title]" /></p>'
|
||||
|
||||
>>> render("title7: [[[this is not a title] [this is a title] http://example.com IMG]]")
|
||||
'<p>title7: <img src="http://example.com" alt="[this is not a title]" title="this is a title" /></p>'
|
||||
|
||||
>>> render("title8: [[test message [title] http://example.com center]]")
|
||||
'<p>title8: <p style="text-align:center"><img src="http://example.com" alt="test message" title="title" /></p></p>'
|
||||
|
||||
>>> render("title9: [[test message [title] http://example.com left]]")
|
||||
'<p>title9: <img src="http://example.com" alt="test message" title="title" style="float:left" /></p>'
|
||||
|
||||
>>> render("title10: [[test message [title] http://example.com right 100px]]")
|
||||
'<p>title10: <img src="http://example.com" alt="test message" title="title" style="float:right" width="100px" /></p>'
|
||||
|
||||
>>> render("title11: [[test message [title] http://example.com center 200px]]")
|
||||
'<p>title11: <p style="text-align:center"><img src="http://example.com" alt="test message" title="title" width="200px" /></p></p>'
|
||||
|
||||
>>> render(r"\\[[probe]]")
|
||||
'<p>[[probe]]</p>'
|
||||
|
||||
>>> render(r"\\\\[[probe]]")
|
||||
'<p>\\\\<span id="probe"></span></p>'
|
||||
|
||||
>>> render(r"\\\\\\[[probe]]")
|
||||
'<p>\\\\[[probe]]</p>'
|
||||
|
||||
>>> render(r"\\\\\\\\[[probe]]")
|
||||
'<p>\\\\\\\\<span id="probe"></span></p>'
|
||||
|
||||
>>> render(r"\\\\\\\\\[[probe]]")
|
||||
'<p>\\\\\\\\[[probe]]</p>'
|
||||
|
||||
>>> render(r"\\\\\\\\\\\[[probe]]")
|
||||
'<p>\\\\\\\\\\\\<span id="probe"></span></p>'
|
||||
|
||||
>>> render("``[[ [\\[[probe\]\\]] URL\\[x\\]]]``:red[dummy_params]")
|
||||
'<span style="color: red"><a href="URL[x]" title="[[probe]]">URL[x]</a></span>'
|
||||
|
||||
>>> render("the \\**text**")
|
||||
'<p>the **text**</p>'
|
||||
|
||||
>>> render("the \\``text``")
|
||||
'<p>the ``text``</p>'
|
||||
|
||||
>>> render("the \\\\''text''")
|
||||
"<p>the ''text''</p>"
|
||||
|
||||
>>> render("the [[link [**with** ``<b>title</b>``:red] http://www.example.com]]")
|
||||
'<p>the <a href="http://www.example.com" title="**with** ``<b>title</b>``:red">link</a></p>'
|
||||
|
||||
>>> render("the [[link \\[**without** ``<b>title</b>``:red\\] http://www.example.com]]")
|
||||
'<p>the <a href="http://www.example.com">link [<strong>without</strong> <span style="color: red"><b>title</b></span>]</a></p>'
|
||||
|
||||
>>> render("aaa-META-``code``:text-LINK-[[link http://www.example.com]]-LINK-[[image http://www.picture.com img]]-end")
|
||||
'<p>aaa-META-<code class="text">code</code>-LINK-<a href="http://www.example.com">link</a>-LINK-<img src="http://www.picture.com" alt="image" />-end</p>'
|
||||
|
||||
>>> render("[[<a>test</a> [<a>test2</a>] <a>text3</a>]]")
|
||||
'<p><a href="<a>text3</a>" title="<a>test2</a>"><a>test</a></a></p>'
|
||||
|
||||
>>> render("[[<a>test</a> [<a>test2</a>] <a>text3</a> IMG]]")
|
||||
'<p><img src="<a>text3</a>" alt="<a>test</a>" title="<a>test2</a>" /></p>'
|
||||
|
||||
>>> render("**bold** ''italic'' ~~strikeout~~")
|
||||
'<p><strong>bold</strong> <em>italic</em> <del>strikeout</del></p>'
|
||||
|
||||
>>> render("this is ``a red on yellow text``:c[#FF0000:#FFFF00]")
|
||||
'<p>this is <span style="color: #FF0000;background-color: #FFFF00;">a red on yellow text</span></p>'
|
||||
|
||||
>>> render("this is ``a text with yellow background``:c[:yellow]")
|
||||
'<p>this is <span style="background-color: yellow;">a text with yellow background</span></p>'
|
||||
|
||||
>>> render("this is ``a colored text (RoyalBlue)``:color[rgb(65,105,225)]")
|
||||
'<p>this is <span style="color: rgb(65,105,225);">a colored text (RoyalBlue)</span></p>'
|
||||
|
||||
>>> render("this is ``a green text``:color[green:]")
|
||||
'<p>this is <span style="color: green;">a green text</span></p>'
|
||||
|
||||
>>> render("**@{probe}**", environment=dict(probe="this is a test"))
|
||||
'<p><strong>this is a test</strong></p>'
|
||||
"""
|
||||
text = str(text or '')
|
||||
if environment:
|
||||
def u2(match,environment=environment):
|
||||
a = match.group('a')
|
||||
return str(environment[a])
|
||||
text = re.compile(r'@\{(?P<a>\w+?)\}').sub(u2,text)
|
||||
if not URL is None:
|
||||
# this is experimental @{function/args}
|
||||
def u2(match, environment=environment):
|
||||
b,a = match.group('b','a')
|
||||
return b + str(environment.get(a, match.group(0)))
|
||||
text = regex_env.sub(u2,text)
|
||||
if URL is not None:
|
||||
# this is experimental @{controller/index/args}
|
||||
# turns into a digitally signed URL
|
||||
def u1(match,URL=URL):
|
||||
f,args = match.group('f'), match.group('args')
|
||||
return URL(f,args=args.split('/'),scheme=True,host=True)
|
||||
text = re.compile(
|
||||
'@\{(?P<f>\w+)/(?P<args>.+?)\}'
|
||||
).sub(u1,text)
|
||||
|
||||
b,f,args = match.group('b','f','args')
|
||||
return b + URL(f,args=args.split('/'),scheme=True,host=True)
|
||||
text = regex_URL.sub(u1,text)
|
||||
|
||||
if latex == 'google':
|
||||
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
||||
text = regex_newlines.sub('\n',text)
|
||||
|
||||
#############################################################
|
||||
# replace all blocks marked with ``...``:class with META
|
||||
# store them into segments they will be treated as code
|
||||
#############################################################
|
||||
segments, i = [], 0
|
||||
if latex == 'google':
|
||||
text = regex_dd.sub('``\g<latex>``:latex ',text)
|
||||
text = regex_newlines.sub('\n',text)
|
||||
while True:
|
||||
item = regex_code.search(text,i)
|
||||
if not item: break
|
||||
if item.group()==META:
|
||||
segments.append((None,None))
|
||||
text = text[:item.start()]+META+text[item.end():]
|
||||
segments = []
|
||||
def mark_code(m):
|
||||
if m.group() in ( META, DISABLED_META ):
|
||||
segments.append((None, None, None, m.group(0)))
|
||||
return m.group()
|
||||
else:
|
||||
c = item.group('c') or ''
|
||||
c = m.group('c') or ''
|
||||
p = m.group('p') or ''
|
||||
b = m.group('b') or ''
|
||||
if 'code' in allowed and not c in allowed['code']: c = ''
|
||||
code = item.group('t').replace('!`!','`')
|
||||
segments.append((code,c))
|
||||
text = text[:item.start()]+META+text[item.end():]
|
||||
i=item.start()+3
|
||||
code = m.group('t').replace('!`!','`')
|
||||
segments.append((code, c, p, m.group(0)))
|
||||
return b + META
|
||||
text = regex_code.sub(mark_code, text)
|
||||
|
||||
#############################################################
|
||||
# do h1,h2,h3,h4,h5,h6,b,i,ol,ul and normalize spaces
|
||||
# replace all blocks marked with [[...]] with LINK
|
||||
# store them into links|medias they will be treated as link
|
||||
#############################################################
|
||||
links = []
|
||||
def mark_link(m):
|
||||
if m.group() == LINK:
|
||||
links.append(None)
|
||||
b = ''
|
||||
else:
|
||||
s = m.group('s') or ''
|
||||
b = m.group('b') or ''
|
||||
links.append(s)
|
||||
return b + LINK
|
||||
text = regex_link.sub(mark_link, text)
|
||||
|
||||
#############################################################
|
||||
# normalize spaces
|
||||
#############################################################
|
||||
text = '\n'.join(t.strip() for t in text.split('\n'))
|
||||
text = cgi.escape(text)
|
||||
|
||||
if auto:
|
||||
text = regex_iframe.sub('<iframe src="\g<k>" frameborder="0" allowfullscreen></iframe>',text)
|
||||
text = regex_embed.sub('<a href="\g<k>" class="embed">\g<k></a>',text)
|
||||
text = regex_qr.sub('<img width="80px" src="http://qrcode.kaywa.com/img.php?s=8&d=\g<k>" alt="qr code" />',text)
|
||||
text = regex_auto_image.sub('<img src="\g<k>" controls />', text)
|
||||
text = regex_auto_video.sub('<video src="\g<k>" controls></video>', text)
|
||||
text = regex_auto_audio.sub('<audio src="\g<k>" controls></audio>', text)
|
||||
text = regex_auto.sub('<a href="\g<k>">\g<k></a>', text)
|
||||
|
||||
#############################################################
|
||||
# do h1,h2,h3,h4,h5,h6,b,i,ol,ul
|
||||
#############################################################
|
||||
for regex, sub in regex_maps:
|
||||
text = regex.sub(sub,text)
|
||||
|
||||
@@ -417,28 +599,6 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
|
||||
else:
|
||||
text = text[:item.start()] + '<<blockquote class="%s">'%c + content + '</blockquote>\n' + text[item.end():]
|
||||
|
||||
#############################################################
|
||||
# deal with images, videos, audios and links
|
||||
#############################################################
|
||||
|
||||
text = regex_anchor.sub('<span id="\g<t>"><span>', text)
|
||||
text = regex_image_center_width.sub('<p style="text-align:center"><img src="\g<k>" alt="\g<t>" width="\g<w>" /></p>', text)
|
||||
text = regex_image_width.sub('<img src="\g<k>" alt="\g<t>" style="float:\g<p>" width="\g<w>" />', text)
|
||||
text = regex_image_center.sub('<p style="text-align:center"><img src="\g<k>" alt="\g<t>" /></p>', text)
|
||||
text = regex_image.sub('<img src="\g<k>" alt="\g<t>" style="float:\g<p>" />', text)
|
||||
text = regex_video.sub('<video controls="controls"><source src="\g<k>" /></video>', text)
|
||||
text = regex_audio.sub('<audio controls="controls"><source src="\g<k>" /></audio>', text)
|
||||
text = regex_link_popup.sub('<a href="\g<k>" target="_blank">\g<t></a>', text)
|
||||
text = regex_link_no_anchor.sub('<a href="\g<k>">\g<k></a>', text)
|
||||
text = regex_link.sub('<a href="\g<k>">\g<t></a>', text)
|
||||
text = regex_qr.sub('<img width="80px" src="http://qrcode.kaywa.com/img.php?s=8&d=\g<k>" alt="qr code" />',text)
|
||||
text = regex_iframe.sub('<iframe src="\g<k>" frameborder="0" allowfullscreen></iframe>',text)
|
||||
text = regex_embed.sub('<a href="\g<k>" class="embed">\g<k></a>',text)
|
||||
text = regex_auto_image.sub('<img src="\g<k>" controls />', text)
|
||||
text = regex_auto_video.sub('<video src="\g<k>" controls></video>', text)
|
||||
text = regex_auto_audio.sub('<audio src="\g<k>" controls></audio>', text)
|
||||
text = regex_auto.sub('<a href="\g<k>">\g<k></a>', text)
|
||||
|
||||
#############################################################
|
||||
# deal with paragraphs (trick <<ul, <<ol, <<table, <<h1, etc)
|
||||
# the << indicates that there should NOT be a new paragraph
|
||||
@@ -457,46 +617,104 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
|
||||
#############################################################
|
||||
text=text.replace('<<','<')
|
||||
|
||||
#############################################################
|
||||
# deal with images, videos, audios and links
|
||||
#############################################################
|
||||
def sub_media(m):
|
||||
d=m.groupdict()
|
||||
if not d['k']:
|
||||
return m.group(0)
|
||||
d['k'] = cgi.escape(d['k'])
|
||||
d['t'] = d['t'] or ''
|
||||
d['width'] = ' width="%s"'%d['w'] if d['w'] else ''
|
||||
d['title'] = ' title="%s"'%cgi.escape(d['a']).replace(META, DISABLED_META) if d['a'] else ''
|
||||
d['style'] = d['p_begin'] = d['p_end'] = ''
|
||||
if d['p'] == 'center':
|
||||
d['p_begin'] = '<p style="text-align:center">'
|
||||
d['p_end'] = '</p>'
|
||||
elif d['p'] in ('left','right'):
|
||||
d['style'] = ' style="float:%s"'%d['p']
|
||||
if d['p'] in ('video','audio'):
|
||||
d['t']=render(d['t'],{},{},'',URL,environment,latex,auto)
|
||||
return '<%(p)s controls="controls"%(title)s%(width)s><source src="%(k)s" />%(t)s</%(p)s>'%d
|
||||
d['alt'] = ' alt="%s"'%cgi.escape(d['t']).replace(META, DISABLED_META) if d['t'] else ''
|
||||
return '%(p_begin)s<img src="%(k)s"%(alt)s%(title)s%(style)s%(width)s />%(p_end)s'%d
|
||||
|
||||
def sub_link(m):
|
||||
d=m.groupdict()
|
||||
if not d['k'] and not d['t']:
|
||||
return m.group(0)
|
||||
d['t'] = d['t'] or ''
|
||||
d['a'] = cgi.escape(d['a']) if d['a'] else ''
|
||||
if d['k']:
|
||||
d['k'] = cgi.escape(d['k'])
|
||||
d['title'] = ' title="%s"' % d['a'].replace(META, DISABLED_META) if d['a'] else ''
|
||||
d['target'] = ' target="_blank"' if d['p'] == 'popup' else ''
|
||||
d['t'] = render(d['t'],{},{},'',URL,environment,latex,auto) if d['t'] else d['k']
|
||||
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>'%d
|
||||
d['t'] = cgi.escape(d['t'])
|
||||
return '<span id="%(t)s">%(a)s</span>'%d
|
||||
|
||||
parts = text.split(LINK)
|
||||
text = parts[0]
|
||||
for i,s in enumerate(links):
|
||||
if s==None:
|
||||
html = LINK
|
||||
else:
|
||||
html = regex_media_level2.sub(sub_media, s)
|
||||
if html == s:
|
||||
html = regex_link_level2.sub(sub_link, html)
|
||||
if html == s:
|
||||
# return unprocessed string as a signal of an error
|
||||
html = '[[%s]]'%s
|
||||
text = text+html+parts[i+1]
|
||||
|
||||
#############################################################
|
||||
# process all code text
|
||||
#############################################################
|
||||
parts = text.split(META)
|
||||
text = parts[0]
|
||||
for i,(code,b) in enumerate(segments):
|
||||
if code==None:
|
||||
html = META
|
||||
else:
|
||||
if b in extra:
|
||||
if code[:1]=='\n': code=code[1:]
|
||||
if code[-1:]=='\n': code=code[:-1]
|
||||
html = extra[b](code)
|
||||
elif b=='cite':
|
||||
html = '['+','.join('<a href="#%s" class="%s">%s</a>' \
|
||||
% (d,b,d) \
|
||||
for d in cgi.escape(code).split(','))+']'
|
||||
elif b=='latex':
|
||||
html = LATEX % code.replace('"','\"').replace('\n',' ')
|
||||
elif code[:1]=='\n' or code[-1:]=='\n':
|
||||
if code[:1]=='\n': code=code[1:]
|
||||
if code[-1:]=='\n': code=code[:-1]
|
||||
html = '<pre><code class="%s">%s</code></pre>' % (b,cgi.escape(code))
|
||||
def expand_meta(m):
|
||||
code,b,p,s = segments.pop(0)
|
||||
if code==None or m.group() == DISABLED_META:
|
||||
return cgi.escape(s)
|
||||
if b in extra:
|
||||
if code[:1]=='\n': code=code[1:]
|
||||
if code[-1:]=='\n': code=code[:-1]
|
||||
if p:
|
||||
return extra[b](code,p)
|
||||
else:
|
||||
if code[:1]=='\n': code=code[1:]
|
||||
if code[-1:]=='\n': code=code[:-1]
|
||||
html = '<code class="%s">%s</code>' % (b,cgi.escape(code))
|
||||
text = text+html+parts[i+1]
|
||||
return extra[b](code)
|
||||
elif b=='cite':
|
||||
return '['+','.join('<a href="#%s" class="%s">%s</a>' \
|
||||
% (d,b,d) \
|
||||
for d in cgi.escape(code).split(','))+']'
|
||||
elif b=='latex':
|
||||
return LATEX % code.replace('"','\"').replace('\n',' ')
|
||||
elif b in html_colors:
|
||||
return '<span style="color: %s">%s</span>' \
|
||||
% (b, render(code,{},{},'',URL,environment,latex,auto))
|
||||
elif b in ('c', 'color') and p:
|
||||
c=p.split(':')
|
||||
fg='color: %s;' % c[0] if c[0] else ''
|
||||
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
|
||||
return '<span style="%s%s">%s</span>' \
|
||||
% (fg, bg, render(code,{},{},'',URL,environment,latex,auto))
|
||||
elif code[:1]=='\n' and code[-1:]=='\n':
|
||||
return '<pre><code class="%s">%s</code></pre>' % (b,cgi.escape(code[1:-1]))
|
||||
return '<code class="%s">%s</code>' % (b,cgi.escape(code[ (code[:1]=='\n')
|
||||
: [None,-1][code[-1:]=='\n']]))
|
||||
text = regex_expand_meta.sub(expand_meta, text)
|
||||
text = remove_backslashes(text)
|
||||
return text
|
||||
|
||||
|
||||
def markmin2html(text,extra={},allowed={},sep='p'):
|
||||
return render(text,extra,allowed,sep)
|
||||
def markmin2html(text, extra={}, allowed={}, sep='p', auto=True):
|
||||
return render(text, extra, allowed, sep, auto=auto)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import doctest
|
||||
if sys.argv[1:2]==['-h']:
|
||||
if sys.argv[1:2] == ['-h']:
|
||||
print '<html><body>'+markmin2html(__doc__)+'</body></html>'
|
||||
elif len(sys.argv)>1:
|
||||
elif len(sys.argv) > 1:
|
||||
fargv = open(sys.argv[1],'r')
|
||||
try:
|
||||
print '<html><body>'+markmin2html(fargv.read())+'</body></html>'
|
||||
|
||||
Reference in New Issue
Block a user