2022-04-10 11:06:53 -04:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
2019-09-20 13:14:55 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-04-10 11:06:53 -04:00
|
|
|
module Xanthous.Command
|
2022-04-10 12:06:10 -04:00
|
|
|
( -- * Commands
|
|
|
|
Command(..)
|
|
|
|
, commandIsHidden
|
|
|
|
-- * Keybindings
|
2022-04-10 11:06:53 -04:00
|
|
|
, Keybinding(..)
|
|
|
|
, keybindings
|
|
|
|
, commands
|
|
|
|
, commandFromKey
|
|
|
|
, directionFromChar
|
|
|
|
) where
|
2019-09-20 13:14:55 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-04-10 11:06:53 -04:00
|
|
|
import Xanthous.Prelude hiding (Left, Right, Down, try)
|
2019-09-20 13:14:55 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-04-10 11:06:53 -04:00
|
|
|
import Graphics.Vty.Input (Key(..), Modifier(..))
|
2020-05-11 23:03:21 -04:00
|
|
|
import qualified Data.Char as Char
|
2022-04-10 11:06:53 -04:00
|
|
|
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)
|
2019-09-20 13:14:55 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-04-10 11:06:53 -04:00
|
|
|
import Xanthous.Data (Direction(..))
|
|
|
|
import Xanthous.Util.QuickCheck (GenericArbitrary(..))
|
2019-09-20 13:14:55 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2019-08-31 13:17:27 -04:00
|
|
|
|
|
|
|
data Command
|
|
|
|
= Quit
|
2022-04-10 12:06:10 -04:00
|
|
|
| Help
|
2022-04-10 11:06:53 -04:00
|
|
|
| Move !Direction
|
|
|
|
| StartAutoMove !Direction
|
2019-08-31 13:17:27 -04:00
|
|
|
| PreviousMessage
|
2019-09-19 13:56:14 -04:00
|
|
|
| PickUp
|
2019-12-23 12:19:51 -05:00
|
|
|
| Drop
|
2019-09-20 13:14:55 -04:00
|
|
|
| Open
|
2020-01-25 11:38:37 -05:00
|
|
|
| Close
|
2019-09-28 13:20:57 -04:00
|
|
|
| Wait
|
2019-10-06 12:50:29 -04:00
|
|
|
| Eat
|
2019-11-29 15:43:46 -05:00
|
|
|
| Look
|
2019-11-29 14:33:52 -05:00
|
|
|
| Save
|
2019-11-30 19:55:43 -05:00
|
|
|
| Read
|
2019-12-22 22:46:43 -05:00
|
|
|
| ShowInventory
|
2021-06-19 15:40:11 -04:00
|
|
|
| DescribeInventory
|
2019-12-22 23:22:25 -05:00
|
|
|
| Wield
|
2021-10-30 12:12:47 -04:00
|
|
|
| Fire
|
2020-01-05 12:55:15 -05:00
|
|
|
| GoUp
|
|
|
|
| GoDown
|
2021-06-18 13:04:43 -04:00
|
|
|
| Rest
|
2019-08-31 13:17:27 -04:00
|
|
|
|
2019-09-28 15:01:21 -04:00
|
|
|
-- | TODO replace with `:` commands
|
|
|
|
| ToggleRevealAll
|
2022-04-10 11:06:53 -04:00
|
|
|
deriving stock (Show, Eq, Generic)
|
|
|
|
deriving anyclass (Hashable, NFData)
|
|
|
|
deriving Arbitrary via GenericArbitrary Command
|
|
|
|
deriving (FromJSON)
|
|
|
|
via WithOptions '[ SumEnc UntaggedVal ]
|
|
|
|
Command
|
|
|
|
|
2022-04-10 12:06:10 -04:00
|
|
|
-- | 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
|
|
|
|
|
2022-04-10 11:06:53 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
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
|
2019-09-28 15:01:21 -04:00
|
|
|
|
2019-08-31 13:17:27 -04:00
|
|
|
commandFromKey :: Key -> [Modifier] -> Maybe Command
|
2019-09-20 13:14:55 -04:00
|
|
|
commandFromKey (KChar (directionFromChar -> Just dir)) [] = Just $ Move dir
|
2020-05-11 23:03:21 -04:00
|
|
|
commandFromKey (KChar c) []
|
|
|
|
| Char.isUpper c
|
|
|
|
, Just dir <- directionFromChar $ Char.toLower c
|
|
|
|
= Just $ StartAutoMove dir
|
2022-04-10 11:06:53 -04:00
|
|
|
commandFromKey k mods = keybindings ^. at keybinding
|
|
|
|
where keybinding = Keybinding k mods
|
2019-09-20 13:14:55 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
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
|