aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Vilcans <martin@librador.com>2012-07-08 23:53:36 +0200
committerMartin Vilcans <martin@librador.com>2012-07-09 23:04:17 +0200
commit1df405204f57c5392fb74f5538e08a5c5291dae2 (patch)
treed63dcb6769a973e73bb88435cc83e5d092041a56
parent6bd28965fde5c2c47862c97f21ae751ed98c9356 (diff)
downloadscreenplain-1df405204f57c5392fb74f5538e08a5c5291dae2.tar.gz
Added page break support.
In HTML output, uses style page-break-before: always Closes #3
-rwxr-xr-xbin/test2
-rw-r--r--screenplain/export/default.css3
-rw-r--r--screenplain/export/html.py12
-rw-r--r--screenplain/parsers/fountain.py11
-rw-r--r--screenplain/types.py6
-rw-r--r--tests/files/page-break.fountain5
-rw-r--r--tests/files/page-break.fountain.html2
-rw-r--r--tests/files_test.py24
-rw-r--r--tests/fountain_test.py12
9 files changed, 71 insertions, 6 deletions
diff --git a/bin/test b/bin/test
index 227a774..dcefe4f 100755
--- a/bin/test
+++ b/bin/test
@@ -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()