@@ -1,5 +1,5 @@
11{-# OPTIONS_HADDOCK hide #-}
2−-- This makes a kind of tri. Has space efficiency issues with large
2+-- This makes a kind of trie. Has space efficiency issues with large
33-- input blocks. Likely building a parser and just applying that would
44-- be better.
55module Graphics.Vty.Input.Classify
@@ -16,25 +16,28 @@ import Graphics.Vty.Input.Classify.Types
1616
1717import Codec.Binary.UTF8.Generic (decode)
1818
19−import Data.List (inits)
19+import Control.Arrow (first)
2020import qualified Data.Map as M( fromList, lookup )
2121import Data.Maybe ( mapMaybe )
2222import qualified Data.Set as S( fromList, member )
2323
24−import Data.Char
2524import Data.Word
2625
27−compile :: ClassifyMap -> String -> KClass
26+import qualified Data.ByteString as BS
27+import qualified Data.ByteString.Char8 as BS8
28+import Data.ByteString.Char8 (ByteString)
29+
30+compile :: ClassifyMap -> ByteString -> KClass
2831compile table = cl' where
2932 -- take all prefixes and create a set of these
30− prefixSet = S.fromList $ concatMap (init . inits . fst) table
33+ prefixSet = S.fromList $ concatMap (init . BS.inits . BS8.pack . fst) table
3134 maxValidInputLength = maximum (map (length . fst) table)
32− eventForInput = M.fromList table
33− cl' [] = Prefix
35+ eventForInput = M.fromList $ map (first BS8.pack) table
36+ cl' inputBlock | BS8.null inputBlock = Prefix
3437 cl' inputBlock = case M.lookup inputBlock eventForInput of
3538 -- if the inputBlock is exactly what is expected for an
3639 -- event then consume the whole block and return the event
37− Just e -> Valid e []
40+ Just e -> Valid e BS8.empty
3841 Nothing -> case S.member inputBlock prefixSet of
3942 True -> Prefix
4043 -- look up progressively smaller tails of the input
@@ -45,40 +48,40 @@ compile table = cl' where
4548 -- H: There will always be one match. The prefixSet
4649 -- contains, by definition, all prefixes of an event.
4750 False ->
48− let inputPrefixes = reverse $ take maxValidInputLength $ tail $ inits inputBlock
51+ let inputPrefixes = reverse . take maxValidInputLength . tail . BS8.inits $ inputBlock
4952 in case mapMaybe (\s -> (,) s `fmap` M.lookup s eventForInput) inputPrefixes of
50− (s,e) : _ -> Valid e (drop (length s) inputBlock)
53+ (s,e) : _ -> Valid e (BS8.drop (BS8.length s) inputBlock)
5154 -- neither a prefix or a full event.
5255 [] -> Invalid
5356
54−classify :: ClassifyMap -> String -> KClass
57+classify :: ClassifyMap -> ByteString -> KClass
5558classify table =
5659 let standardClassifier = compile table
57− in \s -> case s of
60+ in \s -> case BS.uncons s of
5861 _ | bracketedPasteStarted s ->
5962 if bracketedPasteFinished s
6063 then parseBracketedPaste s
6164 else Prefix
62− _ | isMouseEvent s -> classifyMouseEvent s
63− _ | isFocusEvent s -> classifyFocusEvent s
64− c:cs | ord c >= 0xC2 -> classifyUtf8 c cs
65− _ -> standardClassifier s
65+ _ | isMouseEvent s -> classifyMouseEvent s
66+ _ | isFocusEvent s -> classifyFocusEvent s
67+ Just (c,cs) | c >= 0xC2 -> classifyUtf8 c cs
68+ _ -> standardClassifier s
6669
67−classifyUtf8 :: Char -> String -> KClass
70+classifyUtf8 :: Word8 -> ByteString -> KClass
6871classifyUtf8 c cs =
69− let n = utf8Length (ord c)
70− (codepoint,rest) = splitAt n (c:cs)
72+ let n = utf8Length c
73+ (codepoint,rest) = BS8.splitAt (n - 1) cs
7174
7275 codepoint8 :: [Word8]
73− codepoint8 = map (fromIntegral . ord) codepoint
76+ codepoint8 = c:BS.unpack codepoint
7477
7578 in case decode codepoint8 of
76− _ | n < length codepoint -> Prefix
77− Just (unicodeChar, _) -> Valid (EvKey (KChar unicodeChar) []) rest
79+ _ | n < BS.length codepoint + 1 -> Prefix
80+ Just (unicodeChar, _) -> Valid (EvKey (KChar unicodeChar) []) rest
7881 -- something bad happened; just ignore and continue.
79− Nothing -> Invalid
82+ Nothing -> Invalid
8083
81−utf8Length :: (Num t, Ord a, Num a) => a -> t
84+utf8Length :: Word8 -> Int
8285utf8Length c
8386 | c < 0x80 = 1
8487 | c < 0xE0 = 2