All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.meta.prettyprinters.Show.scala Maven / Gradle / Ivy

Go to download

Bag of private and public helpers used in scala.meta's APIs and implementations

The newest version!
package scala.meta
package prettyprinters

import org.scalameta.internal.ScalaCompat.EOL

import scala.language.experimental.macros
import scala.language.implicitConversions

trait Show[-T] {
  def apply(t: T): Show.Result
}

private[meta] object Show {
  sealed abstract class Result {
    def desc: String
    override def toString = {
      val sb = new StringBuilder
      var indentation = 0
      def nl(obj: Result) = {
        sb.append(EOL)
        sb.append("  " * indentation)
        loop(obj)
      }
      def loop(obj: Result): Unit = obj match {
        case None => // do nothing
        case obj: Str => sb.append(obj.value)
        case obj: Sequence => obj.xs.foreach(loop)
        case obj: Repeat =>
          val sep = obj.sep
          val sbLenInit = sb.length
          obj.xs.foreach { x =>
            val sbLen = sb.length
            loop(x)
            if (sbLen != sb.length) sb.append(sep)
          }
          val sbLenLast = sb.length
          if (sbLenInit != sbLenLast) sb.setLength(sbLenLast - sep.length)
        case obj: Indent => indentation += 1; nl(obj.res); indentation -= 1
        case obj: Newline => nl(obj.res)
        case obj: Meta => loop(obj.res)
        case obj: Wrap =>
          val sbLenInit = sb.length
          sb.append(obj.prefix)
          val sbLen = sb.length
          loop(obj.res)
          if (sbLen != sb.length) sb.append(obj.suffix) else sb.setLength(sbLenInit)
        case result: Function => loop(result.fn(sb))
      }
      loop(this)
      sb.toString
    }
    final def isEmpty: Boolean = this eq None
  }

  final case object None extends Result {
    override def desc: String = "None"
  }
  final case class Str(value: String) extends Result {
    override def desc: String = s"Str($value)"
  }
  final case class Sequence(xs: Result*) extends Result {
    override def desc: String = s"Sequence(#${xs.length})"
  }
  final case class Repeat(xs: Seq[Result], sep: String) extends Result {
    override def desc: String = s"Repeat(#${xs.length}, s=$sep)"
  }
  final case class Indent(res: Result) extends Result {
    override def desc: String = s"Indent(r=${res.desc})"
  }
  final case class Newline(res: Result) extends Result {
    override def desc: String = s"Newline(r=${res.desc})"
  }
  final case class Meta(data: Any, res: Result) extends Result {
    override def desc: String = s"Meta(d=$data, r=${res.desc})"
  }
  final case class Wrap(prefix: String, res: Result, suffix: String) extends Result {
    override def desc: String = s"Wrap(p=$prefix, r=${res.desc}, s=$suffix)"
  }
  final case class Function(fn: StringBuilder => Result) extends Result {
    override def desc: String = s"Function(...)"
  }

  def apply[T](f: T => Result): Show[T] = new Show[T] {
    def apply(input: T): Result = f(input)
  }

  def mkseq(xs: Result*): Result = xs.filter(_ ne None) match {
    case Seq() => None
    case Seq(head) => head
    case res => Sequence(res: _*)
  }
  def sequence[T](xs: T*): Result = macro scala.meta.internal.prettyprinters.ShowMacros.sequence

  def indent(res: Result): Result = if (res eq None) None else Indent(res)
  def indent[T](x: T)(implicit show: Show[T]): Result = indent(show(x))

  def repeat[T](xs: Seq[T], sep: String = "")(implicit show: Show[T]): Result =
    repeat(sep)(xs.map(show(_)): _*)
  def repeat[T](xs: Seq[T], prefix: String, sep: String, suffix: String)(implicit
      show: Show[T]
  ): Result = wrap(prefix, repeat(xs, sep), suffix)

  def repeat(xs: Result*): Result = repeat("")(xs: _*)
  def repeat(sep: String)(xs: Result*): Result = {
    val results = xs.filter(_ ne None)
    if (results.isEmpty) None else Repeat(results, sep)
  }
  def repeat(prefix: String, sep: String, suffix: String)(xs: Result*): Result =
    wrap(prefix, repeat(sep)(xs: _*), suffix)

  def newline(res: Result): Result = if (res eq None) None else Newline(res)
  def newline[T](x: T)(implicit show: Show[T]): Result = newline(show(x))

  def meta(data: Any, res: Result): Result = if (res eq None) None else Meta(data, res)
  def meta[T](data: Any, xs: T*): Result = macro scala.meta.internal.prettyprinters.ShowMacros.meta

  // wrap if non-empty
  def wrap[T](x: T, suffix: String)(implicit show: Show[T]): Result = wrap("", x, suffix)
  def wrap[T](prefix: String, x: T)(implicit show: Show[T]): Result = wrap(prefix, x, "")
  def wrap[T](prefix: => String, x: T, suffix: => String)(implicit show: Show[T]): Result =
    wrap(prefix, show(x), suffix)
  def wrap(prefix: => String, res: Result, suffix: => String): Result =
    if (res eq None) None else Wrap(prefix, res, suffix)

  // wrap if cond, even if value ends up being none
  def wrap[T](x: T, suffix: => String, cond: Boolean)(implicit show: Show[T]): Result =
    wrap("", x, suffix, cond)
  def wrap[T](prefix: => String, x: T, cond: Boolean)(implicit show: Show[T]): Result =
    wrap(prefix, x, "", cond)
  def wrap[T](prefix: => String, x: T, suffix: => String, cond: Boolean)(implicit
      show: Show[T]
  ): Result = if (!cond) x else mkseq(prefix, x, suffix)

  def opt[T](x: => T, cond: Boolean)(implicit show: Show[T]): Result = if (cond) x else None
  def opt[T](x: Option[T])(implicit show: Show[T]): Result = x.fold[Result](None)(show(_))
  def opt[T](x: Option[T], suffix: => Result)(implicit show: Show[T]): Result = x
    .fold[Result](None)(x => mkseq(x, suffix))
  def opt[T](prefix: => Result, x: Option[T])(implicit show: Show[T]): Result = x
    .fold[Result](None)(x => mkseq(prefix, x))
  def opt[T](prefix: => Result, x: Option[T], suffix: => Result)(implicit show: Show[T]): Result = x
    .fold[Result](None)(x => mkseq(prefix, x, suffix))

  def alt(a: Result, b: => Result): Result = if (a ne None) a else b
  def alt[A, B](a: A, b: => B)(implicit showA: Show[A], showB: Show[B]): Result =
    alt(showA(a), showB(b))

  def function(fn: StringBuilder => Result): Result = Function(fn)

  implicit def printResult[R <: Result]: Show[R] = apply(identity)
  implicit def printString[T <: String]: Show[T] = apply(Show.Str(_))
  implicit def stringAsResult(value: String): Result = if (value.isEmpty) None else Show.Str(value)
  implicit def showAsResult[T](x: T)(implicit show: Show[T]): Result = show(x)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy