diff options
author | jeberle <jeberle@epfl.ch> | 2008-05-27 09:15:38 +0000 |
---|---|---|
committer | jeberle <jeberle@epfl.ch> | 2008-05-27 09:15:38 +0000 |
commit | 859f7497e1be11fb81e4678990fccdbc093ac403 (patch) | |
tree | 7e3d6b486924917bfb0837220500287ec64e1ed3 /src/dotnet-library | |
parent | a480d4381e2f49479552a8b3f14b82618b54e8e1 (diff) | |
download | scala-859f7497e1be11fb81e4678990fccdbc093ac403.tar.gz scala-859f7497e1be11fb81e4678990fccdbc093ac403.tar.bz2 scala-859f7497e1be11fb81e4678990fccdbc093ac403.zip |
text.Document for .NET target (using System.IO....
text.Document for .NET target (using System.IO.TextWriter)
Diffstat (limited to 'src/dotnet-library')
-rw-r--r-- | src/dotnet-library/scala/text/Document.scala | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/src/dotnet-library/scala/text/Document.scala b/src/dotnet-library/scala/text/Document.scala index ee6cedacd3..0a46b06fe6 100644 --- a/src/dotnet-library/scala/text/Document.scala +++ b/src/dotnet-library/scala/text/Document.scala @@ -1 +1,122 @@ -/* Document does not exist for the dotnet target */ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2007, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Document.scala 11950 2007-06-08 12:08:26Z michelou $ + + +package scala.text + + +import System.IO.TextWriter + +case object DocNil extends Document +case object DocBreak extends Document +case class DocText(txt: String) extends Document +case class DocGroup(doc: Document) extends Document +case class DocNest(indent: Int, doc: Document) extends Document +case class DocCons(hd: Document, tl: Document) extends Document + +/** + * A basic pretty-printing library, based on Lindig's strict version + * of Wadler's adaptation of Hughes' pretty-printer. + * + * @author Michel Schinz + * @version 1.0 + */ +abstract class Document { + def ::(hd: Document): Document = DocCons(hd, this) + def ::(hd: String): Document = DocCons(DocText(hd), this) + def :/:(hd: Document): Document = hd :: DocBreak :: this + def :/:(hd: String): Document = hd :: DocBreak :: this + + /** + * Format this document on <code>writer</code> and try to set line + * breaks so that the result fits in <code>width</code> columns. + * + * @param width ... + * @param writer ... + */ + def format(width: Int, writer: TextWriter) { + type FmtState = (Int, Boolean, Document) + + def fits(w: Int, state: List[FmtState]): Boolean = state match { + case _ if w < 0 => + false + case List() => + true + case (_, _, DocNil) :: z => + fits(w, z) + case (i, b, DocCons(h, t)) :: z => + fits(w, (i,b,h) :: (i,b,t) :: z) + case (_, _, DocText(t)) :: z => + fits(w - t.length(), z) + case (i, b, DocNest(ii, d)) :: z => + fits(w, (i + ii, b, d) :: z) + case (_, false, DocBreak) :: z => + fits(w - 1, z) + case (_, true, DocBreak) :: z => + true + case (i, _, DocGroup(d)) :: z => + fits(w, (i, false, d) :: z) + } + + def spaces(n: Int) { + var rem = n + while (rem >= 16) { writer Write " "; rem -= 16 } + if (rem >= 8) { writer Write " "; rem -= 8 } + if (rem >= 4) { writer Write " "; rem -= 4 } + if (rem >= 2) { writer Write " "; rem -= 2} + if (rem == 1) { writer Write " " } + } + + def fmt(k: Int, state: List[FmtState]): Unit = state match { + case List() => () + case (_, _, DocNil) :: z => + fmt(k, z) + case (i, b, DocCons(h, t)) :: z => + fmt(k, (i, b, h) :: (i, b, t) :: z) + case (i, _, DocText(t)) :: z => + writer Write t + fmt(k + t.length(), z) + case (i, b, DocNest(ii, d)) :: z => + fmt(k, (i + ii, b, d) :: z) + case (i, true, DocBreak) :: z => + writer Write "\n" + spaces(i); + fmt(i, z) + case (i, false, DocBreak) :: z => + writer Write " " + fmt(k + 1, z) + case (i, b, DocGroup(d)) :: z => + val fitsFlat = fits(width - k, (i, false, d) :: z) + fmt(k, (i, !fitsFlat, d) :: z) + } + + fmt(0, (0, false, DocGroup(this)) :: Nil) + } +} + +object Document { + /** The empty document */ + def empty = DocNil + + /** A break, which will either be turned into a space or a line break */ + def break = DocBreak + + /** A document consisting of some text literal */ + def text(s: String): Document = DocText(s) + + /** + * A group, whose components will either be printed with all breaks + * rendered as spaces, or with all breaks rendered as line breaks. + */ + def group(d: Document): Document = DocGroup(d) + + /** A nested document, which will be indented as specified. */ + def nest(i: Int, d: Document): Document = DocNest(i, d) +} |