view fontaine/renderer.py @ 10:2cea36073188

Move core CLI tool code into the package.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 04 Jan 2017 08:46:27 -0800
parents 02d2e4d8b0c1
children
line wrap: on
line source

import re
from fontaine.document import (
    TYPE_ACTION, TYPE_CENTEREDACTION, TYPE_CHARACTER, TYPE_DIALOG,
    TYPE_PARENTHETICAL, TYPE_TRANSITION, TYPE_LYRICS, TYPE_PAGEBREAK)


class BaseDocumentRenderer:
    def __init__(self, text_renderer=None):
        self.text_renderer = text_renderer
        if not text_renderer:
            self.text_renderer = NullTextRenderer()

        self._para_rdrs = {
            TYPE_ACTION: self.write_action,
            TYPE_CENTEREDACTION: self.write_centeredaction,
            TYPE_CHARACTER: self.write_character,
            TYPE_DIALOG: self.write_dialog,
            TYPE_PARENTHETICAL: self.write_parenthetical,
            TYPE_TRANSITION: self.write_transition,
            TYPE_LYRICS: self.write_lyrics,
            TYPE_PAGEBREAK: self.write_pagebreak,
        }

    def _tr(self, text):
        return self.text_renderer.render_text(text)

    def render_doc(self, doc, out):
        self.write_header(doc, out)
        self.render_title_page(doc.title_values, out)
        for s in doc.scenes:
            self.render_scene(s, out)
        self.write_footer(doc, out)

    def render_title_page(self, values, out):
        clean_values = values.copy()
        clean_values.setdefault('title', 'Untitled Screenplay')
        clean_values.setdefault('credit', 'Written by')
        clean_values.setdefault('author', 'Unknown')
        for k in clean_values:
            clean_values[k] = self._tr(clean_values[k])
        self.write_title_page(clean_values, out)

    def render_scene(self, scene, out):
        if scene.header is not None:
            self.write_scene_heading(scene.header, out)
        for p in scene.paragraphs:
            rdr_func = self._para_rdrs[p.type]
            if p.type != TYPE_PAGEBREAK:
                rdr_func(self._tr(p.text), out)
            else:
                rdr_func(out)

    def write_header(self, doc, out):
        pass

    def write_footer(self, doc, out):
        pass

    def write_title_page(self, values, out):
        raise NotImplementedError()

    def write_scene_heading(self, text, out):
        raise NotImplementedError()

    def write_action(self, text, out):
        raise NotImplementedError()

    def write_centeredaction(self, text, out):
        raise NotImplementedError()

    def write_character(self, text, out):
        raise NotImplementedError()

    def write_dialog(self, text, out):
        raise NotImplementedError()

    def write_parenthetical(self, text, out):
        raise NotImplementedError()

    def write_transition(self, text, out):
        raise NotImplementedError()

    def write_lyrics(self, text, out):
        raise NotImplementedError()

    def write_pagebreak(self, out):
        raise NotImplementedError()


RE_ITALICS = re.compile(
    r"(?P<before>^|\s)(?P<esc>\\)?\*(?P<text>.*[^\s\*])\*(?=[^a-zA-Z0-9\*]|$)")
RE_BOLD = re.compile(
    r"(?P<before>^|\s)(?P<esc>\\)?\*\*(?P<text>.*[^\s])\*\*(?=[^a-zA-Z0-9]|$)")
RE_UNDERLINE = re.compile(
    r"(?P<before>^|\s)(?P<esc>\\)?_(?P<text>.*[^\s])_(?=[^a-zA-Z0-9]|$)")


class BaseTextRenderer:
    def render_text(self, text):
        # Replace bold stuff to catch double asterisks.
        text = RE_BOLD.sub(self._do_make_bold, text)
        text = RE_ITALICS.sub(self._do_make_italics, text)
        text = RE_UNDERLINE.sub(self._do_make_underline, text)

        return text

    def _do_make_italics(self, m):
        if m.group('esc'):
            return m.group('before') + '*' + m.group('text') + '*'
        return (
            m.group('before') +
            self.make_italics(m.group('text')))

    def _do_make_bold(self, m):
        if m.group('esc'):
            return m.group('before') + '**' + m.group('text') + '**'
        return (
            m.group('before') +
            self.make_bold(m.group('text')))

    def _do_make_underline(self, m):
        if m.group('esc'):
            return m.group('before') + '_' + m.group('text') + '_'
        return (
            m.group('before') +
            self.make_underline(m.group('text')))

    def make_italics(self, text):
        raise NotImplementedError()

    def make_bold(self, text):
        raise NotImplementedError()

    def make_underline(self, text):
        raise NotImplementedError()


class NullTextRenderer(BaseTextRenderer):
    def make_bold(self, text):
        return text

    def make_italics(self, text):
        return text

    def make_underline(self, text):
        return text