Source code for hieroglyph.builder

"""Available slide building classes."""

import json
import os

from docutils import nodes
import sphinx
from sphinx.builders.html import (
    SingleFileHTMLBuilder,
    StandaloneHTMLBuilder,
    DirectoryHTMLBuilder,
)
from sphinx.util import copy_static_entry

from hieroglyph import writer
from hieroglyph import directives


if sphinx.version_info < (1, 6, 0):
    from sphinx.theming import Theme

    class HTMLThemeFactory:
        """Compatibility shim to make old versions of Sphinx act more like 1.6+."""
        def __init__(self, app):
            self.app = app

        def load_additional_themes(self, paths):
            Theme.init_themes(self.app.confdir, paths)

        def create(self, themename):
            return Theme(themename)

    Theme.get_config = Theme.get_confstr
    Theme.get_theme_dirs = Theme.get_dirchain
else:
    from sphinx.theming import HTMLThemeFactory


def building_slides(app):
    """Returns True if building Slides."""

    return isinstance(app.builder, AbstractSlideBuilder)


[docs]class AbstractSlideBuilder(object): format = 'slides' add_permalinks = False default_translator_class = writer.SlideTranslator
[docs] def init_translator_class(self): """Compatibility shim to support versions of Sphinx prior to 1.6.""" self.translator_class = self.default_translator_class
def get_builtin_theme_dirs(self): return [ os.path.join(os.path.dirname(__file__), 'themes',) ]
[docs] def get_theme_config(self): """Return the configured theme name and options.""" return self.config.slide_theme, self.config.slide_theme_options
[docs] def get_theme_options(self): """Return a dict of theme options, combining defaults and overrides.""" overrides = self.get_theme_config()[1] return self.theme.get_options(overrides)
def init_templates(self): themename, themeoptions = self.get_theme_config() self.create_template_bridge() self._theme_stack = [] self._additional_themes = [] self.theme = self.theme_options = None self.apply_theme(themename, themeoptions)
[docs] def apply_theme(self, themename, themeoptions): """Apply a new theme to the document. This will store the existing theme configuration and apply a new one. """ # push the existing values onto the Stack self._theme_stack.append( (self.theme, self.theme_options) ) theme_factory = HTMLThemeFactory(self.app) theme_factory.load_additional_themes(self.get_builtin_theme_dirs() + self.config.slide_theme_path) self.theme = theme_factory.create(themename) self.theme_options = themeoptions.copy() self.templates.init(self, self.theme) self.templates.environment.filters['json'] = json.dumps if self.theme not in self._additional_themes: self._additional_themes.append(self.theme)
[docs] def pop_theme(self): """Disable the most recent theme, and restore its predecessor.""" self.theme, self.theme_options = self._theme_stack.pop()
def prepare_writing(self, docnames): super(AbstractSlideBuilder, self).prepare_writing(docnames) # override items in the global context if needed if self.config.slide_title: self.globalcontext['docstitle'] = self.config.slide_title def get_doc_context(self, docname, body, metatags): context = super(AbstractSlideBuilder, self).get_doc_context( docname, body, metatags, ) if self.theme: context.update(dict( style=self.theme.get_config('theme', 'stylesheet'), )) return context def write_doc(self, docname, doctree): slideconf = directives.slideconf.get(doctree) if slideconf: slideconf.apply(self) result = super(AbstractSlideBuilder, self).write_doc(docname, doctree) if slideconf: # restore the previous theme configuration slideconf.restore(self) return result
[docs] def post_process_images(self, doctree): """Pick the best candidate for all image URIs.""" super(AbstractSlideBuilder, self).post_process_images(doctree) # figure out where this doctree is in relation to the srcdir relative_base = ( ['..'] * doctree.attributes.get('source')[len(self.srcdir) + 1:].count('/') ) for node in doctree.traverse(nodes.image): if node.get('candidates') is None: node['candidates'] = ('*',) # fix up images with absolute paths if node['uri'].startswith(self.outdir): node['uri'] = '/'.join( relative_base + [ node['uri'][len(self.outdir) + 1:] ] )
def copy_static_files(self): result = super(AbstractSlideBuilder, self).copy_static_files() # add context items for search function used in searchtools.js_t ctx = self.globalcontext.copy() ctx.update(self.indexer.context_for_searchtool()) for theme in self._additional_themes[1:]: themeentries = [os.path.join(themepath, 'static') for themepath in theme.get_theme_dirs()[::-1]] for entry in themeentries: copy_static_entry(entry, os.path.join(self.outdir, '_static'), self, ctx) return result
[docs]class DirectorySlideBuilder(AbstractSlideBuilder, DirectoryHTMLBuilder): """This is the standard Directory Slide HTML builder. Its output is a directory with HTML files, where each file is called ``index.html`` and placed in a subdirectory named like its page name. For example, the document ``markup/rest.rst`` will not result in an output file ``markup/rest.html``, but ``markup/rest/index.html``. When generating links between pages, the ``index.html`` is omitted, so that the URL would look like ``markup/rest/``. The output directry will include any needed style sheets, slide table, and presenter's console JavaScript. Its name is ``dirslides``. """ name = 'dirslides'
[docs]class SlideBuilder(AbstractSlideBuilder, StandaloneHTMLBuilder): """This is the standard Slide HTML builder. Its output is a directory with HTML, along with the needed style sheets, slide table, and presenter's console JavaScript. Its name is ``slides``. """ name = 'slides'
[docs]class SingleFileSlideBuilder(AbstractSlideBuilder, SingleFileHTMLBuilder): """This is the single file Slide HTML builder. Its output is a directory with a single HTML file, along with the needed style sheets and JavaScript. Its name is ``singlefile-slides``. """ name = 'singlefile-slides' default_translator_class = writer.SingleFileSlideTranslator
[docs]class AbstractInlineSlideBuilder(object): name = 'inlineslides' default_translator_class = writer.BaseSlideTranslator def __init__(self, *args, **kwargs): super(AbstractInlineSlideBuilder, self).__init__(*args, **kwargs) self.config.html_static_path.append( os.path.relpath( os.path.join( os.path.dirname(__file__), 'themes', 'inline-slides', 'static', ), self.confdir, ) ) self.css_files.append('_static/slides.css')
[docs]class DirectoryInlineSlideBuilder( AbstractInlineSlideBuilder, DirectoryHTMLBuilder): """This is the Inline Slide Directory HTML builder. The inline slide builder add support for the ``slide`` directive to Sphinx's :py:class:`DirectoryHTMLBuilder`, and adds an additional stylesheet to the output for basic inline display. When using an inline builder :confval:`autoslides` is disabled. Its name is ``dirinlineslides``. .. versionadded:: 0.5 """ name = 'dirinlineslides'
[docs]class InlineSlideBuilder(AbstractInlineSlideBuilder, StandaloneHTMLBuilder): """This is the Inline Slide HTML builder. The inline slide builder add support for the ``slide`` directive to Sphinx's :py:class:`StandaloneHTMLBuilder`, and adds an additional stylesheet to the output for basic inline display. When using an inline builder :confval:`autoslides` is disabled. Its name is ``inlineslides``. .. versionadded:: 0.5 """ name = 'inlineslides'