10 import java.awt.FontMetrics |
10 import java.awt.FontMetrics |
11 |
11 |
12 |
12 |
13 object Pretty |
13 object Pretty |
14 { |
14 { |
|
15 /* spaces */ |
|
16 |
|
17 val spc = ' ' |
|
18 val space = " " |
|
19 |
|
20 private val static_spaces = space * 4000 |
|
21 |
|
22 def spaces(k: Int): String = |
|
23 { |
|
24 require(k >= 0) |
|
25 if (k < static_spaces.length) static_spaces.substring(0, k) |
|
26 else space * k |
|
27 } |
|
28 |
|
29 |
15 /* markup trees with physical blocks and breaks */ |
30 /* markup trees with physical blocks and breaks */ |
16 |
31 |
17 def block(body: XML.Body): XML.Tree = Block(2, body) |
32 def block(body: XML.Body): XML.Tree = Block(2, body) |
18 |
33 |
19 object Block |
34 object Block |
31 |
46 |
32 object Break |
47 object Break |
33 { |
48 { |
34 def apply(w: Int): XML.Tree = |
49 def apply(w: Int): XML.Tree = |
35 XML.Elem(Markup(Isabelle_Markup.BREAK, Isabelle_Markup.Width(w)), |
50 XML.Elem(Markup(Isabelle_Markup.BREAK, Isabelle_Markup.Width(w)), |
36 List(XML.Text(Symbol.spaces(w)))) |
51 List(XML.Text(spaces(w)))) |
37 |
52 |
38 def unapply(tree: XML.Tree): Option[Int] = |
53 def unapply(tree: XML.Tree): Option[Int] = |
39 tree match { |
54 tree match { |
40 case XML.Elem(Markup(Isabelle_Markup.BREAK, Isabelle_Markup.Width(w)), _) => Some(w) |
55 case XML.Elem(Markup(Isabelle_Markup.BREAK, Isabelle_Markup.Width(w)), _) => Some(w) |
41 case _ => None |
56 case _ => None |
57 |
72 |
58 private sealed case class Text(tx: XML.Body = Nil, val pos: Double = 0.0, val nl: Int = 0) |
73 private sealed case class Text(tx: XML.Body = Nil, val pos: Double = 0.0, val nl: Int = 0) |
59 { |
74 { |
60 def newline: Text = copy(tx = FBreak :: tx, pos = 0.0, nl = nl + 1) |
75 def newline: Text = copy(tx = FBreak :: tx, pos = 0.0, nl = nl + 1) |
61 def string(s: String, len: Double): Text = copy(tx = XML.Text(s) :: tx, pos = pos + len) |
76 def string(s: String, len: Double): Text = copy(tx = XML.Text(s) :: tx, pos = pos + len) |
62 def blanks(wd: Int): Text = string(Symbol.spaces(wd), wd.toDouble) |
77 def blanks(wd: Int): Text = string(spaces(wd), wd.toDouble) |
63 def content: XML.Body = tx.reverse |
78 def content: XML.Body = tx.reverse |
64 } |
79 } |
65 |
80 |
66 private val margin_default = 76 |
81 private val margin_default = 76 |
67 private def metric_default(s: String) = s.length.toDouble |
82 private def metric_default(s: String) = s.length.toDouble |
68 |
83 |
69 def font_metric(metrics: FontMetrics): String => Double = |
84 def font_metric(metrics: FontMetrics): String => Double = |
70 if (metrics == null) ((s: String) => s.length.toDouble) |
85 if (metrics == null) ((s: String) => s.length.toDouble) |
71 else { |
86 else { |
72 val unit = metrics.charWidth(Symbol.spc).toDouble |
87 val unit = metrics.charWidth(spc).toDouble |
73 ((s: String) => if (s == "\n") 1.0 else metrics.stringWidth(s) / unit) |
88 ((s: String) => if (s == "\n") 1.0 else metrics.stringWidth(s) / unit) |
74 } |
89 } |
75 |
90 |
76 def formatted(input: XML.Body, margin: Int = margin_default, |
91 def formatted(input: XML.Body, margin: Int = margin_default, |
77 metric: String => Double = metric_default): XML.Body = |
92 metric: String => Double = metric_default): XML.Body = |
141 def unformatted(input: XML.Body): XML.Body = |
156 def unformatted(input: XML.Body): XML.Body = |
142 { |
157 { |
143 def fmt(tree: XML.Tree): XML.Body = |
158 def fmt(tree: XML.Tree): XML.Body = |
144 tree match { |
159 tree match { |
145 case Block(_, body) => body.flatMap(fmt) |
160 case Block(_, body) => body.flatMap(fmt) |
146 case Break(wd) => List(XML.Text(Symbol.spaces(wd))) |
161 case Break(wd) => List(XML.Text(spaces(wd))) |
147 case FBreak => List(XML.Text(Symbol.space)) |
162 case FBreak => List(XML.Text(space)) |
148 case XML.Elem(markup, body) => List(XML.Elem(markup, body.flatMap(fmt))) |
163 case XML.Elem(markup, body) => List(XML.Elem(markup, body.flatMap(fmt))) |
149 case XML.Text(_) => List(tree) |
164 case XML.Text(_) => List(tree) |
150 } |
165 } |
151 input.flatMap(standard_format).flatMap(fmt) |
166 input.flatMap(standard_format).flatMap(fmt) |
152 } |
167 } |