{-# LANGUAGE CPP, ScopedTypeVariables, OverloadedStrings #-}
{-
Copyright (C) 2014 Matthew Pickering <matthewtpickering@gmail.com>

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
-}
module Text.TeXMath.Shared
  ( getMMLType
  , getTextType
  , getLaTeXTextCommand
  , getScalerCommand
  , getScalerValue
  , scalers
  , getSpaceWidth
  , getSpaceChars
  , getDiacriticalCommand
  , diacriticals
  , getOperator
  , readLength
  , fixTree
  , isEmpty
  , empty
  , handleDownup
  ) where


import Text.TeXMath.Types
import Text.TeXMath.TeX
import qualified Data.Map as M
import qualified Data.Set as Set
import qualified Data.Text as T
import Data.Maybe (fromMaybe)
import Data.Ratio ((%))
import Data.List (sort)
import Data.Semigroup ((<>))
import Control.Applicative ((<$>), (<*>))
import Control.Monad (guard)
import Text.Parsec (Parsec, parse, getInput, digit, char, many1, option)
import Data.Generics (everywhere, mkT)

-- As we constuct from the bottom up, this situation can occur.
removeNesting :: Exp -> Exp
removeNesting :: Exp -> Exp
removeNesting (EDelimited o :: Text
o c :: Text
c [Right (EDelimited "" "" xs :: [InEDelimited]
xs)]) = Text -> Text -> [InEDelimited] -> Exp
EDelimited Text
o Text
c [InEDelimited]
xs
removeNesting (EDelimited "" "" [x :: InEDelimited
x]) = (Text -> Exp) -> (Exp -> Exp) -> InEDelimited -> Exp
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (TeXSymbolType -> Text -> Exp
ESymbol TeXSymbolType
Ord) Exp -> Exp
forall a. a -> a
id InEDelimited
x
removeNesting (EGrouped [x :: Exp
x]) = Exp
x
removeNesting x :: Exp
x = Exp
x

removeEmpty :: [Exp] -> [Exp]
removeEmpty :: [Exp] -> [Exp]
removeEmpty xs :: [Exp]
xs = (Exp -> Bool) -> [Exp] -> [Exp]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Exp -> Bool) -> Exp -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Exp -> Bool
isEmpty) [Exp]
xs

-- | An empty group of expressions
empty :: Exp
empty :: Exp
empty = [Exp] -> Exp
EGrouped []

-- | Test to see whether an expression is @empty@.
isEmpty :: Exp -> Bool
isEmpty :: Exp -> Bool
isEmpty (EGrouped []) = Bool
True
isEmpty _ = Bool
False

-- | Walks over a tree of expressions, removing empty expressions, and
-- fixing delimited expressions with no delimiters and unnecessarily
-- grouped expressions.
fixTree :: Exp -> Exp
fixTree :: Exp -> Exp
fixTree = (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
removeNesting) (Exp -> Exp) -> (Exp -> Exp) -> Exp -> Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (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]
removeEmpty)

-- | Maps TextType to the corresponding MathML mathvariant
getMMLType :: TextType -> T.Text
getMMLType :: TextType -> Text
getMMLType t :: TextType
t = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe "normal" ((Text, Text) -> Text
forall a b. (a, b) -> a
fst ((Text, Text) -> Text) -> Maybe (Text, Text) -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TextType -> Map TextType (Text, Text) -> Maybe (Text, Text)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TextType
t Map TextType (Text, Text)
textTypesMap)

-- | Maps TextType to corresponding LaTeX command
getLaTeXTextCommand :: Env -> TextType -> T.Text
getLaTeXTextCommand :: Env -> TextType -> Text
getLaTeXTextCommand e :: Env
e t :: TextType
t =
  let textCmd :: Text
textCmd = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe "\\mathrm"
                  ((Text, Text) -> Text
forall a b. (a, b) -> b
snd ((Text, Text) -> Text) -> Maybe (Text, Text) -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TextType -> Map TextType (Text, Text) -> Maybe (Text, Text)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TextType
t Map TextType (Text, Text)
textTypesMap) in
  if Text -> Env -> Bool
