From ef1635819c057f634cb776b9c57c7d1348b88c26 Mon Sep 17 00:00:00 2001 From: Martin Vilcans Date: Tue, 7 Feb 2012 22:26:14 +0100 Subject: Added scene numbers --- screenplain/export/html.py | 7 +++++++ screenplain/parsers/spmd.py | 30 ++++++++++++++---------------- screenplain/types.py | 8 +++++++- tests/files/scene-numbers.spmd | 7 +++++++ tests/files/scene-numbers.spmd.html | 4 ++++ tests/files_test.py | 6 ++++++ tests/spmd_test.py | 16 +++++++++++++++- 7 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 tests/files/scene-numbers.spmd create mode 100644 tests/files/scene-numbers.spmd.html diff --git a/screenplain/export/html.py b/screenplain/export/html.py index d1f3820..881233c 100644 --- a/screenplain/export/html.py +++ b/screenplain/export/html.py @@ -81,8 +81,15 @@ def _write_dialog_block(dialog, out): def format_slug(slug, out): + num = slug.scene_number with tags(out, 'h2'): + if num: + with tags(out, 'span class="scnuml"'): + out.write(to_html(slug.scene_number)) out.write(to_html(slug.line)) + if num: + with tags(out, 'span class="scnumr"'): + out.write(to_html(slug.scene_number)) def format_action(para, out): diff --git a/screenplain/parsers/spmd.py b/screenplain/parsers/spmd.py index 7df7ce3..89a457c 100644 --- a/screenplain/parsers/spmd.py +++ b/screenplain/parsers/spmd.py @@ -10,15 +10,10 @@ from screenplain.types import ( ) from screenplain.richstring import parse_emphasis -slug_prefixes = ( - 'INT. ', - 'EXT. ', - 'INT./EXT. ', - 'INT/EXT. ', - 'INT ', - 'EXT ', - 'INT/EXT ', - 'I/E ', +slug_regexes = ( + re.compile(r'^(INT|EXT|EST)[ .]'), + re.compile(r'^(INT\.?/EXT\.?)[ .]'), + re.compile(r'^I/E[ .]'), ) TWOSPACE = ' ' * 2 @@ -26,6 +21,7 @@ TWOSPACE = ' ' * 2 centered_re = re.compile(r'\s*>\s*(.*?)\s*<\s*$') dual_dialog_re = re.compile(r'^(.+?)(\s*\^)$') slug_re = re.compile(r'(?:(\.)\s*)?(\S.*?)\s*$') +scene_number_re = re.compile(r'(.*?)\s*(?:#([^#]+)#)\s*$') transition_re = re.compile(r'(>?)\s*(.+?)(:?)$') @@ -62,17 +58,19 @@ class InputParagraph(object): match = slug_re.match(self.lines[0]) if not match: - return + return None period, text = match.groups() - if period: - return Slug(_to_rich(text.upper())) - - upper = text.upper() - if not any(upper.startswith(s) for s in slug_prefixes): + text = text.upper() + if not period and not any(regex.match(text) for regex in slug_regexes): return None - return Slug(_to_rich(upper)) + match = scene_number_re.match(text) + if match: + text, scene_number = match.groups() + return Slug(_to_rich(text), _to_rich(scene_number)) + else: + return Slug(_to_rich(text)) def as_centered_action(self): if not all(centered_re.match(line) for line in self.lines): diff --git a/screenplain/types.py b/screenplain/types.py index 7ef6cc9..fb21c1b 100644 --- a/screenplain/types.py +++ b/screenplain/types.py @@ -9,8 +9,14 @@ class Slug(object): indent = '' top_margin = 1 - def __init__(self, line): + def __init__(self, line, scene_number=None): + """Creates a scene heading (slug). + The line parameter is a RichString with the slugline. + The scene_number parameter is an optional RichString. + + """ self.line = line + self.scene_number = scene_number @property def lines(self): diff --git a/tests/files/scene-numbers.spmd b/tests/files/scene-numbers.spmd new file mode 100644 index 0000000..51064d2 --- /dev/null +++ b/tests/files/scene-numbers.spmd @@ -0,0 +1,7 @@ +INT. SOMEWHERE - DAY #1# + +Bla bla + +INT. SOMEWHERE ELSE - NIGHT #2# + +Bla bla diff --git a/tests/files/scene-numbers.spmd.html b/tests/files/scene-numbers.spmd.html new file mode 100644 index 0000000..8179c79 --- /dev/null +++ b/tests/files/scene-numbers.spmd.html @@ -0,0 +1,4 @@ +

1INT. SOMEWHERE - DAY1

+

Bla bla

+

2INT. SOMEWHERE ELSE - NIGHT2

+

Bla bla

diff --git a/tests/files_test.py b/tests/files_test.py index af478fb..1637dda 100644 --- a/tests/files_test.py +++ b/tests/files_test.py @@ -58,3 +58,9 @@ class ParseTests(unittest2.TestCase): actual, expected = self.convert( 'simple.spmd', 'simple.html', 'simple.spmd.html', '--bare') self.assertMultiLineEqual(expected, actual) + + def test_scene_numbers(self): + actual, expected = self.convert( + 'scene-numbers.spmd', 'scene-numbers.html', + 'scene-numbers.spmd.html', '--bare') + self.assertMultiLineEqual(expected, actual) diff --git a/tests/spmd_test.py b/tests/spmd_test.py index 9f03076..b317b56 100644 --- a/tests/spmd_test.py +++ b/tests/spmd_test.py @@ -5,7 +5,7 @@ import unittest2 from screenplain.parsers.spmd import parse from screenplain.types import Slug, Action, Dialog, DualDialog, Transition -from screenplain.richstring import plain, empty_string +from screenplain.richstring import plain, italic, empty_string class ParseTests(unittest2.TestCase): @@ -62,6 +62,20 @@ class ParseTests(unittest2.TestCase): self.assertEquals(Slug, type(paras[0])) self.assertEquals(plain('SNIPER SCOPE POV'), paras[0].line) + def test_scene_number_is_parsed(self): + paras = parse(['EXT SOMEWHERE - DAY #42#']) + self.assertEquals(plain('EXT SOMEWHERE - DAY'), paras[0].line) + self.assertEquals(plain('42'), paras[0].scene_number) + + def test_only_last_two_hashes_in_slug_used_for_scene_number(self): + paras = parse(['INT ROOM #237 #42#']) + self.assertEquals(plain('42'), paras[0].scene_number) + self.assertEquals(plain('INT ROOM #237'), paras[0].line) + + def test_scene_number_can_be_styled(self): + paras = parse(['.SOMEWHERE #*HELLO*#']) + self.assertEquals(italic('HELLO'), paras[0].scene_number) + # A Character element is any line entirely in caps, with one empty # line before it and without an empty line after it. def test_all_caps_is_character(self): -- cgit