src/Pure/General/pretty.scala
changeset 48704 85a3de10567d
parent 45666 d83797ef0d2d
child 48996 a8bad1369ada
equal deleted inserted replaced
48703:d408ff0abf23 48704:85a3de10567d
    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   }