diff options
Diffstat (limited to 'src/dotty/tools/dotc/util/Text.scala')
-rw-r--r-- | src/dotty/tools/dotc/util/Text.scala | 108 |
1 files changed, 69 insertions, 39 deletions
diff --git a/src/dotty/tools/dotc/util/Text.scala b/src/dotty/tools/dotc/util/Text.scala index a63f36b83..251274371 100644 --- a/src/dotty/tools/dotc/util/Text.scala +++ b/src/dotty/tools/dotc/util/Text.scala @@ -4,33 +4,40 @@ import language.implicitConversions object Texts { - class Text { + abstract 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 + case Vertical(relems) => relems.isEmpty } - def isRigid = isInstanceOf[Rigid] + def isVertical = isInstanceOf[Vertical] + def isClosed = isVertical || isInstanceOf[Closed] + def isFluid = isInstanceOf[Fluid] + def isSplittable = isFluid && !isClosed - def fitsIn(width: Int): Boolean = this match { + def close = new Closed(relems) + + def remaining(width: Int): Int = 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 + 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 lastLineWidth: Int = this match { - case Str(s) => s.length - case _ => relems.head.lastLineWidth + def lastLine: String = this match { + case Str(s) => s + case _ => relems.head.lastLine } def appendToLastLine(that: Text): Text = that match { @@ -44,80 +51,103 @@ object Texts { } private def appendIndented(that: Text)(width: Int): Text = - Rigid(that.layout(width - indentMargin).indented :: this.relems) + Vertical(that.layout(width - indentMargin).indented :: this.relems) - private def append(width: Int)(that: Text): Text = + 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 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 Rigid(relems) => - Rigid(relems map (_ layout 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 Rigid(relems) => Rigid(relems map (_.indented)) + case Vertical(relems) => Vertical(relems map (_.indented)) } def print(sb: StringBuilder): Unit = this match { case Str(s) => sb.append(s) - case txt: CompoundText => + case _ => var follow = false - for (elem <- txt.relems.reverse) { + for (elem <- relems.reverse) { if (follow) sb.append("\n") elem.print(sb) follow = true } } - def show: String = - layout(pageWidth).showRaw - - def showRaw: String = { + def mkString(width: Int): String = { val sb = new StringBuilder - print(sb) + layout(width).print(sb) sb.toString } - def +++ (that: Text) = + 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.isRigid) Rigid(that :: this.relems) - else Rigid(that :: this :: Nil) + if (this.isVertical) Vertical(that :: this.relems) + else Vertical(that :: this :: Nil) } object Text { - def apply(xs: Traversable[Text], sep: String): 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 +++ _) + else ys reduce (_ ~ sep ~ _) } - } - - abstract class CompoundText extends Text { - def relems: List[Text] + 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 Rigid(relems: List[Text]) extends CompoundText - case class Fluid(relems: List[Text]) extends CompoundText + 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 |