textPackage Text
textCmd Env
e
    then Text
textCmd
    else Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe "\\mathrm" (Text -> Map Text Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
textCmd Map Text Text
alts)

-- | Maps MathML mathvariant to the corresponing TextType
getTextType :: T.Text -> TextType
getTextType :: Text -> TextType
getTextType s :: Text
s = TextType -> Maybe TextType -> TextType
forall a. a -> Maybe a -> a
fromMaybe TextType
TextNormal (Text -> Map Text TextType -> Maybe TextType
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
s Map Text TextType
revTextTypesMap)

-- | Maps a LaTeX scaling command to the percentage scaling
getScalerCommand :: Rational -> Maybe T.Text
getScalerCommand :: Rational -> Maybe Text
getScalerCommand width :: Rational
width =
  case [(Rational, Text)] -> [(Rational, Text)]
forall a. Ord a => [a] -> [a]
sort [ (Rational
w, Text
cmd) | (cmd :: Text
cmd, w :: Rational
w) <- [(Text, Rational)]
scalers, Rational
w Rational -> Rational -> Bool
forall a. Ord a => a -> a -> Bool
>= Rational
width ] of
       ((_,cmd :: Text
cmd):_) -> Text -> Maybe Text
forall a. a -> Maybe a
Just Text
cmd
       _           -> Maybe Text
forall a. Maybe a
Nothing
  -- note, we don't use a Map here because we need the first
  -- match:  \Big, not \Bigr

-- | Gets percentage scaling from LaTeX scaling command
getScalerValue :: T.Text -> Maybe Rational
getScalerValue :: Text -> Maybe Rational
getScalerValue command :: Text
command = Text -> [(Text, Rational)] -> Maybe Rational
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
command [(Text, Rational)]
scalers

-- | Given a diacritical mark, returns the corresponding LaTeX command
getDiacriticalCommand  :: Position -> T.Text -> Maybe T.Text
getDiacriticalCommand :: Position -> Text -> Maybe Text
getDiacriticalCommand pos :: Position
pos symbol :: Text
symbol = do
  Text
command <- Text -> Map Text Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
symbol Map Text Text
diaMap
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Text
command Text -> Env -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Env
unavailable)
  let below :: Bool
below = Text
command Text -> Env -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Env
under
  case Position
pos of
    Under -> if Bool
below then Text -> Maybe Text
forall a. a -> Maybe a
Just Text
command else Maybe Text
forall a. Maybe a
Nothing
    Over -> if Bool -> Bool
not Bool
below then Text -> Maybe Text
forall a. a -> Maybe a
Just Text
command else Maybe Text
forall a. Maybe a
Nothing
  where
    diaMap :: Map Text Text
diaMap = [(Text, Text)] -> Map Text Text
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(Text, Text)]
diacriticals

-- Operator Table

getOperator :: Exp -> Maybe TeX
getOperator :: Exp -> Maybe TeX
getOperator op :: Exp
op = (Text -> TeX) -> Maybe Text -> Maybe TeX
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> TeX
ControlSeq (Maybe Text -> Maybe TeX) -> Maybe Text -> Maybe TeX
forall a b. (a -> b) -> a -> b
$ Exp -> Map Exp Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Exp
op Map Exp Text
operators

