diff options
author | Martin Odersky <odersky@gmail.com> | 2013-03-20 08:01:28 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-03-20 08:01:28 +0100 |
commit | 53e0a8a9227820e47e33f1e0b1d91819aec917c4 (patch) | |
tree | d3b0eb2e517bcd2086740cf09828d8a7b4250a25 /src/dotty/tools/dotc/util | |
parent | 2fdf86e4f9a355eeb2ae7f539824270edd76764a (diff) | |
download | dotty-53e0a8a9227820e47e33f1e0b1d91819aec917c4.tar.gz dotty-53e0a8a9227820e47e33f1e0b1d91819aec917c4.tar.bz2 dotty-53e0a8a9227820e47e33f1e0b1d91819aec917c4.zip |
First draft of pretty printing abstractions
Diffstat (limited to 'src/dotty/tools/dotc/util')
-rw-r--r-- | src/dotty/tools/dotc/util/Text.scala | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/util/Text.scala b/src/dotty/tools/dotc/util/Text.scala new file mode 100644 index 000000000..a63f36b83 --- /dev/null +++ b/src/dotty/tools/dotc/util/Text.scala @@ -0,0 +1,123 @@ +package dotty.tools.dotc.util + +import language.implicitConversions + +object Texts { + + class Text { + + protected def indentMargin = 2 + protected def pageWidth = 80 + + def relems: List[Text] + + def isEmpty: Boolean = this match { + case Str(s) => s.isEmpty + case Fluid(relems) => relems forall (_.isEmpty) + case Rigid(relems) => relems.isEmpty + } + + def isRigid = isInstanceOf[Rigid] + + def fitsIn(width: Int): Boolean = this match { + case Str(s) => + s.length <= width + case Fluid(Str(s) :: prevs) => + s.length < width && Fluid(prevs).fitsIn(width - s.length) + case Rigid(_) => + false + } + + def lastLineWidth: Int = this match { + case Str(s) => s.length + case _ => relems.head.lastLineWidth + } + + 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) => + (this /: relems.reverse)(_ appendToLastLine _) + } + + private def appendIndented(that: Text)(width: Int): Text = + Rigid(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.isRigid) appendIndented(that)(width) + else if (this.isRigid) Fluid(that.layout(width) :: this.relems) + else if (that.fitsIn(width - this.lastLineWidth)) appendToLastLine(that) + else appendIndented(that)(width) + + def layout(width: Int): Text = this match { + case Str(_) => + this + case Fluid(relems) => + ((Str(""): Text) /: relems.reverse)(_.append(width)(_)) + case Rigid(relems) => + Rigid(relems map (_ layout width)) + } + + private def indented: Text = this match { + case Str(s) => Str((" " * indentMargin) + s) + case Fluid(relems) => Fluid(relems map (_.indented)) + case Rigid(relems) => Rigid(relems map (_.indented)) + } + + def print(sb: StringBuilder): Unit = this match { + case Str(s) => + sb.append(s) + case txt: CompoundText => + var follow = false + for (elem <- txt.relems.reverse) { + if (follow) sb.append("\n") + elem.print(sb) + follow = true + } + } + + def show: String = + layout(pageWidth).showRaw + + def showRaw: String = { + val sb = new StringBuilder + print(sb) + sb.toString + } + + def +++ (that: Text) = + if (this.isEmpty) that + else if (that.isEmpty) this + else Fluid(that :: this :: Nil) + + def over (that: Text) = + if (this.isRigid) Rigid(that :: this.relems) + else Rigid(that :: this :: Nil) + } + + object Text { + def apply(xs: Traversable[Text], sep: String): Text = { + val ys = xs filterNot (_.isEmpty) + if (ys.isEmpty) Str("") + else ys reduce (_ +++ sep +++ _) + } + } + + abstract class CompoundText extends Text { + def relems: List[Text] + } + + case class Str(s: String) extends Text { + override def relems: List[Text] = List(this) + } + + case class Rigid(relems: List[Text]) extends CompoundText + case class Fluid(relems: List[Text]) extends CompoundText + + implicit def stringToText(s: String): Text = Str(s) +}
\ No newline at end of file |