15 /* markup trees with physical blocks and breaks */ |
15 /* markup trees with physical blocks and breaks */ |
16 |
16 |
17 object Block |
17 object Block |
18 { |
18 { |
19 def apply(indent: Int, body: List[XML.Tree]): XML.Tree = |
19 def apply(indent: Int, body: List[XML.Tree]): XML.Tree = |
20 XML.Elem(Markup.BLOCK, List((Markup.INDENT, indent.toString)), body) |
20 XML.Elem(Markup(Markup.BLOCK, List((Markup.INDENT, indent.toString))), body) |
21 |
21 |
22 def unapply(tree: XML.Tree): Option[(Int, List[XML.Tree])] = |
22 def unapply(tree: XML.Tree): Option[(Int, List[XML.Tree])] = |
23 tree match { |
23 tree match { |
24 case XML.Elem(Markup.BLOCK, List((Markup.INDENT, indent)), body) => |
24 case XML.Elem(Markup(Markup.BLOCK, List((Markup.INDENT, indent))), body) => |
25 Markup.parse_int(indent) match { |
25 Markup.parse_int(indent) match { |
26 case Some(i) => Some((i, body)) |
26 case Some(i) => Some((i, body)) |
27 case None => None |
27 case None => None |
28 } |
28 } |
29 case _ => None |
29 case _ => None |
31 } |
31 } |
32 |
32 |
33 object Break |
33 object Break |
34 { |
34 { |
35 def apply(width: Int): XML.Tree = |
35 def apply(width: Int): XML.Tree = |
36 XML.Elem(Markup.BREAK, List((Markup.WIDTH, width.toString)), |
36 XML.Elem(Markup(Markup.BREAK, List((Markup.WIDTH, width.toString))), |
37 List(XML.Text(Symbol.spaces(width)))) |
37 List(XML.Text(Symbol.spaces(width)))) |
38 |
38 |
39 def unapply(tree: XML.Tree): Option[Int] = |
39 def unapply(tree: XML.Tree): Option[Int] = |
40 tree match { |
40 tree match { |
41 case XML.Elem(Markup.BREAK, List((Markup.WIDTH, width)), _) => Markup.parse_int(width) |
41 case XML.Elem(Markup(Markup.BREAK, List((Markup.WIDTH, width))), _) => Markup.parse_int(width) |
42 case _ => None |
42 case _ => None |
43 } |
43 } |
44 } |
44 } |
45 |
45 |
46 val FBreak = XML.Text("\n") |
46 val FBreak = XML.Text("\n") |
48 |
48 |
49 /* formatted output */ |
49 /* formatted output */ |
50 |
50 |
51 private def standard_format(tree: XML.Tree): List[XML.Tree] = |
51 private def standard_format(tree: XML.Tree): List[XML.Tree] = |
52 tree match { |
52 tree match { |
53 case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(standard_format))) |
53 case XML.Elem(markup, body) => List(XML.Elem(markup, body.flatMap(standard_format))) |
54 case XML.Text(text) => |
54 case XML.Text(text) => |
55 Library.separate(FBreak, |
55 Library.separate(FBreak, |
56 Library.chunks(text).toList.map((s: CharSequence) => XML.Text(s.toString))) |
56 Library.chunks(text).toList.map((s: CharSequence) => XML.Text(s.toString))) |
57 } |
57 } |
58 |
58 |
80 val breakgain = margin / 20 |
80 val breakgain = margin / 20 |
81 val emergencypos = margin / 2 |
81 val emergencypos = margin / 2 |
82 |
82 |
83 def content_length(tree: XML.Tree): Double = |
83 def content_length(tree: XML.Tree): Double = |
84 tree match { |
84 tree match { |
85 case XML.Elem(_, _, body) => (0.0 /: body)(_ + content_length(_)) |
85 case XML.Elem(_, body) => (0.0 /: body)(_ + content_length(_)) |
86 case XML.Text(s) => metric(s) |
86 case XML.Text(s) => metric(s) |
87 } |
87 } |
88 |
88 |
89 def breakdist(trees: List[XML.Tree], after: Double): Double = |
89 def breakdist(trees: List[XML.Tree], after: Double): Double = |
90 trees match { |
90 trees match { |
120 if (text.pos + wd <= (margin - breakdist(ts, after)).max(blockin + breakgain)) |
120 if (text.pos + wd <= (margin - breakdist(ts, after)).max(blockin + breakgain)) |
121 format(ts, blockin, after, text.blanks(wd)) |
121 format(ts, blockin, after, text.blanks(wd)) |
122 else format(ts, blockin, after, text.newline.blanks(blockin.toInt)) |
122 else format(ts, blockin, after, text.newline.blanks(blockin.toInt)) |
123 case FBreak :: ts => format(ts, blockin, after, text.newline.blanks(blockin.toInt)) |
123 case FBreak :: ts => format(ts, blockin, after, text.newline.blanks(blockin.toInt)) |
124 |
124 |
125 case XML.Elem(name, atts, body) :: ts => |
125 case XML.Elem(markup, body) :: ts => |
126 val btext = format(body, blockin, breakdist(ts, after), text.copy(tx = Nil)) |
126 val btext = format(body, blockin, breakdist(ts, after), text.copy(tx = Nil)) |
127 val ts1 = if (text.nl < btext.nl) forcenext(ts) else ts |
127 val ts1 = if (text.nl < btext.nl) forcenext(ts) else ts |
128 val btext1 = btext.copy(tx = XML.Elem(name, atts, btext.content) :: text.tx) |
128 val btext1 = btext.copy(tx = XML.Elem(markup, btext.content) :: text.tx) |
129 format(ts1, blockin, after, btext1) |
129 format(ts1, blockin, after, btext1) |
130 case XML.Text(s) :: ts => format(ts, blockin, after, text.string(s, metric(s))) |
130 case XML.Text(s) :: ts => format(ts, blockin, after, text.string(s, metric(s))) |
131 } |
131 } |
132 format(input.flatMap(standard_format), 0.0, 0.0, Text()).content |
132 format(input.flatMap(standard_format), 0.0, 0.0, Text()).content |
133 } |
133 } |
144 def fmt(tree: XML.Tree): List[XML.Tree] = |
144 def fmt(tree: XML.Tree): List[XML.Tree] = |
145 tree match { |
145 tree match { |
146 case Block(_, body) => body.flatMap(fmt) |
146 case Block(_, body) => body.flatMap(fmt) |
147 case Break(wd) => List(XML.Text(Symbol.spaces(wd))) |
147 case Break(wd) => List(XML.Text(Symbol.spaces(wd))) |
148 case FBreak => List(XML.Text(Symbol.space)) |
148 case FBreak => List(XML.Text(Symbol.space)) |
149 case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(fmt))) |
149 case XML.Elem(markup, body) => List(XML.Elem(markup, body.flatMap(fmt))) |
150 case XML.Text(_) => List(tree) |
150 case XML.Text(_) => List(tree) |
151 } |
151 } |
152 input.flatMap(standard_format).flatMap(fmt) |
152 input.flatMap(standard_format).flatMap(fmt) |
153 } |
153 } |
154 |
154 |