------------------------------------------------------------------------------
-- |
-- Module: Xmobar.Config.Template
-- Copyright: (c) 2022 jao
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: mail@jao.io
-- Stability: unstable
-- Portability: portable
-- Created: Fri Sep 30, 2022 06:33
--
--
-- Parsing template strings
--
------------------------------------------------------------------------------


module Xmobar.Config.Template (parseString) where

import Data.Maybe (fromMaybe)
import qualified Control.Monad as CM

import Text.Parsec ((<|>))
import Text.Read (readMaybe)

import qualified Text.Parsec as P
import qualified Text.Parsec.Combinator as C

import Text.ParserCombinators.Parsec (Parser)

import qualified Xmobar.Config.Types as T

type Context = (T.TextRenderInfo, T.FontIndex, Maybe [T.Action])

retSegment :: Context -> T.Widget -> Parser [T.Segment]
retSegment :: Context -> Widget -> Parser [Segment]
retSegment (TextRenderInfo
i, Int
idx, Maybe [Action]
as) Widget
widget = forall (m :: * -> *) a. Monad m => a -> m a
return [(Widget
widget, TextRenderInfo
i, Int
idx, Maybe [Action]
as)]

-- | Run the template string parser for the given config, producing a list of
-- drawable segment specifications.
parseString :: T.Config -> String -> [T.Segment]
parseString :: Config -> String -> [Segment]
parseString Config
c String
s =
  case forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
P.parse (Context -> Parser [[Segment]]
stringParser forall {a}. (TextRenderInfo, Int, Maybe a)
ci) String
"" String
s of
    Left  ParseError
_ -> [(String -> Widget
T.Text forall a b. (a -> b) -> a -> b
$ String
"Could not parse string: " forall a. [a] -> [a] -> [a]
++ String
s, TextRenderInfo
ti, Int
0, forall a. Maybe a
Nothing)]
    Right [[Segment]]
x -> forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Segment]]
x
  where ci :: (TextRenderInfo, Int, Maybe a)
ci = (TextRenderInfo
ti , Int
0, forall a. Maybe a
Nothing)
        ti :: TextRenderInfo
ti = String -> Int32 -> Int32 -> [Box] -> TextRenderInfo
T.TextRenderInfo (Config -> String
T.fgColor Config
c) Int32
0 Int32
0 []

-- Top level parser reading the full template string
stringParser :: Context -> Parser [[T.Segment]]
stringParser :: Context -> Parser [[Segment]]
stringParser Context
c = forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill (Context -> Parser [Segment]
allParsers Context
c) forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
C.eof

allParsers :: Context -> Parser [T.Segment]
allParsers :: Context -> Parser [Segment]
allParsers Context
c = forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
C.choice (Context -> Parser [Segment]
textParser Context
cforall a. a -> [a] -> [a]
:forall a b. (a -> b) -> [a] -> [b]
map (\Context -> Parser [Segment]
f -> forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try (Context -> Parser [Segment]
f Context
c)) [Context -> Parser [Segment]]
parsers)
  where parsers :: [Context -> Parser [Segment]]
parsers = [ Context -> Parser [Segment]
iconParser, Context -> Parser [Segment]
hspaceParser, Context -> Parser [Segment]
rawParser, Context -> Parser [Segment]
actionParser
                  , Context -> Parser [Segment]
fontParser, Context -> Parser [Segment]
boxParser, Context -> Parser [Segment]
colorParser ]

-- Wrapper for notFollowedBy that returns the result of the first parser.
-- Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy
-- accepts only parsers with return type Char.
notFollowedBy' :: Parser a -> Parser b -> Parser a
notFollowedBy' :: forall a b. Parser a -> Parser b -> Parser a
notFollowedBy' Parser a
p Parser b
e = do a
x <- Parser a
p
                        forall s (m :: * -> *) t a u.
(Stream s m t, Show a) =>
ParsecT s u m a -> ParsecT s u m ()
C.notFollowedBy forall a b. (a -> b) -> a -> b
$ forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try (Parser b
e forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'*')
                        forall (m :: * -> *) a. Monad m => a -> m a
