fix: presentation navigation now works correctly again
This commit is contained in:
parent
3ad18addb0
commit
add8e9a714
125
copret/src/Presentation.scala
Normal file
125
copret/src/Presentation.scala
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package de.qwertyuiop.copret
|
||||||
|
|
||||||
|
import os.Path
|
||||||
|
import Terminal.*
|
||||||
|
import syntax.*
|
||||||
|
|
||||||
|
case class Presentation(
|
||||||
|
slides: Vector[Slide],
|
||||||
|
meta: Map[String, String] = Map.empty,
|
||||||
|
):
|
||||||
|
def start(using keymap: Keymap = Keymap.default) =
|
||||||
|
Terminal.enterRawMode()
|
||||||
|
Terminal.hideCursor()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
run()
|
||||||
|
|
||||||
|
import Presentation._
|
||||||
|
def run()(using keymap: Keymap) =
|
||||||
|
logger.info("Starting presentation")
|
||||||
|
import SlideAction.*
|
||||||
|
@annotation.tailrec
|
||||||
|
def rec(currentPos: Int, action: SlideAction): Unit =
|
||||||
|
logger.info(s"Executing slide $currentPos with action $action")
|
||||||
|
|
||||||
|
inline def redraw() =
|
||||||
|
logger.info(s"redrawing ${currentPos}")
|
||||||
|
// rec(currentPos - 1, QuickNext)
|
||||||
|
navigate(currentPos, true, 0)(executeQuick)
|
||||||
|
|
||||||
|
inline def navigate(pos: Int, condition: Boolean, direction: Int)(
|
||||||
|
executor: Int => Slide => Unit,
|
||||||
|
) =
|
||||||
|
logger.info(s"Navigating from ${pos}, condition is $condition, direction is ${direction}")
|
||||||
|
if condition then
|
||||||
|
executor(pos + direction)(slides(pos + direction))
|
||||||
|
rec(pos + direction, waitkey)
|
||||||
|
else rec(pos, waitkey)
|
||||||
|
|
||||||
|
inline def runInteractive(cmd: Vector[String], path: Path) =
|
||||||
|
logger.info(s"Running interactive command ${cmd} with working directory ${path}")
|
||||||
|
Terminal.showCursor()
|
||||||
|
try os.proc(cmd).call(cwd = path)
|
||||||
|
catch case _ => ()
|
||||||
|
Terminal.hideCursor()
|
||||||
|
Terminal.clear()
|
||||||
|
redraw()
|
||||||
|
|
||||||
|
action match
|
||||||
|
case Start => navigate(0, true, 0)(executeSlide)
|
||||||
|
case Next => navigate(currentPos, currentPos + 1 < slides.size, 1)(executeSlide)
|
||||||
|
case QuickNext => navigate(currentPos, currentPos + 1 < slides.size, 1)(executeQuick)
|
||||||
|
case Prev => navigate(currentPos, currentPos > 0, -1)(executeQuick)
|
||||||
|
case Interactive(cmd, path) => runInteractive(cmd, path)
|
||||||
|
|
||||||
|
case Goto(target) =>
|
||||||
|
for i <- 0 until target
|
||||||
|
do executeSilent(i)()
|
||||||
|
rec(target - 1, QuickNext)
|
||||||
|
|
||||||
|
case GotoSelect =>
|
||||||
|
promptSlide() match
|
||||||
|
case Some(i) => rec(currentPos, Goto(i))
|
||||||
|
case None => redraw()
|
||||||
|
|
||||||
|
case Help =>
|
||||||
|
Terminal.clear()
|
||||||
|
println(keymap.help)
|
||||||
|
waitkey
|
||||||
|
redraw()
|
||||||
|
|
||||||
|
case Other(codes) =>
|
||||||
|
Terminal.printStatus(action.show)
|
||||||
|
rec(currentPos, waitkey)
|
||||||
|
|
||||||
|
case Quit =>
|
||||||
|
Terminal.showCursor()
|
||||||
|
end match
|
||||||
|
end rec
|
||||||
|
rec(0, Start)
|
||||||
|
end run
|
||||||
|
|
||||||
|
def promptSlide() =
|
||||||
|
val maxSlide = slides.size
|
||||||
|
prompt(s"Go to slide (1 - $maxSlide):", _.toIntOption)(
|
||||||
|
(res, input) => res.filter((1 to maxSlide).contains).isEmpty && input.nonEmpty,
|
||||||
|
in => s"No such slide: $in (empty input to abort)",
|
||||||
|
).map(_ - 1)
|
||||||
|
|
||||||
|
def executeSlide(pos: Int)(
|
||||||
|
slide: Slide = slides(pos),
|
||||||
|
): Unit = slide match
|
||||||
|
case Paragraph(contents) => println(contents)
|
||||||
|
case Clear => Terminal.clear()
|
||||||
|
case PauseKey => waitkey(using Keymap.empty)
|
||||||
|
case Pause(msec) => Thread.sleep(msec)
|
||||||
|
case incMd @ IncludeMarkdown(_) => println(incMd.markdownBlock())
|
||||||
|
case Image(file, None) => println(KittyGraphicsProtocol.showImage(file))
|
||||||
|
case Image(file, Some(ImageSize(w, h, aspect))) =>
|
||||||
|
println(KittyGraphicsProtocol.showImage(file)) // TODO
|
||||||
|
case cmd: TypedCommand[_] => cmd.show()
|
||||||
|
case Silent(actions) => actions()
|
||||||
|
case Group(slides) => slides.foreach(executeSlide(pos))
|
||||||
|
case lios @ LazyIOSlide(_, display) => executeSlide(pos)(lios.genSlide())
|
||||||
|
case Meta(genSlide) => executeSlide(pos)(genSlide(this, pos))
|
||||||
|
|
||||||
|
def executeQuick(pos: Int)(
|
||||||
|
slide: Slide = slides(pos),
|
||||||
|
): Unit = slide match
|
||||||
|
case Pause(msec) => ()
|
||||||
|
case PauseKey => ()
|
||||||
|
case cmd: TypedCommand[_] => cmd.quickShow()
|
||||||
|
case Group(slides) => slides.foreach(executeQuick(pos))
|
||||||
|
case lios @ LazyIOSlide(_, display) => executeQuick(pos)(lios.genSlide())
|
||||||
|
case _ => executeSlide(pos)(slide)
|
||||||
|
|
||||||
|
def executeSilent(pos: Int)(
|
||||||
|
slide: Slide = slides(pos),
|
||||||
|
): Unit = slide match
|
||||||
|
case cmd: TypedCommand[_] => cmd.force()
|
||||||
|
case Group(slides) => slides.foreach(executeSilent(pos))
|
||||||
|
case lios @ LazyIOSlide(_, display) =>
|
||||||
|
executeSilent(pos)(lios.genSlide())
|
||||||
|
case Paragraph(_) | Image(_, _) | Clear | IncludeMarkdown(_) | Meta(_) => ()
|
||||||
|
case _ => executeQuick(pos)(slide)
|
||||||
|
end Presentation
|
16
copret/src/logger.scala
Normal file
16
copret/src/logger.scala
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package de.qwertyuiop.copret
|
||||||
|
|
||||||
|
object logger:
|
||||||
|
import java.util.logging.*
|
||||||
|
val log = Logger.getLogger("copret")
|
||||||
|
val fh = FileHandler("/tmp/copret.log")
|
||||||
|
log.addHandler(fh)
|
||||||
|
log.setUseParentHandlers(false)
|
||||||
|
System.setProperty(
|
||||||
|
"java.util.logging.SimpleFormatter.format",
|
||||||
|
"%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS.%1$tN %1$Tp %2$s: %4$s: %5$s%6$s%n",
|
||||||
|
)
|
||||||
|
fh.setFormatter(new SimpleFormatter())
|
||||||
|
fh.setLevel(Level.ALL)
|
||||||
|
|
||||||
|
export log.*
|
|
@ -4,119 +4,6 @@ import os.Path
|
||||||
import Terminal.*
|
import Terminal.*
|
||||||
import syntax.*
|
import syntax.*
|
||||||
|
|
||||||
case class Presentation(
|
|
||||||
slides: Vector[Slide],
|
|
||||||
meta: Map[String, String] = Map.empty,
|
|
||||||
):
|
|
||||||
def start(using keymap: Keymap = Keymap.default) =
|
|
||||||
Terminal.enterRawMode()
|
|
||||||
Terminal.hideCursor()
|
|
||||||
Thread.sleep(1000)
|
|
||||||
run()
|
|
||||||
|
|
||||||
import Presentation._
|
|
||||||
def run()(using keymap: Keymap) =
|
|
||||||
import SlideAction.*
|
|
||||||
@annotation.tailrec
|
|
||||||
def rec(pos: Int, action: SlideAction): Unit =
|
|
||||||
|
|
||||||
inline def redraw() = rec(pos - 1, QuickNext)
|
|
||||||
|
|
||||||
inline def navigate(pos: Int, condition: Boolean, direction: Int)(
|
|
||||||
executor: Int => Slide => Unit,
|
|
||||||
) =
|
|
||||||
if condition then
|
|
||||||
executor(pos + direction)(slides(pos))
|
|
||||||
rec(pos + direction, waitkey)
|
|
||||||
else rec(pos, waitkey)
|
|
||||||
|
|
||||||
inline def runInteractive(cmd: Vector[String], path: Path) =
|
|
||||||
Terminal.showCursor()
|
|
||||||
try os.proc(cmd).call(cwd = path)
|
|
||||||
catch case _ => ()
|
|
||||||
Terminal.hideCursor()
|
|
||||||
Terminal.clear()
|
|
||||||
redraw()
|
|
||||||
|
|
||||||
action match
|
|
||||||
case Start => navigate(0, true, 0)(executeSlide)
|
|
||||||
case Next => navigate(pos, pos + 1 < slides.size, 1)(executeSlide)
|
|
||||||
case QuickNext => navigate(pos, pos + 1 < slides.size, 1)(executeQuick)
|
|
||||||
case Prev => navigate(pos, pos > 0, -1)(executeQuick)
|
|
||||||
case Interactive(cmd, path) => runInteractive(cmd, path)
|
|
||||||
|
|
||||||
case Goto(target) =>
|
|
||||||
for i <- 0 until target
|
|
||||||
do executeSilent(i)()
|
|
||||||
rec(target - 1, QuickNext)
|
|
||||||
|
|
||||||
case GotoSelect =>
|
|
||||||
promptSlide() match
|
|
||||||
case Some(i) => rec(pos, Goto(i))
|
|
||||||
case None => redraw()
|
|
||||||
|
|
||||||
case Help =>
|
|
||||||
Terminal.clear()
|
|
||||||
println(keymap.help)
|
|
||||||
waitkey
|
|
||||||
redraw()
|
|
||||||
|
|
||||||
case Other(codes) =>
|
|
||||||
Terminal.printStatus(action.show)
|
|
||||||
rec(pos, waitkey)
|
|
||||||
|
|
||||||
case Quit =>
|
|
||||||
Terminal.showCursor()
|
|
||||||
end match
|
|
||||||
end rec
|
|
||||||
rec(0, Start)
|
|
||||||
end run
|
|
||||||
|
|
||||||
def promptSlide() =
|
|
||||||
val maxSlide = slides.size - 1
|
|
||||||
prompt(s"Go to slide (0 - $maxSlide):", _.toIntOption)(
|
|
||||||
(res, input) => res.filter((0 to maxSlide).contains).isEmpty && input.nonEmpty,
|
|
||||||
in => s"No such slide: $in (empty input to abort)",
|
|
||||||
)
|
|
||||||
|
|
||||||
def executeSlide(pos: Int)(
|
|
||||||
slide: Slide = slides(pos),
|
|
||||||
): Unit = slide match
|
|
||||||
case Paragraph(contents) => println(contents)
|
|
||||||
case Clear => Terminal.clear()
|
|
||||||
case PauseKey => waitkey(using Keymap.empty)
|
|
||||||
case Pause(msec) => Thread.sleep(msec)
|
|
||||||
case incMd @ IncludeMarkdown(_) => println(incMd.markdownBlock())
|
|
||||||
case Image(file, None) => println(KittyGraphicsProtocol.showImage(file))
|
|
||||||
case Image(file, Some(ImageSize(w, h, aspect))) =>
|
|
||||||
println(KittyGraphicsProtocol.showImage(file)) // TODO
|
|
||||||
case cmd: TypedCommand[_] => cmd.show()
|
|
||||||
case Silent(actions) => actions()
|
|
||||||
case Group(slides) => slides.foreach(executeSlide(pos))
|
|
||||||
case lios @ LazyIOSlide(_, display) => executeSlide(pos)(lios.genSlide())
|
|
||||||
case Meta(genSlide) => executeSlide(pos)(genSlide(this, pos))
|
|
||||||
|
|
||||||
def executeQuick(pos: Int)(
|
|
||||||
slide: Slide = slides(pos),
|
|
||||||
): Unit = slide match
|
|
||||||
case Pause(msec) => ()
|
|
||||||
case PauseKey => ()
|
|
||||||
case cmd: TypedCommand[_] => cmd.quickShow()
|
|
||||||
case Group(slides) => slides.foreach(executeQuick(pos))
|
|
||||||
case lios @ LazyIOSlide(_, display) => executeQuick(pos)(lios.genSlide())
|
|
||||||
case _ => executeSlide(pos)(slide)
|
|
||||||
|
|
||||||
def executeSilent(pos: Int)(
|
|
||||||
slide: Slide = slides(pos),
|
|
||||||
): Unit = slide match
|
|
||||||
case cmd: TypedCommand[_] => cmd.force()
|
|
||||||
case Group(slides) => slides.foreach(executeSilent(pos))
|
|
||||||
case lios @ LazyIOSlide(_, display) =>
|
|
||||||
executeSilent(pos)(lios.genSlide())
|
|
||||||
case Paragraph(_) | Image(_, _) | Clear | IncludeMarkdown(_) | Meta(_) => ()
|
|
||||||
case _ => executeQuick(pos)(slide)
|
|
||||||
end Presentation
|
|
||||||
|
|
||||||
case class ImageSize(width: Double, height: Double, keepAspect: Boolean)
|
case class ImageSize(width: Double, height: Double, keepAspect: Boolean)
|
||||||
|
|
||||||
sealed trait Slide
|
sealed trait Slide
|
||||||
|
@ -209,14 +96,14 @@ object TypedCommand:
|
||||||
def runShell(using Path): Vector[String] => String =
|
def runShell(using Path): Vector[String] => String =
|
||||||
c => runProcess(Vector(shell, "-c", c.mkString(" ")))
|
c => runProcess(Vector(shell, "-c", c.mkString(" ")))
|
||||||
|
|
||||||
def runInteractive(using Path): Vector[String] => String =
|
def runInteractive(using cwd: Path): Vector[String] => String =
|
||||||
c => { os.proc(c).call(stdin = os.Inherit, stdout = os.Inherit, stderr = os.Inherit); "" }
|
c => { os.proc(c).call(stdin = os.Inherit, stdout = os.Inherit, stderr = os.Inherit, cwd = cwd); "" }
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
def apply[T](exec: T => String, display: String, cmd: T) =
|
def apply[T](exec: T => String, display: String, cmd: T): TypedCommand[T] =
|
||||||
new TypedCommand(exec, display, cmd, false, false)
|
TypedCommand(exec, display, cmd, false, false)
|
||||||
|
|
||||||
def shell(cmd: String*)(using Path): TypedCommand[Vector[String]] =
|
def shell(cmd: String*)(using Path): TypedCommand[Vector[String]] =
|
||||||
TypedCommand(runShell, cmd.mkString(" "), cmd.toVector)
|
TypedCommand(runShell, cmd.mkString(" "), cmd.toVector)
|
||||||
|
|
Loading…
Reference in a new issue