operators :: M.Map Exp T.Text
operators :: Map Exp Text
operators = [(Exp, Text)] -> Map Exp Text
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
           [ (Text -> Exp
EMathOperator "arccos", "\\arccos")
           , (Text -> Exp
EMathOperator "arcsin", "\\arcsin")
           , (Text -> Exp
EMathOperator "arctan", "\\arctan")
           , (Text -> Exp
EMathOperator "arg", "\\arg")
           , (Text -> Exp
EMathOperator "cos", "\\cos")
           , (Text -> Exp
EMathOperator "cosh", "\\cosh")
           , (Text -> Exp
EMathOperator "cot", "\\cot")
           , (Text -> Exp
EMathOperator "coth", "\\coth")
           , (Text -> Exp
EMathOperator "csc", "\\csc")
           , (Text -> Exp
EMathOperator "deg", "\\deg")
           , (Text -> Exp
EMathOperator "det", "\\det")
           , (Text -> Exp
EMathOperator "dim", "\\dim")
           , (Text -> Exp
EMathOperator "exp", "\\exp")
           , (Text -> Exp
EMathOperator "gcd", "\\gcd")
           , (Text -> Exp
EMathOperator "hom", "\\hom")
           , (Text -> Exp
EMathOperator "inf", "\\inf")
           , (Text -> Exp
EMathOperator "ker", "\\ker")
           , (Text -> Exp
EMathOperator "lg", "\\lg")
           , (Text -> Exp
EMathOperator "lim", "\\lim")
           , (Text -> Exp
EMathOperator "liminf", "\\liminf")
           , (Text -> Exp
EMathOperator "limsup", "\\limsup")
           , (Text -> Exp
EMathOperator "ln", "\\ln")
           , (Text -> Exp
EMathOperator "log", "\\log")
           , (Text -> Exp
EMathOperator "max", "\\max")
           , (Text -> Exp
EMathOperator "min", "\\min")
           , (Text -> Exp
EMathOperator "Pr", "\\Pr")
           , (Text -> Exp
EMathOperator "sec", "\\sec")
           , (Text -> Exp
EMathOperator "sin", "\\sin")
           , (Text -> Exp
EMathOperator "sinh", "\\sinh")
           , (Text -> Exp
EMathOperator "sup", "\\sup")
           , (Text -> Exp
EMathOperator "tan", "\\tan")
           , (Text -> Exp
EMathOperator "tanh", "\\tanh") ]

-- | Attempts to convert a string into
readLength :: T.Text -> Maybe Rational
readLength :: Text -> Maybe Rational
readLength s :: Text
s = do
  (n :: Rational
n, unit :: Text
unit) <- case (Parsec Text () (Rational, Text)
-> SourceName -> Text -> Either ParseError (Rational, Text)
forall s t a.
Stream s Identity t =>
Parsec s () a -> SourceName -> s -> Either ParseError a
parse Parsec Text () (Rational, Text)
parseLength "" Text
s) of
                  Left _ -> Maybe (Rational, Text)
forall a. Maybe a
Nothing
                  Right v :: (Rational, Text)
v -> (Rational, Text) -> Maybe (Rational, Text)
forall a. a -> Maybe a
Just (Rational, Text)
v
  (Rational
n Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
*) (Rational -> Rational) -> Maybe Rational -> Maybe Rational
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Maybe Rational
unitToMultiplier Text
unit


parseLength :: Parsec T.Text () (Rational, T.Text)
parseLength :: Parsec Text () (Rational, Text)
parseLength = do
    SourceName
neg <- SourceName
-> ParsecT Text () Identity SourceName
-> ParsecT Text () Identity SourceName
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option "" ((Char -> SourceName -> SourceName
forall a. a -> [a] -> [a]
:[]) (Char -> SourceName)
-> ParsecT Text () Identity Char
-> ParsecT Text () Identity SourceName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> ParsecT Text () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char '-')
    SourceName
dec <- ParsecT Text () Identity Char
-> ParsecT Text () Identity SourceName
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
    SourceName
frac <- SourceName
-> ParsecT Text () Identity SourceName
-> ParsecT Text () Identity SourceName
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option "" ((:) (Char -> SourceName -> SourceName)
-> ParsecT Text () Identity Char
-> ParsecT Text () Identity (SourceName -> SourceName)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> ParsecT Text () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char '.' ParsecT Text () Identity (SourceName -> SourceName)
-> ParsecT Text () Identity SourceName
-> ParsecT Text () Identity SourceName
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Text () Identity Char
-> ParsecT Text () Identity SourceName
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit)
    Text
