10 |
10 |
11 The object to be printed is given as a tree with indentation and line |
11 The object to be printed is given as a tree with indentation and line |
12 breaking information. A "break" inserts a newline if the text until |
12 breaking information. A "break" inserts a newline if the text until |
13 the next break is too long to fit on the current line. After the newline, |
13 the next break is too long to fit on the current line. After the newline, |
14 text is indented to the level of the enclosing block. Normally, if a block |
14 text is indented to the level of the enclosing block. Normally, if a block |
15 is broken then all enclosing blocks will also be broken. Only "inconsistent |
15 is broken then all enclosing blocks will also be broken. |
16 breaks" are provided. |
16 |
17 |
17 The stored length of a block is used in break_dist (to treat each inner block as |
18 The stored length of a block is used in breakdist (to treat each inner block as |
|
19 a unit for breaking). |
18 a unit for breaking). |
20 *) |
19 *) |
21 |
20 |
22 signature PRETTY = |
21 signature PRETTY = |
23 sig |
22 sig |
24 val spaces: int -> string |
23 val spaces: int -> string |
25 val default_indent: string -> int -> Output.output |
24 val default_indent: string -> int -> Output.output |
26 val add_mode: string -> (string -> int -> Output.output) -> unit |
25 val add_mode: string -> (string -> int -> Output.output) -> unit |
27 type T |
26 type T |
|
27 val make_block: Output.output * Output.output -> bool -> int -> T list -> T |
28 val str: string -> T |
28 val str: string -> T |
29 val brk: int -> T |
29 val brk: int -> T |
30 val brk_indent: int -> int -> T |
30 val brk_indent: int -> int -> T |
31 val fbrk: T |
31 val fbrk: T |
32 val breaks: T list -> T list |
32 val breaks: T list -> T list |
33 val fbreaks: T list -> T list |
33 val fbreaks: T list -> T list |
34 val blk: int * T list -> T |
34 val blk: int * T list -> T |
35 val block: T list -> T |
35 val block: T list -> T |
36 val strs: string list -> T |
36 val strs: string list -> T |
37 val raw_markup: Output.output * Output.output -> int * T list -> T |
|
38 val markup: Markup.T -> T list -> T |
37 val markup: Markup.T -> T list -> T |
39 val mark: Markup.T -> T -> T |
38 val mark: Markup.T -> T -> T |
40 val mark_str: Markup.T * string -> T |
39 val mark_str: Markup.T * string -> T |
41 val marks_str: Markup.T list * string -> T |
40 val marks_str: Markup.T list * string -> T |
42 val item: T list -> T |
41 val item: T list -> T |
122 |
121 |
123 |
122 |
124 (** printing items: compound phrases, strings, and breaks **) |
123 (** printing items: compound phrases, strings, and breaks **) |
125 |
124 |
126 abstype T = |
125 abstype T = |
127 Block of (Output.output * Output.output) * T list * int * int |
126 Block of (Output.output * Output.output) * T list * bool * int * int |
128 (*markup output, body, indentation, length*) |
127 (*markup output, body, consistent, indentation, length*) |
129 | String of Output.output * int (*text, length*) |
128 | String of Output.output * int (*text, length*) |
130 | Break of bool * int * int (*mandatory flag, width if not taken, extra indentation if taken*) |
129 | Break of bool * int * int (*mandatory flag, width if not taken, extra indentation if taken*) |
131 with |
130 with |
132 |
131 |
133 fun length (Block (_, _, _, len)) = len |
132 fun length (Block (_, _, _, _, len)) = len |
134 | length (String (_, len)) = len |
133 | length (String (_, len)) = len |
135 | length (Break (_, wd, _)) = wd; |
134 | length (Break (_, wd, _)) = wd; |
|
135 |
|
136 fun body_length [] len = len |
|
137 | body_length (e :: es) len = body_length es (length e + len); |
|
138 |
|
139 fun make_block m consistent indent es = Block (m, es, consistent, indent, body_length es 0); |
|
140 fun markup_block m indent es = make_block (Markup.output m) false indent es; |
136 |
141 |
137 |
142 |
138 |
143 |
139 (** derived operations to create formatting expressions **) |
144 (** derived operations to create formatting expressions **) |
140 |
145 |
145 val fbrk = Break (true, 1, 0); |
150 val fbrk = Break (true, 1, 0); |
146 |
151 |
147 fun breaks prts = Library.separate (brk 1) prts; |
152 fun breaks prts = Library.separate (brk 1) prts; |
148 fun fbreaks prts = Library.separate fbrk prts; |
153 fun fbreaks prts = Library.separate fbrk prts; |
149 |
154 |
150 fun raw_markup m (indent, es) = |
155 fun blk (ind, es) = markup_block Markup.empty ind es; |
151 let |
|
152 fun sum [] k = k |
|
153 | sum (e :: es) k = sum es (length e + k); |
|
154 in Block (m, es, indent, sum es 0) end; |
|
155 |
|
156 fun markup_block m arg = raw_markup (Markup.output m) arg; |
|
157 |
|
158 val blk = markup_block Markup.empty; |
|
159 fun block prts = blk (2, prts); |
156 fun block prts = blk (2, prts); |
160 val strs = block o breaks o map str; |
157 val strs = block o breaks o map str; |
161 |
158 |
162 fun markup m prts = markup_block m (0, prts); |
159 fun markup m = markup_block m 0; |
163 fun mark m prt = if m = Markup.empty then prt else markup m [prt]; |
160 fun mark m prt = if m = Markup.empty then prt else markup m [prt]; |
164 fun mark_str (m, s) = mark m (str s); |
161 fun mark_str (m, s) = mark m (str s); |
165 fun marks_str (ms, s) = fold_rev mark ms (str s); |
162 fun marks_str (ms, s) = fold_rev mark ms (str s); |
166 |
163 |
167 val item = markup Markup.item; |
164 val item = markup Markup.item; |
198 |
195 |
199 fun indent 0 prt = prt |
196 fun indent 0 prt = prt |
200 | indent n prt = blk (0, [str (spaces n), prt]); |
197 | indent n prt = blk (0, [str (spaces n), prt]); |
201 |
198 |
202 fun unbreakable (Break (_, wd, _)) = String (output_spaces wd, wd) |
199 fun unbreakable (Break (_, wd, _)) = String (output_spaces wd, wd) |
203 | unbreakable (Block (m, es, indent, wd)) = Block (m, map unbreakable es, indent, wd) |
200 | unbreakable (Block (m, es, _, indent, wd)) = Block (m, map unbreakable es, false, indent, wd) |
204 | unbreakable (e as String _) = e; |
201 | unbreakable (e as String _) = e; |
205 |
202 |
206 |
203 |
207 |
204 |
208 (** formatting **) |
205 (** formatting **) |
247 nl = nl} |
244 nl = nl} |
248 end; |
245 end; |
249 |
246 |
250 (*Add the lengths of the expressions until the next Break; if no Break then |
247 (*Add the lengths of the expressions until the next Break; if no Break then |
251 include "after", to account for text following this block.*) |
248 include "after", to account for text following this block.*) |
252 fun breakdist (Break _ :: _, _) = 0 |
249 fun break_dist (Break _ :: _, _) = 0 |
253 | breakdist (Block (_, _, _, len) :: es, after) = len + breakdist (es, after) |
250 | break_dist (Block (_, _, _, _, len) :: es, after) = len + break_dist (es, after) |
254 | breakdist (String (_, len) :: es, after) = len + breakdist (es, after) |
251 | break_dist (String (_, len) :: es, after) = len + break_dist (es, after) |
255 | breakdist ([], after) = after; |
252 | break_dist ([], after) = after; |
|
253 |
|
254 val force_break = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e; |
|
255 val force_all = map force_break; |
256 |
256 |
257 (*Search for the next break (at this or higher levels) and force it to occur.*) |
257 (*Search for the next break (at this or higher levels) and force it to occur.*) |
258 val forcebreak = fn Break (false, wd, ind) => Break (true, wd, ind) | e => e; |
258 fun force_next [] = [] |
259 fun forcenext [] = [] |
259 | force_next ((e as Break _) :: es) = force_break e :: es |
260 | forcenext ((e as Break _) :: es) = forcebreak e :: es |
260 | force_next (e :: es) = e :: force_next es; |
261 | forcenext (e :: es) = e :: forcenext es; |
|
262 |
261 |
263 in |
262 in |
264 |
263 |
265 fun formatted margin input = |
264 fun formatted margin input = |
266 let |
265 let |
271 blockin is the indentation of the current block; |
270 blockin is the indentation of the current block; |
272 after is the width of the following context until next break.*) |
271 after is the width of the following context until next break.*) |
273 fun format ([], _, _) text = text |
272 fun format ([], _, _) text = text |
274 | format (e :: es, block as (_, blockin), after) (text as {ind, pos, nl, ...}) = |
273 | format (e :: es, block as (_, blockin), after) (text as {ind, pos, nl, ...}) = |
275 (case e of |
274 (case e of |
276 Block ((bg, en), bes, indent, _) => |
275 Block ((bg, en), bes, consistent, indent, blen) => |
277 let |
276 let |
278 val pos' = pos + indent; |
277 val pos' = pos + indent; |
279 val pos'' = pos' mod emergencypos; |
278 val pos'' = pos' mod emergencypos; |
280 val block' = |
279 val block' = |
281 if pos' < emergencypos then (ind |> add_indent indent, pos') |
280 if pos' < emergencypos then (ind |> add_indent indent, pos') |
282 else (add_indent pos'' Buffer.empty, pos''); |
281 else (add_indent pos'' Buffer.empty, pos''); |
|
282 val d = break_dist (es, after) |
|
283 val bes' = if consistent andalso pos + blen > margin - d then force_all bes else bes; |
283 val btext: text = text |
284 val btext: text = text |
284 |> control bg |
285 |> control bg |
285 |> format (bes, block', breakdist (es, after)) |
286 |> format (bes', block', d) |
286 |> control en; |
287 |> control en; |
287 (*if this block was broken then force the next break*) |
288 (*if this block was broken then force the next break*) |
288 val es' = if nl < #nl btext then forcenext es else es; |
289 val es' = if nl < #nl btext then force_next es else es; |
289 in format (es', block, after) btext end |
290 in format (es', block, after) btext end |
290 | Break (force, wd, ind) => |
291 | Break (force, wd, ind) => |
291 (*no break if text to next break fits on this line |
292 (*no break if text to next break fits on this line |
292 or if breaking would add only breakgain to space*) |
293 or if breaking would add only breakgain to space*) |
293 format (es, block, after) |
294 format (es, block, after) |
294 (if not force andalso |
295 (if not force andalso |
295 pos + wd <= Int.max (margin - breakdist (es, after), blockin + breakgain) |
296 pos + wd <= Int.max (margin - break_dist (es, after), blockin + breakgain) |
296 then text |> blanks wd (*just insert wd blanks*) |
297 then text |> blanks wd (*just insert wd blanks*) |
297 else text |> newline |> indentation block |> blanks ind) |
298 else text |> newline |> indentation block |> blanks ind) |
298 | String str => format (es, block, after) (string str text)); |
299 | String str => format (es, block, after) (string str text)); |
299 in |
300 in |
300 #tx (format ([input], (Buffer.empty, 0), 0) empty) |
301 #tx (format ([input], (Buffer.empty, 0), 0) empty) |
301 end; |
302 end; |
302 |
303 |
306 (* special output *) |
307 (* special output *) |
307 |
308 |
308 (*symbolic markup -- no formatting*) |
309 (*symbolic markup -- no formatting*) |
309 fun symbolic prt = |
310 fun symbolic prt = |
310 let |
311 let |
311 fun out (Block ((bg, en), [], _, _)) = Buffer.add bg #> Buffer.add en |
312 fun out (Block ((bg, en), [], _, _, _)) = Buffer.add bg #> Buffer.add en |
312 | out (Block ((bg, en), prts, indent, _)) = |
313 | out (Block ((bg, en), prts, consistent, indent, _)) = |
313 Buffer.add bg #> |
314 Buffer.add bg #> |
314 Buffer.markup (Markup.block indent) (fold out prts) #> |
315 Buffer.markup (Markup.block consistent indent) (fold out prts) #> |
315 Buffer.add en |
316 Buffer.add en |
316 | out (String (s, _)) = Buffer.add s |
317 | out (String (s, _)) = Buffer.add s |
317 | out (Break (false, wd, ind)) = |
318 | out (Break (false, wd, ind)) = |
318 Buffer.markup (Markup.break wd ind) (Buffer.add (output_spaces wd)) |
319 Buffer.markup (Markup.break wd ind) (Buffer.add (output_spaces wd)) |
319 | out (Break (true, _, _)) = Buffer.add (Output.output "\n"); |
320 | out (Break (true, _, _)) = Buffer.add (Output.output "\n"); |
320 in out prt Buffer.empty end; |
321 in out prt Buffer.empty end; |
321 |
322 |
322 (*unformatted output*) |
323 (*unformatted output*) |
323 fun unformatted prt = |
324 fun unformatted prt = |
324 let |
325 let |
325 fun fmt (Block ((bg, en), prts, _, _)) = Buffer.add bg #> fold fmt prts #> Buffer.add en |
326 fun fmt (Block ((bg, en), prts, _, _, _)) = Buffer.add bg #> fold fmt prts #> Buffer.add en |
326 | fmt (String (s, _)) = Buffer.add s |
327 | fmt (String (s, _)) = Buffer.add s |
327 | fmt (Break (_, wd, _)) = Buffer.add (output_spaces wd); |
328 | fmt (Break (_, wd, _)) = Buffer.add (output_spaces wd); |
328 in fmt prt Buffer.empty end; |
329 in fmt prt Buffer.empty end; |
329 |
330 |
330 |
331 |
377 |
378 |
378 |
379 |
379 |
380 |
380 (** ML toplevel pretty printing **) |
381 (** ML toplevel pretty printing **) |
381 |
382 |
382 fun to_ML (Block (m, prts, ind, _)) = ML_Pretty.Block (m, map to_ML prts, ind) |
383 fun to_ML (Block (m, prts, consistent, indent, _)) = |
|
384 ML_Pretty.Block (m, map to_ML prts, consistent, indent) |
383 | to_ML (String s) = ML_Pretty.String s |
385 | to_ML (String s) = ML_Pretty.String s |
384 | to_ML (Break b) = ML_Pretty.Break b; |
386 | to_ML (Break b) = ML_Pretty.Break b; |
385 |
387 |
386 fun from_ML (ML_Pretty.Block (m, prts, ind)) = raw_markup m (ind, map from_ML prts) |
388 fun from_ML (ML_Pretty.Block (m, prts, consistent, indent)) = |
|
389 make_block m consistent indent (map from_ML prts) |
387 | from_ML (ML_Pretty.String s) = String s |
390 | from_ML (ML_Pretty.String s) = String s |
388 | from_ML (ML_Pretty.Break b) = Break b; |
391 | from_ML (ML_Pretty.Break b) = Break b; |
389 |
392 |
390 end; |
393 end; |
391 |
394 |