chiasma-0.2.0.0: lib/Chiasma/Codec/Decode.hs
{-# LANGUAGE TypeOperators #-}
module Chiasma.Codec.Decode where
import qualified Data.Text as Text (null, unpack)
import Data.Text.Read (decimal)
import GHC.Generics (K1(..), M1(..), (:*:)(..))
import Prelude hiding (many)
import Text.Parsec.Char (char, digit)
import Text.ParserCombinators.Parsec (
GenParser,
ParseError,
many,
parse,
)
import Chiasma.Data.TmuxId (PaneId(..), SessionId(..), WindowId(..), panePrefix, sessionPrefix, windowPrefix)
data TmuxDecodeError =
ParseFailure Text ParseError
|
IntParsingFailure Text
|
BoolParsingFailure Text
|
TooFewFields
|
TooManyFields [Text]
deriving (Eq, Show)
class TmuxPrimDecode a where
primDecode :: Text -> Either TmuxDecodeError a
class TmuxDataDecode f where
decode' :: [Text] -> Either TmuxDecodeError ([Text], f a)
instance (TmuxDataDecode f, TmuxDataDecode g) => TmuxDataDecode (f :*: g) where
decode' fields = do
(rest, left) <- decode' fields
(rest1, right) <- decode' rest
return (rest1, left :*: right)
instance TmuxDataDecode f => (TmuxDataDecode (M1 i c f)) where
decode' fields =
second M1 <$> decode' fields
instance TmuxPrimDecode a => (TmuxDataDecode (K1 c a)) where
decode' (a:as) = do
prim <- primDecode a
return (as, K1 prim)
decode' [] = Left TooFewFields
readInt :: Text -> Text -> Either TmuxDecodeError Int
readInt input num =
first (const $ IntParsingFailure input) parsed
where
parsed = do
(num', rest) <- decimal num
if Text.null rest then Right num' else Left ""
instance TmuxPrimDecode Int where
primDecode field = readInt field field
instance TmuxPrimDecode Bool where
primDecode field =
convert =<< readInt field field
where
convert 0 =
Right False
convert 1 =
Right True
convert _ =
Left (BoolParsingFailure $ "got non-bool `" <> show field <> "`")
idParser :: Char -> GenParser Char st Text
idParser sym =
char sym *> (toText <$> many digit)
parseId :: (Int -> a) -> Char -> Text -> Either TmuxDecodeError a
parseId cons sym input = do
num <- first (ParseFailure "id") $ parse (idParser sym) "none" (Text.unpack input)
i <- readInt input num
return $ cons i
instance TmuxPrimDecode SessionId where
primDecode = parseId SessionId sessionPrefix
instance TmuxPrimDecode WindowId where
primDecode = parseId WindowId windowPrefix
instance TmuxPrimDecode PaneId where
primDecode = parseId PaneId panePrefix
instance TmuxPrimDecode [Char] where
primDecode = Right . toString
instance TmuxPrimDecode Text where
primDecode = Right