diff options
Diffstat (limited to 'nikola/plugins/compile')
49 files changed, 2640 insertions, 0 deletions
diff --git a/nikola/plugins/compile/__init__.py b/nikola/plugins/compile/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/nikola/plugins/compile/__init__.py diff --git a/nikola/plugins/compile/asciidoc.plugin b/nikola/plugins/compile/asciidoc.plugin new file mode 100644 index 0000000..47c5608 --- /dev/null +++ b/nikola/plugins/compile/asciidoc.plugin @@ -0,0 +1,10 @@ +[Core] +Name = asciidoc +Module = asciidoc + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile ASCIIDoc into HTML + diff --git a/nikola/plugins/compile/asciidoc.py b/nikola/plugins/compile/asciidoc.py new file mode 100644 index 0000000..67dfe1a --- /dev/null +++ b/nikola/plugins/compile/asciidoc.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on asciidoc. + +You will need, of course, to install asciidoc + +""" + +import codecs +import os +import subprocess + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileAsciiDoc(PageCompiler): + """Compile asciidoc into HTML.""" + + name = "asciidoc" + + def compile_html(self, source, dest, is_two_file=True): + makedirs(os.path.dirname(dest)) + try: + subprocess.check_call(('asciidoc', '-f', 'html', '-s', '-o', dest, source)) + except OSError as e: + if e.strreror == 'No such file or directory': + req_missing(['asciidoc'], 'build this site (compile with asciidoc)', python=False) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write("/////////////////////////////////////////////\n") + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write("/////////////////////////////////////////////\n") + fd.write("\nWrite your post here.") diff --git a/nikola/plugins/compile/bbcode.plugin b/nikola/plugins/compile/bbcode.plugin new file mode 100644 index 0000000..b3d9357 --- /dev/null +++ b/nikola/plugins/compile/bbcode.plugin @@ -0,0 +1,10 @@ +[Core] +Name = bbcode +Module = bbcode + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile BBCode into HTML + diff --git a/nikola/plugins/compile/bbcode.py b/nikola/plugins/compile/bbcode.py new file mode 100644 index 0000000..e998417 --- /dev/null +++ b/nikola/plugins/compile/bbcode.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on bbcode.""" + +import codecs +import os +import re + +try: + import bbcode +except ImportError: + bbcode = None # NOQA + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileBbcode(PageCompiler): + """Compile bbcode into HTML.""" + + name = "bbcode" + + def __init__(self): + if bbcode is None: + return + self.parser = bbcode.Parser() + self.parser.add_simple_formatter("note", "") + + def compile_html(self, source, dest, is_two_file=True): + if bbcode is None: + req_missing(['bbcode'], 'build this site (compile BBCode)') + makedirs(os.path.dirname(dest)) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + if not is_two_file: + data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] + output = self.parser.format(data) + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('[note]<!--\n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->[/note]\n\n') + fd.write("Write your post here.") diff --git a/nikola/plugins/compile/html.plugin b/nikola/plugins/compile/html.plugin new file mode 100644 index 0000000..21dd338 --- /dev/null +++ b/nikola/plugins/compile/html.plugin @@ -0,0 +1,10 @@ +[Core] +Name = html +Module = html + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile HTML into HTML (just copy) + diff --git a/nikola/plugins/compile/html.py b/nikola/plugins/compile/html.py new file mode 100644 index 0000000..a309960 --- /dev/null +++ b/nikola/plugins/compile/html.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html for HTML source files.""" + +import os +import shutil +import codecs + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs + + +class CompileHtml(PageCompiler): + """Compile HTML into HTML.""" + + name = "html" + + def compile_html(self, source, dest, is_two_file=True): + makedirs(os.path.dirname(dest)) + shutil.copyfile(source, dest) + return True + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<!-- \n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->\n\n') + fd.write("\n<p>Write your post here.</p>") diff --git a/nikola/plugins/compile/ipynb.plugin b/nikola/plugins/compile/ipynb.plugin new file mode 100644 index 0000000..3d15bb0 --- /dev/null +++ b/nikola/plugins/compile/ipynb.plugin @@ -0,0 +1,10 @@ +[Core] +Name = ipynb +Module = ipynb + +[Documentation] +Author = Damián Avila +Version = 1.0 +Website = http://www.oquanta.info +Description = Compile IPython notebooks into HTML + diff --git a/nikola/plugins/compile/ipynb/README.txt b/nikola/plugins/compile/ipynb/README.txt new file mode 100644 index 0000000..0a7d6db --- /dev/null +++ b/nikola/plugins/compile/ipynb/README.txt @@ -0,0 +1,44 @@ +To make this work... + +1- You can install the "jinja-site-ipython" theme using this command: + +$ nikola install_theme -n jinja-site-ipython + +(or xkcd-site-ipython, if you want xkcd styling) + +More info here about themes: +http://getnikola.com/handbook.html#getting-more-themes + +OR + +You can to download the "jinja-site-ipython" theme from here: +https://github.com/damianavila/jinja-site-ipython-theme-for-Nikola +and copy the "site-ipython" folder inside the "themes" folder of your site. + + +2- Then, just add: + +post_pages = ( + ("posts/*.ipynb", "posts", "post.tmpl", True), + ("stories/*.ipynb", "stories", "story.tmpl", False), +) + +and + +THEME = 'jinja-site-ipython' (or 'xkcd-site-ipython', if you want xkcd styling) + +to your conf.py. +Finally... to use it: + +$nikola new_page -f ipynb + +**NOTE**: Just IGNORE the "-1" and "-2" options in nikola new_page command, by default this compiler +create one metadata file and the corresponding naive IPython notebook. + +$nikola build + +And deploy the output folder... to see it locally: $nikola serve +If you have any doubts, just ask: @damianavila + +Cheers. +Damián diff --git a/nikola/plugins/compile/ipynb/__init__.py b/nikola/plugins/compile/ipynb/__init__.py new file mode 100644 index 0000000..7c318ca --- /dev/null +++ b/nikola/plugins/compile/ipynb/__init__.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2013 Damian Avila. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on nbconvert.""" + +from __future__ import unicode_literals, print_function +import codecs +import os + +try: + from IPython.nbconvert.exporters import HTMLExporter + from IPython.nbformat import current as nbformat + from IPython.config import Config + flag = True +except ImportError: + flag = None + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileIPynb(PageCompiler): + """Compile IPynb into HTML.""" + + name = "ipynb" + + def compile_html(self, source, dest, is_two_file=True): + if flag is None: + req_missing(['ipython>=1.0.0'], 'build this site (compile ipynb)') + makedirs(os.path.dirname(dest)) + HTMLExporter.default_template = 'basic' + c = Config(self.site.config['IPYNB_CONFIG']) + exportHtml = HTMLExporter(config=c) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + nb = in_file.read() + nb_json = nbformat.reads_json(nb) + (body, resources) = exportHtml.from_notebook_node(nb_json) + out_file.write(body) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + d_name = os.path.dirname(path) + makedirs(os.path.dirname(path)) + meta_path = os.path.join(d_name, kw['slug'] + ".meta") + with codecs.open(meta_path, "wb+", "utf8") as fd: + if onefile: + fd.write('%s\n' % kw['title']) + fd.write('%s\n' % kw['slug']) + fd.write('%s\n' % kw['date']) + fd.write('%s\n' % kw['tags']) + print("Your post's metadata is at: ", meta_path) + with codecs.open(path, "wb+", "utf8") as fd: + fd.write("""{ + "metadata": { + "name": "" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +}""") diff --git a/nikola/plugins/compile/markdown.plugin b/nikola/plugins/compile/markdown.plugin new file mode 100644 index 0000000..157579a --- /dev/null +++ b/nikola/plugins/compile/markdown.plugin @@ -0,0 +1,10 @@ +[Core] +Name = markdown +Module = markdown + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile Markdown into HTML + diff --git a/nikola/plugins/compile/markdown/__init__.py b/nikola/plugins/compile/markdown/__init__.py new file mode 100644 index 0000000..b41c6b5 --- /dev/null +++ b/nikola/plugins/compile/markdown/__init__.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on markdown.""" + +from __future__ import unicode_literals + +import codecs +import os +import re + +try: + from markdown import markdown + + from nikola.plugins.compile.markdown.mdx_nikola import NikolaExtension + nikola_extension = NikolaExtension() + + from nikola.plugins.compile.markdown.mdx_gist import GistExtension + gist_extension = GistExtension() + + from nikola.plugins.compile.markdown.mdx_podcast import PodcastExtension + podcast_extension = PodcastExtension() + +except ImportError: + markdown = None # NOQA + nikola_extension = None + gist_extension = None + podcast_extension = None + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileMarkdown(PageCompiler): + """Compile markdown into HTML.""" + + name = "markdown" + extensions = [gist_extension, nikola_extension, podcast_extension] + site = None + + def compile_html(self, source, dest, is_two_file=True): + if markdown is None: + req_missing(['markdown'], 'build this site (compile Markdown)') + makedirs(os.path.dirname(dest)) + self.extensions += self.site.config.get("MARKDOWN_EXTENSIONS") + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + if not is_two_file: + data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] + output = markdown(data, self.extensions) + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<!-- \n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->\n\n') + fd.write("Write your post here.") diff --git a/nikola/plugins/compile/markdown/mdx_gist.py b/nikola/plugins/compile/markdown/mdx_gist.py new file mode 100644 index 0000000..3c3bef9 --- /dev/null +++ b/nikola/plugins/compile/markdown/mdx_gist.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013 Michael Rabbitt. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Warning: URL formats of "raw" gists are undocummented and subject to change. +# See also: http://developer.github.com/v3/gists/ +# +# Inspired by "[Python] reStructuredText GitHub Gist directive" +# (https://gist.github.com/brianhsu/1407759), public domain by Brian Hsu +''' +Extension to Python Markdown for Embedded Gists (gist.github.com) + +Basic Example: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 4747847] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) + <p>Text of the gist: + <div class="gist"> + <script src="https://gist.github.com/4747847.js"></script> + <noscript> + <pre>import this</pre> + </noscript> + </div> + </p> + +Example with filename: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 4747847 zen.py] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) + <p>Text of the gist: + <div class="gist"> + <script src="https://gist.github.com/4747847.js?file=zen.py"></script> + <noscript> + <pre>import this</pre> + </noscript> + </div> + </p> + +Example using reStructuredText syntax: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... .. gist:: 4747847 zen.py + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) + <p>Text of the gist: + <div class="gist"> + <script src="https://gist.github.com/4747847.js?file=zen.py"></script> + <noscript> + <pre>import this</pre> + </noscript> + </div> + </p> + +Error Case: non-existent Gist ID: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 0] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) + <p>Text of the gist: + <div class="gist"> + <script src="https://gist.github.com/0.js"></script> + <noscript><!-- WARNING: Received a 404 response from Gist URL: https://gist.github.com/raw/0 --></noscript> + </div> + </p> + +Error Case: non-existent file: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 4747847 doesntexist.py] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) + <p>Text of the gist: + <div class="gist"> + <script src="https://gist.github.com/4747847.js?file=doesntexist.py"></script> + <noscript><!-- WARNING: Received a 404 response from Gist URL: https://gist.github.com/raw/4747847/doesntexist.py --></noscript> + </div> + </p> + +''' +from __future__ import unicode_literals, print_function +from markdown.extensions import Extension +from markdown.inlinepatterns import Pattern +from markdown.util import AtomicString +from markdown.util import etree +from nikola.utils import get_logger, req_missing, STDERR_HANDLER + +LOGGER = get_logger('compile_markdown.mdx_gist', STDERR_HANDLER) + +try: + import requests +except ImportError: + requests = None # NOQA + +GIST_JS_URL = "https://gist.github.com/{0}.js" +GIST_FILE_JS_URL = "https://gist.github.com/{0}.js?file={1}" +GIST_RAW_URL = "https://gist.github.com/raw/{0}" +GIST_FILE_RAW_URL = "https://gist.github.com/raw/{0}/{1}" + +GIST_MD_RE = r'\[:gist:\s*(?P<gist_id>\d+)(?:\s*(?P<filename>.+?))?\s*\]' +GIST_RST_RE = r'(?m)^\.\.\s*gist::\s*(?P<gist_id>\d+)(?:\s*(?P<filename>.+))\s*$' + + +class GistFetchException(Exception): + '''Raised when attempt to fetch content of a Gist from github.com fails.''' + def __init__(self, url, status_code): + Exception.__init__(self) + self.message = 'Received a {0} response from Gist URL: {1}'.format( + status_code, url) + + +class GistPattern(Pattern): + """ InlinePattern for footnote markers in a document's body text. """ + + def __init__(self, pattern, configs): + Pattern.__init__(self, pattern) + + def get_raw_gist_with_filename(self, gist_id, filename): + url = GIST_FILE_RAW_URL.format(gist_id, filename) + resp = requests.get(url) + + if not resp.ok: + raise GistFetchException(url, resp.status_code) + + return resp.text + + def get_raw_gist(self, gist_id): + url = GIST_RAW_URL.format(gist_id) + resp = requests.get(url) + + if not resp.ok: + raise GistFetchException(url, resp.status_code) + + return resp.text + + def handleMatch(self, m): + gist_id = m.group('gist_id') + gist_file = m.group('filename') + + gist_elem = etree.Element('div') + gist_elem.set('class', 'gist') + script_elem = etree.SubElement(gist_elem, 'script') + + if requests: + noscript_elem = etree.SubElement(gist_elem, 'noscript') + + try: + if gist_file: + script_elem.set('src', GIST_FILE_JS_URL.format( + gist_id, gist_file)) + raw_gist = (self.get_raw_gist_with_filename( + gist_id, gist_file)) + + else: + script_elem.set('src', GIST_JS_URL.format( + gist_id)) + raw_gist = (self.get_raw_gist(gist_id)) + + # Insert source as <pre/> within <noscript> + pre_elem = etree.SubElement(noscript_elem, 'pre') + pre_elem.text = AtomicString(raw_gist) + + except GistFetchException as e: + LOGGER.warn(e.message) + warning_comment = etree.Comment(' WARNING: {0} '.format(e.message)) + noscript_elem.append(warning_comment) + + else: + req_missing('requests', 'have inline gist source', optional=True) + + return gist_elem + + +class GistExtension(Extension): + def __init__(self, configs={}): + # set extension defaults + self.config = {} + + # Override defaults with user settings + for key, value in configs: + self.setConfig(key, value) + + def extendMarkdown(self, md, md_globals): + gist_md_pattern = GistPattern(GIST_MD_RE, self.getConfigs()) + gist_md_pattern.md = md + md.inlinePatterns.add('gist', gist_md_pattern, "<not_strong") + + gist_rst_pattern = GistPattern(GIST_RST_RE, self.getConfigs()) + gist_rst_pattern.md = md + md.inlinePatterns.add('gist-rst', gist_rst_pattern, ">gist") + + md.registerExtension(self) + + +def makeExtension(configs=None): + return GistExtension(configs) + +if __name__ == '__main__': + import doctest + + # Silence user warnings thrown by tests: + doctest.testmod(optionflags=(doctest.NORMALIZE_WHITESPACE + + doctest.REPORT_NDIFF)) diff --git a/nikola/plugins/compile/markdown/mdx_nikola.py b/nikola/plugins/compile/markdown/mdx_nikola.py new file mode 100644 index 0000000..b0ad2f7 --- /dev/null +++ b/nikola/plugins/compile/markdown/mdx_nikola.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Markdown Extension for Nikola-specific post-processing""" +from __future__ import unicode_literals +import re +from markdown.postprocessors import Postprocessor +from markdown.extensions import Extension + + +class NikolaPostProcessor(Postprocessor): + def run(self, text): + output = text + # h1 is reserved for the title so increment all header levels + for n in reversed(range(1, 9)): + output = re.sub('<h%i>' % n, '<h%i>' % (n + 1), output) + output = re.sub('</h%i>' % n, '</h%i>' % (n + 1), output) + + # python-markdown's highlighter uses the class 'codehilite' to wrap + # code, instead of the standard 'code'. None of the standard + # pygments stylesheets use this class, so swap it to be 'code' + output = re.sub(r'(<div[^>]+class="[^"]*)codehilite([^>]+)', + r'\1code\2', output) + return output + + +class NikolaExtension(Extension): + def extendMarkdown(self, md, md_globals): + pp = NikolaPostProcessor() + md.postprocessors.add('nikola_post_processor', pp, '_end') + md.registerExtension(self) + + +def makeExtension(configs=None): + return NikolaExtension(configs) diff --git a/nikola/plugins/compile/markdown/mdx_podcast.py b/nikola/plugins/compile/markdown/mdx_podcast.py new file mode 100644 index 0000000..be8bb6b --- /dev/null +++ b/nikola/plugins/compile/markdown/mdx_podcast.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013 Michael Rabbitt, Roberto Alsina +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Inspired by "[Python] reStructuredText GitHub Podcast directive" +# (https://gist.github.com/brianhsu/1407759), public domain by Brian Hsu + +from __future__ import print_function, unicode_literals + + +''' +Extension to Python Markdown for Embedded Audio + +Basic Example: + +>>> import markdown +>>> text = """[podcast]http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3[/podcast]""" +>>> html = markdown.markdown(text, [PodcastExtension()]) +>>> print(html) +<p><audio src="http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3"></audio></p> +''' + +from markdown.extensions import Extension +from markdown.inlinepatterns import Pattern +from markdown.util import etree + +PODCAST_RE = r'\[podcast\](?P<url>.+)\[/podcast\]' + + +class PodcastPattern(Pattern): + """ InlinePattern for footnote markers in a document's body text. """ + + def __init__(self, pattern, configs): + Pattern.__init__(self, pattern) + + def handleMatch(self, m): + url = m.group('url').strip() + audio_elem = etree.Element('audio') + audio_elem.set('controls', '') + source_elem = etree.SubElement(audio_elem, 'source') + source_elem.set('src', url) + source_elem.set('type', 'audio/mpeg') + return audio_elem + + +class PodcastExtension(Extension): + def __init__(self, configs={}): + # set extension defaults + self.config = {} + + # Override defaults with user settings + for key, value in configs: + self.setConfig(key, value) + + def extendMarkdown(self, md, md_globals): + podcast_md_pattern = PodcastPattern(PODCAST_RE, self.getConfigs()) + podcast_md_pattern.md = md + md.inlinePatterns.add('podcast', podcast_md_pattern, "<not_strong") + md.registerExtension(self) + + +def makeExtension(configs=None): + return PodcastExtension(configs) + +if __name__ == '__main__': + import doctest + doctest.testmod(optionflags=(doctest.NORMALIZE_WHITESPACE + + doctest.REPORT_NDIFF)) diff --git a/nikola/plugins/compile/misaka.plugin b/nikola/plugins/compile/misaka.plugin new file mode 100644 index 0000000..fef6d71 --- /dev/null +++ b/nikola/plugins/compile/misaka.plugin @@ -0,0 +1,10 @@ +[Core] +Name = misaka +Module = misaka + +[Documentation] +Author = Chris Lee +Version = 0.1 +Website = http://c133.org/ +Description = Compile Markdown into HTML with Mikasa instead of python-markdown + diff --git a/nikola/plugins/compile/misaka.py b/nikola/plugins/compile/misaka.py new file mode 100644 index 0000000..3733a85 --- /dev/null +++ b/nikola/plugins/compile/misaka.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2013 Chris Lee + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on misaka.""" + +from __future__ import unicode_literals + +import codecs +import os +import re + +try: + import misaka +except ImportError: + misaka = None # NOQA + nikola_extension = None + gist_extension = None + podcast_extension = None + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileMisaka(PageCompiler): + """Compile Misaka into HTML.""" + + name = "misaka" + + def __init__(self, *args, **kwargs): + super(CompileMisaka, self).__init__(*args, **kwargs) + if misaka is not None: + self.ext = misaka.EXT_FENCED_CODE | misaka.EXT_STRIKETHROUGH | \ + misaka.EXT_AUTOLINK | misaka.EXT_NO_INTRA_EMPHASIS + + def compile_html(self, source, dest, is_two_file=True): + if misaka is None: + req_missing(['misaka'], 'build this site (compile with misaka)') + makedirs(os.path.dirname(dest)) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + if not is_two_file: + data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] + output = misaka.html(data, extensions=self.ext) + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<!-- \n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->\n\n') + fd.write("\nWrite your post here.") diff --git a/nikola/plugins/compile/pandoc.plugin b/nikola/plugins/compile/pandoc.plugin new file mode 100644 index 0000000..157b694 --- /dev/null +++ b/nikola/plugins/compile/pandoc.plugin @@ -0,0 +1,10 @@ +[Core] +Name = pandoc +Module = pandoc + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile markups into HTML using pandoc + diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py new file mode 100644 index 0000000..3a2911f --- /dev/null +++ b/nikola/plugins/compile/pandoc.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on pandoc. + +You will need, of course, to install pandoc + +""" + +import codecs +import os +import subprocess + +from nikola.plugin_categories import PageCompiler +from nikola.utils import req_missing, makedirs + + +class CompilePandoc(PageCompiler): + """Compile markups into HTML using pandoc.""" + + name = "pandoc" + + def compile_html(self, source, dest, is_two_file=True): + makedirs(os.path.dirname(dest)) + try: + subprocess.check_call(('pandoc', '-o', dest, source)) + except OSError as e: + if e.strreror == 'No such file or directory': + req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<!-- \n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->\n\n') + fd.write("Write your post here.") diff --git a/nikola/plugins/compile/php.plugin b/nikola/plugins/compile/php.plugin new file mode 100644 index 0000000..ac25259 --- /dev/null +++ b/nikola/plugins/compile/php.plugin @@ -0,0 +1,10 @@ +[Core] +Name = php +Module = php + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile PHP into HTML (just copy and name the file .php) + diff --git a/nikola/plugins/compile/php.py b/nikola/plugins/compile/php.py new file mode 100644 index 0000000..44701c8 --- /dev/null +++ b/nikola/plugins/compile/php.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html for HTML+php.""" + +from __future__ import unicode_literals + +import os +import shutil +import codecs + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs + + +class CompilePhp(PageCompiler): + """Compile PHP into PHP.""" + + name = "php" + + def compile_html(self, source, dest, is_two_file=True): + makedirs(os.path.dirname(dest)) + shutil.copyfile(source, dest) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + os.makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<!-- \n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('-->\n\n') + fd.write("\n<p>Write your post here.</p>") + + def extension(self): + return ".php" diff --git a/nikola/plugins/compile/rest.plugin b/nikola/plugins/compile/rest.plugin new file mode 100644 index 0000000..55e9c59 --- /dev/null +++ b/nikola/plugins/compile/rest.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest +Module = rest + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile reSt into HTML + diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py new file mode 100644 index 0000000..c71a5f8 --- /dev/null +++ b/nikola/plugins/compile/rest/__init__.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals +import codecs +import os +import re + +try: + import docutils.core + import docutils.nodes + import docutils.utils + import docutils.io + import docutils.readers.standalone + has_docutils = True +except ImportError: + has_docutils = False + +from nikola.plugin_categories import PageCompiler +from nikola.utils import get_logger, makedirs, req_missing + + +class CompileRest(PageCompiler): + """Compile reSt into HTML.""" + + name = "rest" + logger = None + + def compile_html(self, source, dest, is_two_file=True): + """Compile reSt into HTML.""" + + if not has_docutils: + req_missing(['docutils'], 'build this site (compile reStructuredText)') + makedirs(os.path.dirname(dest)) + error_level = 100 + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + add_ln = 0 + if not is_two_file: + spl = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1) + data = spl[-1] + if len(spl) != 1: + # If errors occur, this will be added to the line + # number reported by docutils so the line number + # matches the actual line number (off by 7 with default + # metadata, could be more or less depending on the post + # author). + add_ln = len(spl[0].splitlines()) + 1 + + output, error_level, deps = rst2html( + data, settings_overrides={ + 'initial_header_level': 2, + 'record_dependencies': True, + 'stylesheet_path': None, + 'link_stylesheet': True, + 'syntax_highlight': 'short', + 'math_output': 'mathjax', + }, logger=self.logger, l_source=source, l_add_ln=add_ln) + out_file.write(output) + deps_path = dest + '.dep' + if deps.list: + with codecs.open(deps_path, "wb+", "utf8") as deps_file: + deps_file.write('\n'.join(deps.list)) + else: + if os.path.isfile(deps_path): + os.unlink(deps_path) + if error_level < 3: + return True + else: + return False + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write("\nWrite your post here.") + + def set_site(self, site): + for plugin_info in site.plugin_manager.getPluginsOfCategory("RestExtension"): + if (plugin_info.name in site.config['DISABLED_PLUGINS'] + or (plugin_info.name in site.EXTRA_PLUGINS and + plugin_info.name not in site.config['ENABLED_EXTRAS'])): + site.plugin_manager.removePluginFromCategory(plugin_info, "RestExtension") + continue + + site.plugin_manager.activatePluginByName(plugin_info.name) + plugin_info.plugin_object.set_site(site) + plugin_info.plugin_object.short_help = plugin_info.description + + self.logger = get_logger('compile_rest', site.loghandlers) + return super(CompileRest, self).set_site(site) + + +def get_observer(settings): + """Return an observer for the docutils Reporter.""" + def observer(msg): + """Report docutils/rest messages to a Nikola user. + + Error code mapping: + + +------+---------+------+----------+ + | dNUM | dNAME | lNUM | lNAME | d = docutils, l = logbook + +------+---------+------+----------+ + | 0 | DEBUG | 1 | DEBUG | + | 1 | INFO | 2 | INFO | + | 2 | WARNING | 4 | WARNING | + | 3 | ERROR | 5 | ERROR | + | 4 | SEVERE | 6 | CRITICAL | + +------+---------+------+----------+ + """ + errormap = {0: 1, 1: 2, 2: 4, 3: 5, 4: 6} + text = docutils.nodes.Element.astext(msg) + out = '[{source}:{line}] {text}'.format(source=settings['source'], line=msg['line'] + settings['add_ln'], text=text) + settings['logger'].log(errormap[msg['level']], out) + + return observer + + +class NikolaReader(docutils.readers.standalone.Reader): + + def new_document(self): + """Create and return a new empty document tree (root node).""" + document = docutils.utils.new_document(self.source.source_path, self.settings) + document.reporter.stream = False + document.reporter.attach_observer(get_observer(self.l_settings)) + return document + + +def rst2html(source, source_path=None, source_class=docutils.io.StringInput, + destination_path=None, reader=None, + parser=None, parser_name='restructuredtext', writer=None, + writer_name='html', settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=None, logger=None, l_source='', l_add_ln=0): + """ + Set up & run a `Publisher`, and return a dictionary of document parts. + Dictionary keys are the names of parts, and values are Unicode strings; + encoding is up to the client. For programmatic use with string I/O. + + For encoded string input, be sure to set the 'input_encoding' setting to + the desired encoding. Set it to 'unicode' for unencoded Unicode string + input. Here's how:: + + publish_parts(..., settings_overrides={'input_encoding': 'unicode'}) + + Parameters: see `publish_programmatically`. + + WARNING: `reader` should be None (or NikolaReader()) if you want Nikola to report + reStructuredText syntax errors. + """ + if reader is None: + reader = NikolaReader() + # For our custom logging, we have special needs and special settings we + # specify here. + # logger a logger from Nikola + # source source filename (docutils gets a string) + # add_ln amount of metadata lines (see comment in compile_html above) + reader.l_settings = {'logger': logger, 'source': l_source, + 'add_ln': l_add_ln} + + pub = docutils.core.Publisher(reader, parser, writer, settings=settings, + source_class=source_class, + destination_class=docutils.io.StringOutput) + pub.set_components(None, parser_name, writer_name) + pub.process_programmatic_settings( + settings_spec, settings_overrides, config_section) + pub.set_source(source, source_path) + pub.set_destination(None, destination_path) + pub.publish(enable_exit_status=enable_exit_status) + + return pub.writer.parts['docinfo'] + pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies diff --git a/nikola/plugins/compile/rest/chart.plugin b/nikola/plugins/compile/rest/chart.plugin new file mode 100644 index 0000000..3e27a25 --- /dev/null +++ b/nikola/plugins/compile/rest/chart.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_chart +Module = chart + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Chart directive based in PyGal + diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py new file mode 100644 index 0000000..ee917b9 --- /dev/null +++ b/nikola/plugins/compile/rest/chart.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from ast import literal_eval + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +try: + import pygal +except ImportError: + pygal = None # NOQA + +from nikola.plugin_categories import RestExtension +from nikola.utils import req_missing + + +class Plugin(RestExtension): + + name = "rest_chart" + + def set_site(self, site): + self.site = site + directives.register_directive('chart', Chart) + return super(Plugin, self).set_site(site) + + +class Chart(Directive): + """ Restructured text extension for inserting charts as SVG + + Usage: + .. chart:: Bar + :title: 'Browser usage evolution (in %)' + :x_labels: ["2002", "2003", "2004", "2005", "2006", "2007"] + + 'Firefox', [None, None, 0, 16.6, 25, 31] + 'Chrome', [None, None, None, None, None, None] + 'IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6] + 'Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4] + """ + + has_content = True + required_arguments = 1 + option_spec = { + "copy": directives.unchanged, + "css": directives.unchanged, + "disable_xml_declaration": directives.unchanged, + "dots_size": directives.unchanged, + "explicit_size": directives.unchanged, + "fill": directives.unchanged, + "font_sizes": directives.unchanged, + "height": directives.unchanged, + "human_readable": directives.unchanged, + "include_x_axis": directives.unchanged, + "interpolate": directives.unchanged, + "interpolation_parameters": directives.unchanged, + "interpolation_precision": directives.unchanged, + "js": directives.unchanged, + "label_font_size": directives.unchanged, + "legend_at_bottom": directives.unchanged, + "legend_box_size": directives.unchanged, + "legend_font_size": directives.unchanged, + "logarithmic": directives.unchanged, + "major_label_font_size": directives.unchanged, + "margin": directives.unchanged, + "no_data_font_size": directives.unchanged, + "no_data_text": directives.unchanged, + "no_prefix": directives.unchanged, + "order_min": directives.unchanged, + "pretty_print": directives.unchanged, + "print_values": directives.unchanged, + "print_zeroes": directives.unchanged, + "range": directives.unchanged, + "rounded_bars": directives.unchanged, + "show_dots": directives.unchanged, + "show_legend": directives.unchanged, + "show_minor_x_labels": directives.unchanged, + "show_y_labels": directives.unchanged, + "spacing": directives.unchanged, + "strict": directives.unchanged, + "stroke": directives.unchanged, + "style": directives.unchanged, + "title": directives.unchanged, + "title_font_size": directives.unchanged, + "to_dict": directives.unchanged, + "tooltip_border_radius": directives.unchanged, + "tooltip_font_size": directives.unchanged, + "truncate_label": directives.unchanged, + "truncate_legend": directives.unchanged, + "value_font_size": directives.unchanged, + "value_formatter": directives.unchanged, + "width": directives.unchanged, + "x_label_rotation": directives.unchanged, + "x_labels": directives.unchanged, + "x_labels_major": directives.unchanged, + "x_labels_major_count": directives.unchanged, + "x_labels_major_every": directives.unchanged, + "x_title": directives.unchanged, + "y_label_rotation": directives.unchanged, + "y_labels": directives.unchanged, + "y_title": directives.unchanged, + "zero": directives.unchanged, + } + + def run(self): + if pygal is None: + msg = req_missing(['pygal'], 'use the Chart directive', optional=True) + return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')] + options = {} + if 'style' in self.options: + style_name = self.options.pop('style') + else: + style_name = 'BlueStyle' + if '(' in style_name: # Parametric style + style = eval('pygal.style.' + style_name) + else: + style = getattr(pygal.style, style_name) + for k, v in self.options.items(): + options[k] = literal_eval(v) + + chart = getattr(pygal, self.arguments[0])(style=style) + chart.config(**options) + for line in self.content: + label, series = literal_eval('({0})'.format(line)) + chart.add(label, series) + + return [nodes.raw('', chart.render().decode('utf8'), format='html')] diff --git a/nikola/plugins/compile/rest/doc.plugin b/nikola/plugins/compile/rest/doc.plugin new file mode 100644 index 0000000..1984f52 --- /dev/null +++ b/nikola/plugins/compile/rest/doc.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_doc +Module = doc + +[Documentation] +Author = Manuel Kaufmann +Version = 0.1 +Website = http://getnikola.com +Description = Role to link another page / post from the blog + diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py new file mode 100644 index 0000000..915a7e1 --- /dev/null +++ b/nikola/plugins/compile/rest/doc.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +from docutils import nodes +from docutils.parsers.rst import roles + +from nikola.utils import split_explicit_title +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + + name = 'rest_doc' + + def set_site(self, site): + self.site = site + roles.register_canonical_role('doc', doc_role) + doc_role.site = site + return super(Plugin, self).set_site(site) + + +def doc_role(name, rawtext, text, lineno, inliner, + options={}, content=[]): + + # split link's text and post's slug in role content + has_explicit_title, title, slug = split_explicit_title(text) + + # check if the slug given is part of our blog posts/pages + twin_slugs = False + post = None + for p in doc_role.site.timeline: + if p.meta('slug') == slug: + if post is None: + post = p + else: + twin_slugs = True + break + + try: + if post is None: + raise ValueError + except ValueError: + msg = inliner.reporter.error( + '"{0}" slug doesn\'t exist.'.format(slug), + line=lineno) + prb = inliner.problematic(rawtext, rawtext, msg) + return [prb], [msg] + + if not has_explicit_title: + # use post's title as link's text + title = post.title() + + permalink = post.permalink() + if twin_slugs: + msg = inliner.reporter.warning( + 'More than one post with the same slug. Using "{0}"'.format(permalink)) + + node = make_link_node(rawtext, title, permalink, options) + return [node], [] + + +def make_link_node(rawtext, text, url, options): + node = nodes.reference(rawtext, text, refuri=url, *options) + return node diff --git a/nikola/plugins/compile/rest/gist.plugin b/nikola/plugins/compile/rest/gist.plugin new file mode 100644 index 0000000..8f498ec --- /dev/null +++ b/nikola/plugins/compile/rest/gist.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_gist +Module = gist + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Gist directive + diff --git a/nikola/plugins/compile/rest/gist.py b/nikola/plugins/compile/rest/gist.py new file mode 100644 index 0000000..e09ed76 --- /dev/null +++ b/nikola/plugins/compile/rest/gist.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +# This file is public domain according to its author, Brian Hsu + +from docutils.parsers.rst import Directive, directives +from docutils import nodes + +try: + import requests +except ImportError: + requests = None # NOQA + +from nikola.plugin_categories import RestExtension +from nikola.utils import req_missing + + +class Plugin(RestExtension): + + name = "rest_gist" + + def set_site(self, site): + self.site = site + directives.register_directive('gist', GitHubGist) + return super(Plugin, self).set_site(site) + + +class GitHubGist(Directive): + """ Embed GitHub Gist. + + Usage: + + .. gist:: GIST_ID + + or + + .. gist:: GIST_URL + + + """ + + required_arguments = 1 + optional_arguments = 1 + option_spec = {'file': directives.unchanged} + final_argument_whitespace = True + has_content = False + + def get_raw_gist_with_filename(self, gistID, filename): + url = '/'.join(("https://gist.github.com/raw", gistID, filename)) + return requests.get(url).text + + def get_raw_gist(self, gistID): + url = "https://gist.github.com/raw/{0}".format(gistID) + return requests.get(url).text + + def run(self): + if 'https://' in self.arguments[0]: + gistID = self.arguments[0].split('/')[-1].strip() + else: + gistID = self.arguments[0].strip() + embedHTML = "" + rawGist = "" + + if 'file' in self.options: + filename = self.options['file'] + if requests is not None: + rawGist = (self.get_raw_gist_with_filename(gistID, filename)) + embedHTML = ('<script src="https://gist.github.com/{0}.js' + '?file={1}"></script>').format(gistID, filename) + else: + if requests is not None: + rawGist = (self.get_raw_gist(gistID)) + embedHTML = ('<script src="https://gist.github.com/{0}.js">' + '</script>').format(gistID) + + if requests is None: + reqnode = nodes.raw( + '', req_missing('requests', 'have inline gist source', + optional=True), format='html') + else: + reqnode = nodes.literal_block('', rawGist) + + return [nodes.raw('', embedHTML, format='html'), + nodes.raw('', '<noscript>', format='html'), + reqnode, + nodes.raw('', '</noscript>', format='html')] diff --git a/nikola/plugins/compile/rest/listing.plugin b/nikola/plugins/compile/rest/listing.plugin new file mode 100644 index 0000000..4c9883e --- /dev/null +++ b/nikola/plugins/compile/rest/listing.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_listing +Module = listing + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Extension for source listings + diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py new file mode 100644 index 0000000..31975bb --- /dev/null +++ b/nikola/plugins/compile/rest/listing.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +""" Define and register a listing directive using the existing CodeBlock """ + + +from __future__ import unicode_literals +from codecs import open as codecs_open # for patching purposes +import os +try: + from urlparse import urlunsplit +except ImportError: + from urllib.parse import urlunsplit # NOQA + +from docutils import core +from docutils import nodes +from docutils.parsers.rst import Directive, directives +from docutils.parsers.rst.directives.misc import Include +try: + from docutils.parsers.rst.directives.body import CodeBlock +except ImportError: # docutils < 0.9 (Debian Sid For The Loss) + class CodeBlock(Directive): + required_arguments = 1 + has_content = True + CODE = '<pre>{0}</pre>' + + def run(self): + """ Required by the Directive interface. Create docutils nodes """ + return [nodes.raw('', self.CODE.format('\n'.join(self.content)), format='html')] + directives.register_directive('code', CodeBlock) + + +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + + name = "rest_listing" + + def set_site(self, site): + self.site = site + # Even though listings don't use CodeBlock anymore, I am + # leaving these to make the code directive work with + # docutils < 0.9 + directives.register_directive('code-block', CodeBlock) + directives.register_directive('sourcecode', CodeBlock) + directives.register_directive('listing', Listing) + return super(Plugin, self).set_site(site) + + +class Listing(Include): + """ listing directive: create a highlighted block of code from a file in listings/ + + Usage: + + .. listing:: nikola.py python + :number-lines: + + """ + has_content = False + required_arguments = 1 + optional_arguments = 1 + + def run(self): + fname = self.arguments.pop(0) + lang = self.arguments.pop(0) + fpath = os.path.join('listings', fname) + self.arguments.insert(0, fpath) + self.options['code'] = lang + with codecs_open(fpath, 'rb+', 'utf8') as fileobject: + self.content = fileobject.read().splitlines() + self.state.document.settings.record_dependencies.add(fpath) + target = urlunsplit(("link", 'listing', fname, '', '')) + generated_nodes = ( + [core.publish_doctree('`{0} <{1}>`_'.format(fname, target))[0]]) + generated_nodes += self.get_code_from_file(fileobject) + return generated_nodes + + def get_code_from_file(self, data): + """ Create CodeBlock nodes from file object content """ + return super(Listing, self).run() + + def assert_has_content(self): + """ Listing has no content, override check from superclass """ + pass diff --git a/nikola/plugins/compile/rest/media.plugin b/nikola/plugins/compile/rest/media.plugin new file mode 100644 index 0000000..5f5276b --- /dev/null +++ b/nikola/plugins/compile/rest/media.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_media +Module = media + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Directive to support oembed via micawber + diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py new file mode 100644 index 0000000..d1930dd --- /dev/null +++ b/nikola/plugins/compile/rest/media.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +try: + import micawber +except ImportError: + micawber = None # NOQA + + +from nikola.plugin_categories import RestExtension +from nikola.utils import req_missing + + +class Plugin(RestExtension): + + name = "rest_media" + + def set_site(self, site): + self.site = site + directives.register_directive('media', Media) + return super(Plugin, self).set_site(site) + + +class Media(Directive): + """ Restructured text extension for inserting any sort of media using micawber.""" + has_content = False + required_arguments = 1 + optional_arguments = 999 + + def run(self): + if micawber is None: + msg = req_missing(['micawber'], 'use the media directive', optional=True) + return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')] + + providers = micawber.bootstrap_basic() + return [nodes.raw('', micawber.parse_text(" ".join(self.arguments), providers), format='html')] diff --git a/nikola/plugins/compile/rest/post_list.plugin b/nikola/plugins/compile/rest/post_list.plugin new file mode 100644 index 0000000..82450a0 --- /dev/null +++ b/nikola/plugins/compile/rest/post_list.plugin @@ -0,0 +1,9 @@ +[Core] +Name = rest_post_list +Module = post_list + +[Documentation] +Author = Udo Spallek +Version = 0.1 +Website = http://getnikola.com +Description = Includes a list of posts with tag and slide based filters. diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py new file mode 100644 index 0000000..eae4016 --- /dev/null +++ b/nikola/plugins/compile/rest/post_list.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2013 Udo Spallek, Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals + +import uuid + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +from nikola import utils +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + name = "rest_post_list" + + def set_site(self, site): + self.site = site + directives.register_directive('post-list', PostList) + PostList.site = site + return super(Plugin, self).set_site(site) + + +class PostList(Directive): + """ + Post List + ========= + :Directive Arguments: None. + :Directive Options: lang, start, stop, reverse, tags, template, id + :Directive Content: None. + + Provides a reStructuredText directive to create a list of posts. + The posts appearing in the list can be filtered by options. + *List slicing* is provided with the *start*, *stop* and *reverse* options. + + The following not required options are recognized: + + ``start`` : integer + The index of the first post to show. + A negative value like ``-3`` will show the *last* three posts in the + post-list. + Defaults to None. + + ``stop`` : integer + The index of the last post to show. + A value negative value like ``-1`` will show every post, but not the + *last* in the post-list. + Defaults to None. + + ``reverse`` : flag + Reverse the order of the post-list. + Defaults is to not reverse the order of posts. + + ``tags`` : string [, string...] + Filter posts to show only posts having at least one of the ``tags``. + Defaults to None. + + ``slugs`` : string [, string...] + Filter posts to show only posts having at least one of the ``slugs``. + Defaults to None. + + ``all`` : flag + Shows all posts and pages in the post list. + Defaults to show only posts with set *use_in_feeds*. + + ``lang`` : string + The language of post *titles* and *links*. + Defaults to default language. + + ``template`` : string + The name of an alternative template to render the post-list. + Defaults to ``post_list_directive.tmpl`` + + ``id`` : string + A manual id for the post list. + Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex. + """ + option_spec = { + 'start': int, + 'stop': int, + 'reverse': directives.flag, + 'tags': directives.unchanged, + 'slugs': directives.unchanged, + 'all': directives.flag, + 'lang': directives.unchanged, + 'template': directives.path, + 'id': directives.unchanged, + } + + def run(self): + start = self.options.get('start') + stop = self.options.get('stop') + reverse = self.options.get('reverse', False) + tags = self.options.get('tags') + tags = [t.strip().lower() for t in tags.split(',')] if tags else [] + slugs = self.options.get('slugs') + slugs = [s.strip() for s in slugs.split(',')] if slugs else [] + show_all = self.options.get('all', False) + lang = self.options.get('lang', utils.LocaleBorg().current_lang) + template = self.options.get('template', 'post_list_directive.tmpl') + post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex) + + posts = [] + step = -1 if reverse is None else None + if show_all is None: + timeline = [p for p in self.site.timeline] + else: + timeline = [p for p in self.site.timeline if p.use_in_feeds] + + for post in timeline[start:stop:step]: + if tags: + cont = True + for tag in tags: + if tag in [t.lower() for t in post.tags]: + cont = False + + if cont: + continue + + if slugs: + cont = True + for slug in slugs: + if slug == post.meta('slug'): + cont = False + + if cont: + continue + + posts += [post] + + if not posts: + return [] + + template_data = { + 'lang': lang, + 'posts': posts, + 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'), + 'post_list_id': post_list_id, + } + output = self.site.template_system.render_template( + template, None, template_data) + return [nodes.raw('', output, format='html')] diff --git a/nikola/plugins/compile/rest/slides.plugin b/nikola/plugins/compile/rest/slides.plugin new file mode 100644 index 0000000..cee4b06 --- /dev/null +++ b/nikola/plugins/compile/rest/slides.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_slides +Module = slides + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Slides directive + diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py new file mode 100644 index 0000000..41c3314 --- /dev/null +++ b/nikola/plugins/compile/rest/slides.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals + +import uuid + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + + name = "rest_slides" + + def set_site(self, site): + self.site = site + directives.register_directive('slides', Slides) + Slides.site = site + return super(Plugin, self).set_site(site) + + +class Slides(Directive): + """ Restructured text extension for inserting slideshows.""" + has_content = True + + def run(self): + if len(self.content) == 0: + return + + output = self.site.template_system.render_template( + 'slides.tmpl', + None, + { + 'content': self.content, + 'carousel_id': 'slides_' + uuid.uuid4().hex, + } + ) + return [nodes.raw('', output, format='html')] + + +directives.register_directive('slides', Slides) diff --git a/nikola/plugins/compile/rest/soundcloud.plugin b/nikola/plugins/compile/rest/soundcloud.plugin new file mode 100644 index 0000000..1d31a8f --- /dev/null +++ b/nikola/plugins/compile/rest/soundcloud.plugin @@ -0,0 +1,10 @@ +[Core] +Name = rest_soundcloud +Module = soundcloud + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Soundcloud directive + diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py new file mode 100644 index 0000000..6fb3e99 --- /dev/null +++ b/nikola/plugins/compile/rest/soundcloud.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + + +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + + name = "rest_soundcloud" + + def set_site(self, site): + self.site = site + directives.register_directive('soundcloud', SoundCloud) + return super(Plugin, self).set_site(site) + + +CODE = ("""<iframe width="{width}" height="{height}" +scrolling="no" frameborder="no" +src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/tracks/""" + """{sid}"> +</iframe>""") + + +class SoundCloud(Directive): + """ Restructured text extension for inserting SoundCloud embedded music + + Usage: + .. soundcloud:: <sound id> + :height: 400 + :width: 600 + + """ + has_content = True + required_arguments = 1 + option_spec = { + 'width': directives.positive_int, + 'height': directives.positive_int, + } + + def run(self): + """ Required by the Directive interface. Create docutils nodes """ + self.check_content() + options = { + 'sid': self.arguments[0], + 'width': 600, + 'height': 160, + } + options.update(self.options) + return [nodes.raw('', CODE.format(**options), format='html')] + + def check_content(self): + """ Emit a deprecation warning if there is content """ + if self.content: + raise self.warning("This directive does not accept content. The " + "'key=value' format for options is deprecated, " + "use ':key: value' instead") diff --git a/nikola/plugins/compile/rest/vimeo.plugin b/nikola/plugins/compile/rest/vimeo.plugin new file mode 100644 index 0000000..e0ff3f1 --- /dev/null +++ b/nikola/plugins/compile/rest/vimeo.plugin @@ -0,0 +1,7 @@ +[Core] +Name = rest_vimeo +Module = vimeo + +[Documentation] +Description = Vimeo directive + diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py new file mode 100644 index 0000000..6d66648 --- /dev/null +++ b/nikola/plugins/compile/rest/vimeo.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +try: + import requests +except ImportError: + requests = None # NOQA +import json + + +from nikola.plugin_categories import RestExtension +from nikola.utils import req_missing + + +class Plugin(RestExtension): + + name = "rest_vimeo" + + def set_site(self, site): + self.site = site + directives.register_directive('vimeo', Vimeo) + return super(Plugin, self).set_site(site) + + +CODE = """<iframe src="http://player.vimeo.com/video/{vimeo_id}" +width="{width}" height="{height}" +frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen> +</iframe> +""" + +VIDEO_DEFAULT_HEIGHT = 500 +VIDEO_DEFAULT_WIDTH = 281 + + +class Vimeo(Directive): + """ Restructured text extension for inserting vimeo embedded videos + + Usage: + .. vimeo:: 20241459 + :height: 400 + :width: 600 + + """ + has_content = True + required_arguments = 1 + option_spec = { + "width": directives.positive_int, + "height": directives.positive_int, + } + + # set to False for not querying the vimeo api for size + request_size = True + + def run(self): + self.check_content() + options = { + 'vimeo_id': self.arguments[0], + 'width': VIDEO_DEFAULT_WIDTH, + 'height': VIDEO_DEFAULT_HEIGHT, + } + if self.request_size: + err = self.check_modules() + if err: + return err + self.set_video_size() + options.update(self.options) + return [nodes.raw('', CODE.format(**options), format='html')] + + def check_modules(self): + msg = None + if requests is None: + msg = req_missing(['requests'], 'use the vimeo directive', optional=True) + return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')] + return None + + def set_video_size(self): + # Only need to make a connection if width and height aren't provided + if 'height' not in self.options or 'width' not in self.options: + self.options['height'] = VIDEO_DEFAULT_HEIGHT + self.options['width'] = VIDEO_DEFAULT_WIDTH + + if json: # we can attempt to retrieve video attributes from vimeo + try: + url = ('http://vimeo.com/api/v2/video/{0}' + '.json'.format(self.arguments[0])) + data = requests.get(url).text + video_attributes = json.loads(data)[0] + self.options['height'] = video_attributes['height'] + self.options['width'] = video_attributes['width'] + except Exception: + # fall back to the defaults + pass + + def check_content(self): + if self.content: + raise self.warning("This directive does not accept content. The " + "'key=value' format for options is deprecated, " + "use ':key: value' instead") diff --git a/nikola/plugins/compile/rest/youtube.plugin b/nikola/plugins/compile/rest/youtube.plugin new file mode 100644 index 0000000..01275be --- /dev/null +++ b/nikola/plugins/compile/rest/youtube.plugin @@ -0,0 +1,8 @@ +[Core] +Name = rest_youtube +Module = youtube + +[Documentation] +Version = 0.1 +Description = Youtube directive + diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py new file mode 100644 index 0000000..3d4bdd3 --- /dev/null +++ b/nikola/plugins/compile/rest/youtube.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + + +from nikola.plugin_categories import RestExtension + + +class Plugin(RestExtension): + + name = "rest_youtube" + + def set_site(self, site): + self.site = site + directives.register_directive('youtube', Youtube) + return super(Plugin, self).set_site(site) + + +CODE = """\ +<iframe width="{width}" +height="{height}" +src="http://www.youtube.com/embed/{yid}?rel=0&hd=1&wmode=transparent" +></iframe>""" + + +class Youtube(Directive): + """ Restructured text extension for inserting youtube embedded videos + + Usage: + .. youtube:: lyViVmaBQDg + :height: 400 + :width: 600 + + """ + has_content = True + required_arguments = 1 + option_spec = { + "width": directives.positive_int, + "height": directives.positive_int, + } + + def run(self): + self.check_content() + options = { + 'yid': self.arguments[0], + 'width': 425, + 'height': 344, + } + options.update(self.options) + return [nodes.raw('', CODE.format(**options), format='html')] + + def check_content(self): + if self.content: + raise self.warning("This directive does not accept content. The " + "'key=value' format for options is deprecated, " + "use ':key: value' instead") diff --git a/nikola/plugins/compile/textile.plugin b/nikola/plugins/compile/textile.plugin new file mode 100644 index 0000000..6439b0f --- /dev/null +++ b/nikola/plugins/compile/textile.plugin @@ -0,0 +1,10 @@ +[Core] +Name = textile +Module = textile + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile Textile into HTML + diff --git a/nikola/plugins/compile/textile.py b/nikola/plugins/compile/textile.py new file mode 100644 index 0000000..b402329 --- /dev/null +++ b/nikola/plugins/compile/textile.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on textile.""" + +import codecs +import os +import re + +try: + from textile import textile +except ImportError: + textile = None # NOQA + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileTextile(PageCompiler): + """Compile textile into HTML.""" + + name = "textile" + + def compile_html(self, source, dest, is_two_file=True): + if textile is None: + req_missing(['textile'], 'build this site (compile Textile)') + makedirs(os.path.dirname(dest)) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + if not is_two_file: + data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1] + output = textile(data, head_offset=1) + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write('<notextile> <!--\n') + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write('--></notextile>\n\n') + fd.write("\nWrite your post here.") diff --git a/nikola/plugins/compile/txt2tags.plugin b/nikola/plugins/compile/txt2tags.plugin new file mode 100644 index 0000000..55eb0a0 --- /dev/null +++ b/nikola/plugins/compile/txt2tags.plugin @@ -0,0 +1,10 @@ +[Core] +Name = txt2tags +Module = txt2tags + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile Txt2tags into HTML + diff --git a/nikola/plugins/compile/txt2tags.py b/nikola/plugins/compile/txt2tags.py new file mode 100644 index 0000000..2f62f04 --- /dev/null +++ b/nikola/plugins/compile/txt2tags.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on txt2tags. + +Txt2tags is not in PyPI, you can install it with + +easy_install -f "http://txt2tags.org/txt2tags.py#egg=txt2tags-2.6" txt2tags + +""" + +import codecs +import os + +try: + from txt2tags import exec_command_line as txt2tags +except ImportError: + txt2tags = None # NOQA + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileTextile(PageCompiler): + """Compile txt2tags into HTML.""" + + name = "txt2tags" + + def compile_html(self, source, dest, is_two_file=True): + if txt2tags is None: + req_missing(['txt2tags'], 'build this site (compile txt2tags)') + makedirs(os.path.dirname(dest)) + cmd = ["-t", "html", "--no-headers", "--outfile", dest, source] + txt2tags(cmd) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + with codecs.open(path, "wb+", "utf8") as fd: + if onefile: + fd.write("\n'''\n<!--\n") + for k, v in metadata.items(): + fd.write('.. {0}: {1}\n'.format(k, v)) + fd.write("-->\n'''\n") + fd.write("\nWrite your post here.") diff --git a/nikola/plugins/compile/wiki.plugin b/nikola/plugins/compile/wiki.plugin new file mode 100644 index 0000000..eee14a8 --- /dev/null +++ b/nikola/plugins/compile/wiki.plugin @@ -0,0 +1,10 @@ +[Core] +Name = wiki +Module = wiki + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://getnikola.com +Description = Compile WikiMarkup into HTML + diff --git a/nikola/plugins/compile/wiki.py b/nikola/plugins/compile/wiki.py new file mode 100644 index 0000000..b2c4afc --- /dev/null +++ b/nikola/plugins/compile/wiki.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on CreoleWiki.""" + +import codecs +import os + +try: + from creole import Parser + from creole.html_emitter import HtmlEmitter + creole = True +except ImportError: + creole = None + +from nikola.plugin_categories import PageCompiler +from nikola.utils import makedirs, req_missing + + +class CompileWiki(PageCompiler): + """Compile CreoleWiki into HTML.""" + + name = "wiki" + + def compile_html(self, source, dest, is_two_file=True): + if creole is None: + req_missing(['creole'], 'build this site (compile CreoleWiki)') + makedirs(os.path.dirname(dest)) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + document = Parser(data).parse() + output = HtmlEmitter(document).emit() + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + makedirs(os.path.dirname(path)) + if onefile: + raise Exception('There are no comments in CreoleWiki markup, so ' + 'one-file format is not possible, use the -2 ' + 'option.') + with codecs.open(path, "wb+", "utf8") as fd: + fd.write("Write your post here.") |
