src/Pure/General/pretty.scala
changeset 36817 ed97e877ff2d
parent 36763 096ebe74aeaf
child 36818 599466689412
equal deleted inserted replaced
36816:da7628b3d231 36817:ed97e877ff2d
    43   val FBreak = XML.Text("\n")
    43   val FBreak = XML.Text("\n")
    44 
    44 
    45 
    45 
    46   /* formatted output */
    46   /* formatted output */
    47 
    47 
    48   private case class Text(tx: List[XML.Tree] = Nil, val pos: Int = 0, val nl: Int = 0)
       
    49   {
       
    50     def newline: Text = copy(tx = FBreak :: tx, pos = 0, nl = nl + 1)
       
    51     def string(s: String): Text = copy(tx = XML.Text(s) :: tx, pos = pos + s.length)
       
    52     def blanks(wd: Int): Text = string(Symbol.spaces(wd))
       
    53     def content: List[XML.Tree] = tx.reverse
       
    54   }
       
    55 
       
    56   private def breakdist(trees: List[XML.Tree], after: Int): Int =
       
    57     trees match {
       
    58       case Break(_) :: _ => 0
       
    59       case FBreak :: _ => 0
       
    60       case XML.Elem(_, _, body) :: ts =>
       
    61         (0 /: body)(_ + XML.content_length(_)) + breakdist(ts, after)
       
    62       case XML.Text(s) :: ts => s.length + breakdist(ts, after)
       
    63       case Nil => after
       
    64     }
       
    65 
       
    66   private def forcenext(trees: List[XML.Tree]): List[XML.Tree] =
       
    67     trees match {
       
    68       case Nil => Nil
       
    69       case FBreak :: _ => trees
       
    70       case Break(_) :: ts => FBreak :: ts
       
    71       case t :: ts => t :: forcenext(ts)
       
    72     }
       
    73 
       
    74   private def standard_format(tree: XML.Tree): List[XML.Tree] =
    48   private def standard_format(tree: XML.Tree): List[XML.Tree] =
    75     tree match {
    49     tree match {
    76       case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(standard_format)))
    50       case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(standard_format)))
    77       case XML.Text(text) =>
    51       case XML.Text(text) =>
    78         Library.separate(FBreak,
    52         Library.separate(FBreak,
    79           Library.chunks(text).toList.map((s: CharSequence) => XML.Text(s.toString)))
    53           Library.chunks(text).toList.map((s: CharSequence) => XML.Text(s.toString)))
    80     }
    54     }
    81 
    55 
       
    56   case class Text(tx: List[XML.Tree] = Nil, val pos: Double = 0.0, val nl: Int = 0)
       
    57   {
       
    58     def newline: Text = copy(tx = FBreak :: tx, pos = 0.0, nl = nl + 1)
       
    59     def string(s: String, len: Double): Text = copy(tx = XML.Text(s) :: tx, pos = pos + len)
       
    60     def blanks(wd: Int): Text = string(Symbol.spaces(wd), wd.toDouble)
       
    61     def content: List[XML.Tree] = tx.reverse
       
    62   }
       
    63 
    82   private val margin_default = 76
    64   private val margin_default = 76
    83 
    65 
    84   def formatted(input: List[XML.Tree], margin: Int = margin_default): List[XML.Tree] =
    66   def formatted(input: List[XML.Tree], margin: Int = margin_default,
       
    67     metric: String => Double = (_.length.toDouble)): List[XML.Tree] =
    85   {
    68   {
    86     val breakgain = margin / 20
    69     val breakgain = margin / 20
    87     val emergencypos = margin / 2
    70     val emergencypos = margin / 2
    88 
    71 
    89     def format(trees: List[XML.Tree], blockin: Int, after: Int, text: Text): Text =
    72     def content_length(tree: XML.Tree): Double =
       
    73       tree match {
       
    74         case XML.Elem(_, _, body) => (0.0 /: body)(_ + content_length(_))
       
    75         case XML.Text(s) => metric(s)
       
    76       }
       
    77 
       
    78     def breakdist(trees: List[XML.Tree], after: Double): Double =
       
    79       trees match {
       
    80         case Break(_) :: _ => 0.0
       
    81         case FBreak :: _ => 0.0
       
    82         case XML.Elem(_, _, body) :: ts =>
       
    83           (0.0 /: body)(_ + content_length(_)) + breakdist(ts, after)
       
    84         case XML.Text(s) :: ts => metric(s) + breakdist(ts, after)
       
    85         case Nil => after
       
    86       }
       
    87 
       
    88     def forcenext(trees: List[XML.Tree]): List[XML.Tree] =
       
    89       trees match {
       
    90         case Nil => Nil
       
    91         case FBreak :: _ => trees
       
    92         case Break(_) :: ts => FBreak :: ts
       
    93         case t :: ts => t :: forcenext(ts)
       
    94       }
       
    95 
       
    96     def format(trees: List[XML.Tree], blockin: Double, after: Double, text: Text): Text =
    90       trees match {
    97       trees match {
    91         case Nil => text
    98         case Nil => text
    92 
    99 
    93         case Block(indent, body) :: ts =>
   100         case Block(indent, body) :: ts =>
    94           val pos1 = text.pos + indent
   101           val pos1 = text.pos + indent
   101           format(ts1, blockin, after, btext)
   108           format(ts1, blockin, after, btext)
   102 
   109 
   103         case Break(wd) :: ts =>
   110         case Break(wd) :: ts =>
   104           if (text.pos + wd <= (margin - breakdist(ts, after)).max(blockin + breakgain))
   111           if (text.pos + wd <= (margin - breakdist(ts, after)).max(blockin + breakgain))
   105             format(ts, blockin, after, text.blanks(wd))
   112             format(ts, blockin, after, text.blanks(wd))
   106           else format(ts, blockin, after, text.newline.blanks(blockin))
   113           else format(ts, blockin, after, text.newline.blanks(blockin.toInt))
   107         case FBreak :: ts => format(ts, blockin, after, text.newline.blanks(blockin))
   114         case FBreak :: ts => format(ts, blockin, after, text.newline.blanks(blockin.toInt))
   108 
   115 
   109         case XML.Elem(name, atts, body) :: ts =>
   116         case XML.Elem(name, atts, body) :: ts =>
   110           val btext = format(body, blockin, breakdist(ts, after), text.copy(tx = Nil))
   117           val btext = format(body, blockin, breakdist(ts, after), text.copy(tx = Nil))
   111           val ts1 = if (text.nl < btext.nl) forcenext(ts) else ts
   118           val ts1 = if (text.nl < btext.nl) forcenext(ts) else ts
   112           val btext1 = btext.copy(tx = XML.Elem(name, atts, btext.content) :: text.tx)
   119           val btext1 = btext.copy(tx = XML.Elem(name, atts, btext.content) :: text.tx)
   113           format(ts1, blockin, after, btext1)
   120           format(ts1, blockin, after, btext1)
   114         case XML.Text(s) :: ts => format(ts, blockin, after, text.string(s))
   121         case XML.Text(s) :: ts => format(ts, blockin, after, text.string(s, metric(s)))
   115       }
   122       }
   116     format(input.flatMap(standard_format), 0, 0, Text()).content
   123     format(input.flatMap(standard_format), 0.0, 0.0, Text()).content
   117   }
   124   }
   118 
   125 
   119   def string_of(input: List[XML.Tree], margin: Int = margin_default): String =
   126   def string_of(input: List[XML.Tree], margin: Int = margin_default): String =
   120     formatted(input).iterator.flatMap(XML.content).mkString
   127     formatted(input).iterator.flatMap(XML.content).mkString
   121 
   128 
   126   {
   133   {
   127     def fmt(tree: XML.Tree): List[XML.Tree] =
   134     def fmt(tree: XML.Tree): List[XML.Tree] =
   128       tree match {
   135       tree match {
   129         case Block(_, body) => body.flatMap(fmt)
   136         case Block(_, body) => body.flatMap(fmt)
   130         case Break(wd) => List(XML.Text(Symbol.spaces(wd)))
   137         case Break(wd) => List(XML.Text(Symbol.spaces(wd)))
   131         case FBreak => List(XML.Text(" "))
   138         case FBreak => List(XML.Text(Symbol.space))
   132         case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(fmt)))
   139         case XML.Elem(name, atts, body) => List(XML.Elem(name, atts, body.flatMap(fmt)))
   133         case XML.Text(_) => List(tree)
   140         case XML.Text(_) => List(tree)
   134       }
   141       }
   135     input.flatMap(standard_format).flatMap(fmt)
   142     input.flatMap(standard_format).flatMap(fmt)
   136   }
   143   }