{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-
Copyright (C) 2010-2013 John MacFarlane <jgm@berkeley.edu>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-}

{- | Functions for writing a parsed formula as a list of Pandoc
     Inlines.
-}

module Text.TeXMath.Writers.Pandoc (writePandoc)
where
import Text.Pandoc.Definition
import qualified Data.Text as T
import Text.TeXMath.Unicode.ToUnicode
import Text.TeXMath.Types
import Text.TeXMath.Shared (getSpaceChars)

-- | Attempts to convert a formula to a list of 'Pandoc' inlines.
writePandoc :: DisplayType
         -> [Exp]
         -> Maybe [Inline]
writePandoc :: DisplayType -> [Exp] -> Maybe [Inline]
writePandoc DisplayType
_ [Exp]
exps = Maybe TextType -> [Exp] -> Maybe [Inline]
expsToInlines forall a. Maybe a
Nothing [Exp]
exps

expsToInlines :: Maybe TextType -> [Exp] -> Maybe [Inline]
expsToInlines :: Maybe TextType -> [Exp] -> Maybe [Inline]
expsToInlines Maybe TextType
tt [Exp]
xs = do
  [[Inline]]
res <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt) ([Exp] -> [Exp]
addSpaces [Exp]
xs)
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Inline]]
res)

-- This adds spaces around certain symbols, in accord
-- with Appendix G of TeXBook.
addSpaces :: [Exp] -> [Exp]
addSpaces :: [Exp] -> [Exp]
addSpaces (ESymbol TeXSymbolType
t1 Text
s1 : ESpace Rational
r : [Exp]
xs)
  = TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
