    {-# LANGUAGE ViewPatterns, ScopedTypeVariables, OverloadedStrings,
       TupleSections #-}
    {-
    Copyright (C) 2009 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 MathML.
    -}

    module Text.TeXMath.Writers.MathML (writeMathML)
    where

    import Text.XML.Light
    import Text.TeXMath.Types
    import Text.TeXMath.Unicode.ToUnicode
    import Data.Generics (everywhere, mkT)
    import Text.TeXMath.Shared (getMMLType, handleDownup,
                                isUppercaseGreek, isRLSequence)
    import Text.TeXMath.Readers.MathML.MMLDict (getMathMLOperator)
    import qualified Data.Text as T
    import Text.Printf

    -- | Transforms an expression tree to a MathML XML tree
    writeMathML :: DisplayType -> [Exp] -> Element
    writeMathML :: DisplayType -> [Exp] -> Element
    writeMathML DisplayType
    dt [Exp]
    exprs =
      Attr -> Element -> Element
    add_attr Attr
    dtattr (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ Element -> Element
    math (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    forall a. Maybe a
    Nothing (Exp -> Element) -> Exp -> Element
    forall a b. (a -> b) -> a -> b
    $ [Exp] -> Exp
    EGrouped
      ([Exp] -> Exp) -> [Exp] -> Exp
    forall a b. (a -> b) -> a -> b
    $ (forall a. Data a => a -> a) -> forall a. Data a => a -> a
    everywhere ((Exp -> Exp) -> a -> a
    forall a b. (Typeable a, Typeable b) => (b -> b) -> a -> a
    mkT ((Exp -> Exp) -> a -> a) -> (Exp -> Exp) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ DisplayType -> Exp -> Exp
    handleDownup DisplayType
    dt) [Exp]
    exprs
        where dtattr :: Attr
    dtattr = QName -> String -> Attr
    Attr (String -> QName
    unqual String
    "display") String
    dt'
              dt' :: String
    dt' =  case DisplayType
    dt of
                          DisplayType
    DisplayBlock  -> String
    "block"
                          DisplayType
    DisplayInline -> String
    "inline"

    math :: Element -> Element
    math :: Element -> Element
    math = Attr -> Element -> Element
    add_attr (QName -> String -> Attr
    Attr (String -> QName
    unqual String
    "xmlns") String
    "http://www.w3.org/1998/Math/MathML") (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Element -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "math"

    mrow :: [Element] -> Element
    mrow :: [Element] -> Element
    mrow = String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mrow"

    showFraction :: Maybe TextType -> FractionType -> Exp -> Exp -> Element
    showFraction :: Maybe TextType -> FractionType -> Exp -> Exp -> Element
    showFraction Maybe TextType
    tt FractionType
    ft Exp
    x Exp
    y =
      case FractionType
    ft of
           FractionType
    NormalFrac   -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mfrac" [Element
    x', Element
    y']
           FractionType
    InlineFrac   -> String -> Text -> Element -> Element
    withAttribute String
    "displaystyle" Text
    "false" (Element -> Element)
    -> ([Element] -> Element) -> [Element] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                             String -> Element -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mstyle" (Element -> Element)
    -> ([Element] -> Element) -> [Element] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                             String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mfrac" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ [Element
    x', Element
    y']
           FractionType
    DisplayFrac  -> String -> Text -> Element -> Element
    withAttribute String
    "displaystyle" Text
    "true" (Element -> Element)
    -> ([Element] -> Element) -> [Element] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                             String -> Element -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mstyle" (Element -> Element)
    -> ([Element] -> Element) -> [Element] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                             String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mfrac" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ [Element
    x', Element
    y']
           FractionType
    NoLineFrac   -> String -> Text -> Element -> Element
    withAttribute String
    "linethickness" Text
    "0" (Element -> Element)
    -> ([Element] -> Element) -> [Element] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                             String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mfrac" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ [Element
    x', Element
    y']
      where x' :: Element
    x' = Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x
            y' :: Element
    y' = Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    y

    spaceWidth :: Rational -> Element
    spaceWidth :: Rational -> Element
    spaceWidth Rational
    w =
      String -> Text -> Element -> Element
    withAttribute String
    "width" (Text -> Text
    dropTrailing0s
         (String -> Text
    T.pack (String -> Text) -> String -> Text
    forall a b. (a -> b) -> a -> b
    $ String -> Double -> String
    forall r. PrintfType r => String -> r
    printf String
    "%.3f" (Rational -> Double
    forall a. Fractional a => Rational -> a
    fromRational Rational
    w :: Double)) Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "em") (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> () -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mspace" ()

    makeStretchy :: FormType -> Element -> Element
    makeStretchy :: FormType -> Element -> Element
    makeStretchy (FormType -> Text
    fromForm -> Text
    t)  = String -> Text -> Element -> Element
    withAttribute String
    "stretchy" Text
    "true"
                                    (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text -> Element -> Element
    withAttribute String
    "form" Text
    t

    fromForm :: FormType -> T.Text
    fromForm :: FormType -> Text
    fromForm FormType
    FInfix   = Text
    "infix"
    fromForm FormType
    FPostfix = Text
    "postfix"
    fromForm FormType
    FPrefix  = Text
    "prefix"

    makeScaled :: Rational -> Element -> Element
    makeScaled :: Rational -> Element -> Element
    makeScaled Rational
    x = String -> Text -> Element -> Element
    withAttribute String
    "minsize" Text
    p (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text -> Element -> Element
    withAttribute String
    "maxsize" Text
    p
                   (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text -> Element -> Element
    setAttribute String
    "stretchy" Text
    "true"
      where p :: Text
    p = String -> Text
    T.pack (String -> Text) -> String -> Text
    forall a b. (a -> b) -> a -> b
    $ String -> Int -> String
    forall r. PrintfType r => String -> r
    printf String
    "%d%%" (Rational -> Int
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    round (Rational
    100Rational -> Rational -> Rational
    forall a. Num a => a -> a -> a
    *Rational
    x) :: Int)

    dropTrailing0s :: T.Text -> T.Text
    dropTrailing0s :: Text -> Text
    dropTrailing0s Text
    t = case Text -> Maybe (Text, Char)
    T.unsnoc Text
    t of -- T.spanEnd does not exist
      Just (Text
    ts, Char
    '0') -> Text -> Text
    addZero (Text -> Text) -> Text -> Text
    forall a b. (a -> b) -> a -> b
    $ (Char -> Bool) -> Text -> Text
    T.dropWhileEnd (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '0') Text
    ts
      Maybe (Text, Char)
    _              -> Text
    t
      where
        addZero :: Text -> Text
    addZero Text
    x = case Text -> Maybe (Text, Char)
    T.unsnoc Text
    x of
          Just (Text
    _, Char
    '.') -> Text -> Char -> Text
    T.snoc Text
    x Char
    '0'
          Maybe (Text, Char)
    _ -> Text
    x

    -- Note: Converts strings to unicode directly, as few renderers support those mathvariants.
    makeText :: TextType -> T.Text -> Element
    makeText :: TextType -> Text -> Element
    makeText TextType
    a Text
    s = case (Bool
    leadingSp, Bool
    trailingSp) of
                       (Bool
    False, Bool
    False) -> Element
    s'
                       (Bool
    True,  Bool
    False) -> [Element] -> Element
    mrow [Element
    sp, Element
    s']
                       (Bool
    False, Bool
    True)  -> [Element] -> Element
    mrow [Element
    s', Element
    sp]
                       (Bool
    True,  Bool
    True)  -> [Element] -> Element
    mrow [Element
    sp, Element
    s', Element
    sp]
      where sp :: Element
    sp = Rational -> Element
    spaceWidth (Rational
    1Rational -> Rational -> Rational
    forall a. Fractional a => a -> a -> a
    /Rational
    3)
            s' :: Element
    s' = String -> Text -> Element -> Element
    withAttribute String
    "mathvariant" Text
    attr (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> Text -> Element
    tunode String
    "mtext" (Text -> Element) -> Text -> Element
    forall a b. (a -> b) -> a -> b
    $ TextType -> Text -> Text
    toUnicode TextType
    a Text
    s
            trailingSp :: Bool
    trailingSp = case Text -> Maybe (Text, Char)
    T.unsnoc Text
    s of
              Just (Text
    _, Char
    c) -> (Char -> Bool) -> Text -> Bool
    T.any (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    c) Text
    " \t"
              Maybe (Text, Char)
    _           -> Bool
    False
            leadingSp :: Bool
    leadingSp  = case Text -> Maybe (Char, Text)
    T.uncons Text
    s of
              Just (Char
    c, Text
    _) -> (Char -> Bool) -> Text -> Bool
    T.any (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    c) Text
    " \t"
              Maybe (Char, Text)
    _           -> Bool
    False
            attr :: Text
    attr = TextType -> Text
    getMMLType TextType
    a

    makeArray :: Maybe TextType -> [Alignment] -> [ArrayLine] -> Element
    makeArray :: Maybe TextType -> [Alignment] -> [ArrayLine] -> Element
    makeArray Maybe TextType
    tt [Alignment]
    as [ArrayLine]
    ls = String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mtable" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $
      (ArrayLine -> Element) -> [ArrayLine] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map (String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mtr" ([Element] -> Element)
    -> (ArrayLine -> [Element]) -> ArrayLine -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
        (Alignment -> [Exp] -> Element)
    -> [Alignment] -> ArrayLine -> [Element]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (\Alignment
    a -> Alignment -> Element -> Element
    setAlignment Alignment
    a (Element -> Element) -> ([Exp] -> Element) -> [Exp] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .  String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mtd"([Element] -> Element) -> ([Exp] -> [Element]) -> [Exp] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt) [Alignment]
    as') [ArrayLine]
    ls
       -- see #205 on the need for style attributes:
       where setAlignment :: Alignment -> Element -> Element
    setAlignment Alignment
    AlignLeft    =
               String -> Text -> Element -> Element
    withAttribute String
    "columnalign" Text
    "left" (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
               String -> Text -> Element -> Element
    withAttribute String
    "style"
                 (if [Alignment] -> Bool
    isRLSequence [Alignment]
    as
                     then Text
    "text-align: left; padding-left: 0"
                     else Text
    "text-align: left")
             setAlignment Alignment
    AlignRight   =
               String -> Text -> Element -> Element
    withAttribute String
    "columnalign" Text
    "right" (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
               String -> Text -> Element -> Element
    withAttribute String
    "style"
                 (if [Alignment] -> Bool
    isRLSequence [Alignment]
    as
                     then Text
    "text-align: right; padding-right: 0"
                     else Text
    "text-align: right")
             setAlignment Alignment
    AlignCenter  =
               String -> Text -> Element -> Element
    withAttribute String
    "columnalign" Text
    "center" (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
               String -> Text -> Element -> Element
    withAttribute String
    "style" Text
    "text-align: center"
             as' :: [Alignment]
    as'                       = [Alignment]
    as [Alignment] -> [Alignment] -> [Alignment]
    forall a. [a] -> [a] -> [a]
    ++ Alignment -> [Alignment]
    forall a. a -> [a]
    repeat Alignment
    AlignCenter

    -- Kept as String for Text.XML.Light
    withAttribute :: String -> T.Text -> Element -> Element
    withAttribute :: String -> Text -> Element -> Element
    withAttribute String
    a = Attr -> Element -> Element
    add_attr (Attr -> Element -> Element)
    -> (Text -> Attr) -> Text -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . QName -> String -> Attr
    Attr (String -> QName
    unqual String
    a) (String -> Attr) -> (Text -> String) -> Text -> Attr
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack

    -- Preserves the order of any existing attributes
    setAttribute :: String -> T.Text -> Element -> Element
    setAttribute :: String -> Text -> Element -> Element
    setAttribute String
    a Text
    v Element
    e = Element
    e { elAttribs = update (elAttribs e) }
      where
        newAttr :: Attr
    newAttr = QName -> String -> Attr
    Attr (String -> QName
    unqual String
    a) (Text -> String
    T.unpack Text
    v)
        update :: [Attr] -> [Attr]
    update [] = [Attr
    newAttr]
        update (Attr
    x:[Attr]
    xs)
            | QName -> String
    qName (Attr -> QName
    attrKey Attr
    x) String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    a =
                Attr
    newAttr Attr -> [Attr] -> [Attr]
    forall a. a -> [a] -> [a]
    : [Attr]
    xs
            | Bool
    otherwise =
                Attr
    x Attr -> [Attr] -> [Attr]
    forall a. a -> [a] -> [a]
    : [Attr] -> [Attr]
    update [Attr]
    xs

    accent :: T.Text -> Element
    accent :: Text -> Element
    accent = Attr -> Element -> Element
    add_attr (QName -> String -> Attr
    Attr (String -> QName
    unqual String
    "accent") String
    "true") (Element -> Element) -> (Text -> Element) -> Text -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
               String -> Text -> Element
    tunode String
    "mo"

    makeFence :: FormType -> Element -> Element
    makeFence :: FormType -> Element -> Element
    makeFence (FormType -> Text
    fromForm -> Text
    t) = String -> Text -> Element -> Element
    withAttribute String
    "stretchy" Text
    "false" (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text -> Element -> Element
    withAttribute String
    "form" Text
    t

    showExp' :: Maybe TextType -> Exp -> Element
    showExp' :: Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt Exp
    e =
      case Exp
    e of
        ESymbol TeXSymbolType
    Accent Text
    x -> Text -> Element
    accent Text
    x
        ESymbol TeXSymbolType
    _ Text
    x      ->
          let isaccent :: Text
    isaccent = case (Text -> [Text] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    elem Text
    "accent") ([Text] -> Bool) -> (Operator -> [Text]) -> Operator -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Operator -> [Text]
    properties (Operator -> Bool) -> Maybe Operator -> Maybe Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                               Text -> FormType -> Maybe Operator
    getMathMLOperator Text
    x FormType
    FPostfix of
                                 Just Bool
    True -> Text
    "true"
                                 Maybe Bool
    _         -> Text
    "false"
          in  String -> Text -> Element -> Element
    withAttribute String
    "accent" Text
    isaccent (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> Text -> Element
    tunode String
    "mo" Text
    x
        Exp
    _                -> Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    e

    showExps :: Maybe TextType -> [Exp] -> [Element]
    showExps :: Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt = (Exp -> Element) -> [Exp] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map (Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt) ([Exp] -> [Element]) -> ([Exp] -> [Exp]) -> [Exp] -> [Element]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Exp] -> [Exp]
    insertFunctionApps

    insertFunctionApps :: [Exp] -> [Exp]
    -- handle this as a special case, or we get an infinite loop
    -- since we insert a new EGrouped to which insertFunctionApp will be applied.
    insertFunctionApps :: [Exp] -> [Exp]
    insertFunctionApps [e :: Exp
    e@EMathOperator{}, ESymbol TeXSymbolType
    _ Text
    "\x2061"] =
      [Exp
    e, TeXSymbolType -> Text -> Exp
    ESymbol TeXSymbolType
    Pun Text
    "\x2061"]
    insertFunctionApps [Exp]
    es' = [Exp] -> [Exp]
    go [Exp]
    es'
     where
      go :: [Exp] -> [Exp]
    go [] = []
      go (e :: Exp
    e@EMathOperator{} : ESymbol TeXSymbolType
    _ Text
    "\x2061" : [Exp]
    es) =
        [Exp] -> Exp
    EGrouped [Exp
    e , TeXSymbolType -> Text -> Exp
    ESymbol TeXSymbolType
    Pun Text
    "\x2061"] Exp -> [Exp] -> [Exp]
    forall a. a -> [a] -> [a]
    : [Exp] -> [Exp]
    go [Exp]
    es
      go (e :: Exp
    e@EMathOperator{} : es :: [Exp]
    es@(Exp
    _:[Exp]
    _)) =
        [Exp] -> Exp
    EGrouped [Exp
    e, TeXSymbolType -> Text -> Exp
    ESymbol TeXSymbolType
    Pun Text
    "\x2061"] Exp -> [Exp] -> [Exp]
    forall a. a -> [a] -> [a]
    : [Exp] -> [Exp]
    go [Exp]
    es
      go (Exp
    e:[Exp]
    es) = Exp
    e Exp -> [Exp] -> [Exp]
    forall a. a -> [a] -> [a]
    : [Exp] -> [Exp]
    go [Exp]
    es

    showExp :: Maybe TextType -> Exp -> Element
    showExp :: Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    e =
     let toUnicodeMaybe :: TextType -> T.Text -> Maybe T.Text
         toUnicodeMaybe :: TextType -> Text -> Maybe Text
    toUnicodeMaybe TextType
    textStyle Text
    t =
           String -> Text
    T.pack (String -> Text) -> Maybe String -> Maybe Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Char -> Maybe Char) -> String -> Maybe String
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ((TextType, Char) -> Maybe Char
    toUnicodeChar ((TextType, Char) -> Maybe Char)
    -> (Char -> (TextType, Char)) -> Char -> Maybe Char
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (TextType
    textStyle,)) (Text -> String
    T.unpack Text
    t)
         -- variant node: tries to convert text to appropriate unicode
         -- characters depending on style
         vnode :: String -> T.Text -> Element
         vnode :: String -> Text -> Element
    vnode String
    elname Text
    t
           = case Maybe TextType
    tt of
               Maybe TextType
    Nothing ->
                 if Text -> Bool
    isUppercaseGreek Text
    t -- see #255
                    then String -> Text -> Element -> Element
    withAttribute String
    "mathvariant" Text
    "normal" (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> Text -> Element
    tunode String
    elname Text
    t
                    else String -> Text -> Element
    tunode String
    elname Text
    t
               Just TextType
    TextNormal -> String -> Text -> Element -> Element
    withAttribute String
    "mathvariant" Text
    "normal" (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $
                                    String -> Text -> Element
    tunode String
    elname Text
    t
               Just TextType
    textStyle ->
                 case TextType -> Text -> Maybe Text
    toUnicodeMaybe TextType
    textStyle Text
    t of
                   -- if we can't find unicode equivalents, rely on mathvariant:
                   Maybe Text
    Nothing -> String -> Text -> Element -> Element
    withAttribute String
    "mathvariant" (TextType -> Text
    getMMLType TextType
    textStyle) (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $
                                 String -> Text -> Element
    tunode String
    elname Text
    t
                   Just Text
    t' -> String -> Text -> Element
    tunode String
    elname Text
    t'
      in case Exp
    e of
       ENumber Text
    x        -> String -> Text -> Element
    vnode String
    "mn" Text
    x
       EGrouped [Exp
    x]     -> Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x
       EGrouped [Exp]
    xs      -> [Element] -> Element
    mrow ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp]
    xs
       EDelimited Text
    start Text
    end [InEDelimited]
    xs -> [Element] -> Element
    mrow ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $
         [ FormType -> Element -> Element
    makeStretchy FormType
    FPrefix (String -> Text -> Element
    vnode String
    "mo" Text
    start) | Bool -> Bool
    not (Text -> Bool
    T.null Text
    start) ] [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++
         (InEDelimited -> Element) -> [InEDelimited] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map ((Text -> Element) -> (Exp -> Element) -> InEDelimited -> Element
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (FormType -> Element -> Element
    makeStretchy FormType
    FInfix (Element -> Element) -> (Text -> Element) -> Text -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text -> Element
    vnode String
    "mo") (Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt)) [InEDelimited]
    xs [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++
         [ FormType -> Element -> Element
    makeStretchy FormType
    FPostfix (String -> Text -> Element
    vnode String
    "mo" Text
    end)
            | Bool -> Bool
    not (Text -> Bool
    T.null Text
    end) ]
       EIdentifier Text
    x    -> String -> Text -> Element
    vnode String
    "mi" Text
    x
       EMathOperator Text
    x  -> String -> Text -> Element
    vnode String
    "mi" Text
    x -- see #257
       ESymbol TeXSymbolType
    Open Text
    x   -> FormType -> Element -> Element
    makeFence FormType
    FPrefix (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> Text -> Element
    vnode String
    "mo" Text
    x
       ESymbol TeXSymbolType
    Close Text
    x  -> FormType -> Element -> Element
    makeFence FormType
    FPostfix (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ String -> Text -> Element
    vnode String
    "mo" Text
    x
       ESymbol TeXSymbolType
    Ord Text
    x
         | Text
    x Text -> Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text
    "\x2061" -> String -> Text -> Element
    vnode String
    "mo" Text
    x
         | Bool
    otherwise    -> String -> Text -> Element
    vnode String
    "mi" Text
    x
       ESymbol TeXSymbolType
    _ Text
    x      -> String -> Text -> Element
    vnode String
    "mo" Text
    x
       ESpace Rational
    x         -> Rational -> Element
    spaceWidth Rational
    x
       EFraction FractionType
    ft Exp
    x Exp
    y -> Maybe TextType -> FractionType -> Exp -> Exp -> Element
    showFraction Maybe TextType
    tt FractionType
    ft Exp
    x Exp
    y
       ESub Exp
    x Exp
    y         -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "msub" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x, Exp
    y]
       ESuper Exp
    x Exp
    y       -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "msup" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x, Exp
    y]
       ESubsup Exp
    x Exp
    y Exp
    z    -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "msubsup" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x, Exp
    y, Exp
    z]
       EUnder Bool
    _ Exp
    x Exp
    y     -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "munder" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x] [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt Exp
    y]
       EOver Bool
    _ Exp
    x (ESymbol TeXSymbolType
    Accent Text
    "\8407") -- see #218, gives better rendering for vectors
                        -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mover" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x] [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt (TeXSymbolType -> Text -> Exp
    ESymbol TeXSymbolType
    Accent Text
    "\8594")]
       EOver Bool
    _ Exp
    x Exp
    y      -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mover" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x] [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt Exp
    y]
       EUnderover Bool
    _ Exp
    x Exp
    y Exp
    z -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "munderover" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $
                              Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x] [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt Exp
    y, Maybe TextType -> Exp -> Element
    showExp' Maybe TextType
    tt Exp
    z]
       EPhantom Exp
    x       -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mphantom" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> [Exp] -> [Element]
    showExps Maybe TextType
    tt [Exp
    x]
       EBoxed Exp
    x         -> String -> Text -> Element -> Element
    withAttribute String
    "notation" Text
    "box" (Element -> Element) -> (Element -> Element) -> Element -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                           String -> Element -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "menclose" (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x
       ESqrt Exp
    x          -> String -> Element -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "msqrt" (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x
       ERoot Exp
    i Exp
    x        -> String -> [Element] -> Element
    forall t. Node t => String -> t -> Element
    unode String
    "mroot" [Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x, Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    i]
       EScaled Rational
    s Exp
    x      -> Rational -> Element -> Element
    makeScaled Rational
    s (Element -> Element) -> Element -> Element
    forall a b. (a -> b) -> a -> b
    $ Maybe TextType -> Exp -> Element
    showExp Maybe TextType
    tt Exp
    x
       EArray [Alignment]
    as [ArrayLine]
    ls     -> Maybe TextType -> [Alignment] -> [ArrayLine] -> Element
    makeArray Maybe TextType
    tt [Alignment]
    as [ArrayLine]
    ls
       EText TextType
    a Text
    s        -> case (Maybe TextType
    tt, TextType
    a) of
                             (Just TextType
    ty, TextType
    TextNormal) -> TextType -> Text -> Element
    makeText TextType
    ty Text
    s
                             (Maybe TextType, TextType)
    _ -> TextType -> Text -> Element
    makeText TextType
    a Text
    s
       EStyled TextType
    a [Exp]
    es     -> Maybe TextType -> Exp -> Element
    showExp (TextType -> Maybe TextType
    forall a. a -> Maybe a
    Just TextType
    a) ([Exp] -> Exp
    EGrouped [Exp]
    es)
       -- see https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mstyle
       -- Historically, this element accepted almost all the MathML attributes and
       -- it was used to override the default attribute values of its descendants.
       -- It was later restricted to only a few relevant styling attributes that
       -- were used in existing web pages. Nowadays, these styling attributes are
       -- common to all MathML elements and so <mstyle> is really just equivalent
       -- to an <mrow> element. However, <mstyle> may still be relevant for
       -- compatibility with MathML implementations outside browsers.

    -- Kept as String for Text.XML.Light
    tunode :: String -> T.Text -> Element
    tunode :: String -> Text -> Element
    tunode String
    s = String -> String -> Element
    forall t. Node t => String -> t -> Element
    unode String
    s (String -> Element) -> (Text -> String) -> Text -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack