Refactor keymap to allow showing help

This commit is contained in:
Alexander Gehrke 2022-05-23 23:17:34 +02:00
parent 0acbca2e62
commit 18c0f6ea7a
2 changed files with 79 additions and 34 deletions

View file

@ -10,19 +10,37 @@ enum SlideAction:
case Next
case QuickNext
case Quit
case Help
case Interactive(cmd: Vector[String], wd: Path)
case Other(code: List[Int])
def show: String = this match
case Start => "go to first slide"
case Goto(slideIndex: Int) => s"jump directly to slide $slideIndex"
case GotoSelect => "jump to slide"
case Prev => "previous slide (skip animations)"
case Next => "next slide"
case QuickNext => "next slide (skip animations)"
case Quit => "quit"
case Help => "show help"
case Interactive(cmd: Vector[String], wd: Path) => s"execute command \"${cmd.mkString(" ")}\""
case Other(code: List[Int]) => s"Unknown key sequence: $code"
object SlideAction:
def runForeground(cmd: String*)(implicit wd: Path) = Interactive(cmd.toVector, wd)
import SlideAction.*
case class Keymap(bindings: Map[List[Int], SlideAction]):
def apply(keycode: List[Int]): SlideAction = bindings.getOrElse(keycode, Other(keycode))
case class Keymap(bindings: Map[Key, SlideAction]):
private val lookup = bindings.map((k,v) => k.codes -> v)
def apply(keycode: List[Int]): SlideAction = lookup.getOrElse(keycode, Other(keycode))
def extend(newBindings: Map[Key, SlideAction]) = Keymap(bindings ++ newBindings)
def ++(newBindings: Map[Key, SlideAction]) = extend(newBindings)
def help: String =
bindings.toSeq.sortBy(_._2.toString).map((k,v) => k.show.padTo(8, ' ') + " " + v.show).mkString("\n")
def extend(newBindings: Map[List[Int], SlideAction]) = Keymap(bindings ++ newBindings)
def ++(newBindings: Map[List[Int], SlideAction]) = Keymap(bindings ++ newBindings)
object Keymap:
val empty = Keymap(Map())
val default = Keymap(Map(
@ -30,53 +48,71 @@ object Keymap:
Key.Left -> Prev,
Key.PageUp -> Prev,
Key('k') -> Prev,
Key(' ') -> Next,
Key.Space -> Next,
Key('j') -> Next,
Key.Down -> QuickNext,
Key.Right -> QuickNext,
Key.PageDown -> QuickNext,
Key('q') -> Quit,
Key('g') -> Start,
Key.Enter -> Start,
Key('s') -> GotoSelect,
Key('?') -> Help,
))
enum Key:
case Code(name: String, codepoints: List[Int])
case Printable(char: Char)
def codes: List[Int] =
this match
case Code(_, cp) => cp
case Printable(char) => List(char.toInt)
def show: String =
this match
case Code(name, _) => name
case Printable(c) => c.toString
object Key:
def apply(char: Char): Key = Printable(char)
def apply(name: String, codepoints: Int*): Key = Code(name, codepoints.toList)
object codes:
val Esc = 27
val Backspace = 127
val Esc = List[Int](codes.Esc)
val Backspace = List[Int](codes.Backspace)
val Delete = List[Int](codes.Esc, '[', '3', '~')
val esc = 27
val backspace = 127
val PageUp = List[Int](codes.Esc, '[', '5', '~')
val PageDown = List[Int](codes.Esc, '[', '6', '~')
val Esc = Key("Escape", codes.esc)
val Backspace = Key("Backspace", codes.backspace)
val Delete = Key("Delete", codes.esc, '[', '3', '~')
val Home = List[Int](codes.Esc, '[', 'H')
val End = List[Int](codes.Esc, '[', 'F')
val PageUp = Key("PageUp", codes.esc, '[', '5', '~')
val PageDown = Key("PageDown", codes.esc, '[', '6', '~')
val F1 = List[Int](codes.Esc, 'P')
val F2 = List[Int](codes.Esc, 'Q')
val F3 = List[Int](codes.Esc, 'R')
val F4 = List[Int](codes.Esc, 'S')
val Home = Key("Home", codes.esc, '[', 'H')
val End = Key("End", codes.esc, '[', 'F')
val F5 = List[Int](codes.Esc, '1', '5', '~')
val F6 = List[Int](codes.Esc, '1', '7', '~')
val F7 = List[Int](codes.Esc, '1', '8', '~')
val F8 = List[Int](codes.Esc, '1', '9', '~')
val F1 = Key("F1", codes.esc, 'P')
val F2 = Key("F2", codes.esc, 'Q')
val F3 = Key("F3", codes.esc, 'R')
val F4 = Key("F4", codes.esc, 'S')
val F9 = List[Int](codes.Esc, '2', '0', '~')
val F10 = List[Int](codes.Esc, '2', '1', '~')
val F11 = List[Int](codes.Esc, '2', '3', '~')
val F12 = List[Int](codes.Esc, '2', '4', '~')
val F5 = Key("F5", codes.esc, '1', '5', '~')
val F6 = Key("F6", codes.esc, '1', '7', '~')
val F7 = Key("F7", codes.esc, '1', '8', '~')
val F8 = Key("F8", codes.esc, '1', '9', '~')
val Tab = List[Int]('\t')
val F9 = Key("F9", codes.esc, '2', '0', '~')
val F10 = Key("F10", codes.esc, '2', '1', '~')
val F11 = Key("F11", codes.esc, '2', '3', '~')
val F12 = Key("F12", codes.esc, '2', '4', '~')
val Up = List[Int](codes.Esc, '[', 'A')
val Down = List[Int](codes.Esc, '[', 'B')
val Right = List[Int](codes.Esc, '[', 'C')
val Left = List[Int](codes.Esc, '[', 'D')
val Space = Key("<space>", ' ')
val Tab = Key("<tab>", '\t')
val Enter = Key("<enter>", '\n')
def apply(char: Char): List[Int] = List(char.toInt)
val Up = Key("Up", codes.esc, '[', 'A')
val Down = Key("Down", codes.esc, '[', 'B')
val Right = Key("Right", codes.esc, '[', 'C')
val Left = Key("Left", codes.esc, '[', 'D')
/* vim:set tw=120: */

View file

@ -10,14 +10,14 @@ case class Presentation(slides: Vector[Slide], meta: Map[String, String] = Map.e
run()
import Presentation._
def run()(using Keymap) =
def run()(using keymap: Keymap) =
import SlideAction.*
@annotation.tailrec def rec(p: Presentation, pos: Int, action: SlideAction): Unit =
action match
case Start =>
executeSlide(p, pos)()
rec(p, 0, waitkey)
case Next | Other(_) =>
case Next =>
if pos + 1 < p.slides.size then
executeSlide(p, pos + 1)()
rec(p, pos + 1, waitkey)
@ -55,6 +55,15 @@ case class Presentation(slides: Vector[Slide], meta: Map[String, String] = Map.e
target match
case Some(i) => rec(p, pos, Goto(i))
case None => rec(p, pos - 1, QuickNext)
case Help =>
Terminal.clear()
println(keymap.help)
waitkey
rec(p, pos - 1, QuickNext)
case Other(codes) =>
Terminal.cursorTo(Terminal.height, 1)
println(action.show)
rec(p, pos, waitkey)
case Quit =>
()
rec(this, 0, Start)