knit-haskell-0.6.0.0: src/Knit/Report/Output.hs
{-# LANGUAGE OverloadedStrings #-}
module Knit.Report.Output
(
-- * Pandoc Writer Configuration
PandocWriterConfig(..)
, TemplateVariables
, WriterOptionsF
, mkPandocWriterConfig
-- * Pandoc Template Types
, TemplatePath(..)
, CssPath(..)
, addCss
-- * file writing helpers
, writeAllPandocResultsWithInfo
, writePandocResultWithInfo
, writeAndMakePathLT
, writeAndMakePath
)
where
import qualified Paths_knit_haskell as Paths
import qualified Data.Map as M
import qualified Text.Pandoc as PA
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Lazy as TL
import qualified System.Directory as SD
import qualified Knit.Effect.Docs as KD
import qualified Knit.Effect.Pandoc as KP
type TemplateVariables = M.Map String String
type WriterOptionsF = PA.WriterOptions -> PA.WriterOptions
data PandocWriterConfig =
PandocWriterConfig
{
templateFP :: Maybe FilePath
-- ^ optional path to pandoc <https://pandoc.org/MANUAL.html#templates template>
, templateVars :: TemplateVariables
-- ^ variable substitutions for the <https://pandoc.org/MANUAL.html#templates template>
, optionsF :: WriterOptionsF
-- ^ change default <https://pandoc.org/MANUAL.html#general-writer-options options>
}
-- | Make a 'PandocWriterConfig' from a PandocTemplate specification
mkPandocWriterConfig
:: TemplatePath
-> TemplateVariables
-> WriterOptionsF
-> IO PandocWriterConfig
mkPandocWriterConfig tp tv wf = do
templateFPM <- pandocTemplatePath tp
return $ PandocWriterConfig templateFPM tv wf
-- | Type to specify path to template,
-- which may be in a directory installed with knit-haskell.
data TemplatePath = DefaultTemplate
| FromIncludedTemplateDir T.Text
| FullySpecifiedTemplatePath T.Text
-- | get correct path to give Pandoc, depending on how things are installed
pandocTemplatePath :: TemplatePath -> IO (Maybe String)
pandocTemplatePath DefaultTemplate = return Nothing
pandocTemplatePath (FullySpecifiedTemplatePath x) = return $ Just (T.unpack x)
pandocTemplatePath (FromIncludedTemplateDir x) =
fmap (Just . (++ "/knit-haskell-templates/" ++ (T.unpack x))) Paths.getDataDir
-- | Type to specify path to Css,
-- which may be in a directory installed with knit-haskell or not.
data CssPath = FromIncludedCssDir T.Text
| FullySpecifiedCssPath T.Text
-- | Add a CssPath to an existing TemplateVariables
-- which may already have Css paths specified
addCss :: CssPath -> TemplateVariables -> IO TemplateVariables
addCss (FullySpecifiedCssPath x) pt = return $ appendCss x pt
addCss (FromIncludedCssDir x) pt = do
dir <- Paths.getDataDir
let fp = (T.pack dir) <> "/knit-haskell-css/" <> x
return $ appendCss fp pt
-- | Append a filepath (given as Text) to the existing Css paths in TemplateVariables
appendCss :: T.Text -> TemplateVariables -> TemplateVariables
appendCss x tv =
let curValM = M.lookup "css" tv
newVal = maybe (T.unpack x) (\y -> y ++ "," ++ T.unpack x) curValM
in M.insert "css" newVal tv
-- utilities for file output
-- | Write each lazy text from a list of 'KD.DocWithInfo'
-- to disk. File names come from the 'KP.PandocInfo'
-- Directory and file extension are function arguments.
writeAllPandocResultsWithInfo
:: T.Text -> T.Text -> [KP.DocWithInfo KP.PandocInfo TL.Text] -> IO ()
writeAllPandocResultsWithInfo dir extension =
fmap (const ()) . traverse (writePandocResultWithInfo dir extension) -- fmap (const ()) :: IO [()] -> IO ()
-- | Write the Lazy Text in a 'KD.DocWithInfo' to disk
-- Name comes from the 'KP.PandocInfo'
-- Directory and file extection are arguments to the function
-- Create the parent directory or directories, if necessary.
writePandocResultWithInfo
:: T.Text -- ^ directory
-> T.Text -- ^ extension
-> KD.DocWithInfo KP.PandocInfo TL.Text
-> IO ()
writePandocResultWithInfo dir extension (KD.DocWithInfo (KP.PandocInfo n _) x)
= do
let fPath = dir <> "/" <> n <> "." <> extension
writeAndMakePathLT fPath x
-- | Write Lazy Text (Pandoc's Html result) to disk.
-- Create the parent directory or directories, if necessary.
writeAndMakePathLT :: T.Text -> TL.Text -> IO ()
writeAndMakePathLT fPath = writeAndMakePath fPath TL.toStrict
-- | Write (to disk) something which can be converted to text.
-- Create the parent directory or directories, if necessary.
writeAndMakePath :: T.Text -> (a -> T.Text) -> a -> IO ()
writeAndMakePath fPath toStrictText x = do
let (dirPath, fName) = T.breakOnEnd "/" fPath
putStrLn
$ T.unpack
$ "If necessary, creating "
<> dirPath
<> " (and parents), and writing "
<> fName
SD.createDirectoryIfMissing True (T.unpack dirPath)
T.writeFile (T.unpack fPath) $ toStrictText x