module System.Console.Haskeline.Key(Key(..),
            Modifier(..),
            BaseKey(..),
            noModifier,
            simpleKey,
            simpleChar,
            metaChar,
            ctrlChar,
            metaKey,
            ctrlKey,
            parseKey
            ) where

import Data.Bits
import Data.Char
import Data.Maybe
import Data.List (intercalate)
import Control.Monad

data Key = Key Modifier BaseKey
            deriving (Key -> Key -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Key -> Key -> Bool
$c/= :: Key -> Key -> Bool
== :: Key -> Key -> Bool
$c== :: Key -> Key -> Bool
Eq,Eq Key
Key -> Key -> Bool
Key -> Key -> Ordering
Key -> Key -> Key
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 :: Key -> Key -> Key
$cmin :: Key -> Key -> Key
max :: Key -> Key -> Key
$cmax :: Key -> Key -> Key
>= :: Key -> Key -> Bool
$c>= :: Key -> Key -> Bool
> :: Key -> Key -> Bool
$c> :: Key -> Key -> Bool
<= :: Key -> Key -> Bool
$c<= :: Key -> Key -> Bool
< :: Key -> Key -> Bool
$c< :: Key -> Key -> Bool
compare :: Key -> Key -> Ordering
$ccompare :: Key -> Key -> Ordering
Ord)

instance Show Key where
    show :: Key -> [Char]
show (Key Modifier
modifier BaseKey
base)
        | Modifier
modifier forall a. Eq a => a -> a -> Bool
== Modifier
noModifier = forall a. Show a => a -> [Char]
show BaseKey
base
        | Bool
otherwise = forall a. Show a => a -> [Char]
show Modifier
modifier forall a. [a] -> [a] -> [a]
++ [Char]
"-" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show BaseKey
base

data Modifier = Modifier {Modifier -> Bool
hasControl, Modifier -> Bool
hasMeta, Modifier -> Bool
hasShift :: Bool}
            deriving (Modifier -> Modifier -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Modifier -> Modifier -> Bool
$c/= :: Modifier -> Modifier -> Bool
== :: Modifier -> Modifier -> Bool
$c== :: Modifier -> Modifier -> Bool
Eq,Eq Modifier
Modifier -> Modifier -> Bool
Modifier -> Modifier -> Ordering
Modifier -> Modifier -> Modifier
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 :: Modifier -> Modifier -> Modifier
$cmin :: Modifier -> Modifier -> Modifier
max :: Modifier -> Modifier -> Modifier
$cmax :: Modifier -> Modifier -> Modifier
>= :: Modifier -> Modifier -> Bool
$c>= :: Modifier -> Modifier -> Bool
> :: Modifier -> Modifier -> Bool
$c> :: Modifier -> Modifier -> Bool
<= :: Modifier -> Modifier -> Bool
$c<= :: Modifier -> Modifier -> Bool
< :: Modifier -> Modifier -> Bool
$c< :: Modifier -> Modifier -> Bool
compare :: Modifier -> Modifier -> Ordering
$ccompare :: Modifier -> Modifier -> Ordering
Ord)

instance Show Modifier where
    show :: Modifier -> [Char]
show Modifier
m = forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"-"
            forall a b. (a -> b) -> a -> b
$ forall a. [Maybe a] -> [a]
catMaybes [forall {a}. (Modifier -> Bool) -> a -> Maybe a
maybeUse Modifier -> Bool
hasControl [Char]
"ctrl"
                        , forall {a}. (Modifier -> Bool) -> a -> Maybe a
maybeUse Modifier -> Bool
hasMeta [Char]
"meta"
                        , forall {a}. (Modifier -> Bool) -> a -> Maybe a
maybeUse Modifier -> Bool
hasShift [Char]
"shift"
                        ]
        where
            maybeUse :: (Modifier -> Bool) -> a -> Maybe a
maybeUse Modifier -> Bool
f a
str = if Modifier -> Bool
f Modifier
m then forall a. a -> Maybe a
Just a
str else forall a. Maybe a
Nothing

noModifier :: Modifier
noModifier :: Modifier
noModifier = Bool -> Bool -> Bool -> Modifier
Modifier Bool
False Bool
False Bool
False

