module Data.Iteratee.Char (
Stream,
Iteratee,
EnumeratorM,
Line,
line,
printLines,
readLines,
enumLines,
enumWords,
module Data.Iteratee.Base
)
where
import qualified Data.Iteratee.Base as Iter
import Data.Iteratee.Base hiding (break)
import Data.Char
import Control.Monad.Trans
import qualified Data.ListLike as LL
import Data.Monoid
type Stream = StreamG [] Char
type Iteratee = IterateeG [] Char
type Line = String
line :: Monad m => IterateeG [] Char m (Either Line Line)
line = Iter.break (\c -> c == '\r' || c == '\n') >>= \l ->
terminators >>= check l
where
check l 0 = return . Left $ l
check l _ = return . Right $ l
terminators = heads "\r\n" >>= \l -> if l == 0 then heads "\n" else return l
printLines :: IterateeG [] Char IO ()
printLines = lines'
where
lines' = Iter.break (\c -> c == '\r' || c == '\n') >>= \l ->
terminators >>= check l
check _ 0 = return ()
check "" _ = return ()
check l _ = liftIO (putStrLn l) >> lines'
terminators = heads "\r\n" >>= \l -> if l == 0 then heads "\n" else return l
readLines :: (Monad m) => IterateeG [] Char m (Either [Line] [Line])
readLines = lines' []
where
lines' acc = Iter.break (\c -> c == '\r' || c == '\n') >>= \l ->
terminators >>= check acc l
check acc _ 0 = return . Left . reverse $ acc
check acc "" _ = return . Right . reverse $ acc
check acc l _ = lines' (l:acc)
terminators = heads "\r\n" >>= \l -> if l == 0 then heads "\n" else return l
enumLines :: (LL.ListLike (s el) el, LL.StringLike (s el), Functor m, Monad m) =>
IterateeG [] (s el) m a ->
IterateeG s el m (IterateeG [] (s el) m a)
enumLines = convStream getter
where
getter = IterateeG step
lChar = (== '\n') . last . LL.toString
step (Chunk xs)
| LL.null xs = return $ Cont getter Nothing
| lChar xs = return $ Done (Just $ LL.lines xs) (Chunk mempty)
| True = return $ Cont (IterateeG (step' xs)) Nothing
step str = return $ Done Nothing str
step' xs (Chunk ys)
| LL.null ys = return $ Cont (IterateeG (step' xs)) Nothing
| lChar ys = return $ Done (Just . LL.lines . mappend xs $ ys)
(Chunk mempty)
| True = let w' = LL.lines $ mappend xs ys
ws = init w'
ck = last w'
in return $ Done (Just ws) (Chunk ck)
step' xs str = return $ Done (Just $ LL.lines xs) str
enumWords :: (LL.ListLike (s el) el
, LL.StringLike (s el)
, Functor m, Monad m)
=> IterateeG [] (s el) m a
-> IterateeG s el m (IterateeG [] (s el) m a)
enumWords = convStream getter
where
getter = IterateeG step
lChar = isSpace . last . LL.toString
step (Chunk xs) | LL.null xs = return $ Cont getter Nothing
step (Chunk xs)
| LL.null xs = return $ Cont getter Nothing
| lChar xs = return $ Done (Just $ LL.words xs) (Chunk mempty)
| True = return $ Cont (IterateeG (step' xs)) Nothing
step str = return $ Done Nothing str
step' xs (Chunk ys)
| LL.null ys = return $ Cont (IterateeG (step' xs)) Nothing
| lChar ys = return $ Done (Just . LL.words . mappend xs $ ys)
(Chunk mempty)
| True = let w' = LL.words $ mappend xs ys
ws = init w'
ck = last w'
in return $ Done (Just ws) (Chunk ck)
step' xs str = return $ Done (Just $ LL.words xs) str
type EnumeratorM m a = EnumeratorGM [] Char m a