{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module LiterateX.Renderer
(
Options(..)
, defaultOptions
, defaultOptionsFor
, render
) where
import Control.Monad (replicateM_)
import qualified Data.Conduit as C
import Data.Conduit (ConduitT)
import qualified Data.Text as T
import Data.Text (Text)
import LiterateX.Types (CodeLanguage, SourceLine, TargetFormat)
import qualified LiterateX.Types.SourceLine as SourceLine
import qualified LiterateX.Types.TargetFormat as TargetFormat
data Options
= Options
{ Options -> TargetFormat
targetFormat :: !TargetFormat
, Options -> Maybe CodeLanguage
codeLanguage :: !(Maybe CodeLanguage)
, Options -> Bool
ignoreShebang :: !Bool
, Options -> Bool
renderCode :: !Bool
, Options -> Bool
numberCodeLines :: !Bool
}
deriving Int -> Options -> ShowS
[Options] -> ShowS
Options -> String
(Int -> Options -> ShowS)
-> (Options -> String) -> ([Options] -> ShowS) -> Show Options
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Options] -> ShowS
$cshowList :: [Options] -> ShowS
show :: Options -> String
$cshow :: Options -> String
showsPrec :: Int -> Options -> ShowS
$cshowsPrec :: Int -> Options -> ShowS
Show
defaultOptions :: Options
defaultOptions :: Options
defaultOptions = Options :: TargetFormat
-> Maybe CodeLanguage -> Bool -> Bool -> Bool -> Options
Options
{ targetFormat :: TargetFormat
targetFormat = TargetFormat
TargetFormat.PandocMarkdown
, codeLanguage :: Maybe CodeLanguage
codeLanguage = Maybe CodeLanguage
forall a. Maybe a
Nothing
, ignoreShebang :: Bool
ignoreShebang = Bool
True
, renderCode :: Bool
renderCode = Bool
True
, numberCodeLines :: Bool
numberCodeLines = Bool
True
}
defaultOptionsFor :: CodeLanguage -> Options
defaultOptionsFor :: CodeLanguage -> Options
defaultOptionsFor CodeLanguage
lang = Options
defaultOptions
{ codeLanguage :: Maybe CodeLanguage
codeLanguage = CodeLanguage -> Maybe CodeLanguage
forall a. a -> Maybe a
Just CodeLanguage
lang
}
render
:: forall m. Monad m
=> Options
-> ConduitT (Int, SourceLine) Text m ()
render :: Options -> ConduitT (Int, SourceLine) Text m ()
render Options{Bool
Maybe CodeLanguage
TargetFormat
numberCodeLines :: Bool
renderCode :: Bool
ignoreShebang :: Bool
codeLanguage :: Maybe CodeLanguage
targetFormat :: TargetFormat
numberCodeLines :: Options -> Bool
renderCode :: Options -> Bool
ignoreShebang :: Options -> Bool
codeLanguage :: Options -> Maybe CodeLanguage
targetFormat :: Options -> TargetFormat
..} = ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sStart
where
sStart
:: Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ()
sStart :: Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sStart (Just (Int
lineNum, SourceLine
sourceLine)) = case SourceLine
sourceLine of
SourceLine.Shebang Text
line
| Bool
renderCode Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
ignoreShebang -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield (Text -> ConduitT (Int, SourceLine) Text m ())
-> Text -> ConduitT (Int, SourceLine) Text m ()
forall a b. (a -> b) -> a -> b
$ Int -> Text
startShebang Int
lineNum
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
endCode
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
| Bool
otherwise -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sStart
SourceLine.Doc Text
line -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sDoc
SourceLine.Code Text
line
| Bool
renderCode -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield (Text -> ConduitT (Int, SourceLine) Text m ())
-> Text -> ConduitT (Int, SourceLine) Text m ()
forall a b. (a -> b) -> a -> b
$ Int -> Text
startCode Int
lineNum
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode Int
0
| Bool
otherwise -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sStart
SourceLine
_BlankOrRule -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sStart
sStart Maybe (Int, SourceLine)
Nothing = () -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sCode
:: Int
-> Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ()
sCode :: Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode !Int
numBlanks (Just (Int
_lineNum, SourceLine
sourceLine)) = case SourceLine
sourceLine of
SourceLine.Code Text
line -> do
Int
-> ConduitT (Int, SourceLine) Text m ()
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
replicateM_ Int
numBlanks (ConduitT (Int, SourceLine) Text m ()
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
-> ConduitT (Int, SourceLine) Text m ()
forall a b. (a -> b) -> a -> b
$ Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
T.empty
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode Int
0
SourceLine
SourceLine.CodeBlank -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode (Int
numBlanks Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
SourceLine.Doc Text
line -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
endCode
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
T.empty
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sDoc
SourceLine
SourceLine.DocBlank -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
endCode
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
SourceLine
SourceLine.Rule -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
endCode
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
SourceLine.Shebang Text
_line -> String -> ConduitT (Int, SourceLine) Text m ()
forall a. HasCallStack => String -> a
error String
"impossible: Shebang in sCode"
sCode Int
_numBlanks Maybe (Int, SourceLine)
Nothing = Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
endCode
sDoc
:: Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ()
sDoc :: Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sDoc (Just (Int
lineNum, SourceLine
sourceLine)) = case SourceLine
sourceLine of
SourceLine.Doc Text
line -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sDoc
SourceLine.Code Text
line
| Bool
renderCode -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
T.empty
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield (Text -> ConduitT (Int, SourceLine) Text m ())
-> Text -> ConduitT (Int, SourceLine) Text m ()
forall a b. (a -> b) -> a -> b
$ Int -> Text
startCode Int
lineNum
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode Int
0
| Bool
otherwise -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
SourceLine.Shebang Text
_line -> String -> ConduitT (Int, SourceLine) Text m ()
forall a. HasCallStack => String -> a
error String
"impossible: Shebang in sDoc"
SourceLine
_BlankOrRule -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
sDoc Maybe (Int, SourceLine)
Nothing = () -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sBlank
:: Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ()
sBlank :: Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank (Just (Int
lineNum, SourceLine
sourceLine)) = case SourceLine
sourceLine of
SourceLine.Code Text
line
| Bool
renderCode -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
T.empty
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield (Text -> ConduitT (Int, SourceLine) Text m ())
-> Text -> ConduitT (Int, SourceLine) Text m ()
forall a b. (a -> b) -> a -> b
$ Int -> Text
startCode Int
lineNum
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int
-> Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sCode Int
0
| Bool
otherwise -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
SourceLine.Doc Text
line -> do
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
T.empty
Text -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
C.yield Text
line
ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sDoc
SourceLine.Shebang Text
_line -> String -> ConduitT (Int, SourceLine) Text m ()
forall a. HasCallStack => String -> a
error String
"impossible: Shebang in sBlank"
SourceLine
_BlankOrRule -> ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
C.await ConduitT (Int, SourceLine) Text m (Maybe (Int, SourceLine))
-> (Maybe (Int, SourceLine)
-> ConduitT (Int, SourceLine) Text m ())
-> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Int, SourceLine) -> ConduitT (Int, SourceLine) Text m ()
sBlank
sBlank Maybe (Int, SourceLine)
Nothing = () -> ConduitT (Int, SourceLine) Text m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
startCode :: Int -> Text
startCode :: Int -> Text
startCode =
TargetFormat -> Maybe CodeLanguage -> Bool -> Int -> Text
TargetFormat.mkBeginCode TargetFormat
targetFormat Maybe CodeLanguage
codeLanguage Bool
numberCodeLines
startShebang :: Int -> Text
startShebang :: Int -> Text
startShebang =
TargetFormat -> Maybe CodeLanguage -> Bool -> Int -> Text
TargetFormat.mkBeginCode TargetFormat
targetFormat Maybe CodeLanguage
forall a. Maybe a
Nothing Bool
numberCodeLines
endCode :: Text
endCode :: Text
endCode = TargetFormat -> Text
TargetFormat.mkEndCode TargetFormat
targetFormat
{-# ANN render ("HLint: ignore Reduce duplication" :: String) #-}