module Cmd.Keymap where
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Util.Lists as Lists
import qualified App.Config as Config
import qualified Cmd.Cmd as Cmd
import qualified Cmd.KeyLayouts as KeyLayouts
import qualified Cmd.Msg as Msg
import qualified Local.KeyLayout
import qualified Ui.Key as Key
import qualified Ui.Types as Types
import Global
type Binding m = (Cmd.KeySpec, Cmd.NamedCmd m)
plain_key :: Cmd.M m => Key.Key -> Text -> m () -> [Binding m]
plain_key :: forall (m :: * -> *). M m => Key -> Text -> m () -> [Binding m]
plain_key = forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_key []
plain_char :: Cmd.M m => Char -> Text -> m () -> [Binding m]
plain_char :: forall (m :: * -> *). M m => Char -> Text -> m () -> [Binding m]
plain_char = forall (m :: * -> *). M m => Key -> Text -> m () -> [Binding m]
plain_key forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Key
Key.Char
shift_char :: Cmd.M m => Char -> Text -> m () -> [Binding m]
shift_char :: forall (m :: * -> *). M m => Char -> Text -> m () -> [Binding m]
shift_char = forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_key [SimpleMod
Shift] forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Key
Key.Char
command_char :: Cmd.M m => Char -> Text -> m () -> [Binding m]
command_char :: forall (m :: * -> *). M m => Char -> Text -> m () -> [Binding m]
command_char = forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_key [SimpleMod
PrimaryCommand] forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Key
Key.Char
secondary_char :: Cmd.M m => Char -> Text -> m () -> [Binding m]
secondary_char :: forall (m :: * -> *). M m => Char -> Text -> m () -> [Binding m]
secondary_char = forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_key [SimpleMod
SecondaryCommand] forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Key
Key.Char
bind_key :: Cmd.M m => [SimpleMod] -> Key.Key -> Text -> m () -> [Binding m]
bind_key :: forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_key [SimpleMod]
smods Key
key Text
desc m ()
cmd = forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (Bool -> Key -> Bindable
Cmd.Key Bool
False Key
key) Text
desc (forall a b. a -> b -> a
const m ()
cmd)
bind_key_status :: [SimpleMod] -> Key.Key -> Text -> m Cmd.Status -> [Binding m]
bind_key_status :: forall (m :: * -> *).
[SimpleMod] -> Key -> Text -> m Status -> [Binding m]
bind_key_status [SimpleMod]
smods Key
key Text
desc m Status
cmd =
forall (m :: * -> *).
[SimpleMod] -> Bindable -> Text -> (Msg -> m Status) -> [Binding m]
bind_status [SimpleMod]
smods (Bool -> Key -> Bindable
Cmd.Key Bool
False Key
key) Text
desc (forall a b. a -> b -> a
const m Status
cmd)
bind_repeatable :: Cmd.M m => [SimpleMod] -> Key.Key -> Text -> m ()
-> [Binding m]
bind_repeatable :: forall (m :: * -> *).
M m =>
[SimpleMod] -> Key -> Text -> m () -> [Binding m]
bind_repeatable [SimpleMod]
smods Key
key Text
desc m ()
cmd =
forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (Bool -> Key -> Bindable
Cmd.Key Bool
True Key
key) Text
desc (forall a b. a -> b -> a
const m ()
cmd)
bind_click :: Cmd.M m => [SimpleMod] -> Types.MouseButton -> Cmd.MouseOn -> Int
-> Text -> (Msg.Msg -> m ()) -> [Binding m]
bind_click :: forall (m :: * -> *).
M m =>
[SimpleMod]
-> MouseButton
-> MouseOn
-> MouseButton
-> Text
-> (Msg -> m ())
-> [Binding m]
bind_click [SimpleMod]
smods MouseButton
btn MouseOn
on MouseButton
clicks Text
desc Msg -> m ()
cmd =
forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (MouseButton -> MouseOn -> MouseButton -> Bindable
Cmd.Click MouseButton
btn MouseOn
on (MouseButton
clicksforall a. Num a => a -> a -> a
-MouseButton
1)) Text
desc Msg -> m ()
cmd
bind_drag :: Cmd.M m => [SimpleMod] -> Types.MouseButton -> Cmd.MouseOn
-> Text -> (Msg.Msg -> m ()) -> [Binding m]
bind_drag :: forall (m :: * -> *).
M m =>
[SimpleMod]
-> MouseButton -> MouseOn -> Text -> (Msg -> m ()) -> [Binding m]
bind_drag [SimpleMod]
smods MouseButton
btn MouseOn
on Text
desc Msg -> m ()
cmd =
forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (MouseButton -> MouseOn -> MouseButton -> Bindable
Cmd.Click MouseButton
btn MouseOn
on MouseButton
0) Text
desc Msg -> m ()
cmd
forall a. [a] -> [a] -> [a]
++ forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (MouseButton -> MouseOn -> Bindable
Cmd.Drag MouseButton
btn MouseOn
on) Text
desc Msg -> m ()
cmd
bind_release :: Cmd.M m => [SimpleMod] -> Types.MouseButton -> Cmd.MouseOn
-> Text -> (Msg.Msg -> m ()) -> [Binding m]
bind_release :: forall (m :: * -> *).
M m =>
[SimpleMod]
-> MouseButton -> MouseOn -> Text -> (Msg -> m ()) -> [Binding m]
bind_release [SimpleMod]
smods MouseButton
btn MouseOn
on = forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods (MouseButton -> MouseOn -> Bindable
Cmd.Release MouseButton
btn MouseOn
on)
bind :: Cmd.M m => [SimpleMod] -> Cmd.Bindable -> Text
-> (Msg.Msg -> m ()) -> [Binding m]
bind :: forall (m :: * -> *).
M m =>
[SimpleMod] -> Bindable -> Text -> (Msg -> m ()) -> [Binding m]
bind [SimpleMod]
smods Bindable
bindable Text
desc Msg -> m ()
cmd =
forall (m :: * -> *).
[SimpleMod] -> Bindable -> Text -> (Msg -> m Status) -> [Binding m]
bind_status [SimpleMod]
smods Bindable
bindable Text
desc ((forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Status
Cmd.Done) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Msg -> m ()
cmd)
bind_status :: [SimpleMod] -> Cmd.Bindable -> Text -> (Msg.Msg -> m Cmd.Status)
-> [Binding m]
bind_status :: forall (m :: * -> *).
[SimpleMod] -> Bindable -> Text -> (Msg -> m Status) -> [Binding m]
bind_status [SimpleMod]
smods_ Bindable
bindable_ Text
name Msg -> m Status
cmd =
[ ( [Modifier] -> Bindable -> KeySpec
key_spec (Bindable -> [SimpleMod] -> [Modifier]
expand_mods Bindable
bindable [SimpleMod]
smods) Bindable
bind
, forall (m :: * -> *). Text -> (Msg -> m Status) -> NamedCmd m
Cmd.NamedCmd Text
name Msg -> m Status
cmd
)
| Bindable
bind <- Bindable -> [Bindable]
expand_bindable Bindable
bindable
]
where
([SimpleMod]
smods, Bindable
bindable) = case Bindable
bindable_ of
Cmd.Key Bool
repeat (Key.Char Char
c) ->
case Layout -> Char -> Maybe Char
KeyLayouts.to_unshifted Layout
Local.KeyLayout.layout Char
c of
Just Char
unshifted ->
(SimpleMod
Shift forall a. a -> [a] -> [a]
: [SimpleMod]
smods_, Bool -> Key -> Bindable
Cmd.Key Bool
repeat (Char -> Key
Key.Char Char
unshifted))
Maybe Char
Nothing -> ([SimpleMod]
smods_, Bindable
bindable_)
Bindable
_ -> ([SimpleMod]
smods_, Bindable
bindable_)
make_keymap :: [Binding m] -> (Cmd.Keymap m, [Text])
make_keymap :: forall (m :: * -> *). [Binding m] -> (Keymap m, [Text])
make_keymap [Binding m]
bindings = (forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [Binding m]
bindings, [Text]
warns)
where
warns :: [Text]
warns = forall a b. (a -> b) -> [a] -> [b]
map [Text] -> Text
warn (forall (m :: * -> *). [Binding m] -> [[Text]]
overlaps [Binding m]
bindings)
warn :: [Text] -> Text
warn [Text]
cmds = Text
"cmds overlap, picking the last one: ["
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
Text.intercalate Text
", " [Text]
cmds forall a. Semigroup a => a -> a -> a
<> Text
"]"
data SimpleMod =
Shift
| PrimaryCommand
| SecondaryCommand
| Mouse Types.MouseButton
deriving (SimpleMod -> SimpleMod -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SimpleMod -> SimpleMod -> Bool
$c/= :: SimpleMod -> SimpleMod -> Bool
== :: SimpleMod -> SimpleMod -> Bool
$c== :: SimpleMod -> SimpleMod -> Bool
Eq, Eq SimpleMod
SimpleMod -> SimpleMod -> Bool
SimpleMod -> SimpleMod -> Ordering
SimpleMod -> SimpleMod -> SimpleMod
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SimpleMod -> SimpleMod -> SimpleMod
$cmin :: SimpleMod -> SimpleMod -> SimpleMod
max :: SimpleMod -> SimpleMod -> SimpleMod
$cmax :: SimpleMod -> SimpleMod -> SimpleMod
>= :: SimpleMod -> SimpleMod -> Bool
$c>= :: SimpleMod -> SimpleMod -> Bool
> :: SimpleMod -> SimpleMod -> Bool
$c> :: SimpleMod -> SimpleMod -> Bool
<= :: SimpleMod -> SimpleMod -> Bool
$c<= :: SimpleMod -> SimpleMod -> Bool
< :: SimpleMod -> SimpleMod -> Bool
$c< :: SimpleMod -> SimpleMod -> Bool
compare :: SimpleMod -> SimpleMod -> Ordering
$ccompare :: SimpleMod -> SimpleMod -> Ordering
Ord, MouseButton -> SimpleMod -> ShowS
[SimpleMod] -> ShowS
SimpleMod -> String
forall a.
(MouseButton -> a -> ShowS)
-> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SimpleMod] -> ShowS
$cshowList :: [SimpleMod] -> ShowS
show :: SimpleMod -> String
$cshow :: SimpleMod -> String
showsPrec :: MouseButton -> SimpleMod -> ShowS
$cshowsPrec :: MouseButton -> SimpleMod -> ShowS
Show)
simple_mod_map :: Map SimpleMod Key.Modifier
simple_mod_map :: Map SimpleMod Modifier
simple_mod_map = forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall a b. (a -> b) -> a -> b
$ case Platform
Config.platform of
Platform
Config.Mac ->
[ (SimpleMod
Shift, Modifier
Key.Shift)
, (SimpleMod
PrimaryCommand, Modifier
Key.Meta)
, (SimpleMod
SecondaryCommand, Modifier
Key.Control)
]
Platform
Config.Linux ->
[ (SimpleMod
Shift, Modifier
Key.Shift)
, (SimpleMod
PrimaryCommand, Modifier
Key.Control)
, (SimpleMod
SecondaryCommand, Modifier
Key.Alt)
]
simple_to_mod :: SimpleMod -> Maybe Cmd.Modifier
simple_to_mod :: SimpleMod -> Maybe Modifier
simple_to_mod (Mouse MouseButton
btn) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ MouseButton -> Maybe (MouseButton, Track) -> Modifier
Cmd.MouseMod MouseButton
btn forall a. Maybe a
Nothing
simple_to_mod SimpleMod
simple = Modifier -> Modifier
Cmd.KeyMod forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup SimpleMod
simple Map SimpleMod Modifier
simple_mod_map
key_spec :: [Cmd.Modifier] -> Cmd.Bindable -> Cmd.KeySpec
key_spec :: [Modifier] -> Bindable -> KeySpec
key_spec [Modifier]
mods Bindable
bindable = Set Modifier -> Bindable -> KeySpec
Cmd.KeySpec (forall a. Ord a => [a] -> Set a
Set.fromList [Modifier]
mods) Bindable
bindable
overlaps :: [Binding m] -> [[Text]]
overlaps :: forall (m :: * -> *). [Binding m] -> [[Text]]
overlaps [Binding m]
bindings =
[forall a b. (a -> b) -> [a] -> [b]
map forall {a} {m :: * -> *}. Pretty a => (a, NamedCmd m) -> Text
cmd_name [Binding m]
grp | [Binding m]
grp <- forall key a. Ord key => (a -> key) -> [a] -> [[a]]
Lists.groupSort forall a b. (a, b) -> a
fst [Binding m]
bindings, forall (t :: * -> *) a. Foldable t => t a -> MouseButton
length [Binding m]
grp forall a. Ord a => a -> a -> Bool
> MouseButton
1]
where
cmd_name :: (a, NamedCmd m) -> Text
cmd_name (a
kspec, Cmd.NamedCmd Text
name Msg -> m Status
_) =
forall a. Pretty a => a -> Text
pretty a
kspec forall a. Semigroup a => a -> a -> a
<> Text
": " forall a. Semigroup a => a -> a -> a
<> Text
name
expand_bindable :: Cmd.Bindable -> [Cmd.Bindable]
expand_bindable :: Bindable -> [Bindable]
expand_bindable (Cmd.Key Bool
True Key
key) = [Bool -> Key -> Bindable
Cmd.Key Bool
False Key
key, Bool -> Key -> Bindable
Cmd.Key Bool
True Key
key]
expand_bindable Bindable
b = [Bindable
b]
expand_mods :: Cmd.Bindable -> [SimpleMod] -> [Cmd.Modifier]
expand_mods :: Bindable -> [SimpleMod] -> [Modifier]
expand_mods Bindable
bindable [SimpleMod]
smods = forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe SimpleMod -> Maybe Modifier
simple_to_mod ([SimpleMod]
prefix forall a. [a] -> [a] -> [a]
++ [SimpleMod]
smods)
where
prefix :: [SimpleMod]
prefix = case Bindable
bindable of
Cmd.Click MouseButton
n MouseOn
_ MouseButton
_ -> [MouseButton -> SimpleMod
Mouse MouseButton
n]
Cmd.Drag MouseButton
n MouseOn
_ -> [MouseButton -> SimpleMod
Mouse MouseButton
n]
Bindable
_ -> []