emanote-1.0.2.0: src/Emanote/Model/Title.hs
{-# LANGUAGE DeriveAnyClass #-}
module Emanote.Model.Title (
Title,
-- * Title conversion
fromRoute,
fromInlines,
toInlines,
-- * Rendering a Title
titleSplice,
titleSpliceNoHtml,
toPlain,
) where
import Commonmark.Extensions.WikiLink (plainify)
import Data.Aeson (ToJSON)
import Emanote.Route qualified as R
import Heist.Extra.Splices.Pandoc qualified as HP
import Heist.Interpreted qualified as HI
import Relude
import Text.Pandoc.Definition qualified as B
import Text.Pandoc.Walk qualified as W
data Title
= TitlePlain Text
| TitlePandoc [B.Inline]
deriving stock (Show, Generic)
deriving anyclass (ToJSON)
instance Eq Title where
(==) =
-- Use toPlain here, rather than toInlines, because the same text can have
-- different inlines structure. For example, "Foo Bar" can be represented as
-- [Str "Foo", Space, Str "Bar"],
-- or as,
-- [Str "Foo Bar"]
on (==) toPlain
instance Ord Title where
compare =
on compare toPlain
instance Semigroup Title where
TitlePlain a <> TitlePlain b =
TitlePlain (a <> b)
x <> y =
TitlePandoc $ on (<>) toInlines x y
instance IsString Title where
fromString = TitlePlain . toText
fromRoute :: R.LMLRoute -> Title
fromRoute =
TitlePlain . R.withLmlRoute R.routeBaseName
fromInlines :: [B.Inline] -> Title
fromInlines = TitlePandoc
toInlines :: Title -> [B.Inline]
toInlines = \case
TitlePlain s -> one (B.Str s)
TitlePandoc is -> is
toPlain :: Title -> Text
toPlain = \case
TitlePlain s -> s
TitlePandoc is -> plainify is
titleSplice ::
forall b.
(W.Walkable B.Inline b, b ~ [B.Inline]) =>
HP.RenderCtx ->
(b -> b) ->
Title ->
HI.Splice Identity
titleSplice ctx f = \case
TitlePlain x ->
HI.textSplice x
TitlePandoc is -> do
let titleDoc = B.Pandoc mempty $ one $ B.Plain $ f is
HP.pandocSplice ctx titleDoc
titleSpliceNoHtml :: Title -> HI.Splice Identity
titleSpliceNoHtml =
HI.textSplice . toPlain