------------------------------------------------------------------------------
-- |
-- Module      : LiterateX
-- Description : API
-- Copyright   : Copyright (c) 2021 Travis Cardwell
-- License     : MIT
--
-- This module provides high-level as well as low-level API functions for
-- transforming literate source code.
------------------------------------------------------------------------------

{-# LANGUAGE FlexibleInstances #-}

module LiterateX
  ( -- * Constants
    version
    -- * API
    -- ** High-Level
    -- $HighLevelAPI
  , transformTextToText
  , transformTextToHandle
  , transformTextToFile
  , transformHandleToText
  , transformHandleToHandle
  , transformHandleToFile
  , transformFileToText
  , transformFileToHandle
  , transformFileToFile
    -- ** Low-Level
    -- $LowLevelAPI
  , runPure
  , runIO
  , runResource
    -- *** Producers
  , sourceString
  , sourceText
  , sourceLazyText
  , sourceByteString
  , sourceLazyByteString
  , sourceHandle
  , sourceFile
    -- *** Consumers
  , sinkString
  , sinkText
  , sinkLazyText
  , sinkByteString
  , sinkLazyByteString
  , sinkHandle
  , sinkFile
    -- *** Transformers
  , transform
  ) where

-- https://hackage.haskell.org/package/base
import Control.Monad.IO.Class (MonadIO)
import Data.Version (showVersion)
import System.IO (Handle)

-- https://hackage.haskell.org/package/bytestring
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL

-- https://hackage.haskell.org/package/conduit
import qualified Conduit as C
import Data.Conduit ((.|))
import qualified Data.Conduit.Combinators as CC
import qualified Data.Conduit.List as CL

-- https://hackage.haskell.org/package/text
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.Encoding.Error as TEE
import qualified Data.Text.Lazy as TL

-- https://hackage.haskell.org/package/unliftio
import UnliftIO (MonadUnliftIO)

-- (literatex)
import qualified LiterateX.Parser as Parser
import qualified LiterateX.Renderer as Renderer
import LiterateX.Types (SourceFormat)

-- (literatex:cabal)
import qualified Paths_literatex as Project

------------------------------------------------------------------------------
-- $Constants

-- | LiterateX version string (\"@literatex-haskell X.X.X@\")
version :: String
version :: String
version = String
"literatex-haskell " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
showVersion Version
Project.version

------------------------------------------------------------------------------
-- $HighLevelAPI
--
-- This high-level API provides functions for transforming literate source
-- code.  These functions provide support for transforming from/to lazy
-- 'TL.Text', 'Handle's, and files.
--
-- Example usage:
--
-- @
-- {-\# LANGUAGE OverloadedStrings \#-}
--
-- module Main (main) where
--
-- -- https://hackage.haskell.org/package/literatex
-- import qualified LiterateX
-- import qualified LiterateX.Renderer as Renderer
-- import qualified LiterateX.Types.SourceFormat as SourceFormat
--
-- main :: IO ()
-- main = LiterateX.transformFileToFile
--     SourceFormat.LiterateHaskell
--     (Renderer.defaultOptionsFor "haskell")
--     "demo.lhs"
--     "demo.md"
-- @

-- | Transform from lazy 'TL.Text' to lazy 'TL.Text'
--
-- @since 0.0.1.0
transformTextToText
  :: SourceFormat
  -> Renderer.Options
  -> TL.Text
  -> TL.Text
transformTextToText :: SourceFormat -> Options -> Text -> Text
transformTextToText SourceFormat
sourceFormat Options
rendererOpts Text
source =
    SourceFormat
-> Options
-> ConduitT () Text Identity ()
-> ConduitT Text Void Identity Text
-> Text
forall r.
SourceFormat
-> Options
-> ConduitT () Text Identity ()
-> ConduitT Text Void Identity r
-> r
runPure SourceFormat
sourceFormat Options
rendererOpts (Text -> ConduitT () Text Identity ()
forall (m :: * -> *) i. Monad m => Text -> ConduitT i Text m ()
sourceLazyText Text
source) ConduitT Text Void Identity Text
forall (m :: * -> *) o. Monad m => ConduitT Text o m Text
sinkLazyText

-- | Transform from lazy 'TL.Text' to a 'Handle'
--
-- @since 0.0.1.0
transformTextToHandle
  :: MonadIO m
  => SourceFormat
  -> Renderer.Options
  -> TL.Text
  -> Handle
  -> m ()
transformTextToHandle :: SourceFormat -> Options -> Text -> Handle -> m ()
transformTextToHandle SourceFormat
sourceFormat Options
rendererOpts Text
source Handle
target =
    SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m ()
-> m ()
forall (m :: * -> *) r.
MonadIO m =>
SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m r
-> m r
runIO SourceFormat
sourceFormat Options
rendererOpts
      (Text -> ConduitT () Text m ()
forall (m :: * -> *) i. Monad m => Text -> ConduitT i Text m ()
sourceLazyText Text
source)
      (Handle -> ConduitT Text Void m ()
forall (m :: * -> *) o. MonadIO m => Handle -> ConduitT Text o m ()
sinkHandle Handle
target)

-- | Transform from lazy 'TL.Text' to a file
--
-- @since 0.0.1.0
transformTextToFile
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> TL.Text
  -> FilePath
  -> m ()
transformTextToFile :: SourceFormat -> Options -> Text -> String -> m ()
transformTextToFile SourceFormat
sourceFormat Options
rendererOpts Text
source String
target =
    SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) ()
-> m ()
forall (m :: * -> *) r.
MonadUnliftIO m =>
SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts
      (Text -> ConduitT () Text (ResourceT m) ()
forall (m :: * -> *) i. Monad m => Text -> ConduitT i Text m ()
sourceLazyText Text
source)
      (String -> ConduitT Text Void (ResourceT m) ()
forall (m :: * -> *) o.
MonadResource m =>
String -> ConduitT Text o m ()
sinkFile String
target)

-- | Transform from a 'Handle' to lazy 'TL.Text'
--
-- @since 0.0.1.0
transformHandleToText
  :: MonadIO m
  => SourceFormat
  -> Renderer.Options
  -> Handle
  -> m TL.Text
transformHandleToText :: SourceFormat -> Options -> Handle -> m Text
transformHandleToText SourceFormat
sourceFormat Options
rendererOpts Handle
source =
    SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m Text
-> m Text
forall (m :: * -> *) r.
MonadIO m =>
SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m r
-> m r
runIO SourceFormat
sourceFormat Options
rendererOpts (Handle -> ConduitT () Text m ()
forall (m :: * -> *) i. MonadIO m => Handle -> ConduitT i Text m ()
sourceHandle Handle
source) ConduitT Text Void m Text
forall (m :: * -> *) o. Monad m => ConduitT Text o m Text
sinkLazyText

-- | Transform from a 'Handle' to a 'Handle'
--
-- @since 0.0.1.0
transformHandleToHandle
  :: MonadIO m
  => SourceFormat
  -> Renderer.Options
  -> Handle
  -> Handle
  -> m ()
transformHandleToHandle :: SourceFormat -> Options -> Handle -> Handle -> m ()
transformHandleToHandle SourceFormat
sourceFormat Options
rendererOpts Handle
source Handle
target =
    SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m ()
-> m ()
forall (m :: * -> *) r.
MonadIO m =>
SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m r
-> m r
runIO SourceFormat
sourceFormat Options
rendererOpts (Handle -> ConduitT () Text m ()
forall (m :: * -> *) i. MonadIO m => Handle -> ConduitT i Text m ()
sourceHandle Handle
source) (Handle -> ConduitT Text Void m ()
forall (m :: * -> *) o. MonadIO m => Handle -> ConduitT Text o m ()
sinkHandle Handle
target)

-- | Transform from a 'Handle' to a file
--
-- @since 0.0.1.0
transformHandleToFile
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> Handle
  -> FilePath
  -> m ()
transformHandleToFile :: SourceFormat -> Options -> Handle -> String -> m ()
transformHandleToFile SourceFormat
sourceFormat Options
rendererOpts Handle
source String
target =
    SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) ()
-> m ()
forall (m :: * -> *) r.
MonadUnliftIO m =>
SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts
      (Handle -> ConduitT () Text (ResourceT m) ()
forall (m :: * -> *) i. MonadIO m => Handle -> ConduitT i Text m ()
sourceHandle Handle
source)
      (String -> ConduitT Text Void (ResourceT m) ()
forall (m :: * -> *) o.
MonadResource m =>
String -> ConduitT Text o m ()
sinkFile String
target)

-- | Transform from a file to lazy 'TL.Text'
--
-- @since 0.0.1.0
transformFileToText
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> FilePath
  -> m TL.Text
transformFileToText :: SourceFormat -> Options -> String -> m Text
transformFileToText SourceFormat
sourceFormat Options
rendererOpts String
source =
    SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) Text
