{-# LANGUAGE OverloadedStrings #-}
module Text.Pandoc.Writers.Math
  ( texMathToInlines
  , convertMath
  , defaultMathJaxURL
  , defaultKaTeXURL
  )
where

import qualified Data.Text as T
import Text.Pandoc.Class.PandocMonad
import Text.Pandoc.Definition
import Text.Pandoc.Logging
import Text.TeXMath (DisplayType (..), Exp, readTeX, writePandoc)
import Text.Pandoc.Options (defaultMathJaxURL, defaultKaTeXURL)

-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
-- Defaults to raw formula between @$@ or @$$@ characters if entire formula
-- can't be converted.
texMathToInlines :: PandocMonad m
                 => MathType
                 -> T.Text         -- ^ String to parse (assumes @'\n'@ line endings)
                 -> m [Inline]
texMathToInlines :: forall (m :: * -> *).
PandocMonad m =>
MathType -> Text -> m [Inline]
texMathToInlines MathType
mt Text
inp = do
  Either Inline (Maybe [Inline])
res <- (DisplayType -> [Exp] -> Maybe [Inline])
-> MathType -> Text -> m (Either Inline (Maybe [Inline]))
forall (m :: * -> *) a.
PandocMonad m =>
(DisplayType -> [Exp] -> a)
-> MathType -> Text -> m (Either Inline a)
convertMath DisplayType -> [Exp] -> Maybe [Inline]
writePandoc MathType
mt Text
inp
  case Either Inline (Maybe [Inline])
res of
       Right (Just [Inline]
ils)  -> [Inline] -> m [Inline]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Inline]
ils
       Right Maybe [Inline]
Nothing   -> do
         LogMessage -> m ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> m ()) -> LogMessage -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> Text -> LogMessage
CouldNotConvertTeXMath Text
inp Text
""
         [Inline] -> m [Inline]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [MathType -> Text -> Inline
mkFallback MathType
mt Text
inp]
       Left Inline
il           -> [Inline] -> m [Inline]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Inline
il]

mkFallback :: MathType -> T.Text -> Inline
mkFallback :: MathType -> Text -> Inline
mkFallback MathType
mt Text
str = Text -> Inline
Str (Text
delim Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
str Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
delim)
   where delim :: Text
delim = case MathType
mt of
                      MathType
DisplayMath -> Text
"$$"
                      MathType
InlineMath  -> Text
"$"

-- | Converts a raw TeX math formula using a writer function,
-- issuing a warning and producing a fallback (a raw string)
-- on failure.
convertMath :: PandocMonad m
            => (DisplayType -> [Exp] -> a) -> MathType -> T.Text
            -> m (Either Inline a)
convertMath :: forall (m :: * -> *) a.
PandocMonad m =>
(DisplayType -> [Exp] -> a)
-> MathType -> Text -> m (Either Inline a)
convertMath DisplayType -> [Exp] -> a
writer MathType
mt Text
str =
  case DisplayType -> [Exp] -> a
writer DisplayType
dt ([Exp] -> a) -> Either Text [Exp] -> Either Text a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Either Text [Exp]
readTeX Text
str of
       Right a
r  -> Either Inline a -> m (Either Inline a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Either Inline a
forall a b. b -> Either a b
Right a
r)
       Left Text
e   -> do
         LogMessage -> m ()
forall (m :: * -> *). PandocMonad m => LogMessage -> m ()
report (LogMessage -> m ()) -> LogMessage -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> Text -> LogMessage
CouldNotConvertTeXMath Text
str Text
e
         Either Inline a -> m (Either Inline a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> Either Inline a
forall a b. a -> Either a b
Left (Inline -> Either Inline a) -> Inline -> Either Inline a
forall a b. (a -> b) -> a -> b
$ MathType -> Text -> Inline
mkFallback MathType
mt Text
str)
   where dt :: DisplayType
dt = case MathType
mt of
                   MathType
DisplayMath -> DisplayType
DisplayBlock
                   MathType
InlineMath  -> DisplayType
DisplayInline