t1 Text
s1 forall a. a -> [a] -> [a]
: Rational -> Exp
ESpace Rational
r forall a. a -> [a] -> [a]
: [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces (ESymbol TeXSymbolType
t1 Text
s1 : [Exp]
xs)
  | TeXSymbolType
t1 forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [TeXSymbolType
Bin, TeXSymbolType
Op, TeXSymbolType
Rel, TeXSymbolType
Open, TeXSymbolType
Pun]
  = TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
t1 Text
s1 forall a. a -> [a] -> [a]
: [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces (ESymbol TeXSymbolType
t1 Text
s1 : ESymbol TeXSymbolType
Pun Text
s2 : [Exp]
xs)
  = TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
t1 Text
s1 forall a. a -> [a] -> [a]
: TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
Pun Text
s2 forall a. a -> [a] -> [a]
: [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces (ESymbol TeXSymbolType
t2 Text
s2 : [Exp]
xs)
  | Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Exp]
xs)
  = TeXSymbolType -> Exp -> [Exp]
addSpace TeXSymbolType
t2 (TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
t2 Text
s2) forall a. [a] -> [a] -> [a]
++ [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces (EMathOperator Text
s : [Exp]
xs) =
  Text -> Exp
EMathOperator Text
s forall a. a -> [a] -> [a]
: Exp
thinspace forall a. a -> [a] -> [a]
: [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces (Exp
x:[Exp]
xs) = Exp
x forall a. a -> [a] -> [a]
: [Exp] -> [Exp]
addSpaces [Exp]
xs
addSpaces [] = []

addSpace :: TeXSymbolType -> Exp -> [Exp]
addSpace :: TeXSymbolType -> Exp -> [Exp]
addSpace TeXSymbolType
t Exp
x =
  case TeXSymbolType
t of
      TeXSymbolType
Bin -> [Exp
medspace, Exp
x, Exp
medspace]
      TeXSymbolType
Rel -> [Exp
widespace, Exp
x, Exp
widespace]
      TeXSymbolType
Pun -> [Exp
x, Exp
thinspace]
      TeXSymbolType
_   -> [Exp
x]

thinspace, medspace, widespace :: Exp
thinspace :: Exp
thinspace = TextType -> Text -> Exp
EText TextType
TextNormal Text
"\x2006"
medspace :: Exp
medspace  = TextType -> Text -> Exp
EText TextType
TextNormal Text
"\x2005"
widespace :: Exp
widespace = TextType -> Text -> Exp
EText TextType
TextNormal Text
"\x2004"

renderStr :: Maybe TextType -> T.Text -> [Inline]
renderStr :: Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
_ Text
"" = []
renderStr Maybe TextType
Nothing Text
s = [Text -> Inline
Str Text
s]
renderStr (Just TextType
tt) Text
s =
  case TextType
tt of
       TextType
TextNormal       -> [Text -> Inline
Str Text
s]
       TextType
TextBold         -> [[Inline] -> Inline
Strong [Text -> Inline
Str Text
s]]
       TextType
TextItalic       -> [[Inline] -> Inline
Emph   [Text -> Inline
Str Text
s]]
       TextType
TextMonospace    -> [Attr -> Text -> Inline
Code Attr
nullAttr Text
s]
       TextType
TextSansSerif    -> [Text -> Inline
Str Text
s]
       TextType
TextDoubleStruck -> [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ TextType -> Text -> Text
toUnicode TextType
tt Text
s]
       TextType
TextScript       -> [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ TextType -> Text -> Text
toUnicode TextType
tt Text
s]
       TextType
TextFraktur      -> [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ TextType -> Text -> Text
toUnicode TextType
tt Text
s]
       TextType
TextBoldItalic    -> [[Inline] -> Inline
Strong [[Inline] -> Inline
Emph [Text -> Inline
Str Text
s]]]
       TextType
TextSansSerifBold -> [[Inline] -> Inline
Strong [Text -> Inline
Str Text
s]]
       TextType
TextBoldScript    -> [[Inline] -> Inline
Strong [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ TextType -> Text -> Text
toUnicode TextType
tt Text
s]]
       TextType
TextBoldFraktur   -> [[Inline] -> Inline
Strong [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ TextType -> Text -> Text
toUnicode TextType
tt Text
s]]
       TextType
TextSansSerifItalic -> [[Inline] -> Inline
Emph [Text -> Inline
Str Text
s]]
       TextType
TextSansSerifBoldItalic -> [[Inline] -> Inline
Strong [[Inline] -> Inline
Emph [Text -> Inline
Str Text
s]]]

expToInlines :: Maybe TextType -> Exp -> Maybe [Inline]
expToInlines :: Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt (ENumber Text
s) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
s
expToInlines Maybe TextType
Nothing (EIdentifier Text
s) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr (forall a. a -> Maybe a
Just TextType
TextItalic) Text
s
expToInlines Maybe TextType
tt (EIdentifier Text
s) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
s
expToInlines Maybe TextType
tt (EMathOperator Text
s) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
s
expToInlines Maybe TextType
tt (ESymbol TeXSymbolType
_ Text
s) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
s
expToInlines Maybe TextType
tt (EDelimited Text
start Text
end [InEDelimited]
xs) = do
  [[Inline]]
xs' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt) (Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt)) [InEDelimited]
xs
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
start forall a. [a] -> [a] -> [a]
++ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Inline]]
xs' forall a. [a] -> [a] -> [a]
++ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt Text
end
expToInlines Maybe TextType
tt (EGrouped [Exp]
xs)    = Maybe TextType -> [Exp] -> Maybe [Inline]
expsToInlines Maybe TextType
tt [Exp]
xs
expToInlines Maybe TextType
_ (EStyled TextType
tt' [Exp]
xs)  = Maybe TextType -> [Exp] -> Maybe [Inline]
expsToInlines (forall a. a -> Maybe a
Just TextType
tt') [Exp]
xs
expToInlines Maybe TextType
_ (ESpace Rational
n)        = forall a. a -> Maybe a
Just [Text -> Inline
Str forall a b. (a -> b) -> a -> b
$ Rational -> Text
getSpaceChars Rational
n]
expToInlines Maybe TextType
_ (ESqrt Exp
_)         = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (ERoot Exp
_ Exp
_)       = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (EFraction FractionType
_ Exp
_ Exp
_) = forall a. Maybe a
Nothing
expToInlines Maybe TextType
tt (ESub Exp
x Exp
y) = do
  [Inline]
x' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
x
  [Inline]
y' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
y
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Inline]
x' forall a. [a] -> [a] -> [a]
++ [[Inline] -> Inline
Subscript [Inline]
y']
expToInlines Maybe TextType
tt (ESuper Exp
x Exp
y) = do
  [Inline]
x' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
x
  [Inline]
y' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
y
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Inline]
x' forall a. [a] -> [a] -> [a]
++ [[Inline] -> Inline
Superscript [Inline]
y']
expToInlines Maybe TextType
tt (ESubsup Exp
x Exp
y Exp
z) = do
  [Inline]
x' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
x
  [Inline]
y' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
y
  [Inline]
z' <- Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
z
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Inline]
x' forall a. [a] -> [a] -> [a]
++ [[Inline] -> Inline
Subscript [Inline]
y'] forall a. [a] -> [a] -> [a]
++ [[Inline] -> Inline
Superscript [Inline]
z']
expToInlines Maybe TextType
_ (EText TextType
tt' Text
x) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr (forall a. a -> Maybe a
Just TextType
tt') Text
x
expToInlines Maybe TextType
tt (EOver Bool
b (EGrouped [EIdentifier (Text -> String
T.unpack -> [Char
c])]) (ESymbol TeXSymbolType
Accent (Text -> String
T.unpack -> [Char
accent]))) = Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt (Bool -> Exp -> Exp -> Exp
EOver Bool
b (Text -> Exp
EIdentifier forall a b. (a -> b) -> a -> b
$ Char -> Text
T.singleton Char
c) (TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
Accent forall a b. (a -> b) -> a -> b
$ Char -> Text
T.singleton Char
accent))
expToInlines Maybe TextType
tt (EOver Bool
_ (EIdentifier (Text -> String
T.unpack -> [Char
c])) (ESymbol TeXSymbolType
Accent (Text -> String
T.unpack -> [Char
accent]))) =
    case Char
accent of
         Char
'\x203E' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0304']  -- bar
         Char
'\x0304' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0304']  -- bar combining
         Char
'\x00B4' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0301']  -- acute
         Char
'\x0301' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0301']  -- acute combining
         Char
'\x0060' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0300']  -- grave
         Char
'\x0300' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0300']  -- grave combining
         Char
'\x02D8' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0306']  -- breve
         Char
'\x0306' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0306']  -- breve combining
         Char
'\x02C7' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x030C']  -- check
         Char
'\x030C' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x030C']  -- check combining
         Char
'.'      -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0307']  -- dot
         Char
'\x0307' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0307']  -- dot combining
         Char
'\x00B0' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x030A']  -- ring
         Char
'\x030A' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x030A']  -- ring combining
         Char
'\x20D7' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x20D7']  -- arrow right
         Char
'\x20D6' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x20D6']  -- arrow left
         Char
'\x005E' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0302']  -- hat
         Char
'\x0302' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0302']  -- hat combining
         Char
'~'      -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0303']  -- tilde
         Char
'\x0303' -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Maybe TextType -> Text -> [Inline]
renderStr Maybe TextType
tt' forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack [Char
c,Char
'\x0303']  -- tilde combining
         Char
_        -> forall a. Maybe a
Nothing
      where tt' :: Maybe TextType
tt' = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. a -> Maybe a
Just TextType
TextItalic) forall a. a -> Maybe a
Just Maybe TextType
tt
expToInlines Maybe TextType
tt (EScaled Rational
_ Exp
e) = Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt Exp
e
expToInlines Maybe TextType
tt (EUnder Bool
convertible Exp
b Exp
e)
  | Bool
convertible = Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt (Exp -> Exp -> Exp
ESub Exp
b Exp
e)
  | Bool
otherwise   = forall a. Maybe a
Nothing
expToInlines Maybe TextType
tt (EOver Bool
convertible Exp
b Exp
e)
  | Bool
convertible = Maybe TextType -> Exp -> Maybe [Inline]
expToInlines Maybe TextType
tt (Exp -> Exp -> Exp
ESuper Exp
b Exp
e)
  | Bool
otherwise   = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (EUnderover Bool
_ Exp
_ Exp
_ Exp
_) = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (EPhantom Exp
_) = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (EBoxed Exp
_) = forall a. Maybe a
Nothing
expToInlines Maybe TextType
_ (EArray [Alignment]
_ [ArrayLine]
_) = forall a. Maybe a
Nothing