diff options
| author | tv <tv@shackspace.de> | 2014-12-30 14:51:13 +0100 | 
|---|---|---|
| committer | tv <tv@shackspace.de> | 2015-10-17 02:12:27 +0200 | 
| commit | a5a3f35da8d06ee4e5db4bc4ebc29b4c60fec6fe (patch) | |
| tree | d66680fbcd1d017dd16e7368532e400729743798 /src | |
| parent | 768a1f96c9d7a8dc1bb6e68d94d117d3e7409a69 (diff) | |
rewrite Scanner to use Event
Diffstat (limited to 'src')
| -rw-r--r-- | src/Scanner.hs | 283 | 
1 files changed, 80 insertions, 203 deletions
| diff --git a/src/Scanner.hs b/src/Scanner.hs index 3c96a6e..361a1c6 100644 --- a/src/Scanner.hs +++ b/src/Scanner.hs @@ -1,217 +1,102 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-}  module Scanner -    ( getKey -    , hGetKey +    ( scan      ) where -import Prelude hiding ((/)) -import Control.Applicative -import Control.Monad.Error -import Control.Monad.State -import Control.Monad.Writer -import Data.Bits -import Data.Char -import System.IO +import Data.Char (ord) +import Event +import System.IO (Handle, hGetChar, hLookAhead, hWaitForInput) --- high level interface - -getKey :: IO String -getKey = hGetKey stdin - -hGetKey :: Handle -> IO String -hGetKey h = do -    _ <- hLookAhead h -- wait for input -    ((_, raw_s), _) <- runScanner $ scan h -    return $ map toChar raw_s - - - -type P = C -type I = C -type F = C - - -data Token -    = CS [P] [I] F -    | Chr C -  deriving (Show) - - -type ScanLog = [C] - - -type ScanError = String - - -data ScanState = ScanState -    { _result :: Maybe Token -- TODO underscore supresses warning, rename before usage.. -    , buffer :: [C] -    } - - -emptyScanState :: ScanState -emptyScanState = ScanState Nothing [] - - -newtype Scanner m a = Scanner -    (ErrorT ScanError (WriterT ScanLog (StateT ScanState m)) a) -  deriving -    ( Applicative -    , Functor -    , Monad -    , MonadIO -    , MonadState ScanState -    , MonadError ScanError -    , MonadWriter ScanLog -    ) - - -runScanner :: Scanner m a -> m ((Either ScanError a, ScanLog), ScanState) -runScanner (Scanner a) = -    runStateT (runWriterT (runErrorT a)) emptyScanState - - --- TODO max timeout  timeout :: Int  timeout = 1 -scan, scanESC, scanCS :: -    ( Monad m -    , MonadIO m -    , MonadError ScanError m -    , MonadState ScanState m -    , MonadWriter ScanLog m -    ) -    => Handle -    -> m () - -scan h = do -    c <- liftIO $ hGetC h -    tell [c] -    case () of _ -                | c == 01/11 -> scanESC h -                | otherwise -> return () - - -scanESC h = do -    mb_c <- liftIO $ hWaitGetC timeout h -    whenJust mb_c $ \ c -> do -        tell [c] -        case () of _ -                    | c == 05/11 -> -                        -- CSI -                        scanCS h - -                    | c == 01/11 -> -                        -- XXX M-F1 and other crazy chords may cause -                        -- \ESC\ESC... on wu, so we just recurse here... -                        scanESC h - -                    | c == 04/15 -> -                        -- XXX Non-CSI SS3 -                        one h $ between (04/00) (07/14) - -                    | otherwise -> return () - - -scanCS h = do -    zeroOrMore h $ between (03/00) (03/15)    -- parameter bytes -    zeroOrMore h $ between (02/00) (02/15)    -- intermediate bytes -    one h $ between (04/00) (07/14)           -- final byte - - -between :: C -> C -> (C -> Bool) -between lo hi = \ x -> lo <= x && x <= hi - - -zeroOrMore, one :: -    ( Monad m -    , MonadIO m -    , MonadError ScanError m -    , MonadState ScanState m -    , MonadWriter ScanLog m -    ) -    => Handle -    -> (C -> Bool) -    -> m () - -zeroOrMore h p = do -    mb_c <- liftIO $ hWaitLookAheadC timeout h -    whenJust mb_c $ \ c -> -        when (p c) $ do -            _ <- liftIO $ hGetC h -- drop -            tell [c] -            modify $ \q -> q { buffer = buffer q ++ [c] } -            zeroOrMore h p - - -one h p = do -    mb_c <- liftIO $ hWaitLookAheadC timeout h -    whenJust mb_c $ \ c -> do -        if p c -            then do -                _ <- liftIO getChar -                tell [c] -                modify $ \q -> q { buffer = buffer q ++ [c] } -            else do -                throwError "expected one TODO" - - - - - - - - -whenJust :: Monad m => Maybe a -> (a -> m ()) -> m () -whenJust mb f = -    case mb of -        Just a -> f a -        Nothing -> return () - - - -(/) :: Int -> Int -> C -c / r = C c r +scan :: Handle -> IO Event +scan h = +    hGetChar h >>= \case +        '\ESC' -> scanESC h +        c -> return $ EKey [c] + -data C = C { column :: Int, row :: Int } -    deriving (Eq) +scanESC :: Handle -> IO Event +scanESC h = +    hWaitGetChar timeout h >>= \case +        Nothing -> return $ EKey "\ESC" +        Just c +            | c == '[' -> -- 05/11 +                scanCS h +            | c == '\ESC' -> -- 01/11 +                -- XXX M-F1 and other crazy chords may cause +                -- \ESC\ESC... on wu, so we just recurse here... +                scanESC h +            | c == 'O' -> -- 04/15 +                -- XXX Non-CSI SS3 +                -- XXX finalByte is maybe calles somehow else here, but it's +                -- the same range +                one h finalByte ['O','\ESC'] >>= +                return . EKey . reverse +            | otherwise -> +                return $ EKey ['\ESC',c] + + +scanCS :: Handle -> IO Event +scanCS h = +    hWaitLookAhead timeout h >>= \case +        Nothing -> return $ EKey "\ESC" -- TODO move this to scanESC +        Just c +            | c == 'M' -> do +                -- VT200 mouse +                _ <- hGetChar h -- drop 'M' +                b <- hGetChar h +                x <- hGetChar h +                y <- hGetChar h +                return $ EMouse b (ord x - 32) (ord y - 32) +            | otherwise -> +                zeroOrMore h parameterByte ['[', '\ESC'] >>= +                zeroOrMore h intermediateByte >>= +                one h finalByte >>= +                return . EKey . reverse + -instance Show C where -  show C{..} =  -      (padl 2 '0' $ show column) ++ "/" ++ (padl 2 '0' $ show row) -    where -      padl n c s -        | length s < n = padl n c (c : s) -        | otherwise = s +zeroOrMore :: Handle -> (Char -> Bool) -> [Char] -> IO [Char] +zeroOrMore h p buf = +    hWaitLookAhead timeout h >>= \case +        Nothing -> return buf +        Just c +            | p c -> +                hGetChar h {-drop c-} >> zeroOrMore h p (c:buf) +            | otherwise -> +                return buf -instance Ord C where -    compare (C c1 r1) (C c2 r2) = -        case compare c1 c2 of -            EQ -> compare r1 r2 -            x -> x +one :: Handle -> (Char -> Bool) -> [Char] -> IO [Char] +one h p buf = +    hWaitLookAhead timeout h >>= \case +        Nothing -> return buf -- TODO error? +        Just c +            | p c -> do +                _ <- hGetChar h -- drop c +                return (c:buf) +            | otherwise -> +                error "expected one TODO" -fromChar :: Char -> C -fromChar c = let i = ord c in C ((shift i (-4)) .&. 0xf) (i .&. 0xf) +parameterByte :: Char -> Bool +parameterByte = between '0' '?'     -- 03/00 03/15 -toChar :: C -> Char -toChar (C col row) = chr $ (shift col 4) .|. row +intermediateByte :: Char -> Bool +intermediateByte = between ' ' '/'  -- 02/00 02/15 - --- +finalByte :: Char -> Bool +finalByte = between '@' '~'         -- 04/00 07/14 -hGetC :: Handle -> IO C -hGetC h = hGetChar h >>= return . fromChar +between :: Ord a => a -> a -> (a -> Bool) +between lo hi = \ x -> lo <= x && x <= hi  hWaitGetChar :: Int -> Handle -> IO (Maybe Char) @@ -222,17 +107,9 @@ hWaitGetChar t h = do          else return Nothing -hWaitGetC :: Int -> Handle -> IO (Maybe C) -hWaitGetC t h = do -    mb_ch <- hWaitGetChar t h -    case mb_ch of -        Nothing -> return Nothing -        Just ch -> return $ Just $ fromChar $ ch - - -hWaitLookAheadC :: Int -> Handle -> IO (Maybe C) -hWaitLookAheadC t h = do +hWaitLookAhead :: Int -> Handle -> IO (Maybe Char) +hWaitLookAhead t h = do      ready <- hWaitForInput h t      if ready -        then hLookAhead h >>= return . Just . fromChar +        then hLookAhead h >>= return . Just          else return Nothing | 
