Change-Id: I581a37df0a20fa54878da4446007dbe677e057da Reviewed-on: https://cl.tvl.fyi/c/depot/+/5444 Autosubmit: grfn <grfn@gws.fyi> Reviewed-by: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
145 lines
4.5 KiB
Haskell
145 lines
4.5 KiB
Haskell
{-# LANGUAGE TemplateHaskell #-}
|
|
--------------------------------------------------------------------------------
|
|
module Xanthous.Command
|
|
( -- * Commands
|
|
Command(..)
|
|
, commandIsHidden
|
|
-- * Keybindings
|
|
, Keybinding(..)
|
|
, keybindings
|
|
, commands
|
|
, commandFromKey
|
|
, directionFromChar
|
|
) where
|
|
--------------------------------------------------------------------------------
|
|
import Xanthous.Prelude hiding (Left, Right, Down, try)
|
|
--------------------------------------------------------------------------------
|
|
import Graphics.Vty.Input (Key(..), Modifier(..))
|
|
import qualified Data.Char as Char
|
|
import Data.Aeson (FromJSON (parseJSON), FromJSONKey, FromJSONKeyFunction (FromJSONKeyTextParser))
|
|
import qualified Data.Aeson as A
|
|
import Data.Aeson.Generic.DerivingVia
|
|
import Text.Megaparsec (Parsec, errorBundlePretty, parse, eof, try)
|
|
import Text.Megaparsec.Char (string', char', printChar)
|
|
import Data.FileEmbed (embedFile)
|
|
import qualified Data.Yaml as Yaml
|
|
import Test.QuickCheck.Arbitrary
|
|
import Data.Aeson.Types (Parser)
|
|
--------------------------------------------------------------------------------
|
|
import Xanthous.Data (Direction(..))
|
|
import Xanthous.Util.QuickCheck (GenericArbitrary(..))
|
|
--------------------------------------------------------------------------------
|
|
|
|
data Command
|
|
= Quit
|
|
| Help
|
|
| Move !Direction
|
|
| StartAutoMove !Direction
|
|
| PreviousMessage
|
|
| PickUp
|
|
| Drop
|
|
| Open
|
|
| Close
|
|
| Wait
|
|
| Eat
|
|
| Look
|
|
| Save
|
|
| Read
|
|
| ShowInventory
|
|
| DescribeInventory
|
|
| Wield
|
|
| Fire
|
|
| GoUp
|
|
| GoDown
|
|
| Rest
|
|
|
|
-- | TODO replace with `:` commands
|
|
| ToggleRevealAll
|
|
deriving stock (Show, Eq, Generic)
|
|
deriving anyclass (Hashable, NFData)
|
|
deriving Arbitrary via GenericArbitrary Command
|
|
deriving (FromJSON)
|
|
via WithOptions '[ SumEnc UntaggedVal ]
|
|
Command
|
|
|
|
-- | Should the command be hidden from the help menu?
|
|
--
|
|
-- Note that this is true for both debug commands and movement commands, as the
|
|
-- latter is documented non-automatically
|
|
commandIsHidden :: Command -> Bool
|
|
commandIsHidden (Move _) = True
|
|
commandIsHidden (StartAutoMove _) = True
|
|
commandIsHidden ToggleRevealAll = True
|
|
commandIsHidden _ = False
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
data Keybinding = Keybinding !Key ![Modifier]
|
|
deriving stock (Show, Eq, Generic)
|
|
deriving anyclass (Hashable, NFData)
|
|
|
|
parseKeybindingFromText :: Text -> Parser Keybinding
|
|
parseKeybindingFromText
|
|
= either (fail . errorBundlePretty) pure
|
|
. parse keybinding "<JSON>"
|
|
where
|
|
key :: Parsec Void Text Key
|
|
key = KUp <$ string' "<up>"
|
|
<|> KDown <$ string' "<down>"
|
|
<|> KLeft <$ string' "<left>"
|
|
<|> KRight <$ string' "<right>"
|
|
<|> KChar <$> printChar
|
|
|
|
modifier :: Parsec Void Text Modifier
|
|
modifier = modf <* char' '-'
|
|
where
|
|
modf = MAlt <$ char' 'a'
|
|
<|> MMeta <$ char' 'm'
|
|
<|> MCtrl <$ char' 'c'
|
|
<|> MShift <$ char' 's'
|
|
|
|
keybinding :: Parsec Void Text Keybinding
|
|
keybinding = do
|
|
mods <- many (try modifier)
|
|
k <- key
|
|
eof
|
|
pure $ Keybinding k mods
|
|
|
|
instance FromJSON Keybinding where
|
|
parseJSON = A.withText "Keybinding" parseKeybindingFromText
|
|
|
|
instance FromJSONKey Keybinding where
|
|
fromJSONKey = FromJSONKeyTextParser parseKeybindingFromText
|
|
|
|
rawKeybindings :: ByteString
|
|
rawKeybindings = $(embedFile "src/Xanthous/keybindings.yaml")
|
|
|
|
keybindings :: HashMap Keybinding Command
|
|
keybindings = either (error . Yaml.prettyPrintParseException) id
|
|
$ Yaml.decodeEither' rawKeybindings
|
|
|
|
commands :: HashMap Command Keybinding
|
|
commands = mapFromList . map swap . itoList $ keybindings
|
|
|
|
commandFromKey :: Key -> [Modifier] -> Maybe Command
|
|
commandFromKey (KChar (directionFromChar -> Just dir)) [] = Just $ Move dir
|
|
commandFromKey (KChar c) []
|
|
| Char.isUpper c
|
|
, Just dir <- directionFromChar $ Char.toLower c
|
|
= Just $ StartAutoMove dir
|
|
commandFromKey k mods = keybindings ^. at keybinding
|
|
where keybinding = Keybinding k mods
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
directionFromChar :: Char -> Maybe Direction
|
|
directionFromChar 'h' = Just Left
|
|
directionFromChar 'j' = Just Down
|
|
directionFromChar 'k' = Just Up
|
|
directionFromChar 'l' = Just Right
|
|
directionFromChar 'y' = Just UpLeft
|
|
directionFromChar 'u' = Just UpRight
|
|
directionFromChar 'b' = Just DownLeft
|
|
directionFromChar 'n' = Just DownRight
|
|
directionFromChar '.' = Just Here
|
|
directionFromChar _ = Nothing
|