# Modified syntax-highlighting directive support taken from Michael Alyn # Miller's restxsl. The actual syntax highlighting code itself has been # replaced. # XXX # This is still in a semi-working state # mech_name &c. is pinched from MochiKit and does not work yet # Copyright (c) 2006, Michael Alyn Miller . # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice unmodified, this list of conditions, and the following # disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of Michael Alyn Miller nor the names of the # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. import os, sys, imp import docutils.core import docutils.nodes import docutils.utils import docutils.parsers.rst from docutils.core import publish_parts from docutils.parsers.rst import roles TEMPLATE = u"""%(html_prolog)s %(html_head)s %(html_body)s """ def mech_name(text): name = text.split('(', 1)[0].split()[0] base = '' if name.startswith('MochiKit.'): # cross-reference parts = name.split('.') base = parts[1] + '.html' if parts[-1] in ("call", "apply"): parts.pop() name = '.'.join(parts[2:]) return base, name def role_ref(role, rawtext, text, lineno, inliner, options=None, content=[]): if options is None: options = {} base, name = mech_name(text) ref = base if name: ref += '#fn-' + name.lower() roles.set_classes(options) options.setdefault('classes', []).append('ref') node = docutils.nodes.reference( text, docutils.utils.unescape(text), refuri=ref, **options) return [node], [] def role_def(role, rawtext, text, lineno, inliner, options=None, content=[]): if options is None: options = {} base, name = mech_name(text) assert base == '' ref = 'fn-' + docutils.utils.unescape(name.lower()) anchor = docutils.nodes.raw('', '\n\n' % (ref,), format='html') roles.set_classes(options) options.setdefault('classes', []).append('def') node = docutils.nodes.reference( text, utils.unescape(text), refuri='#' + ref, **options) return [anchor, node], [] def code_block_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """ Provides syntax highlighting for blocks of code. It is used with the following syntax:: .. code-block:: python import sys def main(argv): print "Hello world" if __name__ == "__main__": main(sys.argv) The directive requires the name of a language (case-insensitive) as its only argument. Currently only Python is supported. All code in the indented block following the directive will be colorized. The directive can also be told to include a source file directly:: .. code-block:: :language: Python :source-file: ../myfile.py You cannot both specify a source-file and include code directly. """ from colorize import colorize_ex # Get the language name. Try the arguments first, then fall back to # the options. try: language = arguments[0] except IndexError: language = options['language'] # The user cannot specify content and give us a source-file, they # must choose one or the other. if content and 'source-file' in options: error = state_machine.reporter.error( 'Must specify a source-file or provide content, not both.', docutils.nodes.literal_block(block_text, block_text), line=lineno) return [error] # Load the content from a file if we were not given any content. if not content: try: sourceFile = state_machine.input_lines.source( lineno - state_machine.input_offset - 1) sourceDir = os.path.dirname(os.path.abspath(sourceFile)) path = options['source-file'] path = os.path.normpath(os.path.join(sourceDir, path)) path = docutils.utils.relative_path(None, path) state.document.settings.record_dependencies.add(path) content = [line.rstrip() for line in file(path)] except IOError: error = state_machine.reporter.error( 'Could not read file %s.' % (path), docutils.nodes.literal_block(block_text, block_text), line=lineno) return [error] if language.lower() != "python": error = state_machine.reporter.error( 'No lexer found for language "%s".' % (language), docutils.nodes.literal_block(block_text, block_text), line=lineno) return [error] # Render the content to HTML. The HTML is wrapped in a .. # block. formatted = [] formatted.append('') formatted.append(colorize_ex('\n'.join(content))) formatted.append('\n') # Enclose the rendered HTML in a raw docutils node and return the # node. raw = docutils.nodes.raw('', "\n".join(formatted), format='html') return [raw] # Configure the code-block directive. code_block_directive.arguments = (0, 2, True) code_block_directive.options = { 'language': docutils.parsers.rst.directives.unchanged, 'source-file': docutils.parsers.rst.directives.path, } code_block_directive.content = True def register(): from colorize import colorize_ex docutils.parsers.rst.directives.register_directive( 'code-block', code_block_directive) roles.register_canonical_role('ref', role_ref) roles.register_canonical_role('def', role_def) def rst2html_main(): try: import locale locale.setlocale(locale.LC_ALL, '') except: pass register() description = ('Generates (X)HTML documents from standalone ' 'reStructuredText sources. ' + docutils.core.default_description) docutils.core.publish_cmdline(writer_name='html', description=description) def rst2html_main_ex(): try: import locale locale.setlocale(locale.LC_ALL, '') except: pass register() basepath = os.path.join('doc/rst', '') destpath = os.path.join('doc/html', '') for root, dirs, files in os.walk(basepath): if '.svn' in dirs: dirs.remove('.svn') destroot = destpath + root[len(basepath):] if not os.path.exists(destroot): os.makedirs(destroot) for fn in files: basefn, ext = os.path.splitext(fn) if ext == '.rst': srcfn = os.path.join(root, fn) dest = os.path.join(destroot, basefn + '.html') if basefn != "index": try: if os.path.getmtime(dest) >= os.path.getmtime(srcfn): print srcfn, "not changed" continue except OSError: pass print srcfn parts = publish_parts( source_path=srcfn, source=open(srcfn, 'rb').read().decode('utf8'), destination_path=dest, writer_name='html', settings_overrides=dict( embed_stylesheet=False, stylesheet_path='include/css/documentation.css', ), ) parts['html_head'] = parts['html_head'] % ('utf-8',) parts['html_prolog'] = parts['html_prolog'] % ('utf-8',) doc = (TEMPLATE % parts).encode("utf8") out = open(dest, 'wb') out.write(doc) out.close() if __name__ == '__main__': rst2html_main()