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

scribe.ANSI.scala Maven / Gradle / Ivy

The newest version!
package scribe

import scala.io.AnsiColor

object ANSI {
  private lazy val threadLocal = new ThreadLocal[Map[String, ANSI]] {
    override def initialValue(): Map[String, ANSI] = Map.empty
  }

  private val escCode: Char = 0x1B.toChar

  object bg {
    private def create(value: String): ANSI = ANSI(value, "bg", AnsiColor.RESET)

    lazy val Black: ANSI = create("")
    lazy val Blue: ANSI = create("")
    lazy val Cyan: ANSI = create("")
    lazy val Green: ANSI = create("")
    lazy val Magenta: ANSI = create("")
    lazy val Red: ANSI = create("")
    lazy val White: ANSI = create("")
    lazy val Yellow: ANSI = create("\u001b[43m")

    lazy val Gray: ANSI = create("\u001b[40;1m")
    lazy val BrightBlue: ANSI = create("\u001b[44;1m")
    lazy val BrightCyan: ANSI = create("\u001b[46;1m")
    lazy val BrightGreen: ANSI = create("\u001b[42;1m")
    lazy val BrightMagenta: ANSI = create("\u001b[45;1m")
    lazy val BrightRed: ANSI = create("\u001b[41;1m")
    lazy val BrightWhite: ANSI = create("\u001b[47;1m")
    lazy val BrightYellow: ANSI = create("\u001b[43;1m")
  }

  private def esc(suffix: String): String = s"$escCode[$suffix"
  private def esc(num: Int, suffix: String): String = esc(s"$num$suffix")
  private def esc(num1: Int, num2: Int, suffix: String): String = esc(s"$num1;$num2$suffix")

  object ctrl {
    private def create(count: Int, s: String): String = (0 until count).map(_ => s).mkString

    def Backspace(characters: Int = 1): String = create(characters, "\b")
    def ClearScreen: String = esc(2, "J")
    def CursorBack(characters: Int = 1): String = esc(characters, "D")
    def CursorDown(lines: Int = 1): String = esc(lines, "B")
    def CursorForward(characters: Int = 1): String = esc(characters, "C")
    def CursorUp(rows: Int = 1): String = esc(rows, "A")
    def CursorMove(row: Int, column: Int): String = esc(row, column, "f")
    def EraseLine: String = esc("K")
    def FormFeed: String = "\f"
    def NewLine: String = "\n"
    def Reset: String = AnsiColor.RESET
    lazy val RestorePosition: String = esc("u")
    lazy val Return: String = "\r"
    lazy val SavePosition: String = esc("s")
    def Tab: String = "\t"
  }

  object fg {
    private def create(value: String): ANSI = ANSI(value, "fg", AnsiColor.RESET)

    lazy val Black: ANSI = create("")
    lazy val Blue: ANSI = create("")
    lazy val Cyan: ANSI = create("")
    lazy val Green: ANSI = create("")
    lazy val Magenta: ANSI = create("")
    lazy val Red: ANSI = create("")
    lazy val White: ANSI = create("")
    lazy val Yellow: ANSI = create("")

    lazy val Gray: ANSI = create("")
    lazy val BrightBlue: ANSI = create("")
    lazy val BrightCyan: ANSI = create("")
    lazy val BrightGreen: ANSI = create("")
    lazy val BrightMagenta: ANSI = create("")
    lazy val BrightRed: ANSI = create("")
    lazy val BrightWhite: ANSI = create("")
    lazy val BrightYellow: ANSI = create("")
  }

  object fx {
    private def create(value: String): ANSI = ANSI(value, "fx", AnsiColor.RESET)

    lazy val Blink: ANSI = create("")
    lazy val Bold: ANSI = create("")
    lazy val Invisible: ANSI = create("")
    lazy val Italic: ANSI = create("")
    lazy val Reversed: ANSI = create("")
    lazy val Strikethrough: ANSI = create("")
    lazy val Underline: ANSI = create("")
  }
}

case class ANSI(ansi: String, `type`: String, default: String) {
  def apply(value: => String): String = {
    val map = ANSI.threadLocal.get()
    val previous = map.get(`type`)
    ANSI.threadLocal.set(map + (`type` -> this))
    val reset = previous.map(_.ansi).getOrElse(default)
    val end = if (reset == AnsiColor.RESET) {
      s"$reset${map.filterNot(_._1 == `type`).map(_._2.ansi).mkString}"
    } else {
      reset
    }
    try {
      s"$ansi$value$end"
    } finally {
      ANSI.threadLocal.set(map)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy