module Yi.Keymap.Vim2.EventUtils
( stringToEvent
, eventToString
, parseEvents
, stringToRepeatableAction
, normalizeCount
, splitCountedCommand
) where
import Yi.Prelude
import Prelude ()
import Data.Char (toUpper, isDigit)
import Data.List (break)
import qualified Data.Map as M
import Data.Tuple (swap)
import Yi.Event
import Yi.Keymap.Keys (char, ctrlCh, spec)
import Yi.Keymap.Vim2.Common
specMap :: M.Map EventString Key
specMap = M.fromList $ specList
invSpecMap :: M.Map Key EventString
invSpecMap = M.fromList $ fmap swap specList
specList :: [(String, Key)]
specList =
[ ("<Esc>", KEsc)
, ("<CR>", KEnter)
, ("<BS>", KBS)
, ("<Tab>", KTab)
, ("<Down>", KDown)
, ("<Up>", KUp)
, ("<Left>", KLeft)
, ("<Right>", KRight)
, ("<PageUp>", KPageUp)
, ("<PageDown>", KPageDown)
, ("<Home>", KHome)
, ("<End>", KEnd)
, ("<Ins>", KIns)
, ("<Del>", KDel)
]
stringToEvent :: String -> Event
stringToEvent ('<':'C':'-':c:'>':[]) = ctrlCh c
stringToEvent "<lt>" = char '<'
stringToEvent [c] = char c
stringToEvent ('<':'F':d:'>':[]) | isDigit d = spec (KFun $ read [d])
stringToEvent ('<':'F':'1':d:'>':[]) | isDigit d = spec (KFun $ 10 + read [d])
stringToEvent s =
case M.lookup s specMap of
Just k -> spec k
Nothing -> error $ "Couldn't convert string <" ++ s ++ "> to event"
eventToString :: Event -> String
eventToString (Event (KASCII '<') []) = "<lt>"
eventToString (Event (KASCII c) []) = [c]
eventToString (Event (KASCII c) [MCtrl]) = ['<', 'C', '-', c, '>']
eventToString (Event (KASCII c) [MShift]) = [toUpper c]
eventToString (Event (KFun x) []) = "<F" ++ show x ++ ">"
eventToString e@(Event k []) =
case M.lookup k invSpecMap of
Just s -> s
Nothing -> error $ "Couldn't convert event <" ++ show e ++ "> to string"
eventToString e = error $ "Couldn't convert event <" ++ show e ++ "> to string"
parseEvents :: String -> [Event]
parseEvents = fst . foldl' go ([], [])
where go (evs, s) '\n' = (evs, s)
go (evs, []) '<' = (evs, "<")
go (evs, []) c = (evs ++ [char c], [])
go (evs, s) '>' = (evs ++ [stringToEvent (s ++ ">")], [])
go (evs, s) c = (evs, s ++ [c])
stringToRepeatableAction :: String -> RepeatableAction
stringToRepeatableAction s = RepeatableAction count command
where (count, command) = splitCountedCommand s
splitCountedCommand :: String -> (Int, String)
splitCountedCommand s = (count, commandString)
where (countString, commandString) = break (not . isDigit) s
count = case countString of
[] -> 1
_ -> read countString
normalizeCount :: String -> String
normalizeCount s = if null countedObject
then s
else show (operatorCount * objectCount) ++ operator ++ object
where (operatorCount, rest1) = splitCountedCommand s
(operator, countedObject) = break isDigit rest1
(objectCount, object) = splitCountedCommand countedObject