return a
x

-- Parse a maximal string without markup
textParser :: Context -> Parser [T.Segment]
textParser :: Context -> Parser [Segment]
textParser Context
c =
  forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.noneOf String
"<" forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try (forall a b. Parser a -> Parser b -> Parser a
notFollowedBy' (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
P.char Char
'<') forall {u}. ParsecT String u Identity String
suffixes))
  forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Context -> Widget -> Parser [Segment]
retSegment Context
c forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Widget
T.Text
  where suffixes :: ParsecT String u Identity String
suffixes = forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
C.choice forall a b. (a -> b) -> a -> b
$  forall a b. (a -> b) -> [a] -> [b]
map (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string)
                   [ String
"icon=" , String
"hspace=", String
"raw="
                   , String
"action=", String
"/action>", String
"fn=", String
"/fn>"
                   , String
"box", String
"/box>", String
"fc=", String
"/fc>" ]

-- Parse a "raw" tag, which we use to prevent other tags from creeping in.
-- The format here is net-string-esque: a literal "<raw=" followed by a string
-- of digits (base 10) denoting the length of the raw string, a literal ":" as
-- digit-string-terminator, the raw string itself, and then a literal "/>".
rawParser :: Context -> Parser [T.Segment]
rawParser :: Context -> Parser [Segment]
rawParser Context
c = do
  forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<raw="
  String
lenstr <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.digit
  forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
P.char Char
':'
  case forall a. Read a => ReadS a
reads String
lenstr of
    [(Integer
len,[])] -> do
      forall (f :: * -> *). Alternative f => Bool -> f ()
CM.guard ((Integer
len :: Integer) forall a. Ord a => a -> a -> Bool
<= forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int))
      String
s <- forall s (m :: * -> *) t u a.
Stream s m t =>
Int -> ParsecT s u m a -> ParsecT s u m [a]
C.count (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
len) forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.anyChar
      forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"/>"
      Context -> Widget -> Parser [Segment]
retSegment Context
c (String -> Widget
T.Text String
s)
    [(Integer, String)]
_ -> forall (m :: * -> *) a. MonadPlus m => m a
CM.mzero

iconParser :: Context -> Parser [T.Segment]
iconParser :: Context -> Parser [Segment]
iconParser Context
c = do
  forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<icon="
  String
i <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.noneOf String
">") (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"/>"))
  Context -> Widget -> Parser [Segment]
retSegment Context
c (String -> Widget
T.Icon String
i)

hspaceParser :: Context -> Parser [T.Segment]
hspaceParser :: Context -> Parser [Segment]
hspaceParser Context
c = do
  forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<hspace="
  String
pVal <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.digit (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"/>"))
  Context -> Widget -> Parser [Segment]
retSegment Context
c (Int32 -> Widget
T.Hspace (forall a. a -> Maybe a -> a
fromMaybe Int32
0 forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
pVal))

actionParser :: Context -> Parser [T.Segment]
actionParser :: Context -> Parser [Segment]
actionParser (TextRenderInfo
ti, Int
fi, Maybe [Action]
act) = do
  forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<action="
  String
command <- forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
C.between (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
P.char Char
'`') (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
P.char Char
'`') (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.noneOf String
"`"))
             forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.noneOf String
">")
  String
buttons <- (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
P.char Char
'>' forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return String
"1") forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m ()
P.spaces forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
    forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
C.between (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"button=") (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
">") (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.oneOf String
"12345")))
  let a :: Action
a = [Button] -> String -> Action
T.Spawn (String -> [Button]
toButtons String
buttons) String
command
      a' :: Maybe [Action]
a' = case Maybe [Action]
act of
        Maybe [Action]
Nothing -> forall a. a -> Maybe a
Just [Action
a]
        Just [Action]
act' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Action
a forall a. a -> [a] -> [a]
: [Action]
act'
  [[Segment]]