unit <- ParsecT Text () Identity Text
forall (m :: * -> *) s u. Monad m => ParsecT s u m s
getInput
    -- This is safe as dec and frac must be a double of some kind
    let [(Double
n :: Double, [])] = ReadS Double
forall a. Read a => ReadS a
reads (SourceName
neg SourceName -> SourceName -> SourceName
forall a. [a] -> [a] -> [a]
++ SourceName
dec SourceName -> SourceName -> SourceName
forall a. [a] -> [a] -> [a]
++ SourceName
frac)
    (Rational, Text) -> Parsec Text () (Rational, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (Double
n Double -> Double -> Double
forall a. Num a => a -> a -> a
* 18) Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 18, Text
unit)

textTypesMap :: M.Map TextType (T.Text, T.Text)
textTypesMap :: Map TextType (Text, Text)
textTypesMap = [(TextType, (Text, Text))] -> Map TextType (Text, Text)
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(TextType, (Text, Text))]
textTypes

revTextTypesMap :: M.Map T.Text TextType
revTextTypesMap :: Map Text TextType
revTextTypesMap = [(Text, TextType)] -> Map Text TextType
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(Text, TextType)] -> Map Text TextType)
-> [(Text, TextType)] -> Map Text TextType
forall a b. (a -> b) -> a -> b
$ ((TextType, (Text, Text)) -> (Text, TextType))
-> [(TextType, (Text, Text))] -> [(Text, TextType)]
forall a b. (a -> b) -> [a] -> [b]
map (\(k :: TextType
k, (v :: Text
v,_)) -> (Text
v,TextType
k)) [(TextType, (Text, Text))]
textTypes

--TextType to (MathML, LaTeX)
textTypes :: [(TextType, (T.Text, T.Text))]
textTypes :: [(TextType, (Text, Text))]
textTypes =
  [ ( TextType
TextNormal       , ("normal", "\\mathrm"))
  , ( TextType
TextBold         , ("bold", "\\mathbf"))
  , ( TextType
TextItalic       , ("italic","\\mathit"))
  , ( TextType
TextMonospace    , ("monospace","\\mathtt"))
  , ( TextType
TextSansSerif    , ("sans-serif","\\mathsf"))
  , ( TextType
TextDoubleStruck , ("double-struck","\\mathbb"))
  , ( TextType
TextScript       , ("script","\\mathcal"))
  , ( TextType
TextFraktur      , ("fraktur","\\mathfrak"))
  , ( TextType
TextBoldItalic          , ("bold-italic","\\mathbfit"))
  , ( TextType
TextSansSerifBold       , ("bold-sans-serif","\\mathbfsfup"))
  , ( TextType
TextSansSerifBoldItalic , ("sans-serif-bold-italic","\\mathbfsfit"))
  , ( TextType
TextBoldScript          , ("bold-script","\\mathbfscr"))
  , ( TextType
TextBoldFraktur         , ("bold-fraktur","\\mathbffrak"))
  , ( TextType
TextSansSerifItalic     , ("sans-serif-italic","\\mathsfit")) ]

unicodeMath, base :: Set.Set T.Text
unicodeMath :: Set Text
unicodeMath = Env -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList
  ["\\mathbfit", "\\mathbfsfup", "\\mathbfsfit", "\\mathbfscr",
   "\\mathbffrak", "\\mathsfit"]
base :: Set Text
base = Env -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList
  ["\\mathbb", "\\mathrm", "\\mathbf", "\\mathit", "\\mathsf",
   "\\mathtt", "\\mathfrak", "\\mathcal"]

alts :: M.Map T.Text T.Text
alts :: Map Text Text
alts = [(Text, Text)] -> Map Text Text
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
  [ ("\\mathbfit", "\\mathbf")
  , ("\\mathbfsfup", "\\mathbf")
  , ("\\mathbfsfit", "\\mathbf")
  , ("\\mathbfscr", "\\mathcal")
  , ("\\mathbffrak", "\\mathfrak")
  , ("\\mathsfit", "\\mathsf")
  ]