-> m Text
forall (m :: * -> *) r.
MonadUnliftIO m =>
SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts (String -> ConduitT () Text (ResourceT m) ()
forall (m :: * -> *) i.
MonadResource m =>
String -> ConduitT i Text m ()
sourceFile String
source) ConduitT Text Void (ResourceT m) Text
forall (m :: * -> *) o. Monad m => ConduitT Text o m Text
sinkLazyText

-- | Transform from a file to a 'Handle'
--
-- @since 0.0.1.0
transformFileToHandle
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> FilePath
  -> Handle
  -> m ()
transformFileToHandle :: SourceFormat -> Options -> String -> Handle -> m ()
transformFileToHandle SourceFormat
sourceFormat Options
rendererOpts String
source Handle
target =
    SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) ()
-> m ()
forall (m :: * -> *) r.
MonadUnliftIO m =>
SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts
      (String -> ConduitT () Text (ResourceT m) ()
forall (m :: * -> *) i.
MonadResource m =>
String -> ConduitT i Text m ()
sourceFile String
source)
      (Handle -> ConduitT Text Void (ResourceT m) ()
forall (m :: * -> *) o. MonadIO m => Handle -> ConduitT Text o m ()
sinkHandle Handle
target)

-- | Transform from a file to a file
--
-- @since 0.0.1.0
transformFileToFile
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> FilePath
  -> FilePath
  -> m ()