s <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill (Context -> Parser [Segment]
allParsers (TextRenderInfo
ti, Int
fi, Maybe [Action]
a')) (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"</action>")
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Segment]]
s)

toButtons :: String -> [T.Button]
toButtons :: String -> [Button]
toButtons = forall a b. (a -> b) -> [a] -> [b]
map (\Char
x -> forall a. Read a => String -> a
read [Char
x])

colorParser :: Context -> Parser [T.Segment]
colorParser :: Context -> Parser [Segment]
colorParser (T.TextRenderInfo String
_ Int32
_ Int32
_ [Box]
bs, Int
fidx, Maybe [Action]
a) = do
  String
c <- forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
C.between (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<fc=") (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
">") (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 forall {u}. ParsecT String u Identity Char
colorc)
  let colorParts :: (String, String)
colorParts = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
':') String
c
  let (String
ot,String
ob) = case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
',') (forall a. Int -> [a] -> [a]
drop Int
1 forall a b. (a -> b) -> a -> b
$ forall a b. (a, b) -> b
snd (String, String)
colorParts) of
                  (String
top,Char
',':String
btm) -> (String
top, String
btm)
                  (String
top,      String
_) -> (String
top, String
top)
      tri :: TextRenderInfo
tri = String -> Int32 -> Int32 -> [Box] -> TextRenderInfo
T.TextRenderInfo (forall a b. (a, b) -> a
fst (String, String)
colorParts)
                           (forall a. a -> Maybe a -> a
fromMaybe (-Int32
1) forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
ot)
                           (forall a. a -> Maybe a -> a
fromMaybe (-Int32
1) forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
ob)
                           [Box]
bs
  [[Segment]]
s <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill (Context -> Parser [Segment]
allParsers (TextRenderInfo
tri, Int
fidx, Maybe [Action]
a)) (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"</fc>")
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Segment]]
s)
  where colorc :: ParsecT String u Identity Char
colorc = forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.alphaNum forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.oneOf String
",:#"

boxParser :: Context -> Parser [T.Segment]
boxParser :: Context -> Parser [Segment]
boxParser (T.TextRenderInfo String
cs Int32
ot Int32
ob [Box]
bs, Int
f, Maybe [Action]
a) = do
  String
c <- forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
C.between (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<box") (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
">")
                 (forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
C.option String
"" (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 (forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.alphaNum forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
P.oneOf String
"= #,")))
  let b :: Box
b = BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box BoxBorder
T.BBFull (Align -> Int32 -> BoxOffset
T.BoxOffset Align
T.C Int32
0) CInt
1 String
cs (Int32 -> Int32 -> Int32 -> Int32 -> BoxMargins
T.BoxMargins Int32
0 Int32
0 Int32
0 Int32
0)
  let g :: Box
g = Box -> [String] -> Box
boxReader Box
b (String -> [String]
words String
c)
  [[Segment]]
s <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill
       (Context -> Parser [Segment]
allParsers (String -> Int32 -> Int32 -> [Box] -> TextRenderInfo
T.TextRenderInfo String
cs Int32
ot Int32
ob (Box
g forall a. a -> [a] -> [a]
: [Box]
bs), Int
f, Maybe [Action]
a))
       (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"</box>")
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Segment]]
s)

boxReader :: T.Box -> [String] -> T.Box
boxReader :: Box -> [String] -> Box
boxReader Box
b [] = Box
b
boxReader Box
b (String
x:[String]
xs) = Box -> [String] -> Box
boxReader (Box -> String -> String -> Box
boxParamReader Box
b String
param String
val) [String]
xs
  where (String
param,String
val) = case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
'=') String
x of
                        (String
p,Char
'=':String
v) -> (String
p, String
v)
                        (String
p,    String
_) -> (String
p, String
"")

boxParamReader :: T.Box -> String -> String -> T.Box
boxParamReader :: Box -> String -> String -> Box
boxParamReader Box
b String
_ String
"" = Box
b