textPackage :: T.Text -> [T.Text] -> Bool
textPackage :: Text -> Env -> Bool
textPackage s :: Text
s e :: Env
e
  | Text
s Text -> Set Text -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Text
unicodeMath = "unicode-math" Text -> Env -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Env
e
  | Text
s Text -> Set Text -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Text
base    = Bool
True
  | Bool
otherwise = Bool
True

-- | Mapping between LaTeX scaling commands and the scaling factor
scalers :: [(T.Text, Rational)]
scalers :: [(Text, Rational)]
scalers =
          [ ("\\bigg", Rational
widthbigg)
          , ("\\Bigg", Rational
widthBigg)
          , ("\\big", Rational
widthbig)
          , ("\\Big", Rational
widthBig)
          , ("\\biggr", Rational
widthbigg)
          , ("\\Biggr", Rational
widthBigg)
          , ("\\bigr", Rational
widthbig)
          , ("\\Bigr", Rational
widthBig)
          , ("\\biggl", Rational
widthbigg)
          , ("\\Biggl", Rational
widthBigg)
          , ("\\bigl", Rational
widthbig)]
  where widthbig :: Rational
widthbig = 6 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ 5
        widthBig :: Rational
widthBig = 9 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ 5
        widthbigg :: Rational
widthbigg = 12 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ 5
        widthBigg :: Rational
widthBigg = 3

-- | Returns the space width for a unicode space character, or Nothing.
getSpaceWidth :: Char -> Maybe Rational
getSpaceWidth :: Char -> Maybe Rational
getSpaceWidth ' '      = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (4Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/18)
getSpaceWidth '\xA0'   = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (4Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/18)
getSpaceWidth '\x2000' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/2)
getSpaceWidth '\x2001' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just 1
getSpaceWidth '\x2002' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/2)
getSpaceWidth '\x2003' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just 1
getSpaceWidth '\x2004' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/3)
getSpaceWidth '\x2005' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (4Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/18)
getSpaceWidth '\x2006' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/6)
getSpaceWidth '\x2007' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/3) -- ? width of a digit
getSpaceWidth '\x2008' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/6) -- ? width of a period
getSpaceWidth '\x2009' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/6)
getSpaceWidth '\x200A' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (1Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/9)
getSpaceWidth '\x200B' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just 0
getSpaceWidth '\x202F' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (3Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/18)
getSpaceWidth '\x205F' = Rational -> Maybe Rational
forall a. a -> Maybe a
Just (4Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/18)
getSpaceWidth _        = Maybe Rational
forall a. Maybe a
Nothing

-- | Returns the sequence of unicode space characters closest to the
-- specified width.
getSpaceChars :: Rational -> T.Text
getSpaceChars :: Rational -> Text
getSpaceChars r :: Rational
r
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = "\x200B" -- no negative space chars in unicode
  | Bool
otherwise = Rational -> Text
forall t. (Ord t, Fractional t) => t -> Text
fracSpaces Rational
f Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
emQuads Int
n
  where
    (n :: Int
n, f :: Rational
f) = Rational -> (Int, Rational)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction Rational
r
    emQuads :: Int -> Text
emQuads x :: Int
x = Int -> Text -> Text
T.replicate Int
x "\x2001"
    fracSpaces :: t -> Text
fracSpaces x :: t
x
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 2t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\x200A"
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 3t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\x2006"
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 4t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\xA0"   -- could also be "\x2005"
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 5t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\x2005"
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 7t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\x2004"
      | t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= 9t -> t -> t
forall a. Fractional a => a -> a -> a
/18 = "\x2000"
      | Bool
