12 def __init__(self
): pass
13 def end_paragraph(self
, blankline
): pass
14 def add_line_break(self
): pass
15 def add_hor_rule(self
): pass
16 def add_label_data(self
, format
, counter
): pass
17 def add_flowing_data(self
, data
): pass
18 def add_literal_data(self
, data
): pass
19 def flush_softspace(self
): pass
20 def push_font(self
, x
): pass
21 def pop_font(self
): pass
22 def push_margin(self
, margin
): pass
23 def pop_margin(self
): pass
24 def set_spacing(self
, spacing
): pass
25 def push_style(self
, style
): pass
26 def pop_style(self
): pass
29 class AbstractFormatter
:
31 def __init__(self
, writer
):
32 self
.writer
= writer
# Output device
33 self
.font_stack
= [] # Font state
34 self
.margin_stack
= [] # Margin state
35 self
.spacing
= None # Vertical spacing state
36 self
.style_stack
= [] # Other state, e.g. color
37 self
.nospace
= 1 # Should leading space be suppressed
38 self
.softspace
= 0 # Should a space be inserted
40 def end_paragraph(self
, blankline
):
42 self
.writer
.send_paragraph(blankline
)
46 def add_line_break(self
):
47 self
.writer
.send_line_break()
51 def add_hor_rule(self
):
52 self
.writer
.send_hor_rule()
56 def add_label_data(self
, format
, counter
):
57 data
= self
.format_counter(format
, counter
)
58 self
.writer
.send_label_data(data
)
60 def format_counter(self
, format
, counter
):
69 c
= self
.format_letter(c
, counter
)
71 c
= self
.format_roman(c
, counter
)
77 def format_letter(self
, case
, counter
):
80 counter
, x
= divmod(counter
-1, 26)
81 s
= chr(ord(case
) + x
)
85 def format_roman(self
, case
, counter
):
86 ones
= ['i', 'x', 'c', 'm']
87 fives
= ['v', 'l', 'd']
90 # This will die of IndexError when counter is too big
92 counter
, x
= divmod(counter
, 10)
94 s
= ones
[index
] + ones
[index
+1]
96 s
= ones
[index
] + fives
[index
]
103 s
= s
+ ones
[index
]*x
106 if case
== 'I': label
= string
.upper(label
)
109 def add_flowing_data(self
, data
):
111 # The following looks a bit convoluted but is a great improvement over
112 # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
113 prespace
= data
[0] in string
.whitespace
114 postspace
= data
[-1] in string
.whitespace
115 data
= string
.join(string
.split(data
))
116 if self
.nospace
and prespace
:
121 self
.nospace
= self
.softspace
= 0
124 if prespace
: data
= ' ' + data
125 self
.writer
.send_flowing_data(data
)
127 def add_literal_data(self
, data
):
128 if self
.softspace
and data
[:1] != '\n':
130 self
.nospace
= self
.softspace
= 0
131 self
.writer
.send_literal_data(data
)
133 def flush_softspace(self
):
135 self
.nospace
= self
.softspace
= 0
136 self
.writer
.send_flowing_data(' ')
138 def push_font(self
, (size
, i
, b
, tt
)):
140 csize
, ci
, cb
, ctt
= self
.font_stack
[-1]
141 if size
is AS_IS
: size
= csize
142 if i
is AS_IS
: i
= ci
143 if b
is AS_IS
: b
= cb
144 if tt
is AS_IS
: tt
= ctt
145 font
= (size
, i
, b
, tt
)
146 self
.font_stack
.append(font
)
147 self
.writer
.new_font(font
)
151 del self
.font_stack
[-1]
153 font
= self
.font_stack
[-1]
156 self
.writer
.new_font(font
)
158 def push_margin(self
, margin
):
159 self
.margin_stack
.append(margin
)
160 self
.writer
.new_margin(margin
, len(self
.margin_stack
))
162 def pop_margin(self
):
163 if self
.margin_stack
:
164 del self
.margin_stack
[-1]
165 if self
.margin_stack
:
166 margin
= self
.margin_stack
[-1]
169 self
.writer
.new_margin(margin
, len(self
.margin_stack
))
171 def set_spacing(self
, spacing
):
172 self
.spacing
= spacing
173 self
.writer
.new_spacing(spacing
)
175 def push_style(self
, style
):
176 self
.style_stack
.append(style
)
177 self
.writer
.new_styles(tuple(self
.style_stack
))
181 del self
.style_stack
[-1]
182 self
.writer
.new_styles(tuple(self
.style_stack
))
185 class AbstractWriter
:
190 def new_font(self
, font
):
191 print "new_font(%s)" % `font`
193 def new_margin(self
, margin
, level
):
194 print "new_margin(%s, %d)" % (`margin`
, level
)
196 def new_spacing(self
, spacing
):
197 print "new_spacing(%s)" % `spacing`
199 def new_styles(self
, styles
):
200 print "new_styles(%s)" % `styles`
202 def send_paragraph(self
, blankline
):
203 print "send_paragraph(%s)" % `blankline`
205 def send_line_break(self
):
206 print "send_line_break()"
208 def send_hor_rule(self
):
209 print "send_hor_rule()"
211 def send_label_data(self
, data
):
212 print "send_label_data(%s)" % `data`
214 def send_flowing_data(self
, data
):
215 print "send_flowing_data(%s)" % `data`
217 def send_literal_data(self
, data
):
218 print "send_literal_data(%s)" % `data`
221 class DumbWriter(AbstractWriter
):
223 def __init__(self
, file=None, maxcol
=72):
224 self
.file = file or sys
.stdout
226 AbstractWriter
.__init
__(self
)
233 def send_paragraph(self
, blankline
):
234 self
.file.write('\n' + '\n'*blankline
)
238 def send_line_break(self
):
239 self
.file.write('\n')
243 def send_hor_rule(self
):
244 self
.file.write('\n')
245 self
.file.write('-'*self
.maxcol
)
246 self
.file.write('\n')
250 def send_literal_data(self
, data
):
251 self
.file.write(data
)
252 i
= string
.rfind(data
, '\n')
256 data
= string
.expandtabs(data
)
257 self
.col
= self
.col
+ len(data
)
260 def send_flowing_data(self
, data
):
262 atbreak
= self
.atbreak
or data
[0] in string
.whitespace
265 write
= self
.file.write
266 for word
in string
.split(data
):
268 if col
+ len(word
) >= maxcol
:
275 col
= col
+ len(word
)
278 self
.atbreak
= data
[-1] in string
.whitespace
281 def test(file = None):
283 f
= AbstractFormatter(w
)
287 fp
= open(sys
.argv
[1])
297 f
.add_flowing_data(line
)
301 if __name__
== '__main__':