eleanor 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +3 -0
- data/INSTALL +43 -0
- data/LICENSE +19 -0
- data/README +439 -0
- data/Rakefile +88 -0
- data/bin/eleanor +127 -0
- data/data/eleanor/eleanor.yaml +165 -0
- data/examples/example.txt +167 -0
- data/lib/eleanor.rb +511 -0
- data/lib/eleanor/hpdfpaper.rb +328 -0
- data/lib/eleanor/length.rb +172 -0
- data/lib/eleanor/parser.rb +1255 -0
- data/setup.rb +1585 -0
- data/src/ragel/parser.rl +166 -0
- metadata +81 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'rake/clean'
|
|
3
|
+
require 'rake/gempackagetask'
|
|
4
|
+
require 'rake/rdoctask'
|
|
5
|
+
|
|
6
|
+
NAME = 'Eleanor'
|
|
7
|
+
UNIX_NAME = NAME.downcase
|
|
8
|
+
VER = '1.0.0'
|
|
9
|
+
|
|
10
|
+
NONLIB_RDOC_FILES = %w[CHANGELOG INSTALL LICENSE README src/ragel/parser.rl]
|
|
11
|
+
|
|
12
|
+
RDOC_FILES = NONLIB_RDOC_FILES +
|
|
13
|
+
%w[lib/eleanor.rb
|
|
14
|
+
lib/eleanor/hpdfpaper.rb
|
|
15
|
+
lib/eleanor/length.rb]
|
|
16
|
+
|
|
17
|
+
RDOC_OPTS = ['--inline-source',
|
|
18
|
+
'--extension', 'rl=rb',
|
|
19
|
+
'--exclude', 'lib/eleanor/parser.rb',
|
|
20
|
+
'--title', "#{NAME} #{VER} Reference",
|
|
21
|
+
'--main', 'README']
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
PKG_FILES = FileList['CHANGELOG', 'INSTALL', 'LICENSE', 'README',
|
|
25
|
+
'Rakefile', 'setup.rb',
|
|
26
|
+
'bin/*', 'data/**/*', 'examples/*.txt',
|
|
27
|
+
'lib/*', 'lib/**/*', 'src/**/*']
|
|
28
|
+
|
|
29
|
+
CLEAN.include %w[.config InstalledFiles doc examples/*.pdf pkg]
|
|
30
|
+
|
|
31
|
+
GEMSPEC=
|
|
32
|
+
Gem::Specification.new do |s|
|
|
33
|
+
s.name= UNIX_NAME
|
|
34
|
+
s.version= VER
|
|
35
|
+
s.has_rdoc= true
|
|
36
|
+
s.rdoc_options += RDOC_OPTS
|
|
37
|
+
s.extra_rdoc_files= NONLIB_RDOC_FILES
|
|
38
|
+
s.summary= 'Formats speculative screenplays'
|
|
39
|
+
s.description= <<-EOF
|
|
40
|
+
Eleanor is a Ruby script and accompanying library for formatting
|
|
41
|
+
speculative screenplays. It parses plain text written in a simple format
|
|
42
|
+
and outputs pretty PDF that conforms to standard rules of screenplay
|
|
43
|
+
layout. Eleanor's primary goal is to create PDF that is indistinguishable
|
|
44
|
+
from PDF produced by professional screenwriting software such as Final
|
|
45
|
+
Draft.
|
|
46
|
+
EOF
|
|
47
|
+
s.author= 'chiisaitsu'
|
|
48
|
+
s.email= 'chiisaitsu@gmail.com'
|
|
49
|
+
s.homepage= 'http://rubyforge.org/projects/eleanor'
|
|
50
|
+
s.files= PKG_FILES
|
|
51
|
+
s.executables= ['eleanor']
|
|
52
|
+
s.requirements << 'libHaru Free PDF Library: http://libharu.org'
|
|
53
|
+
s.rubyforge_project= 'eleanor'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
desc 'rake build'
|
|
57
|
+
task :default => [:build]
|
|
58
|
+
|
|
59
|
+
desc 'Build the parser with Ragel'
|
|
60
|
+
task :build do
|
|
61
|
+
sh "ragel -R -o lib/eleanor/parser.rb src/ragel/parser.rl"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
desc 'Build the examples'
|
|
65
|
+
task :examples do
|
|
66
|
+
Dir.glob('examples/*.txt') do |fname|
|
|
67
|
+
sh "ruby -I./lib bin/eleanor -c data/eleanor/eleanor.yaml #{fname}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'Install to site_ruby'
|
|
72
|
+
task :install do
|
|
73
|
+
sh "ruby setup.rb"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
task :package => [:clean]
|
|
77
|
+
|
|
78
|
+
Rake::GemPackageTask.new(GEMSPEC) do |t|
|
|
79
|
+
t.need_tar_gz= true
|
|
80
|
+
t.need_zip= true
|
|
81
|
+
t.gem_spec= GEMSPEC
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Rake::RDocTask.new do |t|
|
|
85
|
+
t.options= RDOC_OPTS
|
|
86
|
+
t.rdoc_dir= 'doc/rdoc'
|
|
87
|
+
t.rdoc_files= RDOC_FILES
|
|
88
|
+
end
|
data/bin/eleanor
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2008 chiisaitsu <chiisaitsu@gmail.com>
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
require 'eleanor'
|
|
25
|
+
rescue LoadError
|
|
26
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
27
|
+
require 'eleanor'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require 'optparse'
|
|
31
|
+
|
|
32
|
+
usr_config_fn= File.join(ENV['HOME'] || '', '.eleanorrc')
|
|
33
|
+
sys_config_fn= File.join(Config::CONFIG['datadir'], 'eleanor', 'eleanor.yaml')
|
|
34
|
+
rel_config_fn= File.expand_path(File.join(File.dirname(__FILE__), '..',
|
|
35
|
+
'data', 'eleanor', 'eleanor.yaml'))
|
|
36
|
+
|
|
37
|
+
conf= {
|
|
38
|
+
:paper => 'eleanor/hpdfpaper',
|
|
39
|
+
:config => if File.exist? usr_config_fn
|
|
40
|
+
usr_config_fn
|
|
41
|
+
elsif File.exist? sys_config_fn
|
|
42
|
+
sys_config_fn
|
|
43
|
+
elsif File.exist? rel_config_fn
|
|
44
|
+
rel_config_fn
|
|
45
|
+
else
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
options= OptionParser.new do |opts|
|
|
51
|
+
opts.banner= "usage: #{File.basename($0)} [options] screenplay.txt"
|
|
52
|
+
opts.separator('')
|
|
53
|
+
opts.separator(' Options:')
|
|
54
|
+
opts.on('-c', '--config FILE',
|
|
55
|
+
'Load configuration from FILE',
|
|
56
|
+
"(default: #{conf[:config] || 'none'})") do |val|
|
|
57
|
+
conf[:config]= val
|
|
58
|
+
end
|
|
59
|
+
opts.on('-d', '--dump-pages', 'Print paginated screenplay to stdout') do |val|
|
|
60
|
+
conf[:dump_pages]= val
|
|
61
|
+
end
|
|
62
|
+
opts.on('--dump-paras', 'Print non-paginated paragraphs to stdout') do |val|
|
|
63
|
+
conf[:dump_paras]= val
|
|
64
|
+
end
|
|
65
|
+
opts.on('-h', '--help', 'Show this message') do
|
|
66
|
+
puts opts
|
|
67
|
+
exit
|
|
68
|
+
end
|
|
69
|
+
opts.on('-o', '--output FILE',
|
|
70
|
+
'Set output FILE (default: screenplay.pdf)') do |val|
|
|
71
|
+
conf[:outfile]= val
|
|
72
|
+
end
|
|
73
|
+
opts.on('--paginate', 'Stop after pagination') do |val|
|
|
74
|
+
conf[:paginate]= val
|
|
75
|
+
end
|
|
76
|
+
opts.on('--paper FILE',
|
|
77
|
+
'Set backend to FILE', "(default: #{conf[:paper]})") do |val|
|
|
78
|
+
conf[:paper]= val
|
|
79
|
+
end
|
|
80
|
+
opts.on('--parse', 'Stop after parsing') do |val|
|
|
81
|
+
conf[:parse]= val
|
|
82
|
+
end
|
|
83
|
+
opts.on('-v', '--verbose', 'Print working info to stderr') do |val|
|
|
84
|
+
conf[:verbose]= val
|
|
85
|
+
end
|
|
86
|
+
opts.on_tail('')
|
|
87
|
+
opts.on_tail(' Examples:',
|
|
88
|
+
" #{File.basename($0)} screenplay.txt",
|
|
89
|
+
" #{File.basename($0)} -o finaldraft.pdf screenplay.txt")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
options.parse!
|
|
94
|
+
raise OptionParser::ParseError unless ARGV.size == 1
|
|
95
|
+
rescue OptionParser::ParseError
|
|
96
|
+
puts options
|
|
97
|
+
exit
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if conf[:config].nil?
|
|
101
|
+
abort "error: No configuration file found. Reinstall #{Eleanor::NAME} " \
|
|
102
|
+
"or load a configuration file with --config."
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
begin
|
|
106
|
+
require conf[:paper]
|
|
107
|
+
rescue LoadError
|
|
108
|
+
abort "error: Could not load backend. The string you specify will be " \
|
|
109
|
+
"passed to 'require'."
|
|
110
|
+
end
|
|
111
|
+
Eleanor.load_config(conf[:config])
|
|
112
|
+
infile= ARGV.shift
|
|
113
|
+
screenplay= Eleanor.parse(infile)
|
|
114
|
+
|
|
115
|
+
if screenplay
|
|
116
|
+
$stderr.puts "parsing complete" if conf[:verbose]
|
|
117
|
+
puts screenplay.to_s(false) if conf[:dump_paras]
|
|
118
|
+
exit if conf[:parse]
|
|
119
|
+
screenplay.paginate!
|
|
120
|
+
$stderr.puts "pagination complete" if conf[:verbose]
|
|
121
|
+
puts screenplay if conf[:dump_pages]
|
|
122
|
+
exit if conf[:paginate]
|
|
123
|
+
screenplay.write_to_paper!
|
|
124
|
+
screenplay.save_paper(conf[:outfile], infile)
|
|
125
|
+
else
|
|
126
|
+
abort 'error: parsing failed'
|
|
127
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# This is Eleanor's default configuration file. It's written in YAML.
|
|
2
|
+
# You shouldn't modify it. Instead, pass your own to Eleanor's command line
|
|
3
|
+
# with the --config option. Or, for a more permanent solution, create your own
|
|
4
|
+
# file $HOME/.eleanorrc, where $HOME is the output of
|
|
5
|
+
#
|
|
6
|
+
# ruby -e "p ENV['HOME']"
|
|
7
|
+
#
|
|
8
|
+
# Eleanor will use that file instead.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
Screenplay:
|
|
12
|
+
char_spacing: -0.195.points
|
|
13
|
+
font: Courier
|
|
14
|
+
font_size: 12.points
|
|
15
|
+
line_height_points: 12
|
|
16
|
+
|
|
17
|
+
Page:
|
|
18
|
+
header: |
|
|
19
|
+
@page_no == 1 ? @screenplay.title : nil
|
|
20
|
+
header_margin_top: 0.5.inches
|
|
21
|
+
height: 11.inches
|
|
22
|
+
margin_bottom: 1.inches
|
|
23
|
+
margin_top: 1.inches
|
|
24
|
+
page_number_display: |
|
|
25
|
+
@page_no > 1 ? "#@page_no." : nil
|
|
26
|
+
page_number_margin_right: 1.25.inches
|
|
27
|
+
page_number_margin_top: 0.5.inches
|
|
28
|
+
width: 8.5.inches
|
|
29
|
+
|
|
30
|
+
TitlePage:
|
|
31
|
+
margin_bottom: 1.5.inches
|
|
32
|
+
margin_left: 1.inches
|
|
33
|
+
margin_top: 2.5.inches
|
|
34
|
+
|
|
35
|
+
Paragraph:
|
|
36
|
+
can_break_across_pages: false
|
|
37
|
+
align: left
|
|
38
|
+
keep_with_nexts: []
|
|
39
|
+
min_orphan_lines_allowed: 2
|
|
40
|
+
min_orphan_sentences_allowed: 2
|
|
41
|
+
min_widow_lines_allowed: 2
|
|
42
|
+
min_widow_sentences_allowed: 2
|
|
43
|
+
|
|
44
|
+
Action:
|
|
45
|
+
can_break_across_pages: true
|
|
46
|
+
keep_with_nexts: [Insert]
|
|
47
|
+
limit_to_one_line: false
|
|
48
|
+
margin_bottom: 1.lines
|
|
49
|
+
margin_left: 1.5.inches
|
|
50
|
+
margin_top: |
|
|
51
|
+
if @is_first_on_page
|
|
52
|
+
(@split_state == :widow ? -1 : 0).lines
|
|
53
|
+
else
|
|
54
|
+
1.lines
|
|
55
|
+
end
|
|
56
|
+
width: 6.inches
|
|
57
|
+
|
|
58
|
+
CharacterCue:
|
|
59
|
+
continuation_modifier: CONT'D
|
|
60
|
+
keep_with_nexts: [Dialog, Parenthetical]
|
|
61
|
+
limit_to_one_line: true
|
|
62
|
+
margin_bottom: 0.lines
|
|
63
|
+
margin_left: 3.5.inches
|
|
64
|
+
margin_top: |
|
|
65
|
+
if @is_first_on_page
|
|
66
|
+
(@split_state == :widow ? -1 : 0).lines
|
|
67
|
+
else
|
|
68
|
+
1.lines
|
|
69
|
+
end
|
|
70
|
+
widow_modifier: CONT'D
|
|
71
|
+
width: 3.75.inches
|
|
72
|
+
|
|
73
|
+
Dialog:
|
|
74
|
+
can_break_across_pages: true
|
|
75
|
+
keep_with_nexts: |
|
|
76
|
+
next_para.is_a?(Parenthetical) && @sentences.size == 1
|
|
77
|
+
limit_to_one_line: false
|
|
78
|
+
margin_bottom: 0.lines
|
|
79
|
+
margin_left: 2.5.inches
|
|
80
|
+
margin_top: 0.lines
|
|
81
|
+
width: 3.5.inches
|
|
82
|
+
|
|
83
|
+
Insert:
|
|
84
|
+
limit_to_one_line: false
|
|
85
|
+
margin_bottom: 1.lines
|
|
86
|
+
margin_left: 2.5.inches
|
|
87
|
+
margin_top: 1.lines
|
|
88
|
+
width: 3.5.inches
|
|
89
|
+
|
|
90
|
+
MontageHeading:
|
|
91
|
+
keep_with_nexts: [MontageItem]
|
|
92
|
+
limit_to_one_line: true
|
|
93
|
+
margin_bottom: 1.lines
|
|
94
|
+
margin_left: 1.5.inches
|
|
95
|
+
margin_top: |
|
|
96
|
+
(@is_first_on_page ? 0 : 2).lines
|
|
97
|
+
width: 6.inches
|
|
98
|
+
|
|
99
|
+
MontageItem:
|
|
100
|
+
limit_to_one_line: false
|
|
101
|
+
margin_bottom: 1.lines
|
|
102
|
+
margin_left: 1.5.inches
|
|
103
|
+
margin_top: |
|
|
104
|
+
(@is_first_on_page ? 0 : 1).lines
|
|
105
|
+
width: 6.inches
|
|
106
|
+
|
|
107
|
+
More:
|
|
108
|
+
limit_to_one_line: true
|
|
109
|
+
margin_bottom: 0.lines
|
|
110
|
+
margin_left: 3.5.inches
|
|
111
|
+
margin_top: 0.lines
|
|
112
|
+
text: (MORE)
|
|
113
|
+
width: 2.5.inches
|
|
114
|
+
|
|
115
|
+
Parenthetical:
|
|
116
|
+
keep_with_nexts: [Dialog]
|
|
117
|
+
limit_to_one_line: false
|
|
118
|
+
margin_bottom: 0.lines
|
|
119
|
+
margin_left: 2.9.inches
|
|
120
|
+
margin_top: 0.lines
|
|
121
|
+
width: 2.5.inches
|
|
122
|
+
|
|
123
|
+
SceneHeading:
|
|
124
|
+
keep_with_nexts: [Action, CharacterCue]
|
|
125
|
+
limit_to_one_line: true
|
|
126
|
+
margin_bottom: 1.lines
|
|
127
|
+
margin_left: 1.5.inches
|
|
128
|
+
margin_top: |
|
|
129
|
+
if defined?(prev_para) &&
|
|
130
|
+
(prev_para.is_a?(Transition) ||
|
|
131
|
+
(prev_para.is_a?(SlugLine) &&
|
|
132
|
+
/BEGIN FLASHBACK/i =~ prev_para.input_line))
|
|
133
|
+
1.lines
|
|
134
|
+
else
|
|
135
|
+
(@is_first_on_page ? 0 : 2).lines
|
|
136
|
+
end
|
|
137
|
+
width: 6.inches
|
|
138
|
+
|
|
139
|
+
SlugLine:
|
|
140
|
+
keep_with_nexts: |
|
|
141
|
+
case next_para
|
|
142
|
+
when Action, Insert
|
|
143
|
+
true
|
|
144
|
+
when SceneHeading
|
|
145
|
+
/BEGIN FLASHBACK/i =~ @input_line ? true : false
|
|
146
|
+
else
|
|
147
|
+
false
|
|
148
|
+
end
|
|
149
|
+
limit_to_one_line: true
|
|
150
|
+
margin_bottom: 1.lines
|
|
151
|
+
margin_left: 1.5.inches
|
|
152
|
+
margin_top: |
|
|
153
|
+
(@is_first_on_page ? 0 : 1).lines
|
|
154
|
+
width: 6.inches
|
|
155
|
+
|
|
156
|
+
Transition:
|
|
157
|
+
align: |
|
|
158
|
+
/FADE IN/i =~ @input_line ? 'left' : 'right'
|
|
159
|
+
limit_to_one_line: true
|
|
160
|
+
margin_bottom: 1.lines
|
|
161
|
+
margin_left: 1.5.inches
|
|
162
|
+
margin_right: 1.25.inches
|
|
163
|
+
margin_top: |
|
|
164
|
+
(@is_first_on_page ? 0 : 1).lines
|
|
165
|
+
width: 1.63.inches
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
|
|
2
|
+
_A TALE OF NON SEQUITURS_
|
|
3
|
+
Fenwick Stufflebeam
|
|
4
|
+
123 Millicent Kenton Lane
|
|
5
|
+
Hollywood, CA 90210
|
|
6
|
+
(555) 555-1337
|
|
7
|
+
fstufflebeam@hmail.com
|
|
8
|
+
|
|
9
|
+
FADE IN:
|
|
10
|
+
|
|
11
|
+
EXT. FOREST CLEARING - NIGHT
|
|
12
|
+
|
|
13
|
+
A clear, starry night. A milky full moon hangs high in the sky. Somewhere an owl hoots.
|
|
14
|
+
|
|
15
|
+
The bushes rustle. A dirtied girl pushes her way through the greenery, leaves and twigs slapping her face. Her name is ELEANOR. She carries a laptop computer under her arm.
|
|
16
|
+
|
|
17
|
+
ELEANOR
|
|
18
|
+
(calling)
|
|
19
|
+
Why! _Oh, why_!
|
|
20
|
+
|
|
21
|
+
Crickets. Eleanor sits on a nearby tree stump, head on hands.
|
|
22
|
+
|
|
23
|
+
Suddenly a tiny little man with shoulder-length brown hair scampers out of the trees. He is WHY THE LUCKY STIFF. He has a high-pitched voice, as if he has been inhaling helium.
|
|
24
|
+
|
|
25
|
+
WHY THE LUCKY STIFF
|
|
26
|
+
Here I am!
|
|
27
|
+
|
|
28
|
+
ELEANOR
|
|
29
|
+
Oh, thank God.
|
|
30
|
+
|
|
31
|
+
Why the Lucky Stiff jumps up on Eleanor's knee and produces a tiny flute. He plays a tune as he dances a little jig.
|
|
32
|
+
|
|
33
|
+
WHY THE LUCKY STIFF
|
|
34
|
+
Reese's Pieces and Old Navy fleeces! Norway has rakfisk but Finland has cheeses!
|
|
35
|
+
|
|
36
|
+
ELEANOR
|
|
37
|
+
Uh, OK.
|
|
38
|
+
(opening her laptop)
|
|
39
|
+
Listen, could you tell me how to use this thing?
|
|
40
|
+
|
|
41
|
+
WHY THE LUCKY STIFF
|
|
42
|
+
Ding dong!
|
|
43
|
+
|
|
44
|
+
He scurries to a tree and beckons Eleanor to follow.
|
|
45
|
+
|
|
46
|
+
WHY THE LUCKY STIFF
|
|
47
|
+
(pointing at tree)
|
|
48
|
+
_Rules_ here there be!
|
|
49
|
+
|
|
50
|
+
ELEANOR
|
|
51
|
+
Are you going to keep talking like that?
|
|
52
|
+
|
|
53
|
+
WHY THE LUCKY STIFF
|
|
54
|
+
Creamy ground beef!
|
|
55
|
+
|
|
56
|
+
With his little hand he pulls back a bough to reveal a carving on the trunk that reads:
|
|
57
|
+
|
|
58
|
+
"Two blank lines before scene headings and montages. One blank line before all else except dialogs and parentheticals. Spaces before character cues, dialog, parentheticals, transitions, inserts. No newlines in paragraphs. Two spaces between sentences."
|
|
59
|
+
|
|
60
|
+
ELEANOR
|
|
61
|
+
I don't understand.
|
|
62
|
+
|
|
63
|
+
WHY THE LUCKY STIFF
|
|
64
|
+
Plain text! Whoozits.
|
|
65
|
+
|
|
66
|
+
ELEANOR
|
|
67
|
+
What?
|
|
68
|
+
|
|
69
|
+
WHY THE LUCKY STIFF
|
|
70
|
+
You type, you type. The words flow like a sinking sun in a bathtub full of green jell-o.
|
|
71
|
+
|
|
72
|
+
He hops onto Eleanor's computer and by dancing on its keys types all that has transpired before this moment, in the format prescribed by the tree. Then he runs the command:
|
|
73
|
+
|
|
74
|
+
"ruby eleanor example.txt"
|
|
75
|
+
|
|
76
|
+
A beautiful PDF appears on Eleanor's computer.
|
|
77
|
+
|
|
78
|
+
ELEANOR
|
|
79
|
+
Oh!
|
|
80
|
+
|
|
81
|
+
SUDDENLY, WHY THE LUCKY STIFF
|
|
82
|
+
|
|
83
|
+
turns on his heels and sprints into the trees.
|
|
84
|
+
|
|
85
|
+
ELEANOR
|
|
86
|
+
|
|
87
|
+
drops her laptop in the commotion but picks it up and follows in hot pursuit deep into the woods.
|
|
88
|
+
|
|
89
|
+
ELEANOR'S P.O.V. - TREE BRANCHES
|
|
90
|
+
|
|
91
|
+
slap her in the face.
|
|
92
|
+
|
|
93
|
+
ELEANOR
|
|
94
|
+
(calling)
|
|
95
|
+
I'm not writing an action movie! This is supposed to be a quirky independent!
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
SERIES OF SHOTS - ELEANOR CHASES WHY THE LUCKY STIFF
|
|
99
|
+
|
|
100
|
+
A) Dodging branches and roots in the forest.
|
|
101
|
+
|
|
102
|
+
B) Trudging through a thick swamp.
|
|
103
|
+
|
|
104
|
+
C) Jumping across rooftops in a large city as cars sit stuck in traffic below.
|
|
105
|
+
|
|
106
|
+
D) Back into the dark forest.
|
|
107
|
+
|
|
108
|
+
DISSOLVE TO:
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
INT. HOLLOW TREE - NIGHT
|
|
112
|
+
|
|
113
|
+
A storybook gnomish home. Eleanor stumbles in, out of breath. Why the Lucky Stiff sits in a tiny rocking chair next to the fireplace, smoking a long pipe.
|
|
114
|
+
|
|
115
|
+
ELEANOR
|
|
116
|
+
(wheezing)
|
|
117
|
+
Jesus.
|
|
118
|
+
(pausing to look around)
|
|
119
|
+
So this is where you live.
|
|
120
|
+
|
|
121
|
+
WHY THE LUCKY STIFF
|
|
122
|
+
Here I be. Tinkle tops and lemon drops.
|
|
123
|
+
|
|
124
|
+
ELEANOR
|
|
125
|
+
Look, I have more questions.
|
|
126
|
+
|
|
127
|
+
WHY THE LUCKY STIFF
|
|
128
|
+
Let me tell you a story.
|
|
129
|
+
|
|
130
|
+
BEGIN FLASHBACK:
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
INT. PIGGLY WIGGLY - DAY
|
|
134
|
+
|
|
135
|
+
Why the Lucky Stiff pushes a diminutive shopping cart.
|
|
136
|
+
|
|
137
|
+
WHY THE LUCKY STIFF
|
|
138
|
+
(to himself)
|
|
139
|
+
Crackers. Soy beans. Hamburger patties. Sunshine rainbows and kitty cat kisses. Red-letter bibles and hose for the missus. Hey ho, yeah? What's all this, now? Bean sprouts from China and milk from a cow.
|
|
140
|
+
|
|
141
|
+
END FLASHBACK.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
INT. HOLLOW TREE - NIGHT
|
|
145
|
+
|
|
146
|
+
Eleanor is exasperated.
|
|
147
|
+
|
|
148
|
+
ELEANOR
|
|
149
|
+
You're a nice guy, and you sure do know a lot, but I can't understand anything you say.
|
|
150
|
+
|
|
151
|
+
WHY THE LUCKY STIFF
|
|
152
|
+
Hey, but look! My dialog was split in twain!
|
|
153
|
+
|
|
154
|
+
ELEANOR
|
|
155
|
+
No, it wasn't.
|
|
156
|
+
|
|
157
|
+
WHY THE LUCKY STIFF
|
|
158
|
+
No, no, no, not in the plain text. In the PDF, yo!
|
|
159
|
+
|
|
160
|
+
ELEANOR
|
|
161
|
+
But I haven't written anything.
|
|
162
|
+
|
|
163
|
+
Why the Lucky Stiff pads over to Eleanor, who places her computer on the ground. He types in everything that has transpired so far except for what he had typed previously.
|
|
164
|
+
|
|
165
|
+
INSERT - ELEANOR'S COMPUTER SCREEN, A BEAUTIFUL PDF
|
|
166
|
+
|
|
167
|
+
FADE OUT.
|