otherwise = Char -> Text -> Text
T.cons '\x2000' (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ t -> Text
fracSpaces (t
x t -> t -> t
forall a. Num a => a -> a -> a
- (1t -> t -> t
forall a. Fractional a => a -> a -> a
/2))

-- Accents which go under the character
under :: [T.Text]
under :: Env
under = ["\\underbrace", "\\underline", "\\underbar", "\\underbracket"]

-- We want to parse these but we can't represent them in LaTeX
unavailable :: [T.Text]
unavailable :: Env
unavailable = ["\\overbracket", "\\underbracket"]


-- | Mapping between unicode combining character and LaTeX accent command
diacriticals :: [(T.Text, T.Text)]
diacriticals :: [(Text, Text)]
diacriticals =
               [ ("\x00B4", "\\acute")
               , ("\x0301", "\\acute")
               , ("\x0060", "\\grave")
               , ("\x0300", "\\grave")
               , ("\x02D8", "\\breve")
               , ("\x0306", "\\breve")
               , ("\x02C7", "\\check")
               , ("\x030C", "\\check")
               , ("\x307", "\\dot")
               , ("\x308", "\\ddot")
               , ("\x20DB", "\\dddot")
               , ("\x20DC", "\\ddddot")
               , ("\x00B0", "\\mathring")
               , ("\x030A", "\\mathring")
               , ("\x20D7", "\\vec")
               , ("\x20D7", "\\overrightarrow")
               , ("\x20D6", "\\overleftarrow")
               , ("\x005E", "\\hat")
               , ("\x02C6", "\\widehat")
               , ("\x0302", "\\widehat")
               , ("\x02DC", "\\widetilde")
               , ("\x0303", "\\tilde")
               , ("\x0303", "\\widetilde")
               , ("\x0304", "\\bar")
               , ("\x203E", "\\bar")
               , ("\x23DE", "\\overbrace")
               , ("\x23B4", "\\overbracket") -- Only availible in mathtools
               , ("\x00AF", "\\overline")
               , ("\x0305", "\\overline")
               , ("\x23DF", "\\underbrace")
               , ("\x23B5", "\\underbracket") -- mathtools
               , ("\x0332", "\\underline")
               , ("_", "\\underline")
               , ("\x0333", "\\underbar")
               ]




-- Converts unit to multiplier to reach em
unitToMultiplier :: T.Text -> Maybe Rational
unitToMultiplier :: Text -> Maybe Rational
unitToMultiplier s :: Text
s = Text -> Map Text Rational -> Maybe Rational
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
s Map Text Rational
units
  where
    units :: Map Text Rational
units = [(Text, Rational)] -> Map Text Rational
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList  [ ( "pt" , 10)
                        , ( "mm" , (351Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/10))
                        , ( "cm" , (35Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/100))
                        , ( "in" , (14Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/100))
                        , ( "ex" , (232Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/100))
                        , ( "em" , 1)
                        , ( "mu" , 18)
                        , ( "dd" , (93Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/100))
                        , ( "bp" , (996Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/1000))
                        , ( "pc" , (83Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/100)) ]

handleDownup :: DisplayType -> Exp -> Exp
handleDownup :: DisplayType -> Exp -> Exp
handleDownup DisplayInline (EUnder True x :: Exp
x y :: Exp
y)       = Exp -> Exp -> Exp
ESub Exp
x Exp
y
handleDownup DisplayInline (EOver True x :: Exp
x y :: Exp
y)        = Exp -> Exp -> Exp
ESuper Exp
x Exp
y
handleDownup DisplayInline (EUnderover True x :: Exp
x y :: Exp
y z :: Exp
z) = Exp -> Exp -> Exp -> Exp
ESubsup Exp
x Exp
y Exp
z
handleDownup DisplayBlock  (EUnder True x :: Exp
x y :: Exp
y)       = Bool -> Exp -> Exp -> Exp
EUnder Bool
False Exp
x Exp
y
handleDownup DisplayBlock  (EOver True x :: Exp
x y :: Exp
y)        = Bool -> Exp -> Exp -> Exp
EOver Bool
False  Exp
x Exp
y
handleDownup DisplayBlock  (EUnderover True x :: Exp
x y :: Exp
y z :: Exp
z) = Bool -> Exp -> Exp -> Exp -> Exp
EUnderover Bool
False Exp
x Exp
y Exp
z
handleDownup _             x :: Exp
x                       = Exp
x