aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/printing/Texts.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-05-14 12:22:35 +0200
committerMartin Odersky <odersky@gmail.com>2013-05-14 12:22:35 +0200
commitfec318dedaa10bf7ffaebd7aaf4a99e05ac0312a (patch)
tree8d5f9560806325c922eceb847f5c13b096aa7013 /src/dotty/tools/dotc/printing/Texts.scala
parentb866c49bde62ee8ee52358dee746db64741b5891 (diff)
downloaddotty-fec318dedaa10bf7ffaebd7aaf4a99e05ac0312a.tar.gz
dotty-fec318dedaa10bf7ffaebd7aaf4a99e05ac0312a.tar.bz2
dotty-fec318dedaa10bf7ffaebd7aaf4a99e05ac0312a.zip
Refactored Printers, Showable and Text into new package dotc.printing.
Diffstat (limited to 'src/dotty/tools/dotc/printing/Texts.scala')
-rw-r--r--src/dotty/tools/dotc/printing/Texts.scala153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/printing/Texts.scala b/src/dotty/tools/dotc/printing/Texts.scala
new file mode 100644
index 000000000..2ff4edc9a
--- /dev/null
+++ b/src/dotty/tools/dotc/printing/Texts.scala
@@ -0,0 +1,153 @@
+package dotty.tools.dotc
+package printing
+
+object Texts {
+
+ abstract class Text {
+
+ protected def indentMargin = 2
+
+ def relems: List[Text]
+
+ def isEmpty: Boolean = this match {
+ case Str(s) => s.isEmpty
+ case Fluid(relems) => relems forall (_.isEmpty)
+ case Vertical(relems) => relems.isEmpty
+ }
+
+ def isVertical = isInstanceOf[Vertical]
+ def isClosed = isVertical || isInstanceOf[Closed]
+ def isFluid = isInstanceOf[Fluid]
+ def isSplittable = isFluid && !isClosed
+
+ def close = new Closed(relems)
+
+ def remaining(width: Int): Int = this match {
+ case Str(s) =>
+ width - s.length
+ case Fluid(Nil) =>
+ width
+ case Fluid(last :: prevs) =>
+ val r = last remaining width
+ if (r < 0) r else Fluid(prevs) remaining r
+ case Vertical(_) =>
+ -1
+ }
+
+ def lastLine: String = this match {
+ case Str(s) => s
+ case _ => relems.head.lastLine
+ }
+
+ def appendToLastLine(that: Text): Text = that match {
+ case Str(s2) =>
+ this match {
+ case Str(s1) => Str(s1 + s2)
+ case Fluid(Str(s1) :: prev) => Fluid(Str(s1 + s2) :: prev)
+ case Fluid(relems) => Fluid(that :: relems)
+ }
+ case Fluid(relems) =>
+ (this /: relems.reverse)(_ appendToLastLine _)
+ }
+
+ private def appendIndented(that: Text)(width: Int): Text =
+ Vertical(that.layout(width - indentMargin).indented :: this.relems)
+
+ private def append(width: Int)(that: Text): Text = {
+ if (this.isEmpty) that.layout(width)
+ else if (that.isEmpty) this
+ else if (that.isVertical) appendIndented(that)(width)
+ else if (this.isVertical) Fluid(that.layout(width) :: this.relems)
+ else if (that.remaining(width - lastLine.length) >= 0) appendToLastLine(that)
+ else if (that.isSplittable) (this /: that.relems.reverse)(_.append(width)(_))
+ else appendIndented(that)(width)
+ }
+
+ def layout(width: Int): Text = this match {
+ case Str(_) =>
+ this
+ case Fluid(relems) =>
+ ((Str(""): Text) /: relems.reverse)(_.append(width)(_))
+ case Vertical(relems) =>
+ Vertical(relems map (_ layout width))
+ }
+
+ def map(f: String => String): Text = this match {
+ case Str(s) => Str(f(s))
+ case Fluid(relems) => Fluid(relems map (_ map f))
+ case Vertical(relems) => Vertical(relems map (_ map f))
+ }
+
+ def stripPrefix(pre: String): Text = this match {
+ case Str(s) =>
+ if (s.startsWith(pre)) s drop pre.length else s
+ case Fluid(relems) =>
+ val elems = relems.reverse
+ val head = elems.head.stripPrefix(pre)
+ if (head eq elems.head) this else Fluid((head :: elems.tail).reverse)
+ case Vertical(relems) =>
+ val elems = relems.reverse
+ val head = elems.head.stripPrefix(pre)
+ if (head eq elems.head) this else Vertical((head :: elems.tail).reverse)
+ }
+
+ private def indented: Text = this match {
+ case Str(s) => Str((" " * indentMargin) + s)
+ case Fluid(relems) => Fluid(relems map (_.indented))
+ case Vertical(relems) => Vertical(relems map (_.indented))
+ }
+
+ def print(sb: StringBuilder): Unit = this match {
+ case Str(s) =>
+ sb.append(s)
+ case _ =>
+ var follow = false
+ for (elem <- relems.reverse) {
+ if (follow) sb.append("\n")
+ elem.print(sb)
+ follow = true
+ }
+ }
+
+ def mkString(width: Int): String = {
+ val sb = new StringBuilder
+ layout(width).print(sb)
+ sb.toString
+ }
+
+ def ~ (that: Text) =
+ if (this.isEmpty) that
+ else if (that.isEmpty) this
+ else Fluid(that :: this :: Nil)
+
+ def ~~ (that: Text) =
+ if (this.isEmpty) that
+ else if (that.isEmpty) this
+ else Fluid(that :: Str(" ") :: this :: Nil)
+
+ def over (that: Text) =
+ if (this.isVertical) Vertical(that :: this.relems)
+ else Vertical(that :: this :: Nil)
+ }
+
+ object Text {
+ def apply(): Text = Str("")
+ def apply(xs: Traversable[Text], sep: String = " "): Text = {
+ val ys = xs filterNot (_.isEmpty)
+ if (ys.isEmpty) Str("")
+ else ys reduce (_ ~ sep ~ _)
+ }
+ def lines(xs: Traversable[Text]) = Vertical(xs.toList.reverse)
+ }
+
+ case class Str(s: String) extends Text {
+ override def relems: List[Text] = List(this)
+ }
+
+ case class Vertical(relems: List[Text]) extends Text
+ case class Fluid(relems: List[Text]) extends Text
+
+ class Closed(relems: List[Text]) extends Fluid(relems)
+
+ implicit def stringToText(s: String): Text = Str(s)
+} \ No newline at end of file