roguestar-gl-0.2.2: src/Keymaps/Keymaps.lhs
\section{Keymaps}
\texttt{Keymap}s are simple mappings from a sequence of keystrokes to the names of various commands.
\begin{code}
module Keymaps.Keymaps
(Keymap,
KeymapName,
fixKeymap,
filterKeySequence,
keysToActionNames,
actionNameToKeys)
where
import Actions
import Data.List
import Control.Monad
type Keymap = [(String,String)]
type KeymapName = String
\end{code}
\texttt{fixKeymap} processes a keymap to make it usable. If you type in a multi-character command and it executes before you press enter,
you forgot to use \texttt{fixKeymap}.
\begin{code}
fixKeymap :: Keymap -> Keymap
fixKeymap = concatMap $ \(x,y) ->
case x of
[c] -> [([c],y)]
('>':keystrokes) | (not $ null keystrokes) -> [(keystrokes,y)]
command -> let keystrokes = concat $ intersperse "-" $ words command in [(keystrokes ++ "\r",y),(keystrokes ++ "\n",y)]
\end{code}
\texttt{validKeyMap} reduces a \texttt{Keymap} to one that contains only those actions that are valid at this instant.
\begin{code}
validKeyMap :: ActionInput -> Keymap -> IO [(String,String)]
validKeyMap action_input raw_keymap =
do valid_actions <- getValidActions action_input Nothing
return $ filter (\x -> snd x `elem` valid_actions) raw_keymap
\end{code}
\texttt{filterKeySequence} transforms a key sequence into either the empty string, if it isn't the prefix of any valid action,
or completes the key sequence if it is the prefix of exactly one valid action.
\begin{code}
filterKeySequence :: ActionInput -> Keymap -> String -> IO String
filterKeySequence _ _ key_sequence | (length $ words key_sequence) == 0 = return ""
filterKeySequence action_input keymap key_sequence =
do valid_key_map <- validKeyMap action_input keymap
let possible_completions = filter (\x -> elem key_sequence $ inits x) $ map fst $ valid_key_map
return $ case length possible_completions of
0 -> ""
1 -> if key_sequence /= head possible_completions
then init $ head possible_completions
else key_sequence
_ -> maximumBy (\x -> \y -> compare (length x) (length y)) $ foldr1 intersect $ map inits possible_completions
\end{code}
\texttt{keysToActionNames} gets a list of the names of all action that could be exected by the given key sequence at this instant.
A result of zero indicates that the key sequence isn't a valid command. A result with more than one element indicates
a collision in the key map, which is an error.
\begin{code}
keysToActionNames :: ActionInput -> Keymap -> String -> IO [String]
keysToActionNames action_input keymap key_sequence =
liftM (map snd . filter (\x -> fst x == key_sequence)) $ validKeyMap action_input keymap
\end{code}
\texttt{actionNameToKeys} provides reverse lookup versus keysToActionNames.
\begin{code}
actionNameToKeys :: ActionInput -> Keymap -> String -> IO [String]
actionNameToKeys action_input keymap action_name =
liftM (map fst . filter (\x -> snd x == action_name)) $ validKeyMap action_input keymap
\end{code}