boxParamReader (T.Box BoxBorder
bb BoxOffset
off CInt
lw String
fc BoxMargins
mgs) String
"type" String
val =
  BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box (forall a. a -> Maybe a -> a
fromMaybe BoxBorder
bb forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe (String
"BB" forall a. [a] -> [a] -> [a]
++ String
val)) BoxOffset
off CInt
lw String
fc BoxMargins
mgs

boxParamReader (T.Box BoxBorder
bb (T.BoxOffset Align
alg Int32
off) CInt
lw String
fc BoxMargins
mgs) String
"offset" (Char
a:String
o) =
  BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box BoxBorder
bb (Align -> Int32 -> BoxOffset
T.BoxOffset Align
align Int32
offset) CInt
lw String
fc BoxMargins
mgs
  where offset :: Int32
offset = forall a. a -> Maybe a -> a
fromMaybe Int32
off forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
o
        align :: Align
align = forall a. a -> Maybe a -> a
fromMaybe Align
alg forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe [Char
a]

boxParamReader (T.Box BoxBorder
bb BoxOffset
off CInt
lw String
fc BoxMargins
mgs) String
"width" String
val =
  BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box BoxBorder
bb BoxOffset
off (forall a. a -> Maybe a -> a
fromMaybe CInt
lw forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
val) String
fc BoxMargins
mgs

boxParamReader (T.Box BoxBorder
bb BoxOffset
off CInt
lw String
_ BoxMargins
mgs) String
"color" String
val =
  BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box BoxBorder
bb BoxOffset
off CInt
lw String
val BoxMargins
mgs

boxParamReader (T.Box BoxBorder
bb BoxOffset
off CInt
lw String
fc mgs :: BoxMargins
mgs@(T.BoxMargins Int32
mt Int32
mr Int32
mb Int32
ml)) (Char
'm':String
pos) String
v =
  let mgs' :: BoxMargins
mgs' = case String
pos of
               String
"t" -> Int32 -> Int32 -> Int32 -> Int32 -> BoxMargins
T.BoxMargins (forall {a}. Read a => a -> a
maybeVal Int32
mt) Int32
mr Int32
mb Int32
ml
               String
"r" -> Int32 -> Int32 -> Int32 -> Int32 -> BoxMargins
T.BoxMargins Int32
mt (forall {a}. Read a => a -> a
maybeVal Int32
mr) Int32
mb Int32
ml
               String
"b" -> Int32 -> Int32 -> Int32 -> Int32 -> BoxMargins
T.BoxMargins Int32
mt Int32
mr (forall {a}. Read a => a -> a
maybeVal Int32
mb) Int32
ml
               String
"l" -> Int32 -> Int32 -> Int32 -> Int32 -> BoxMargins
T.BoxMargins Int32
mt Int32
mr Int32
mb (forall {a}. Read a => a -> a
maybeVal Int32
ml)
               String
_   -> BoxMargins
mgs
      maybeVal :: a -> a
maybeVal a
d = forall a. a -> Maybe a -> a
fromMaybe a
d (forall a. Read a => String -> Maybe a
readMaybe String
v)
  in BoxBorder -> BoxOffset -> CInt -> String -> BoxMargins -> Box
T.Box BoxBorder
bb BoxOffset
off CInt
lw String
fc BoxMargins
mgs'

boxParamReader Box
b String
_ String
_ = Box
b

fontParser :: Context -> Parser [T.Segment]
fontParser :: Context -> Parser [Segment]
fontParser (TextRenderInfo
i, Int
_, Maybe [Action]
a) = do
  String
f <- forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
C.between (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"<fn=") (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
">") (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
C.many1 forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
P.digit)
  [[Segment]]
s <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
C.manyTill (Context -> Parser [Segment]
allParsers (TextRenderInfo
i, forall a. a -> Maybe a -> a
fromMaybe Int
0 forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> Maybe a
readMaybe String
f, Maybe [Action]
a))
                  (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
P.try forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
P.string String
"</fn>")
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Segment]]
s)