-- Note: a few of these aren't really keys (e.g., KillLine),
-- but they provide useful enough binding points to include.
data BaseKey = KeyChar Char
             | FunKey Int
             | LeftKey | RightKey | DownKey | UpKey
             | KillLine | Home | End | PageDown | PageUp
             | Backspace | Delete
             | SearchReverse | SearchForward
            deriving (BaseKey -> BaseKey -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BaseKey -> BaseKey -> Bool
$c/= :: BaseKey -> BaseKey -> Bool
== :: BaseKey -> BaseKey -> Bool
$c== :: BaseKey -> BaseKey -> Bool
Eq, Eq BaseKey
BaseKey -> BaseKey -> Bool
BaseKey -> BaseKey -> Ordering
BaseKey -> BaseKey -> BaseKey
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 :: BaseKey -> BaseKey -> BaseKey
$cmin :: BaseKey -> BaseKey -> BaseKey
max :: BaseKey -> BaseKey -> BaseKey
$cmax :: BaseKey -> BaseKey -> BaseKey
>= :: BaseKey -> BaseKey -> Bool
$c>= :: BaseKey -> BaseKey -> Bool
> :: BaseKey -> BaseKey -> Bool
$c> :: BaseKey -> BaseKey -> Bool
<= :: BaseKey -> BaseKey -> Bool
$c<= :: BaseKey -> BaseKey -> Bool
< :: BaseKey -> BaseKey -> Bool
$c< :: BaseKey -> BaseKey -> Bool
compare :: BaseKey -> BaseKey -> Ordering
$ccompare :: BaseKey -> BaseKey -> Ordering
Ord)

instance Show BaseKey where
    show :: BaseKey -> [Char]
show (KeyChar Char
'\n') = [Char]
"Return"
    show (KeyChar Char
'\t') = [Char]
"Tab"
    show (KeyChar Char
'\ESC') = [Char]
"Esc"
    show (KeyChar Char
c)
        | Char -> Bool
isPrint Char
c = [Char
c]
        | Char -> Bool
isPrint Char
unCtrld = [Char]
"ctrl-" forall a. [a] -> [a] -> [a]
++ [Char
unCtrld]
        | Bool
otherwise = forall a. Show a => a -> [Char]
show Char
c
      where
        unCtrld :: Char
unCtrld = forall a. Enum a => Int -> a
toEnum (forall a. Enum a => a -> Int
fromEnum Char
c forall a. Bits a => a -> a -> a
.|. Int
ctrlBits)
    show (FunKey Int
n) = Char
'f' forall a. a -> [a] -> [a]
: forall a. Show a => a -> [Char]
show Int
n
    show BaseKey
LeftKey = [Char]
"Left"
    show BaseKey
RightKey = [Char]
"Right"
    show BaseKey
DownKey = [Char]
"Down"
    show BaseKey
UpKey = [Char]
"Up"
    show BaseKey
KillLine = [Char]
"KillLine"
    show BaseKey
Home = [Char]
"Home"
    show BaseKey
End = [Char]
"End"
    show BaseKey
PageDown = [Char]
"PageDown"
    show BaseKey
PageUp = [Char]
"PageUp"
    show BaseKey
Backspace = [Char]
"Backspace"
    show BaseKey
Delete = [Char]
"Delete"
    show BaseKey
SearchReverse = [Char]
"SearchReverse"
    show BaseKey
SearchForward = [Char]
"SearchForward"

simpleKey :: BaseKey -> Key
simpleKey :: BaseKey -> Key
simpleKey = Modifier -> BaseKey -> Key
Key Modifier
noModifier

metaKey :: Key -> Key
metaKey :: Key -> Key
metaKey (Key Modifier
m BaseKey
bc) = Modifier -> BaseKey -> Key
Key Modifier
m {hasMeta :: Bool
hasMeta = Bool
True} BaseKey
bc

ctrlKey :: Key -> Key
ctrlKey :: Key -> Key
ctrlKey (Key Modifier
m BaseKey
bc) = Modifier -> BaseKey -> Key
Key Modifier
m {hasControl :: Bool
hasControl = Bool
True} BaseKey
bc

simpleChar, metaChar, ctrlChar :: Char -> Key
simpleChar :: Char -> Key
simpleChar = BaseKey -> Key
simpleKey forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> BaseKey
KeyChar
metaChar :: Char -> Key
metaChar = Key -> Key
metaKey forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Key
simpleChar

ctrlChar :: Char -> Key
ctrlChar = Char -> Key
simpleChar forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Char
setControlBits

setControlBits :: Char -> Char
setControlBits :: Char -> Char
setControlBits Char
'?' = forall a. Enum a => Int -> a
toEnum Int
127
setControlBits Char
c = forall a. Enum a => Int -> a
toEnum forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> Int
fromEnum Char
c forall a. Bits a => a -> a -> a
.&. forall a. Bits a => a -> a
complement Int
ctrlBits

ctrlBits :: Int
ctrlBits :: Int
ctrlBits = forall a. Bits a => Int -> a
bit Int
5 forall a. Bits a => a -> a -> a
.|. forall a. Bits a => Int -> a
bit Int
6