transformFileToFile :: SourceFormat -> Options -> String -> String -> m ()
transformFileToFile SourceFormat
sourceFormat Options
rendererOpts String
source String
target =
    SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) ()
-> m ()
forall (m :: * -> *) r.
MonadUnliftIO m =>
SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts
      (String -> ConduitT () Text (ResourceT m) ()
forall (m :: * -> *) i.
MonadResource m =>
String -> ConduitT i Text m ()
sourceFile String
source)
      (String -> ConduitT Text Void (ResourceT m) ()
forall (m :: * -> *) o.
MonadResource m =>
String -> ConduitT Text o m ()
sinkFile String
target)

------------------------------------------------------------------------------
-- $LowLevelAPI
--
-- This low-level API provides more control over transforming literate source
-- code, using "Conduit".  The 'transform' transformer implements the
-- transformation, transforming lines of input 'T.Text' to lines of output
-- 'T.Text'.  Various producers are provided to produce lines of input
-- 'T.Text' from common sources, and various consumers are provided to consume
-- lines of output 'T.Text' to common sinks.  These can be used separately if
-- necessary, but some run functions are provided for common usage.
--
-- Example usage:
--
-- @
-- {-\# LANGUAGE OverloadedStrings \#-}
--
-- module Main (main) where
--
-- -- https://hackage.haskell.org/package/base
-- import System.IO (stdout)
--
-- -- https://hackage.haskell.org/package/literatex
-- import qualified LiterateX
-- import qualified LiterateX.Renderer as Renderer
-- import qualified LiterateX.Types.SourceFormat as SourceFormat
--
-- main :: IO ()
-- main = do
--     let demoBS = "..."
--     LiterateX.runIO
--       SourceFormat.LiterateHaskell
--       (Renderer.defaultOptionsFor "haskell")
--       (LiterateX.sourceByteString demoBS)
--       (LiterateX.sinkHandle stdout)
-- @

-- | Run a pure LiterateX transformation
--
-- This function works with the following input line producers:
--
-- * 'sourceString'
-- * 'sourceText'
-- * 'sourceLazyText'
-- * 'sourceByteString'
-- * 'sourceLazyByteString'
--
-- This function works with the following output line consumers:
--
-- * 'sinkString'
-- * 'sinkText'
-- * 'sinkLazyText'
-- * 'sinkByteString'
-- * 'sinkLazyByteString'
--
-- @since 0.0.1.0
runPure
  :: SourceFormat
  -> Renderer.Options
  -> C.ConduitT () T.Text C.Identity ()     -- ^ input line producer
  -> C.ConduitT T.Text C.Void C.Identity r  -- ^ output line consumer
  -> r
runPure :: SourceFormat
-> Options
-> ConduitT () Text Identity ()
-> ConduitT Text Void Identity r
-> r
runPure SourceFormat
sourceFormat Options
rendererOpts ConduitT () Text Identity ()
source ConduitT Text Void Identity r
sink = ConduitT () Void Identity r -> r
forall r. ConduitT () Void Identity r -> r
C.runConduitPure (ConduitT () Void Identity r -> r)
-> ConduitT () Void Identity r -> r
forall a b. (a -> b) -> a -> b
$
    ConduitT () Text Identity ()
source ConduitT () Text Identity ()
-> ConduitT Text Void Identity r -> ConduitT () Void Identity r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| SourceFormat -> Options -> ConduitT Text Text Identity ()
forall (m :: * -> *).
Monad m =>
SourceFormat -> Options -> ConduitT Text Text m ()
transform SourceFormat
sourceFormat Options
rendererOpts ConduitT Text Text Identity ()
-> ConduitT Text Void Identity r -> ConduitT Text Void Identity r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text Void Identity r
sink

-- | Run a LiterateX transformation using IO
--
-- This function works with the following input line producers:
--
-- * 'sourceString'
-- * 'sourceText'
-- * 'sourceLazyText'
-- * 'sourceByteString'
-- * 'sourceLazyByteString'
-- * 'sourceHandle'
--
-- This function works with the following output line consumers:
--
-- * 'sinkString'
-- * 'sinkText'
-- * 'sinkLazyText'
-- * 'sinkByteString'
-- * 'sinkLazyByteString'
-- * 'sinkHandle'
--
-- @since 0.0.1.0
runIO
  :: MonadIO m
  => SourceFormat
  -> Renderer.Options
  -> C.ConduitT () T.Text m ()     -- ^ input line producer
  -> C.ConduitT T.Text C.Void m r  -- ^ output line consumer
  -> m r
runIO :: SourceFormat
-> Options
-> ConduitT () Text m ()
-> ConduitT Text Void m r
-> m r
runIO SourceFormat
sourceFormat Options
rendererOpts ConduitT () Text m ()
source ConduitT Text Void m r
sink = ConduitT () Void m r -> m r
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
C.runConduit (ConduitT () Void m r -> m r) -> ConduitT () Void m r -> m r
forall a b. (a -> b) -> a -> b
$
    ConduitT () Text m ()
source ConduitT () Text m ()
-> ConduitT Text Void m r -> ConduitT () Void m r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| SourceFormat -> Options -> ConduitT Text Text m ()
forall (m :: * -> *).
Monad m =>
SourceFormat -> Options -> ConduitT Text Text m ()
transform SourceFormat
sourceFormat Options
rendererOpts ConduitT Text Text m ()
-> ConduitT Text Void m r -> ConduitT Text Void m r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text Void m r
sink

-- | Run a LiterateX transformation using resource management
--
-- This function works with the following input line producers:
--
-- * 'sourceString'
-- * 'sourceText'
-- * 'sourceLazyText'
-- * 'sourceByteString'
-- * 'sourceLazyByteString'
-- * 'sourceHandle'
-- * 'sourceFile'
--
-- This function works with the following output line consumers:
--
-- * 'sinkString'
-- * 'sinkText'
-- * 'sinkLazyText'
-- * 'sinkByteString'
-- * 'sinkLazyByteString'
-- * 'sinkHandle'
-- * 'sinkFile'
--
-- @since 0.0.1.0
runResource
  :: MonadUnliftIO m
  => SourceFormat
  -> Renderer.Options
  -> C.ConduitT () T.Text (C.ResourceT m) ()     -- ^ input line producer
  -> C.ConduitT T.Text C.Void (C.ResourceT m) r  -- ^ output line consumer
  -> m r
runResource :: SourceFormat
-> Options
-> ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> m r
runResource SourceFormat
sourceFormat Options
rendererOpts ConduitT () Text (ResourceT m) ()
source ConduitT Text Void (ResourceT m) r
sink = ConduitT () Void (ResourceT m) r -> m r
forall (m :: * -> *) r.
MonadUnliftIO m =>
ConduitT () Void (ResourceT m) r -> m r
C.runConduitRes (ConduitT () Void (ResourceT m) r -> m r)
-> ConduitT () Void (ResourceT m) r -> m r
forall a b. (a -> b) -> a -> b
$
    ConduitT () Text (ResourceT m) ()
source ConduitT () Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> ConduitT () Void (ResourceT m) r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| SourceFormat -> Options -> ConduitT Text Text (ResourceT m) ()
forall (m :: * -> *).
Monad m =>
SourceFormat -> Options -> ConduitT Text Text m ()
transform SourceFormat
sourceFormat Options
rendererOpts ConduitT Text Text (ResourceT m) ()
-> ConduitT Text Void (ResourceT m) r
-> ConduitT Text Void (ResourceT m) r
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text Void (ResourceT m) r
sink

------------------------------------------------------------------------------
-- $Producers

-- | Produce input lines from a 'String' source
--
-- @since 0.0.1.0
sourceString
  :: Monad m
  => String
  -> C.ConduitT i T.Text m ()
sourceString :: String -> ConduitT i Text m ()
sourceString = [Text] -> ConduitT i Text m ()
forall (m :: * -> *) mono i.
(Monad m, MonoFoldable mono) =>
mono -> ConduitT i (Element mono) m ()
CC.yieldMany ([Text] -> ConduitT i Text m ())
-> (String -> [Text]) -> String -> ConduitT i Text m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
T.pack ([String] -> [Text]) -> (String -> [String]) -> String -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

-- | Produce input lines from a 'T.Text' source
--
-- @since 0.0.1.0
sourceText
  :: Monad m
  => T.Text
  -> C.ConduitT i T.Text m ()
sourceText :: Text -> ConduitT i Text m ()
sourceText Text
source = Text -> ConduitT i Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
source ConduitT i Text m ()
-> ConduitM Text Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.linesUnbounded

-- | Produce input lines from a lazy 'TL.Text' source
--
-- @since 0.0.1.0
sourceLazyText
  :: Monad m
  => TL.Text
  -> C.ConduitT i T.Text m ()
sourceLazyText :: Text -> ConduitT i Text m ()
sourceLazyText Text
source = Text -> ConduitT i Text m ()
forall (m :: * -> *) lazy strict i.
(Monad m, LazySequence lazy strict) =>
lazy -> ConduitT i strict m ()
CC.sourceLazy Text
source ConduitT i Text m ()
-> ConduitM Text Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.linesUnbounded

-- | Produce input lines from a 'BS.ByteString' source
--
-- @since 0.0.1.0
sourceByteString
  :: Monad m
  => BS.ByteString
  -> C.ConduitT i T.Text m ()
sourceByteString :: ByteString -> ConduitT i Text m ()
sourceByteString ByteString
source =
    ByteString -> ConduitT i ByteString m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield ByteString
source ConduitT i ByteString m ()
-> ConduitM ByteString Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.linesUnboundedAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString Text m () -> ConduitM ByteString Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString Text m ()
forall (m :: * -> *). Monad m => ConduitT ByteString Text m ()
decodeUtf8LinesLenient

-- | Produce input lines from a lazy 'BS.ByteString' source
--
-- @since 0.0.1.0
sourceLazyByteString
  :: Monad m
  => BSL.ByteString
  -> C.ConduitT i T.Text m ()
sourceLazyByteString :: ByteString -> ConduitT i Text m ()
sourceLazyByteString ByteString
source =
    ByteString -> ConduitT i ByteString m ()
forall (m :: * -> *) lazy strict i.
(Monad m, LazySequence lazy strict) =>
lazy -> ConduitT i strict m ()
CC.sourceLazy ByteString
source ConduitT i ByteString m ()
-> ConduitM ByteString Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.linesUnboundedAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString Text m () -> ConduitM ByteString Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString Text m ()
forall (m :: * -> *). Monad m => ConduitT ByteString Text m ()
decodeUtf8LinesLenient

-- | Produce input lines from a 'Handle' source
--
-- @since 0.0.1.0
sourceHandle
  :: MonadIO m
  => Handle
  -> C.ConduitT i T.Text m ()
sourceHandle :: Handle -> ConduitT i Text m ()
sourceHandle Handle
source =
    Handle -> ConduitT i ByteString m ()
forall (m :: * -> *) i.
MonadIO m =>
Handle -> ConduitT i ByteString m ()
CC.sourceHandle Handle
source ConduitT i ByteString m ()
-> ConduitM ByteString Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.linesUnboundedAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString Text m () -> ConduitM ByteString Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString Text m ()
forall (m :: * -> *). Monad m => ConduitT ByteString Text m ()
decodeUtf8LinesLenient

-- | Produce input lines from a file source
--
-- @since 0.0.1.0
sourceFile
  :: C.MonadResource m
  => FilePath
  -> C.ConduitT i T.Text m ()
sourceFile :: String -> ConduitT i Text m ()
sourceFile String
source =
    String -> ConduitT i ByteString m ()
forall (m :: * -> *) i.
MonadResource m =>
String -> ConduitT i ByteString m ()
CC.sourceFile String
source ConduitT i ByteString m ()
-> ConduitM ByteString Text m () -> ConduitT i Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.linesUnboundedAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString Text m () -> ConduitM ByteString Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString Text m ()
forall (m :: * -> *). Monad m => ConduitT ByteString Text m ()
decodeUtf8LinesLenient

------------------------------------------------------------------------------
-- $Consumers

-- | Consume output lines, returning a 'String'
--
-- @since 0.0.1.0
sinkString
  :: Monad m
  => C.ConduitT T.Text o m String
sinkString :: ConduitT Text o m String
sinkString = (Text -> String)
-> ConduitT Text o m Text -> ConduitT Text o m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> String
TL.unpack (ConduitT Text o m Text -> ConduitT Text o m String)
-> ConduitT Text o m Text -> ConduitT Text o m String
forall a b. (a -> b) -> a -> b
$ ConduitT Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.unlines ConduitT Text Text m ()
-> ConduitT Text o m Text -> ConduitT Text o m Text
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text o m Text
forall (m :: * -> *) lazy strict o.
(Monad m, LazySequence lazy strict) =>
ConduitT strict o m lazy
CC.sinkLazy

-- | Consume output lines, returning 'T.Text'
--
-- @since 0.0.1.0
sinkText
  :: Monad m
  => C.ConduitT T.Text o m T.Text
sinkText :: ConduitT Text o m Text
sinkText = (Text -> Text) -> ConduitT Text o m Text -> ConduitT Text o m Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
TL.toStrict (ConduitT Text o m Text -> ConduitT Text o m Text)
-> ConduitT Text o m Text -> ConduitT Text o m Text
forall a b. (a -> b) -> a -> b
$ ConduitT Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.unlines ConduitT Text Text m ()
-> ConduitT Text o m Text -> ConduitT Text o m Text
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text o m Text
forall (m :: * -> *) lazy strict o.
(Monad m, LazySequence lazy strict) =>
ConduitT strict o m lazy
CC.sinkLazy

-- | Consume output lines, returning lazy 'T.Text'
--
-- @since 0.0.1.0
sinkLazyText
  :: Monad m
  => C.ConduitT T.Text o m TL.Text
sinkLazyText :: ConduitT Text o m Text
sinkLazyText = ConduitT Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.unlines ConduitT Text Text m ()
-> ConduitT Text o m Text -> ConduitT Text o m Text
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text o m Text
forall (m :: * -> *) lazy strict o.
(Monad m, LazySequence lazy strict) =>
ConduitT strict o m lazy
CC.sinkLazy

-- | Consume output lines, returning a 'BS.ByteString'
--
-- @since 0.0.1.0
sinkByteString
  :: Monad m
  => C.ConduitT T.Text o m BS.ByteString
sinkByteString :: ConduitT Text o m ByteString
sinkByteString =
    (ByteString -> ByteString)
-> ConduitT Text o m ByteString -> ConduitT Text o m ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString
BSL.toStrict (ConduitT Text o m ByteString -> ConduitT Text o m ByteString)
-> ConduitT Text o m ByteString -> ConduitT Text o m ByteString
forall a b. (a -> b) -> a -> b
$ ConduitT Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.unlines ConduitT Text Text m ()
-> ConduitT Text o m ByteString -> ConduitT Text o m ByteString
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text ByteString m ()
forall (m :: * -> *) text binary.
(Monad m, Utf8 text binary) =>
ConduitT text binary m ()
CC.encodeUtf8 ConduitT Text ByteString m ()
-> ConduitM ByteString o m ByteString
-> ConduitT Text o m ByteString
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString o m ByteString
forall (m :: * -> *) lazy strict o.
(Monad m, LazySequence lazy strict) =>
ConduitT strict o m lazy
CC.sinkLazy

-- | Consume output lines, returning a lazy 'BS.ByteString'
--
-- @since 0.0.1.0
sinkLazyByteString
  :: Monad m
  => C.ConduitT T.Text o m BSL.ByteString
sinkLazyByteString :: ConduitT Text o m ByteString
sinkLazyByteString = ConduitT Text Text m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Char) =>
ConduitT seq seq m ()
CC.unlines ConduitT Text Text m ()
-> ConduitT Text o m ByteString -> ConduitT Text o m ByteString
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT Text ByteString m ()
forall (m :: * -> *) text binary.
(Monad m, Utf8 text binary) =>
ConduitT text binary m ()
CC.encodeUtf8 ConduitT Text ByteString m ()
-> ConduitM ByteString o m ByteString
-> ConduitT Text o m ByteString
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString o m ByteString
forall (m :: * -> *) lazy strict o.
(Monad m, LazySequence lazy strict) =>
ConduitT strict o m lazy
CC.sinkLazy

