{-# LANGUAGE OverloadedStrings #-}
module Text.Pandoc.Readers.LaTeX.Macro
  ( macroDef
  )
where
import Text.Pandoc.Extensions (Extension(..))
import Text.Pandoc.Logging (LogMessage(MacroAlreadyDefined))
import Text.Pandoc.Readers.LaTeX.Parsing
import Text.Pandoc.TeX
import Text.Pandoc.Class
import Text.Pandoc.Shared (safeRead)
import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
                            optional, space, spaces, withRaw, (<|>))
import Control.Applicative ((<|>), optional)
import qualified Data.Map as M
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.List.NonEmpty as NonEmpty
import Data.List.NonEmpty (NonEmpty(..))

macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
macroDef :: forall (m :: * -> *) a.
(PandocMonad m, Monoid a) =>
(Text -> a) -> LP m a
macroDef Text -> a
constructor = do
    (_, s) <- LP m () -> LP m ((), [Tok])
forall (m :: * -> *) a. PandocMonad m => LP m a -> LP m (a, [Tok])
withRaw (LP m ()
commandDef LP m () -> LP m () -> LP m ()
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> LP m ()
environmentDef)
    (constructor (untokenize s) <$
      guardDisabled Ext_latex_macros)
     <|> return mempty
  where commandDef :: LP m ()
commandDef = do
          nameMacroPairs <- LP m [(Text, Macro)]
forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
newcommand LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
            LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall (m :: * -> *).
PandocMonad m =>
LP m [(Text, Macro)] -> LP m [(Text, Macro)]
checkGlobal (LP m [(Text, Macro)]
forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
letmacro LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> LP m [(Text, Macro)]
forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
edefmacro LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> LP m [(Text, Macro)]
forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
defmacro LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> LP m [(Text, Macro)]
forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
newif)
          guardDisabled Ext_latex_macros <|>
            mapM_ insertMacro nameMacroPairs
        environmentDef :: LP m ()
environmentDef = do
          mbenv <- LP m (Maybe (Text, Macro, Macro))
forall (m :: * -> *).
PandocMonad m =>
LP m (Maybe (Text, Macro, Macro))
newenvironment
          case mbenv of
            Maybe (Text, Macro, Macro)
Nothing -> () -> LP m ()
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
            Just (Text
name, Macro
macro1, Macro
macro2) ->
              Extension -> LP m ()
forall s (m :: * -> *) a st.
(Stream s m a, HasReaderOptions st) =>
Extension -> ParsecT s st m ()
guardDisabled Extension
Ext_latex_macros LP m () -> LP m () -> LP m ()
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                do (Text, Macro) -> LP m ()
forall (m :: * -> *). PandocMonad m => (Text, Macro) -> LP m ()
insertMacro (Text
name, Macro
macro1)
                   (Text, Macro) -> LP m ()
forall (m :: * -> *). PandocMonad m => (Text, Macro) -> LP m ()
insertMacro (Text
"end" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name, Macro
macro2)
        -- @\newenvironment{envname}[n-args][default]{begin}{end}@
        -- is equivalent to
        -- @\newcommand{\envname}[n-args][default]{begin}@
        -- @\newcommand{\endenvname}@

