comparison fontaine/renderer.py @ 3:6019eee799bf

Add base classes for rendering.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 03 Jan 2017 09:05:48 -0800
parents 74b83e3d921e
children e3d52edde00b
comparison
equal deleted inserted replaced
2:59fe8cb6190d 3:6019eee799bf
1 import re 1 import re
2 from fontaine.document import (
3 TYPE_ACTION, TYPE_CENTEREDACTION, TYPE_CHARACTER, TYPE_DIALOG,
4 TYPE_PARENTHETICAL, TYPE_TRANSITION, TYPE_LYRICS, TYPE_PAGEBREAK)
5
6
7 class BaseDocumentRenderer:
8 def __init__(self, text_renderer=None):
9 self.text_renderer = text_renderer
10 if not text_renderer:
11 self.text_renderer = NullTextRenderer()
12
13 self._para_rdrs = {
14 TYPE_ACTION: self.write_action,
15 TYPE_CENTEREDACTION: self.write_centeredaction,
16 TYPE_CHARACTER: self.write_character,
17 TYPE_DIALOG: self.write_dialog,
18 TYPE_PARENTHETICAL: self.write_parenthetical,
19 TYPE_TRANSITION: self.write_transition,
20 TYPE_LYRICS: self.write_lyrics,
21 TYPE_PAGEBREAK: self.write_pagebreak,
22 }
23
24 def _tr(self, text):
25 return self.text_renderer.render_text(text)
26
27 def render_doc(self, doc):
28 self.write_header(doc)
29 self.render_title_page(doc.title_values)
30 for s in doc.scenes:
31 self.render_scene(s)
32 self.write_footer(doc)
33
34 def render_title_page(self, values):
35 # Render known metadata.
36 title = values.get('title')
37 credit = values.get('credit')
38 author = values.get('author') or values.get('authors')
39 source = values.get('source')
40 center_text = '\n\n'.join([
41 i for i in [title, credit, author, source]
42 if i is not None])
43 self.write_title_heading(self._tr(center_text))
44
45 ddate = values.get('date') or values.get('draft date')
46 contact = values.get('contact')
47 bottom_text = '\n\n'.join([
48 i for i in [ddate, contact]
49 if i is not None])
50 self.write_title_footer(self._tr(bottom_text))
51
52 def render_scene(self, scene):
53 if scene.header is not None:
54 self.write_scene_heading(scene.header)
55 for p in scene.paragraphs:
56 rdr_func = self._para_rdrs[p.type]
57 if p.type != TYPE_PAGEBREAK:
58 rdr_func(self._tr(p.text))
59 else:
60 rdr_func()
61
62 def write_header(self, doc):
63 pass
64
65 def write_footer(self, doc):
66 pass
67
68 def write_title_heading(self, text):
69 raise NotImplementedError()
70
71 def write_title_footer(self, text):
72 raise NotImplementedError()
73
74 def write_scene_heading(self, text):
75 raise NotImplementedError()
76
77 def write_action(self, text):
78 raise NotImplementedError()
79
80 def write_centeredaction(self, text):
81 raise NotImplementedError()
82
83 def write_character(self, text):
84 raise NotImplementedError()
85
86 def write_dialog(self, text):
87 raise NotImplementedError()
88
89 def write_parenthetical(self, text):
90 raise NotImplementedError()
91
92 def write_transition(self, text):
93 raise NotImplementedError()
94
95 def write_lyrics(self, text):
96 raise NotImplementedError()
97
98 def write_pagebreak(self):
99 raise NotImplementedError()
2 100
3 101
4 RE_ITALICS = re.compile( 102 RE_ITALICS = re.compile(
5 r"(?P<before>^|\s)(?P<esc>\\)?\*(?P<text>.*[^\s\*])\*(?=[^a-zA-Z0-9\*]|$)") 103 r"(?P<before>^|\s)(?P<esc>\\)?\*(?P<text>.*[^\s\*])\*(?=[^a-zA-Z0-9\*]|$)")
6 RE_BOLD = re.compile( 104 RE_BOLD = re.compile(
7 r"(?P<before>^|\s)(?P<esc>\\)?\*\*(?P<text>.*[^\s])\*\*(?=[^a-zA-Z0-9]|$)") 105 r"(?P<before>^|\s)(?P<esc>\\)?\*\*(?P<text>.*[^\s])\*\*(?=[^a-zA-Z0-9]|$)")
8 RE_UNDERLINE = re.compile( 106 RE_UNDERLINE = re.compile(
9 r"(?P<before>^|\s)(?P<esc>\\)?_(?P<text>.*[^\s])_(?=[^a-zA-Z0-9]|$)") 107 r"(?P<before>^|\s)(?P<esc>\\)?_(?P<text>.*[^\s])_(?=[^a-zA-Z0-9]|$)")
10 108
11 109
12 class BaseRenderer: 110 class BaseTextRenderer:
13 def render_text(self, text): 111 def render_text(self, text):
14 # Replace bold stuff to catch double asterisks. 112 # Replace bold stuff to catch double asterisks.
15 text = RE_BOLD.sub(self._do_write_bold, text) 113 text = RE_BOLD.sub(self._do_make_bold, text)
16 text = RE_ITALICS.sub(self._do_write_italics, text) 114 text = RE_ITALICS.sub(self._do_make_italics, text)
17 text = RE_UNDERLINE.sub(self._do_write_underline, text) 115 text = RE_UNDERLINE.sub(self._do_make_underline, text)
18 116
19 return text 117 return text
20 118
21 def _do_write_italics(self, m): 119 def _do_make_italics(self, m):
22 if m.group('esc'): 120 if m.group('esc'):
23 return m.group('before') + '*' + m.group('text') + '*' 121 return m.group('before') + '*' + m.group('text') + '*'
24 return ( 122 return (
25 m.group('before') + 123 m.group('before') +
26 self.write_italics(m.group('text'))) 124 self.make_italics(m.group('text')))
27 125
28 def _do_write_bold(self, m): 126 def _do_make_bold(self, m):
29 if m.group('esc'): 127 if m.group('esc'):
30 return m.group('before') + '**' + m.group('text') + '**' 128 return m.group('before') + '**' + m.group('text') + '**'
31 return ( 129 return (
32 m.group('before') + 130 m.group('before') +
33 self.write_bold(m.group('text'))) 131 self.make_bold(m.group('text')))
34 132
35 def _do_write_underline(self, m): 133 def _do_make_underline(self, m):
36 if m.group('esc'): 134 if m.group('esc'):
37 return m.group('before') + '_' + m.group('text') + '_' 135 return m.group('before') + '_' + m.group('text') + '_'
38 return ( 136 return (
39 m.group('before') + 137 m.group('before') +
40 self.write_underline(m.group('text'))) 138 self.make_underline(m.group('text')))
41 139
42 def write_italics(self, text): 140 def make_italics(self, text):
43 raise NotImplementedError() 141 raise NotImplementedError()
44 142
45 def write_bold(self, text): 143 def make_bold(self, text):
46 raise NotImplementedError() 144 raise NotImplementedError()
47 145
48 def write_underline(self, text): 146 def make_underline(self, text):
49 raise NotImplementedError() 147 raise NotImplementedError()
148
149
150 class NullTextRenderer(BaseTextRenderer):
151 def make_bold(self, text):
152 return text
153
154 def make_italics(self, text):
155 return text
156
157 def make_underline(self, text):
158 return text