{-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE UndecidableInstances #-} {-| Module : Knit.Report Description : Re-export all the things required for pandoc-built reports. Copyright : (c) Adam Conner-Sax 2019 License : BSD-3-Clause Maintainer : adam_conner_sax@yahoo.com Stability : experimental This module re-exports the basic pieces to build reports using Pandoc as well as providing functions to do the "knitting"--produce the documents. That is, it is intended as one-stop-shopping for using this library to produce Html from various fragments which Pandoc can read. are available, and might be useful for seeing how all this works. Notes: 1. The "Knit.Effect.RandomFu" effect is not imported since the names might clash with "Polysemy.Random". Import either effect directly if you need it. 2. You can add logging from within document creation using 'logLE'. 3. The "Knit.Report.Input.MarkDown.PandocMarkDown" module is exported so if you want to use a different markdown flavor you may need to hide "addMarkDown" when you import this module. 4. If you use any other effects in your polysemy stack (e.g., Random or RandomFu), you will need to interpret/run them before calling knitHtml/knitHtmls. -} module Knit.Report ( -- * Knit knitHtml , knitHtmls , liftKnit , KnitBase -- * Inputs , module Knit.Report.Input.Table.Colonnade , module Knit.Report.Input.MarkDown.PandocMarkDown , module Knit.Report.Input.Html , module Knit.Report.Input.Html.Blaze , module Knit.Report.Input.Html.Lucid , module Knit.Report.Input.Latex , module Knit.Report.Input.Visualization.Hvega -- * Output , module Knit.Report.Output , module Knit.Report.Output.Html -- * Effects , module Polysemy , module Knit.Effect.Pandoc , module Knit.Effect.PandocMonad , module Knit.Effect.Logger ) where import Polysemy ( Member , Semantic , Lift ) import Knit.Effect.Pandoc ( ToPandoc , Requirement(..) , PandocReadFormat(..) , PandocWriteFormat(..) , Pandocs ) import Knit.Effect.PandocMonad import Knit.Effect.Logger ( LogSeverity(..) , logAll , nonDiagnostic , logLE , wrapPrefix , filteredLogEntriesToIO , LogWithPrefixesLE ) import Knit.Report.Input.Table.Colonnade ( addColonnadeTextTable , addColonnadeHtmlTable , addColonnadeCellTable ) import Knit.Report.Input.MarkDown.PandocMarkDown ( addMarkDown ) import Knit.Report.Input.Html ( addStrictTextHtml , addLazyTextHtml ) import Knit.Report.Input.Html.Blaze ( addBlaze ) import Knit.Report.Input.Html.Lucid ( addLucid ) import Knit.Report.Input.Latex ( addLatex ) import Knit.Report.Input.Visualization.Hvega ( addHvega ) import Knit.Report.Output ( PandocWriterConfig(..) ) import Knit.Report.Output.Html ( pandocWriterToBlazeDocument , mindocOptionsF ) import Text.Pandoc ( PandocError ) import Control.Monad.Except ( MonadIO ) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import GHC.Exts ( Constraint ) import qualified Polysemy as P import qualified Polysemy.Error as PE import qualified Polysemy.IO as PI import qualified Text.Pandoc as PA import qualified Text.Blaze.Html.Renderer.Text as BH import qualified Knit.Report.Output.Html as KO import qualified Knit.Effect.Docs as KD import qualified Knit.Effect.Pandoc as KP import qualified Knit.Effect.PandocMonad as KPM import qualified Knit.Effect.Logger as KLog -- | Create multiple HTML docs (as Text) from the named sets of pandoc fragments. -- In use, you may need a type-application to specify m. -- This allows use of any underlying monad to handle the Pandoc effects. knitHtmls :: forall m . (MonadIO m, LastMember (P.Lift m) (KnitEffectStack m)) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> PandocWriterConfig -- ^ configuration for the Pandoc Html Writer -> P.Semantic (KnitEffectDocsStack m) () -- ^ Knit effects "over" m -> m (Either PA.PandocError [KP.NamedDoc TL.Text]) -- ^ named documents, converted to Html as Text or error knitHtmls loggingPrefixM ls writeConfig = runSemT (consumeKnitEffectMany loggingPrefixM ls writeConfig) -- | Create HTML Text from pandoc fragments -- In use, you may need a type-application to specify m. -- This allows use of any underlying monad to handle the Pandoc effects. knitHtml :: forall m . (MonadIO m, LastMember (P.Lift m) (KnitEffectStack m)) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> PandocWriterConfig -- ^ configuration for the Pandoc Html Writer -> P.Semantic (KnitEffectDocStack m) () -- ^ Knit effects "over" m -> m (Either PA.PandocError TL.Text) -- ^ document, converted to Html as Text, or error knitHtml loggingPrefixM ls writeConfig = runSemT (consumeKnitEffectOne loggingPrefixM ls writeConfig) -- | Constraints required to build a document while also using effects from a base monad m. type KnitBase m effs = (MonadIO m, P.Member (P.Lift m) effs) -- | lift an action in a base monad into a Polysemy monad liftKnit :: Member (Lift m) r => m a -> Semantic r a liftKnit = P.sendM -- From here down is unexported. -- | The exact stack we are interpreting when we knit type KnitEffectStack m = '[ KPM.Pandoc , KLog.Logger KLog.LogEntry , KLog.PrefixLog , PE.Error PA.PandocError , P.Lift IO , P.Lift m ] -- | Add a Multi-doc writer to the front of the effect list type KnitEffectDocsStack m = (KD.Docs KP.PandocWithRequirements ': KnitEffectStack m) -- | Add a single-doc writer to the front of the effect list type KnitEffectDocStack m = (KP.ToPandoc ': KnitEffectStack m) -- | require that the effect @eff@ be last in the list of effects @r@ type family LastMember (eff :: k) (r :: [k]) :: Constraint where LastMember eff '[] = () LastMember eff (e : es) = (P.Member eff (e ': es), LastMember eff es) -- | run all effects, given that last one is @Lift m@ runSemT :: Monad m => (P.Semantic r a -> P.Semantic '[P.Lift m] b) -> P.Semantic r a -> m b runSemT consume = P.runM . consume -- | run all effects in @KnitEffectStack m@ except the final @Lift m@ consumeKnitEffectStack :: forall m a . (MonadIO m, LastMember (P.Lift m) (KnitEffectStack m)) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> P.Semantic (KnitEffectStack m) a -> P.Semantic '[P.Lift m] (Either PA.PandocError a) consumeKnitEffectStack loggingPrefixM ls = PI.runIO @m -- interpret (Lift IO) using m . PE.runError . KLog.filteredLogEntriesToIO ls . KPM.interpretInIO -- PA.PandocIO . maybe id KLog.wrapPrefix loggingPrefixM -- | run all effects in @KnitEffectDocsStack m@ except the final @Lift m@ consumeKnitEffectMany :: forall m . (MonadIO m, LastMember (P.Lift m) (KnitEffectStack m)) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> PandocWriterConfig -- ^ configuration for the Pandoc Html Writer -> P.Semantic (KnitEffectDocsStack m) () -> P.Semantic '[P.Lift m] (Either PA.PandocError [KP.NamedDoc TL.Text]) consumeKnitEffectMany loggingPrefixM ls writeConfig = consumeKnitEffectStack @m loggingPrefixM ls . KD.toNamedDocListWithM (fmap BH.renderHtml . KO.toBlazeDocument writeConfig) -- | run all effects in @KnitEffectDocStack m@ except the final @Lift m@ consumeKnitEffectOne :: forall m . (MonadIO m, LastMember (P.Lift m) (KnitEffectStack m)) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> PandocWriterConfig -- ^ configuration for the Pandoc Html Writer -> P.Semantic (KnitEffectDocStack m) () -> P.Semantic '[P.Lift m] (Either PA.PandocError TL.Text) consumeKnitEffectOne loggingPrefixM ls writeConfig = fmap (fmap (fmap BH.renderHtml)) (consumeKnitEffectStack @m loggingPrefixM ls) . KO.pandocWriterToBlazeDocument writeConfig {- type KnitEffectC m r = ( P.Member KPM.Pandoc r , KLog.LogWithPrefixesLE r , P.Member (PE.Error PA.PandocError) r , P.Member (P.Lift IO) r , P.Member (P.Lift m) r ) consumeKnitEffectPoly :: forall m r a . (PA.PandocMonad m, MonadIO m, KnitEffectC m r, LastMember (P.Lift m) r) => Maybe T.Text -- ^ outer logging prefix -> [KLog.LogSeverity] -- ^ what to output in log -> P.Semantic r a -> P.Semantic '[P.Lift m] (Either PA.PandocError a) consumeKnitEffectPoly loggingPrefixM ls = PI.runIO @m . PE.runError . KLog.filteredLogEntriesToIO ls . KPM.runPandoc @m -- PA.PandocIO . maybe id KLog.wrapPrefix loggingPrefixM -}