diff options
author | Martin Vilcans <martin@librador.com> | 2012-07-08 23:53:36 +0200 |
---|---|---|
committer | Martin Vilcans <martin@librador.com> | 2012-07-09 23:04:17 +0200 |
commit | 1df405204f57c5392fb74f5538e08a5c5291dae2 (patch) | |
tree | d63dcb6769a973e73bb88435cc83e5d092041a56 | |
parent | 6bd28965fde5c2c47862c97f21ae751ed98c9356 (diff) | |
download | screenplain-1df405204f57c5392fb74f5538e08a5c5291dae2.tar.gz |
Added page break support.
In HTML output, uses style page-break-before: always
Closes #3
-rwxr-xr-x | bin/test | 2 | ||||
-rw-r--r-- | screenplain/export/default.css | 3 | ||||
-rw-r--r-- | screenplain/export/html.py | 12 | ||||
-rw-r--r-- | screenplain/parsers/fountain.py | 11 | ||||
-rw-r--r-- | screenplain/types.py | 6 | ||||
-rw-r--r-- | tests/files/page-break.fountain | 5 | ||||
-rw-r--r-- | tests/files/page-break.fountain.html | 2 | ||||
-rw-r--r-- | tests/files_test.py | 24 | ||||
-rw-r--r-- | tests/fountain_test.py | 12 |
9 files changed, 71 insertions, 6 deletions
@@ -1,3 +1,3 @@ #!/bin/bash -nosetests --nocapture --with-doctest $* && \ +nosetests --nocapture --with-doctest --doctest-tests $* && \ pep8 screenplain tests diff --git a/screenplain/export/default.css b/screenplain/export/default.css index e3ab992..70dd579 100644 --- a/screenplain/export/default.css +++ b/screenplain/export/default.css @@ -162,3 +162,6 @@ font-weight: inherit; -o-user-select: none; user-select: none; } +.page-break { +page-break-before: always; +} diff --git a/screenplain/export/html.py b/screenplain/export/html.py index 7ac7854..2243780 100644 --- a/screenplain/export/html.py +++ b/screenplain/export/html.py @@ -85,6 +85,7 @@ class Formatter(object): DualDialog: self.format_dual, Transition: self.format_transition, Section: self.format_section, + PageBreak: self.format_page_break, } def convert(self, screenplay): @@ -93,6 +94,7 @@ class Formatter(object): `screenplay` is a sequence of paragraphs. """ + self.page_break_before_next = False for para in screenplay: format_function = self._format_functions.get(type(para), None) if format_function: @@ -156,7 +158,17 @@ class Formatter(object): with self._tag('div', classes='transition'): self.out.write(to_html(para.line)) + def format_page_break(self, para): + self.page_break_before_next = True + def _tag(self, tag_name, classes=None): + if self.page_break_before_next: + if isinstance(classes, basestring): + classes = [classes] + else: + classes = classes or [] + self.page_break_before_next = False + classes.append('page-break') return tag(self.out, tag_name, classes) diff --git a/screenplain/parsers/fountain.py b/screenplain/parsers/fountain.py index 15b0755..7fda23d 100644 --- a/screenplain/parsers/fountain.py +++ b/screenplain/parsers/fountain.py @@ -7,7 +7,7 @@ from itertools import takewhile import re from screenplain.types import ( - Slug, Action, Dialog, DualDialog, Transition, Section + Slug, Action, Dialog, DualDialog, Transition, Section, PageBreak ) from screenplain.richstring import parse_emphasis, plain @@ -32,6 +32,7 @@ slug_re = re.compile(r'(?:(\.)(?=[^.])\s*)?(\S.*?)\s*$') scene_number_re = re.compile(r'(.*?)\s*(?:#([\w\-.]+)#)\s*$') section_re = re.compile(r'^(#{1,6})\s*([^#].*)$') transition_re = re.compile(r'(>?)\s*(.+?)(TO:)?$') +page_break_re = re.compile(r'^={3,}$') def _to_rich(line_or_line_list): @@ -54,6 +55,7 @@ class InputParagraph(object): Modifies the `previous_paragraphs` list. """ ( + self.append_page_break(previous_paragraphs) or self.append_synopsis(previous_paragraphs) or self.append_sections_and_synopsises(previous_paragraphs) or self.append_slug(previous_paragraphs) or @@ -180,6 +182,13 @@ class InputParagraph(object): else: return False + def append_page_break(self, paragraphs): + if len(self.lines) == 1 and page_break_re.match(self.lines[0]): + paragraphs.append(PageBreak()) + return True + else: + return False + def _preprocess_line(raw_line): r"""Replaces tabs with spaces and removes trailing end of line markers. diff --git a/screenplain/types.py b/screenplain/types.py index a73e92b..f8454ef 100644 --- a/screenplain/types.py +++ b/screenplain/types.py @@ -2,8 +2,6 @@ # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license.php -import textwrap - class Slug(object): @@ -82,3 +80,7 @@ class Transition(object): @property def lines(self): return [self.line] + + +class PageBreak(object): + pass diff --git a/tests/files/page-break.fountain b/tests/files/page-break.fountain new file mode 100644 index 0000000..941470d --- /dev/null +++ b/tests/files/page-break.fountain @@ -0,0 +1,5 @@ +First some action + +==== + +INT. SOMEWHERE - DAY diff --git a/tests/files/page-break.fountain.html b/tests/files/page-break.fountain.html new file mode 100644 index 0000000..7191953 --- /dev/null +++ b/tests/files/page-break.fountain.html @@ -0,0 +1,2 @@ +<div class="action"><p>First some action</p></div> +<h6 class="page-break">INT. SOMEWHERE - DAY</h6> diff --git a/tests/files_test.py b/tests/files_test.py index 46eb349..0a0480e 100644 --- a/tests/files_test.py +++ b/tests/files_test.py @@ -8,17 +8,33 @@ import unittest2 import tempfile import os.path import shutil +import re from screenplain.main import main source_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'files')) +line_break_re = re.compile('\s*\n\s*') +spaces_re = re.compile('[ \t]+') + def read_file(path): with open(path) as stream: return stream.read() +def clean_string(s): + r"""Removes duplicated spaces and line breaks in a string. + + >>> clean_string('foo \n \nbar\n\n') + 'foo\nbar\n' + >>> clean_string('foo bar') + 'foo bar' + + """ + return spaces_re.sub(' ', line_break_re.sub('\n', s)) + + class ParseTests(unittest2.TestCase): """High level tests that runs Screenplain using command line arguments. """ @@ -47,7 +63,7 @@ class ParseTests(unittest2.TestCase): main(list(options) + [input_path, output_path]) actual = read_file(output_path) expected = read_file(self.source(expected_results_file)) - return actual, expected + return clean_string(actual), clean_string(expected) def test_fountain_to_fdx(self): actual, expected = self.convert( @@ -76,3 +92,9 @@ class ParseTests(unittest2.TestCase): 'boneyard.fountain', 'sections.html', 'boneyard.fountain.html', '--bare') self.assertMultiLineEqual(expected, actual) + + def test_page_break(self): + actual, expected = self.convert( + 'page-break.fountain', 'page-break.html', + 'page-break.fountain.html', '--bare') + self.assertMultiLineEqual(expected, actual) diff --git a/tests/fountain_test.py b/tests/fountain_test.py index ab3e9e7..0ca3c72 100644 --- a/tests/fountain_test.py +++ b/tests/fountain_test.py @@ -5,7 +5,7 @@ import unittest2 from screenplain.parsers import fountain from screenplain.types import ( - Slug, Action, Dialog, DualDialog, Transition, Section + Slug, Action, Dialog, DualDialog, Transition, Section, PageBreak ) from screenplain.richstring import plain, italic, empty_string from StringIO import StringIO @@ -481,5 +481,15 @@ class TitlePageTests(unittest2.TestCase): ] self.assertIsNone(fountain.parse_title_page(lines)) + +class PageBreakTests(unittest2.TestCase): + def test_page_break_sets_page_break_flag_on_next_paragraph(self): + paras = list(parse([ + '====', + '', + 'So here we go' + ])) + self.assertEquals([PageBreak, Action], [type(p) for p in paras]) + if __name__ == '__main__': unittest2.main() |