packages feed

Allure-0.4.2: src/Keybindings.hs

module Keybindings where

import qualified Data.Map as M
import qualified Data.List as L

import Utils.Assert
import Action
import Command
import Geometry
import qualified Keys as K

-- | Keybindings.
data Keybindings = Keybindings
  { kdir   :: DirCommand
  , kudir  :: DirCommand
  , kother :: M.Map K.Key Command
  }

handleKey :: X -> Keybindings -> K.Key -> Action ()
handleKey lxsize kb k =
  K.handleDirection lxsize k (caction $ kdir kb) $
    K.handleUDirection lxsize k (caction $ kudir kb) $
      case M.lookup k (kother kb) of
        Just c  -> caction c
        Nothing -> abortWith $ "unknown command (" ++ K.showKey k ++ ")"

keyHelp :: (K.Key -> [K.Key]) -> Keybindings -> String
keyHelp aliases kb =
  let
    fmt k h = replicate 15 ' ' ++ k ++ replicate ((13 - length k) `max` 1) ' '
                               ++ h ++ replicate ((35 - length h) `max` 1) ' '
    fmts s  = replicate 2  ' ' ++ s ++ replicate ((71 - length s) `max` 1) ' '
    blank   = fmt "" ""
    movKs   =
      [ ""
      , "You move throughout the level using the numerical keypad or"
      , "the vi text editor keys (also known as \"Rogue-like keys\")."
      , ""
      , "               7 8 9     y k u"
      , "                \\|/       \\|/"
      , "               4-5-6     h-.-l"
      , "                /|\\       /|\\"
      , "               1 2 3     b j n"
      , ""
      , "Shift and a movement key make the hero run in the indicated direction,"
      , "until anything of interest is spotted. '5' and '.' skip a turn."
      , ""
      , "To search, open or attack, bump into walls, doors or monsters."
      , ""
      , "For more playing instructions see file PLAYING.md."
      , ""
      , "Press space to see the next page."
      , ""
      , ""
      ]
    mov     = map fmts movKs
    keyC    = fmt "keys" "command"
--    footer  =
--      fmts "(To search, open or attack, bump into walls, doors or monsters.)"
    disp k  = L.concatMap show $ aliases k
    rest    = [ fmt (disp k) h
              | (k, Described h _) <- M.toAscList (kother kb) ]
  in
    unlines ([blank] ++ mov ++ [blank, keyC] ++ rest)
--             [blank, footer, blank])

-- | Maps a key to the canonical key for the command it denotes.
-- Takes into account the keypad and any macros from a config file.
-- Macros cannot depend on each other, but they can on canonMoveKey.
-- This has to be fully evaluated to catch errors in macro definitions early.
macroKey :: [(String, String)] -> M.Map K.Key K.Key
macroKey section =
  let trans k = case K.keyTranslate k of
                  K.Unknown s -> assert `failure` ("unknown macro key " ++ s)
                  kt -> kt
      trMacro (from, to) = let fromTr = trans from
                               !toTr  = K.canonMoveKey $ trans to
                           in  if fromTr == toTr
                               then assert `failure` ("degenerate alias", toTr)
                               else (fromTr, toTr)
  in  M.fromList $ L.map trMacro section