-- | Consume output lines, writing to a 'Handle'
--
-- @since 0.0.1.0
sinkHandle
  :: MonadIO m
  => Handle
  -> C.ConduitT T.Text o m ()
sinkHandle :: Handle -> ConduitT Text o m ()
sinkHandle Handle
target = ConduitT Text ByteString m ()
forall (m :: * -> *) text binary.
(Monad m, Utf8 text binary) =>
ConduitT text binary m ()
CC.encodeUtf8 ConduitT Text ByteString m ()
-> ConduitM ByteString o m () -> ConduitT Text o m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.unlinesAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString o m () -> ConduitM ByteString o m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| Handle -> ConduitM ByteString o m ()
forall (m :: * -> *) o.
MonadIO m =>
Handle -> ConduitT ByteString o m ()
CC.sinkHandle Handle
target

-- | Consume output lines, writing to a file
--
-- @since 0.0.1.0
sinkFile
  :: C.MonadResource m
  => FilePath
  -> C.ConduitT T.Text o m ()
sinkFile :: String -> ConduitT Text o m ()
sinkFile String
target = ConduitT Text ByteString m ()
forall (m :: * -> *) text binary.
(Monad m, Utf8 text binary) =>
ConduitT text binary m ()
CC.encodeUtf8 ConduitT Text ByteString m ()
-> ConduitM ByteString o m () -> ConduitT Text o m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitT ByteString ByteString m ()
forall (m :: * -> *) seq.
(Monad m, IsSequence seq, Element seq ~ Word8) =>
ConduitT seq seq m ()
CC.unlinesAscii ConduitT ByteString ByteString m ()
-> ConduitM ByteString o m () -> ConduitM ByteString o m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| String -> ConduitM ByteString o m ()
forall (m :: * -> *) o.
MonadResource m =>
String -> ConduitT ByteString o m ()
CC.sinkFile String
target

