Handle escape codes in text for centering
This commit is contained in:
parent
2dc7e0a0e4
commit
8111309560
|
@ -18,29 +18,30 @@ case class Theme(styles: Map[String, fansi.Attrs], figletFonts: Map[String, Stri
|
||||||
def ++(newFonts: Map[String, String])(implicit d: DummyImplicit) = copy(figletFonts = figletFonts ++ newFonts)
|
def ++(newFonts: Map[String, String])(implicit d: DummyImplicit) = copy(figletFonts = figletFonts ++ newFonts)
|
||||||
|
|
||||||
object Theme:
|
object Theme:
|
||||||
given default: Theme = Theme(Map(
|
given default: Theme = Theme(
|
||||||
|
Map(
|
||||||
"titleLine" -> (fansi.Bold.On ++ fansi.Color.DarkGray),
|
"titleLine" -> (fansi.Bold.On ++ fansi.Color.DarkGray),
|
||||||
"code" -> fansi.Color.Yellow
|
"code" -> fansi.Color.Yellow,
|
||||||
),
|
),
|
||||||
Map("titleLine" -> "smbraille")
|
Map("titleLine" -> "smbraille"),
|
||||||
)
|
)
|
||||||
|
|
||||||
object Format:
|
object Format:
|
||||||
def alignRight(str: String, padding: Int = 2) =" " * (columns - str.length - padding) + str + " " * padding
|
def alignRight(str: String, padding: Int = 2) = " " * (columns - str.length - padding) + str + " " * padding
|
||||||
|
|
||||||
def center(str: String) = " " * ((columns - str.length) / 2) + str
|
def center(str: String) = " " * ((columns - str.length) / 2) + str
|
||||||
|
|
||||||
def figlet(str: String, font: String):String = new String(%%("figlet", "-t", "-f", font, str)().out.bytes)
|
def figlet(str: String, font: String): String = new String(%%("figlet", "-t", "-f", font, str)().out.bytes)
|
||||||
|
|
||||||
def centerLines(str: String) = str.split("\n").map(center).mkString("\n")
|
def centerLines(str: String) = str.split("\n").map(center).mkString("\n")
|
||||||
def centerBlock(str: String) =
|
def centerBlock(str: String) =
|
||||||
val lines = str.split("\n")
|
val lines = str.split("\n")
|
||||||
val maxLen = lines.map(_.length).max
|
val maxLen = lines.map(s => Terminal.stripEscapes(s).length).max
|
||||||
val pad = " " * ((columns - maxLen) / 2)
|
val pad = " " * ((columns - maxLen) / 2)
|
||||||
lines.map(pad + _).mkString("\n")
|
lines.map(pad + _).mkString("\n")
|
||||||
|
|
||||||
def distribute(texts: String*) =
|
def distribute(texts: String*) =
|
||||||
val totalPad = columns - texts.map(_.length).sum
|
val totalPad = columns - texts.map(s => Terminal.stripEscapes(s).length).sum
|
||||||
val numPads = texts.size - 1
|
val numPads = texts.size - 1
|
||||||
val pad = " " * (totalPad / numPads)
|
val pad = " " * (totalPad / numPads)
|
||||||
texts.init.mkString(pad) + pad + " " * (totalPad % numPads) + texts.last
|
texts.init.mkString(pad) + pad + " " * (totalPad % numPads) + texts.last
|
||||||
|
|
|
@ -210,7 +210,7 @@ object TypedCommand:
|
||||||
c => runProcess(Vector(shell, "-c", c.mkString(" ")))
|
c => runProcess(Vector(shell, "-c", c.mkString(" ")))
|
||||||
|
|
||||||
def runInteractive(using Path): Vector[String] => String =
|
def runInteractive(using Path): Vector[String] => String =
|
||||||
c => { os.proc(c).call(); "" }
|
c => { os.proc(c).call(stdin = os.Inherit, stdout = os.Inherit, stderr = os.Inherit); "" }
|
||||||
|
|
||||||
def apply(cmd: String*)(using Path): TypedCommand[Vector[String]] =
|
def apply(cmd: String*)(using Path): TypedCommand[Vector[String]] =
|
||||||
TypedCommand(run, cmd.mkString(" "), cmd.toVector)
|
TypedCommand(run, cmd.mkString(" "), cmd.toVector)
|
||||||
|
|
|
@ -4,24 +4,21 @@ import os.Path
|
||||||
|
|
||||||
trait Templates:
|
trait Templates:
|
||||||
def titleLine(title: String)(using theme: Theme) = Paragraph(
|
def titleLine(title: String)(using theme: Theme) = Paragraph(
|
||||||
"\n" + Format
|
"\n" + Format.figlet(title, theme.font("titleLine", "pagga")).block.blue + "\n",
|
||||||
.figlet(title, theme.font("titleLine", "pagga"))
|
|
||||||
.block
|
|
||||||
.blue + "\n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def header(using theme: Theme) = Meta((p, pos) => {
|
def header(using theme: Theme) = Meta((p, pos) => {
|
||||||
val left = p.meta.getOrElse("author", "")
|
val left = p.meta.getOrElse("author", "")
|
||||||
val center = p.meta.getOrElse("title", "")
|
val center = p.meta.getOrElse("title", "")
|
||||||
val right = s"${pos} / ${p.slides.size - 1}"
|
val right = s"${pos + 1} / ${p.slides.size}"
|
||||||
theme.style("titleLine")(Format.distribute(left, center, right)).text
|
theme.style("titleLine")(Format.distribute(left, center, right)).text
|
||||||
})
|
})
|
||||||
|
|
||||||
def slide(title: String)(slides: Slide*)(using Theme) = Group(
|
def slide(title: String)(slides: Slide*)(using Theme) = Group(
|
||||||
Clear :: header :: titleLine(title) :: slides.toList
|
Clear :: header :: titleLine(title) :: slides.toList,
|
||||||
)
|
)
|
||||||
def slide(slides: Slide*)(using Theme) = Group(
|
def slide(slides: Slide*)(using Theme) = Group(
|
||||||
Clear :: header :: slides.toList
|
Clear :: header :: slides.toList,
|
||||||
)
|
)
|
||||||
|
|
||||||
def markdown(title: String, content: Path)(using Theme) = slide(title)(
|
def markdown(title: String, content: Path)(using Theme) = slide(title)(
|
||||||
|
@ -30,11 +27,12 @@ trait Templates:
|
||||||
"/usr/bin/mdcat",
|
"/usr/bin/mdcat",
|
||||||
"--columns",
|
"--columns",
|
||||||
(columns * 0.8).toInt.toString,
|
(columns * 0.8).toInt.toString,
|
||||||
content.toString
|
content.toString,
|
||||||
)(using os.pwd).block
|
)(using os.pwd).block,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val --- = Paragraph(("═" * columns).yellow.toString)
|
lazy val --- = Paragraph(("═" * columns).yellow.toString)
|
||||||
|
end Templates
|
||||||
|
|
||||||
/* vim:set tw=120: */
|
/* vim:set tw=120: */
|
||||||
|
|
|
@ -64,7 +64,11 @@ object Terminal:
|
||||||
def csi = if (isTmux) "\u001bPtmux\u001b\u001b[" else "\u001b["
|
def csi = if (isTmux) "\u001bPtmux\u001b\u001b[" else "\u001b["
|
||||||
def osc = if (isTmux) "\u001bPtmux\u001b\u001b]" else "\u001b]"
|
def osc = if (isTmux) "\u001bPtmux\u001b\u001b]" else "\u001b]"
|
||||||
def apc = if (isTmux) "\u001bPtmux;\u001b\u001b_" else "\u001b_"
|
def apc = if (isTmux) "\u001bPtmux;\u001b\u001b_" else "\u001b_"
|
||||||
def st = if (isTmux) "\u0007\u001b\\" else "\u0007"
|
def st = if (isTmux) "\u0007\u001b\\" else "\u001b\\"
|
||||||
|
|
||||||
|
def stripEscapes(str: String) =
|
||||||
|
// match CSI until letter or OSC/APC until ST
|
||||||
|
str.replaceAll("\u001b(\\[[^a-zA-Z]*[a-zA-Z]|(\\]|_).*?(\u0007|\u001b\\\\))", "")
|
||||||
|
|
||||||
def hideCursor() = print(s"${csi}?25l")
|
def hideCursor() = print(s"${csi}?25l")
|
||||||
def showCursor() = print(s"${csi}?25h")
|
def showCursor() = print(s"${csi}?25h")
|
||||||
|
|
Loading…
Reference in a new issue