insertMacro :: PandocMonad m => (Text, Macro) -> LP m ()
insertMacro :: forall (m :: * -> *). PandocMonad m => (Text, Macro) -> LP m ()
insertMacro (Text
name, macro' :: Macro
macro'@(Macro MacroScope
GlobalScope ExpansionPoint
_ [ArgSpec]
_ Maybe [Tok]
_ [Tok]
_)) =
  (LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ()
forall (m :: * -> *) u s. Monad m => (u -> u) -> ParsecT s u m ()
updateState ((LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ())
-> (LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ()
forall a b. (a -> b) -> a -> b
$ \LaTeXState
s ->
     LaTeXState
s{ sMacros = NonEmpty.map (M.insert name macro') (sMacros s) }
insertMacro (Text
name, macro' :: Macro
macro'@(Macro MacroScope
GroupScope ExpansionPoint
_ [ArgSpec]
_ Maybe [Tok]
_ [Tok]
_)) =
  (LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ()
forall (m :: * -> *) u s. Monad m => (u -> u) -> ParsecT s u m ()
updateState ((LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ())
-> (LaTeXState -> LaTeXState) -> ParsecT TokStream LaTeXState m ()
forall a b. (a -> b) -> a -> b
$ \LaTeXState
s ->
     LaTeXState
s{ sMacros = M.insert name macro' (NonEmpty.head (sMacros s)) :|
                      NonEmpty.tail (sMacros s) }

lookupMacro :: PandocMonad m => Text -> LP m Macro
lookupMacro :: forall (m :: * -> *). PandocMonad m => Text -> LP m Macro
lookupMacro Text
name = do
   macros :| _ <- LaTeXState -> NonEmpty (Map Text Macro)
sMacros (LaTeXState -> NonEmpty (Map Text Macro))
-> ParsecT TokStream LaTeXState m LaTeXState
-> ParsecT TokStream LaTeXState m (NonEmpty (Map Text Macro))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT TokStream LaTeXState m LaTeXState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
   case M.lookup name macros of
     Just Macro
m -> Macro -> ParsecT TokStream LaTeXState m Macro
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Macro
m
     Maybe Macro
Nothing -> String -> ParsecT TokStream LaTeXState m Macro
forall a. String -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Macro not found"

letmacro :: PandocMonad m => LP m [(Text, Macro)]
letmacro :: forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
letmacro = do
  Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"let"
  LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall (m :: * -> *) a. PandocMonad m => LP m a -> LP m a
withVerbatimMode (LP m [(Text, Macro)] -> LP m [(Text, Macro)])
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a b. (a -> b) -> a -> b
$ do
    Tok _ (CtrlSeq name) _ <- LP m Tok
forall (m :: * -> *). PandocMonad m => LP m Tok
anyControlSeq
    optional $ symbol '='
    spaces
    -- we first parse in verbatim mode, and then expand macros,
    -- because we don't want \let\foo\bar to turn into
    -- \let\foo hello if we have previously \def\bar{hello}
    target <- anyControlSeq <|> singleChar
    case target of
      (Tok SourcePos
_ (CtrlSeq Text
name') Text
_) ->
         (do m <- Text -> LP m Macro
forall (m :: * -> *). PandocMonad m => Text -> LP m Macro
lookupMacro Text
name'
             pure [(name, m)])
         LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [(Text, Macro)] -> LP m [(Text, Macro)]
forall a. a -> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [(Text
name,
                    MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GroupScope ExpansionPoint
ExpandWhenDefined [] Maybe [Tok]
forall a. Maybe a
Nothing [Tok
target])]
      Tok
_ -> [(Text, Macro)] -> LP m [(Text, Macro)]
forall a. a -> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [(Text
name, MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GroupScope ExpansionPoint
ExpandWhenDefined [] Maybe [Tok]
forall a. Maybe a
Nothing [Tok
target])]

checkGlobal :: PandocMonad m => LP m [(Text, Macro)] -> LP m [(Text, Macro)]
checkGlobal :: forall (m :: * -> *).
PandocMonad m =>
LP m [(Text, Macro)] -> LP m [(Text, Macro)]
checkGlobal LP m [(Text, Macro)]
p =
  (Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"global" LP m Tok -> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a b.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
      (((Text, Macro) -> (Text, Macro))
-> [(Text, Macro)] -> [(Text, Macro)]
forall a b. (a -> b) -> [a] -> [b]
map (\(Text
n, Macro MacroScope
_ ExpansionPoint
expand [ArgSpec]
arg Maybe [Tok]
optarg [Tok]
contents) ->
                (Text
n, MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GlobalScope ExpansionPoint
expand [ArgSpec]
arg Maybe [Tok]
optarg [Tok]
contents)) ([(Text, Macro)] -> [(Text, Macro)])
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LP m [(Text, Macro)]
p))
   LP m [(Text, Macro)]
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> LP m [(Text, Macro)]
p

edefmacro :: PandocMonad m => LP m [(Text, Macro)]
edefmacro :: forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
edefmacro = do
  scope <- (MacroScope
GroupScope MacroScope
-> ParsecT TokStream LaTeXState m Tok
-> ParsecT TokStream LaTeXState m MacroScope
forall a b.
a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> ParsecT TokStream LaTeXState m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"edef")
       ParsecT TokStream LaTeXState m MacroScope
-> ParsecT TokStream LaTeXState m MacroScope
-> ParsecT TokStream LaTeXState m MacroScope
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (MacroScope
GlobalScope MacroScope
-> ParsecT TokStream LaTeXState m Tok
-> ParsecT TokStream LaTeXState m MacroScope
forall a b.
a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> ParsecT TokStream LaTeXState m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"xdef")
  (name, contents) <- withVerbatimMode $ do
    Tok _ (CtrlSeq name) _ <- anyControlSeq
    -- we first parse in verbatim mode, and then expand macros,
    -- because we don't want \let\foo\bar to turn into
    -- \let\foo hello if we have previously \def\bar{hello}
    contents <- bracedOrToken
    return (name, contents)
  -- expand macros
  contents' <- parseFromToks (many anyTok) contents
  return [(name, Macro scope ExpandWhenDefined [] Nothing contents')]

defmacro :: PandocMonad m => LP m [(Text, Macro)]
defmacro :: forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
defmacro = do
  -- we use withVerbatimMode, because macros are to be expanded
  -- at point of use, not point of definition
  scope <- (MacroScope
GroupScope MacroScope
-> ParsecT TokStream LaTeXState m Tok
-> ParsecT TokStream LaTeXState m MacroScope
forall a b.
a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> ParsecT TokStream LaTeXState m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"def")
       ParsecT TokStream LaTeXState m MacroScope
-> ParsecT TokStream LaTeXState m MacroScope
-> ParsecT TokStream LaTeXState m MacroScope
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (MacroScope
GlobalScope MacroScope
-> ParsecT TokStream LaTeXState m Tok
-> ParsecT TokStream LaTeXState m MacroScope
forall a b.
a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> ParsecT TokStream LaTeXState m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"gdef")
  withVerbatimMode $ do
    Tok _ (CtrlSeq name) _ <- anyControlSeq
    argspecs <- many (argspecArg <|> argspecPattern)
    contents <- bracedOrToken
    return [(name, Macro scope ExpandWhenUsed argspecs Nothing contents)]

-- \newif\iffoo' defines:
-- \iffoo to be \iffalse
-- \footrue to be a command that defines \iffoo to be \iftrue
-- \foofalse to be a command that defines \iffoo to be \iffalse
newif :: PandocMonad m => LP m [(Text, Macro)]
newif :: forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
newif = do
  Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"newif"
  LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall (m :: * -> *) a. PandocMonad m => LP m a -> LP m a
withVerbatimMode (LP m [(Text, Macro)] -> LP m [(Text, Macro)])
-> LP m [(Text, Macro)] -> LP m [(Text, Macro)]
forall a b. (a -> b) -> a -> b
$ do
    Tok pos (CtrlSeq name) _ <- LP m Tok
forall (m :: * -> *). PandocMonad m => LP m Tok
anyControlSeq
    -- \def\iffoo\iffalse
    -- \def\footrue{\def\iffoo\iftrue}
    -- \def\foofalse{\def\iffoo\iffalse}
    let base = Int -> Text -> Text
T.drop Int
2 Text
name
    return [ (name, Macro GroupScope ExpandWhenUsed [] Nothing
                    [Tok pos (CtrlSeq "iffalse") "\\iffalse"])
           , (base <> "true",
                   Macro GroupScope ExpandWhenUsed [] Nothing
                   [ Tok pos (CtrlSeq "def") "\\def"
                   , Tok pos (CtrlSeq name) ("\\" <> name)
                   , Tok pos Symbol "{"
                   , Tok pos (CtrlSeq "iftrue") "\\iftrue"
                   , Tok pos Symbol "}"
                   ])
           , (base <> "false",
                   Macro GroupScope ExpandWhenUsed [] Nothing
                   [ Tok pos (CtrlSeq "def") "\\def"
                   , Tok pos (CtrlSeq name) ("\\" <> name)
                   , Tok pos Symbol "{"
                   , Tok pos (CtrlSeq "iffalse") "\\iffalse"
                   , Tok pos Symbol "}"
                   ])
           ]

argspecArg :: PandocMonad m => LP m ArgSpec
argspecArg :: forall (m :: * -> *). PandocMonad m => LP m ArgSpec
argspecArg = do
  Tok _ (Arg i) _ <- (Tok -> Bool) -> LP m Tok
forall (m :: * -> *). PandocMonad m => (Tok -> Bool) -> LP m Tok
satisfyTok Tok -> Bool
isArgTok
  return $ ArgNum i

argspecPattern :: PandocMonad m => LP m ArgSpec
argspecPattern :: forall (m :: * -> *). PandocMonad m => LP m ArgSpec
argspecPattern =
  [Tok] -> ArgSpec
Pattern ([Tok] -> ArgSpec)
-> ParsecT TokStream LaTeXState m [Tok]
-> ParsecT TokStream LaTeXState m ArgSpec
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT TokStream LaTeXState m Tok
-> ParsecT TokStream LaTeXState m [Tok]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ((Tok -> Bool) -> ParsecT TokStream LaTeXState m Tok
forall (m :: * -> *). PandocMonad m => (Tok -> Bool) -> LP m Tok
satisfyTok (\(Tok SourcePos
_ TokType
toktype' Text
txt) ->
                              (TokType
toktype' TokType -> TokType -> Bool
forall a. Eq a => a -> a -> Bool
== TokType
Symbol Bool -> Bool -> Bool
|| TokType
toktype' TokType -> TokType -> Bool
forall a. Eq a => a -> a -> Bool
== TokType
Word) Bool -> Bool -> Bool
&&
                              (Text
txt Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"{" Bool -> Bool -> Bool
&& Text
txt Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"\\" Bool -> Bool -> Bool
&& Text
txt Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"}")))

newcommand :: PandocMonad m => LP m [(Text, Macro)]
newcommand :: forall (m :: * -> *). PandocMonad m => LP m [(Text, Macro)]
newcommand = do
  Tok pos (CtrlSeq mtype) _ <- Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"newcommand" LP m Tok -> LP m Tok -> LP m Tok
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                             Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"renewcommand" LP m Tok -> LP m Tok -> LP m Tok
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                             Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"providecommand" LP m Tok -> LP m Tok -> LP m Tok
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                             Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"DeclareMathOperator" LP m Tok -> LP m Tok -> LP m Tok
forall a.
ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                             Text -> LP m Tok
forall (m :: * -> *). PandocMonad m => Text -> LP m Tok
controlSeq Text
"DeclareRobustCommand"
  withVerbatimMode $ do
    Tok _ (CtrlSeq name) txt <- do
      optional (symbol '*')
      anyControlSeq <|>
        (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}')
    spaces
    numargs <- option 0 $ try bracketedNum
    let argspecs = (Int -> ArgSpec) -> [Int] -> [ArgSpec]
forall a b. (a -> b) -> [a] -> [b]
map Int -> ArgSpec
ArgNum [Int
1..Int
numargs]
    spaces
    optarg <- option Nothing $ Just <$> try bracketedToks
    spaces
    contents' <- bracedOrToken
    let contents =
         case Text
mtype of
              Text
"DeclareMathOperator" ->
                 SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos (Text -> TokType
CtrlSeq Text
"mathop") Text
"\\mathop"
                 Tok -> [Tok] -> [Tok]
forall a. a -> [a] -> [a]
: SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos TokType
Symbol Text
"{"
                 Tok -> [Tok] -> [Tok]
forall a. a -> [a] -> [a]
: SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos (Text -> TokType
CtrlSeq Text
"mathrm") Text
"\\mathrm"
                 Tok -> [Tok] -> [Tok]
forall a. a -> [a] -> [a]
: SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos TokType
Symbol Text
"{"
                 Tok -> [Tok] -> [Tok]
forall a. a -> [a] -> [a]
: ([Tok]
contents' [Tok] -> [Tok] -> [Tok]
forall a. [a] -> [a] -> [a]
++
                   [ SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos TokType
Symbol Text
"}", SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos TokType
Symbol Text
"}" ])
              Text
_                     -> [Tok]
contents'
    let macro = MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GroupScope ExpansionPoint
ExpandWhenUsed [ArgSpec]
argspecs Maybe [Tok]
optarg [Tok]
contents
    (do lookupMacro name
        case mtype of
          Text
"providecommand" -> [(Text, Macro)] -> ParsecT TokStream LaTeXState m [(Text, Macro)]
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return []
          Text
"renewcommand" -> [(Text, Macro)] -> ParsecT TokStream LaTeXState m [(Text, Macro)]
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return [(Text
name, Macro
macro)]
          Text
_ -> [] [(Text, Macro)]
-> ParsecT TokStream LaTeXState m ()
-> ParsecT TokStream LaTeXState m [(Text, Macro)]
forall a b.
a
-> ParsecT TokStream LaTeXState m b
-> ParsecT TokStream LaTeXState m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ LogMessage -> ParsecT TokStream LaTeXState m ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (Text -> SourcePos -> LogMessage
MacroAlreadyDefined Text
txt SourcePos
pos))
      <|> pure [(name, macro)]

newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
newenvironment :: forall (m :: * -> *).
PandocMonad m =>
LP m (Maybe (Text, Macro, Macro))
newenvironment = do
  pos <- ParsecT TokStream LaTeXState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
  Tok _ (CtrlSeq mtype) _ <- controlSeq "newenvironment" <|>
                             controlSeq "renewenvironment" <|>
                             controlSeq "provideenvironment"
  withVerbatimMode $ do
    optional $ symbol '*'
    spaces
    name <- untokenize <$> braced
    spaces
    numargs <- option 0 $ try bracketedNum
    spaces
    optarg <- option Nothing $ Just <$> try bracketedToks
    let argspecs = (Int -> ArgSpec) -> [Int] -> [ArgSpec]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
i -> Int -> ArgSpec
ArgNum Int
i) [Int
1..Int
numargs]
    startcontents <- spaces >> bracedOrToken
    endcontents <- spaces >> bracedOrToken
    -- we need the environment to be in a group so macros defined
    -- inside behave correctly:
    let bg = SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos (Text -> TokType
CtrlSeq Text
"bgroup") Text
"\\bgroup "
    let eg = SourcePos -> TokType -> Text -> Tok
Tok SourcePos
pos (Text -> TokType
CtrlSeq Text
"egroup") Text
"\\egroup "
    let result = (Text
name,
                    MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GroupScope ExpansionPoint
ExpandWhenUsed [ArgSpec]
argspecs Maybe [Tok]
optarg
                      (Tok
bgTok -> [Tok] -> [Tok]
forall a. a -> [a] -> [a]
:[Tok]
startcontents),
                    MacroScope
-> ExpansionPoint -> [ArgSpec] -> Maybe [Tok] -> [Tok] -> Macro
Macro MacroScope
GroupScope ExpansionPoint
ExpandWhenUsed [] Maybe [Tok]
forall a. Maybe a
Nothing
                      ([Tok]
endcontents [Tok] -> [Tok] -> [Tok]
forall a. [a] -> [a] -> [a]
++ [Tok
eg]))
    (do lookupMacro name
        case mtype of
          Text
"provideenvironment" -> Maybe (Text, Macro, Macro)
-> ParsecT TokStream LaTeXState m (Maybe (Text, Macro, Macro))
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Text, Macro, Macro)
forall a. Maybe a
Nothing
          Text
"renewenvironment" -> Maybe (Text, Macro, Macro)
-> ParsecT TokStream LaTeXState m (Maybe (Text, Macro, Macro))
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Text, Macro, Macro) -> Maybe (Text, Macro, Macro)
forall a. a -> Maybe a
Just (Text, Macro, Macro)
result)
          Text
_ -> do
             LogMessage -> LP m ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> LP m ()) -> LogMessage -> LP m ()
forall a b. (a -> b) -> a -> b
$ Text -> SourcePos -> LogMessage
MacroAlreadyDefined Text
name SourcePos
pos
             Maybe (Text, Macro, Macro)
-> ParsecT TokStream LaTeXState m (Maybe (Text, Macro, Macro))
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Text, Macro, Macro)
forall a. Maybe a
Nothing)
      <|> return (Just result)

bracketedNum :: PandocMonad m => LP m Int
bracketedNum :: forall (m :: * -> *). PandocMonad m => LP m Int
bracketedNum = do
  ds <- [Tok] -> Text
untokenize ([Tok] -> Text)
-> ParsecT TokStream LaTeXState m [Tok]
-> ParsecT TokStream LaTeXState m Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT TokStream LaTeXState m [Tok]
forall (m :: * -> *). PandocMonad m => LP m [Tok]
bracketedToks
  case safeRead ds of
       Just Int
i -> Int -> ParsecT TokStream LaTeXState m Int
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
i
       Maybe Int
_      -> Int -> ParsecT TokStream LaTeXState m Int
forall a. a -> ParsecT TokStream LaTeXState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0