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 = [ ("", KEsc) , ("", KEnter) , ("", KBS) , ("", KTab) , ("", KDown) , ("", KUp) , ("", KLeft) , ("", KRight) , ("", KPageUp) , ("", KPageDown) , ("", KHome) , ("", KEnd) , ("", KIns) , ("", KDel) ] stringToEvent :: String -> Event stringToEvent ('<':'C':'-':c:'>':[]) = ctrlCh c stringToEvent "" = 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 '<') []) = "" eventToString (Event (KASCII c) []) = [c] eventToString (Event (KASCII c) [MCtrl]) = ['<', 'C', '-', c, '>'] eventToString (Event (KASCII c) [MShift]) = [toUpper c] eventToString (Event (KFun 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 -- 2d3w -> 6dw -- 6dw -> 6dw -- dw -> dw 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