Skip to content

Instantly share code, notes, and snippets.

@bishabosha
Last active April 16, 2019 23:49
Show Gist options
  • Save bishabosha/48551d3679ad1de0096c0ae51692152c to your computer and use it in GitHub Desktop.
Save bishabosha/48551d3679ad1de0096c0ae51692152c to your computer and use it in GitHub Desktop.
Dotty tail recursive object pretty print - naive indentation
type StackT = List[String]
type StatT = StackT => StackT
type ProgT = List[StatT]
def prettyPrint(
a: Any,
indentSize: Int = 2,
maxElementWidth: Int = 60,
depth: Int = 0): String = {
@tailrec
def pretty0(prog: ProgT, terms: List[(Int, Any)]): ProgT = {
def indent(depth: Int) = " " * depth * indentSize
def fieldIndent(depth: Int) = indent(depth) + (" " * indentSize)
terms match {
case Nil => prog
case (depth, term) :: terms => term match {
case s: String =>
val str = Console.GREEN + s + Console.RESET
pretty0((stack => indent(depth) + str :: stack) :: prog, terms)
case xs: Array[_] =>
val stat: StatT = { stack =>
val (xs1, rest) = stack.splitAt(xs.size)
val str = xs1.mkString(
indent(depth) + "[\n", ",\n", "\n" + indent(depth) + "]")
str :: rest
}
pretty0(stat :: prog, xs.map((depth + 1,_)).toList ::: terms)
case xs: Iterable[_] =>
val stat: StatT = { stack =>
val (xs1, rest) = stack.splitAt(xs.size)
val str = xs1.mkString(
indent(depth) + "[\n", ",\n", "\n" + indent(depth) + "]")
str :: rest
}
pretty0(stat :: prog, xs.map((depth + 1,_)).toList ::: terms)
case p: Product =>
val prefix = Console.YELLOW + p.productPrefix + Console.RESET
val values = p.productIterator
val stat: StatT = { stack =>
if values.isEmpty then {
indent + prefix :: stack
} else {
val (values1, rest) = stack.splitAt(values.size)
val str = values1.mkString(
indent(depth) + s"$prefix(\n", ",\n", "\n" + indent(depth) + ")")
str :: rest
}
}
pretty0(stat :: prog, p.productIterator.map((depth + 1,_)).toList ::: terms)
case e: Enum => // singleton enums arent products
val str = Console.YELLOW + e + Console.RESET
pretty0((stack => indent(depth) + str :: stack) :: prog, terms)
case n: Number =>
val str = Console.RED + n.toString + Console.RESET
pretty0((stack => indent(depth) + str :: stack) :: prog, terms)
case n: Boolean =>
val str = Console.BLUE + n.toString + Console.RESET
pretty0((stack => indent(depth) + str :: stack) :: prog, terms)
case o =>
pretty0((stack => indent(depth) + o :: stack) :: prog, terms)
}
}
}
pretty0(List.empty, List((depth, a)))
.foldLeft(List.empty[String])((acc, f) => f(acc))
.head
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment