{-# LANGUAGE OverloadedStrings #-}
module Data.GCode.Pipes where
import Control.Monad
import Control.Monad.Trans.State.Strict
import Data.ByteString (ByteString)
import System.IO (Handle)
import Data.GCode.Types
import Data.GCode.Canon
import Data.GCode.Eval
import Data.GCode.Line
import Data.GCode.Parse
import Data.GCode.Pretty
import qualified Data.GCode.Canon.Convert
import Pipes
import Pipes.Attoparsec (ParsingError)
import Pipes.Safe (SafeT)
import qualified Data.ByteString.Char8
import qualified Data.Map.Strict
import qualified Pipes.Attoparsec
import qualified Pipes.ByteString
import qualified Pipes.Prelude
import qualified Pipes.Safe
import qualified System.IO
parseProducer :: Handle -> Producer Code (SafeT IO) (Either (ParsingError, Producer ByteString (SafeT IO) ()) ())
parseProducer = parseProducer' 1024
parseProducer' :: MonadIO m
=> Int
-> Handle
-> Producer Code m (Either (ParsingError, Producer ByteString m ()) ())
parseProducer' bufSize handle = Pipes.Attoparsec.parsed
parseGCodeLine (Pipes.ByteString.hGetSome bufSize handle)
withFile :: FilePath -> (Handle -> (SafeT IO) r) -> IO r
withFile filepath job =
System.IO.withFile filepath System.IO.ReadMode $ \handle ->
Pipes.Safe.runSafeT $ job handle
pipeToList :: FilePath -> Proxy () Code () a (SafeT IO) () -> IO [a]
pipeToList filepath pipeTail = withFile filepath $ \h ->
Pipes.Prelude.toListM
$ (() <$ parseProducer h)
>-> pipeTail
gcodeToCanonList :: FilePath -> IO [Canon]
gcodeToCanonList filepath = pipeToList filepath $ evalP >-> evalCanonP
gcodeToLines :: FilePath -> IO [Line]
gcodeToLines filepath = pipeToList filepath $ evalP >-> evalCanonLinesP
gcodePipe :: FilePath -> (Consumer Code (SafeT IO) ()) -> IO ()
gcodePipe filepath pipeTail =
System.IO.withFile filepath System.IO.ReadMode $ \handle ->
Pipes.Safe.runSafeT . runEffect $
(() <$ parseProducer handle)
>-> pipeTail
runPipe :: FilePath
-> Maybe FilePath
-> (Pipe Code ByteString (SafeT IO) ())
-> IO ()
runPipe input Nothing pipeMiddle = gcodePipe input (pipeMiddle >-> Pipes.ByteString.stdout)
runPipe input (Just output) pipeMiddle =
System.IO.withFile output System.IO.WriteMode $ \outhandle ->
gcodePipe input (pipeMiddle >-> Pipes.ByteString.toHandle outhandle)
foldedPipe :: FilePath
-> (Producer Code (Pipes.Safe.SafeT IO) () -> Effect (Pipes.Safe.SafeT IO) r)
-> IO r
foldedPipe filepath fold =
System.IO.withFile filepath System.IO.ReadMode $ \handle ->
Pipes.Safe.runSafeT . runEffect $
fold (() <$ parseProducer handle)
totalizeP :: Pipe Code Code (SafeT IO) ()
totalizeP = flip evalStateT Data.Map.Strict.empty $ forever $ do
x <- lift await
inEffect <- get
let updatedCode = updateFromCurrentModals inEffect x
updatedModals = updateModals inEffect updatedCode
put updatedModals
lift $ yield updatedCode
evalP :: Pipe Code Code (SafeT IO) ()
evalP = flip evalStateT newState $ forever $ do
x <- lift await
st <- get
let (result, steppedState, _rest) = step st [x]
put steppedState
case result of
Just r -> lift $ yield r
Nothing -> return ()
evalCanonP :: Pipe Code Canon (SafeT IO) ()
evalCanonP = flip evalStateT initCanonState $ forever $ do
x <- lift await
st <- get
forM_ (Data.GCode.Canon.Convert.toCanon x) $ \c -> do
let steppedState = stepCanon st c
put steppedState
lift $ yield c
evalCanonLinesP :: Pipe Code Line (SafeT IO) ()
evalCanonLinesP = flip evalStateT initCanonState $ forever $ do
x <- lift await
st <- get
forM_ (Data.GCode.Canon.Convert.toCanon x) $ \c -> do
let steppedState = stepCanon st c
put steppedState
forM_ (toLines st steppedState c) $ lift . yield
prettySinkWith :: (a -> ByteString) -> Pipe a ByteString (SafeT IO) ()
prettySinkWith fn =
Pipes.Prelude.map fn
prettySink :: Pipe Code ByteString (SafeT IO) ()
prettySink =
Pipes.Prelude.map ppGCodeLine
>-> Pipes.Prelude.map (Data.ByteString.Char8.pack . (++"\n"))
compactSink :: Pipe Code ByteString (SafeT IO) ()
compactSink =
Pipes.Prelude.map ppGCodeLineCompact
>-> Pipes.Prelude.map (Data.ByteString.Char8.pack . (++"\n"))
addNewLine :: ByteString -> ByteString
addNewLine to = Data.ByteString.Char8.append to "\n"
wrapPrinter :: (a -> String) -> a -> ByteString
wrapPrinter p = addNewLine . Data.ByteString.Char8.pack . p