specialKeys :: [(String,BaseKey)]
specialKeys :: [([Char], BaseKey)]
specialKeys = [([Char]
"left",BaseKey
LeftKey)
              ,([Char]
"right",BaseKey
RightKey)
              ,([Char]
"down",BaseKey
DownKey)
              ,([Char]
"up",BaseKey
UpKey)
              ,([Char]
"killline",BaseKey
KillLine)
              ,([Char]
"home",BaseKey
Home)
              ,([Char]
"end",BaseKey
End)
              ,([Char]
"pagedown",BaseKey
PageDown)
              ,([Char]
"pageup",BaseKey
PageUp)
              ,([Char]
"backspace",BaseKey
Backspace)
              ,([Char]
"delete",BaseKey
Delete)
              ,([Char]
"return",Char -> BaseKey
KeyChar Char
'\n')
              ,([Char]
"enter",Char -> BaseKey
KeyChar Char
'\n')
              ,([Char]
"tab",Char -> BaseKey
KeyChar Char
'\t')
              ,([Char]
"esc",Char -> BaseKey
KeyChar Char
'\ESC')
              ,([Char]
"escape",Char -> BaseKey
KeyChar Char
'\ESC')
              ,([Char]
"reversesearchhistory",BaseKey
SearchReverse)
              ,([Char]
"forwardsearchhistory",BaseKey
SearchForward)
              ]

parseModifiers :: [String] -> BaseKey -> Key
parseModifiers :: [[Char]] -> BaseKey -> Key
parseModifiers [[Char]]
strs = Modifier -> BaseKey -> Key
Key Modifier
mods
    where mods :: Modifier
mods = forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) (forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Modifier -> Modifier
parseModifier [[Char]]
strs) Modifier
noModifier

parseModifier :: String -> (Modifier -> Modifier)
parseModifier :: [Char] -> Modifier -> Modifier
parseModifier [Char]
str Modifier
m = case forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower [Char]
str of
    [Char]
"ctrl" -> Modifier
m {hasControl :: Bool
hasControl = Bool
True}
    [Char]
"control" -> Modifier
m {hasControl :: Bool
hasControl = Bool
True}
    [Char]
"meta" -> Modifier
m {hasMeta :: Bool
hasMeta = Bool
True}
    [Char]
"shift" -> Modifier
m {hasShift :: Bool
hasShift = Bool
True}
    [Char]
_ -> Modifier
m

breakAtDashes :: String -> [String]
breakAtDashes :: [Char] -> [[Char]]
breakAtDashes [Char]
"" = []
breakAtDashes [Char]
str = case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
'-') [Char]
str of
    ([Char]
xs,Char
'-':[Char]
rest) -> [Char]
xs forall a. a -> [a] -> [a]
: [Char] -> [[Char]]
breakAtDashes [Char]
rest
    ([Char]
xs,[Char]
_) -> [[Char]
xs]

parseKey :: String -> Maybe Key
parseKey :: [Char] -> Maybe Key
parseKey [Char]
str = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Key -> Key
canonicalizeKey forall a b. (a -> b) -> a -> b
$ 
    case forall a. [a] -> [a]
reverse ([Char] -> [[Char]]
breakAtDashes [Char]
str) of
        [[Char]
ks] -> forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM BaseKey -> Key
simpleKey ([Char] -> Maybe BaseKey
parseBaseKey [Char]
ks)
        [Char]
ks:[[Char]]
ms -> forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ([[Char]] -> BaseKey -> Key
parseModifiers [[Char]]
ms) ([Char] -> Maybe BaseKey
parseBaseKey [Char]
ks)
        [] -> forall a. Maybe a
Nothing

parseBaseKey :: String -> Maybe BaseKey
parseBaseKey :: [Char] -> Maybe BaseKey
parseBaseKey [Char]
ks = forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower [Char]
ks) [([Char], BaseKey)]
specialKeys
                forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` [Char] -> Maybe BaseKey
parseFunctionKey [Char]
ks
                forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` [Char] -> Maybe BaseKey
parseKeyChar [Char]
ks
    where
        parseKeyChar :: [Char] -> Maybe BaseKey
parseKeyChar [Char
c] | Char -> Bool
isPrint Char
c = forall a. a -> Maybe a
Just (Char -> BaseKey
KeyChar Char
c)
        parseKeyChar [Char]
_ = forall a. Maybe a
Nothing

        parseFunctionKey :: [Char] -> Maybe BaseKey
parseFunctionKey (Char
f:[Char]
ns) | Char
f forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
"fF" = case forall a. Read a => ReadS a
reads [Char]
ns of
            [(Int
n,[Char]
"")]    -> forall a. a -> Maybe a
Just (Int -> BaseKey
FunKey Int
n)
            [(Int, [Char])]
_           -> forall a. Maybe a
Nothing
        parseFunctionKey [Char]
_ = forall a. Maybe a
Nothing

canonicalizeKey :: Key -> Key
canonicalizeKey :: Key -> Key
canonicalizeKey (Key Modifier
m (KeyChar Char
c))
    | Modifier -> Bool
hasControl Modifier
m = Modifier -> BaseKey -> Key
Key Modifier
m {hasControl :: Bool
hasControl = Bool
False}
                        (Char -> BaseKey
KeyChar (Char -> Char
setControlBits Char
c))
    | Modifier -> Bool
hasShift Modifier
m = Modifier -> BaseKey -> Key
Key Modifier
m {hasShift :: Bool
hasShift = Bool
False} (Char -> BaseKey
KeyChar (Char -> Char
toUpper Char
c))
canonicalizeKey Key
k = Key
k