-- | This module provides 'KeyEvents', a data type for mapping
-- application-defined abstract events to user-facing names (e.g.
-- for use in configuration files and documentation). This data
-- structure gives you a place to define the correspondence between
-- your application's key events and their names. A 'KeyEvents' also
-- effectively tells the key binding system about the collection of
-- possible abstract events that can be handled.
--
-- A 'KeyEvents' is used to construct a
-- 'Brick.Keybindings.KeyConfig.KeyConfig' with
-- 'Brick.Keybindings.KeyConfig.newKeyConfig'.
module Brick.Keybindings.KeyEvents
  ( KeyEvents
  , keyEvents
  , keyEventsList
  , lookupKeyEvent
  , keyEventName
  )
where

import qualified Data.Bimap as B
import qualified Data.Text as T

-- | A bidirectional mapping between events @k@ and their user-readable
-- names.
data KeyEvents k = KeyEvents (B.Bimap T.Text k)
                 deriving (KeyEvents k -> KeyEvents k -> Bool
(KeyEvents k -> KeyEvents k -> Bool)
-> (KeyEvents k -> KeyEvents k -> Bool) -> Eq (KeyEvents k)
forall k. Eq k => KeyEvents k -> KeyEvents k -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall k. Eq k => KeyEvents k -> KeyEvents k -> Bool
== :: KeyEvents k -> KeyEvents k -> Bool
$c/= :: forall k. Eq k => KeyEvents k -> KeyEvents k -> Bool
/= :: KeyEvents k -> KeyEvents k -> Bool
Eq, Int -> KeyEvents k -> ShowS
[KeyEvents k] -> ShowS
KeyEvents k -> String
(Int -> KeyEvents k -> ShowS)
-> (KeyEvents k -> String)
-> ([KeyEvents k] -> ShowS)
-> Show (KeyEvents k)
forall k. Show k => Int -> KeyEvents k -> ShowS
forall k. Show k => [KeyEvents k] -> ShowS
forall k. Show k => KeyEvents k -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall k. Show k => Int -> KeyEvents k -> ShowS
showsPrec :: Int -> KeyEvents k -> ShowS
$cshow :: forall k. Show k => KeyEvents k -> String
show :: KeyEvents k -> String
$cshowList :: forall k. Show k => [KeyEvents k] -> ShowS
showList :: [KeyEvents k] -> ShowS
Show)

-- | Build a new 'KeyEvents' map from the specified list of events and
-- names. Key event names are stored in lowercase.
--
-- Calls 'error' if any events have the same name (ignoring case) or if
-- multiple names map to the same event.
keyEvents :: (Ord k) => [(T.Text, k)] -> KeyEvents k
keyEvents :: forall k. Ord k => [(Text, k)] -> KeyEvents k
keyEvents [(Text, k)]
pairs =
    let m :: Bimap Text k
m = [(Text, k)] -> Bimap Text k
forall a b. (Ord a, Ord b) => [(a, b)] -> Bimap a b
B.fromList [(Text -> Text
T.strip (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.toLower Text
n, k
e) | (Text
n, k
e) <- [(Text, k)]
pairs]
    in if Bimap Text k -> Int
forall a b. Bimap a b -> Int
B.size Bimap Text k
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= [(Text, k)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Text, k)]
pairs
       then String -> KeyEvents k
forall a. HasCallStack => String -> a
error String
"keyEvents: input list contains duplicates by name or by event value"
       else Bimap Text k -> KeyEvents k
forall k. Bimap Text k -> KeyEvents k
KeyEvents (Bimap Text k -> KeyEvents k) -> Bimap Text k -> KeyEvents k
forall a b. (a -> b) -> a -> b
$ [(Text, k)] -> Bimap Text k
forall a b. (Ord a, Ord b) => [(a, b)] -> Bimap a b
B.fromList [(Text, k)]
pairs

-- | Convert the 'KeyEvents' to a list.
keyEventsList :: KeyEvents k -> [(T.Text, k)]
keyEventsList :: forall k. KeyEvents k -> [(Text, k)]
keyEventsList (KeyEvents Bimap Text k
m) = Bimap Text k -> [(Text, k)]
forall a b. Bimap a b -> [(a, b)]
B.toList Bimap Text k
m

-- | Look up the specified event name to get its abstract event. The
-- lookup ignores leading and trailing whitespace as well as case.
lookupKeyEvent :: (Ord k) => KeyEvents k -> T.Text -> Maybe k
lookupKeyEvent :: forall k. Ord k => KeyEvents k -> Text -> Maybe k
lookupKeyEvent (KeyEvents Bimap Text k
m) Text
name = Text -> Bimap Text k -> Maybe k
forall a b (m :: * -> *).
(Ord a, Ord b, MonadThrow m) =>
a -> Bimap a b -> m b
B.lookup (Text -> Text
T.strip (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.toLower Text
name) Bimap Text k
m

-- | Given an abstract event, get its event name.
keyEventName :: (Ord k) => KeyEvents k -> k -> Maybe T.Text
keyEventName :: forall k. Ord k => KeyEvents k -> k -> Maybe Text
keyEventName (KeyEvents Bimap Text k
m) k
e = k -> Bimap Text k -> Maybe Text
forall a b (m :: * -> *).
(Ord a, Ord b, MonadThrow m) =>
b -> Bimap a b -> m a
B.lookupR k
e Bimap Text k
m