aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/Readers/Typst/Parsing.hs
blob: 92a2be4cad9343db9c263e34be6153584dfec725 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Text.Pandoc.Readers.Typst.Parsing
  ( P,
    PState(..),
    defaultPState,
    pTok,
    pWithContents,
    ignored,
    getField,
    chunks,
  )
where
import Control.Monad (MonadPlus)
import Control.Monad.Reader (lift)
import qualified Data.Foldable as F
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Sequence (Seq)
import Data.Text (Text)
import Text.Parsec
    ( ParsecT, getInput, setInput, tokenPrim )
import Typst.Types
    ( Identifier, Content(Elt), FromVal(..), Val(VNone) )
import Text.Pandoc.Class.PandocMonad ( PandocMonad, report )
import Text.Pandoc.Logging (LogMessage(..))
import Text.Pandoc.Definition

data PState = PState
        { sLabels :: [Text]
        , sMeta :: Meta }
        deriving (Show)

defaultPState :: PState
defaultPState =
  PState
  { sLabels = []
  , sMeta = mempty }

type P m a = ParsecT [Content] PState m a
-- state tracks a list of labels in the document

pTok :: PandocMonad m => (Content -> Bool) -> P m Content
pTok f = tokenPrim show showPos match
  where
    showPos _oldpos (Elt _ (Just pos) _) _ = pos
    showPos oldpos _ _ = oldpos
    match x | f x = Just x
    match _ = Nothing

ignored :: PandocMonad m => Text -> P m ()
ignored msg = lift $ report $ IgnoredElement msg

pWithContents :: PandocMonad m => P m a -> Seq Content -> P m a
pWithContents pa cs = do
  inp <- getInput
  setInput $ F.toList cs
  res <- pa
  setInput inp
  pure res

-- | Get field value from element, defaulting to VNone.
getField ::
  (MonadFail m, MonadPlus m, FromVal a) =>
  Identifier ->
  M.Map Identifier Val ->
  m a
getField name fields = fromVal $ fromMaybe VNone $ M.lookup name fields

-- | Split a list into chunks of a given size. The last chunk may be smaller.
chunks :: Int -> [a] -> [[a]]
chunks _ [] = []
chunks n xs = take n xs : chunks n (drop n xs)