------------------------------------------------------------------------------
-- $Transformers

-- | Transform input lines to output lines
--
-- @since 0.0.1.0
transform
  :: Monad m
  => SourceFormat
  -> Renderer.Options
  -> C.ConduitT T.Text T.Text m ()
transform :: SourceFormat -> Options -> ConduitT Text Text m ()
transform SourceFormat
sourceFormat Options
rendererOpts
    = SourceFormat -> ConduitT Text SourceLine m ()
forall (m :: * -> *).
Monad m =>
SourceFormat -> ConduitT Text SourceLine m ()
Parser.parse SourceFormat
sourceFormat
    ConduitT Text SourceLine m ()
-> ConduitM SourceLine Text m () -> ConduitT Text Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| (SourceLine -> Int -> (Int, [(Int, SourceLine)]))
-> Int -> ConduitT SourceLine (Int, SourceLine) m ()
forall (m :: * -> *) a accum b.
Monad m =>
(a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()
CL.concatMapAccum (\SourceLine
x Int
n -> (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, [(Int
n, SourceLine
x)])) Int
1
    ConduitT SourceLine (Int, SourceLine) m ()
-> ConduitM (Int, SourceLine) Text m ()
-> ConduitM SourceLine Text m ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| Options -> ConduitM (Int, SourceLine) Text m ()
forall (m :: * -> *).
Monad m =>
Options -> ConduitT (Int, SourceLine) Text m ()
Renderer.render Options
rendererOpts

------------------------------------------------------------------------------
-- $Internal

-- | Decode UTF-8 'BS.ByteString' lines to 'T.Text'
--
-- Note that 'CC.decodeUtf8Lenient' decodes UTF-8 streams and therefore
-- discards empty strings.  This version decodes UTF-8 lines and does not
-- discard empty lines.
decodeUtf8LinesLenient
  :: Monad m
  => C.ConduitT BS.ByteString T.Text m ()
decodeUtf8LinesLenient :: ConduitT ByteString Text m ()
decodeUtf8LinesLenient =
    (ByteString -> ConduitT ByteString Text m ())
-> ConduitT ByteString Text m ()
forall (m :: * -> *) i o r.
Monad m =>
(i -> ConduitT i o m r) -> ConduitT i o m ()
C.awaitForever ((ByteString -> ConduitT ByteString Text m ())
 -> ConduitT ByteString Text m ())
-> (ByteString -> ConduitT ByteString Text m ())
-> ConduitT ByteString Text m ()
forall a b. (a -> b) -> a -> b
$ Text -> ConduitT ByteString Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield (Text -> ConduitT ByteString Text m ())
-> (ByteString -> Text)
-> ByteString
-> ConduitT ByteString Text m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OnDecodeError -> ByteString -> Text
TE.decodeUtf8With OnDecodeError
TEE.lenientDecode