{-# LANGUAGE OverloadedStrings #-}
module Language.Ltml.ToLaTeX.Renderer
( renderLaTeX
, renderLaTeXPretty
) where
import Data.Int (Int64)
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Builder as B
import Language.Ltml.ToLaTeX.LaTeXType (LaTeX (..))
renderLaTeX :: LaTeX -> T.Text
renderLaTeX :: LaTeX -> Text
renderLaTeX = LazyText -> Text
LT.toStrict (LazyText -> Text) -> (LaTeX -> LazyText) -> LaTeX -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> LazyText
B.toLazyText (Builder -> LazyText) -> (LaTeX -> Builder) -> LaTeX -> LazyText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LaTeX -> Builder
build
where
build :: LaTeX -> B.Builder
build :: LaTeX -> Builder
build (Text Text
t) = Text -> Builder
escape Text
t
build (Raw Text
t) = Text -> Builder
B.fromText Text
t
build (CommandS Text
name) =
Builder
"\\" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
build (Command Text
name [Text]
opts [LaTeX]
args) =
Builder
"\\"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
renderOpts [Text]
opts
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Builder -> Builder
wrapInBraces (Builder -> Builder) -> (LaTeX -> Builder) -> LaTeX -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LaTeX -> Builder
build) [LaTeX]
args)
build (Environment Text
name [Text]
opts [LaTeX]
body) =
Builder
"\\begin{"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
renderOpts [Text]
opts
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map LaTeX -> Builder
build [LaTeX]
body)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\\end{"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}"
build (Braced LaTeX
latex) = Builder -> Builder
wrapInBraces (LaTeX -> Builder
build LaTeX
latex)
build (Sequence [LaTeX]
xs) = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map LaTeX -> Builder
build [LaTeX]
xs)
renderLaTeXPretty :: LaTeX -> T.Text
renderLaTeXPretty :: LaTeX -> Text
renderLaTeXPretty = LazyText -> Text
LT.toStrict (LazyText -> Text) -> (LaTeX -> LazyText) -> LaTeX -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> LazyText
B.toLazyText (Builder -> LazyText) -> (LaTeX -> Builder) -> LaTeX -> LazyText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> LaTeX -> Builder
build Int64
0
where
build :: Int64 -> LaTeX -> B.Builder
build :: Int64 -> LaTeX -> Builder
build Int64
_ (Text Text
t) = Text -> Builder
escape Text
t
build Int64
_ (Raw Text
t) = Text -> Builder
B.fromText Text
t
build Int64
_ (CommandS Text
name) =
Builder
"\\" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" "
build Int64
n (Command Text
name [Text]
opts [LaTeX]
args) =
Builder
"\\"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
renderOpts [Text]
opts
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Builder -> Builder
wrapInBraces (Builder -> Builder) -> (LaTeX -> Builder) -> LaTeX -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> LaTeX -> Builder
build Int64
n) [LaTeX]
args)
build Int64
n (Environment Text
name [Text]
opts [LaTeX]
body) =
Builder
"\n"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText (Int -> Text -> Text
T.replicate (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n) Text
"\t")
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\\begin{"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
renderOpts [Text]
opts
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat
( (LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map
( (Text -> Builder
B.fromText (Int -> Text -> Text
T.replicate (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64
n Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int64
1)) Text
"\t") Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>)
(Builder -> Builder) -> (LaTeX -> Builder) -> LaTeX -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n")
(Builder -> Builder) -> (LaTeX -> Builder) -> LaTeX -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> LaTeX -> Builder
build (Int64
n Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int64
1)
)
[LaTeX]
body
)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText (Int -> Text -> Text
T.replicate (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n) Text
"\t")
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\\end{"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText Text
name
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}\n"
build Int64
n (Braced LaTeX
latex) = Builder -> Builder
wrapInBraces (Int64 -> LaTeX -> Builder
build Int64
n LaTeX
latex)
build Int64
n (Sequence [LaTeX]
xs) = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((LaTeX -> Builder) -> [LaTeX] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Int64 -> LaTeX -> Builder
build Int64
n) [LaTeX]
xs)
renderOpts :: [T.Text] -> B.Builder
renderOpts :: [Text] -> Builder
renderOpts [] = Builder
forall a. Monoid a => a
mempty
renderOpts [Text]
os = Builder
"[" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
B.fromText (Text -> [Text] -> Text
T.intercalate Text
"," [Text]
os) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"]"
wrapInBraces :: B.Builder -> B.Builder
wrapInBraces :: Builder -> Builder
wrapInBraces Builder
b = Builder
"{" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}"
escape :: T.Text -> B.Builder
escape :: Text -> Builder
escape = (Char -> Builder -> Builder) -> Builder -> Text -> Builder
forall a. (Char -> a -> a) -> a -> Text -> a
T.foldr Char -> Builder -> Builder
escapeChar Builder
forall a. Monoid a => a
mempty
escapeChar :: Char -> B.Builder -> B.Builder
escapeChar :: Char -> Builder -> Builder
escapeChar Char
'#' Builder
acc = Builder
"\\#" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'$' Builder
acc = Builder
"\\$" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'%' Builder
acc = Builder
"\\%" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'&' Builder
acc = Builder
"\\&" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'~' Builder
acc = Builder
"\\~{}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'_' Builder
acc = Builder
"\\verb|_|" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'^' Builder
acc = Builder
"\\^{}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'\\' Builder
acc = Builder
"\\textbackslash{}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'{' Builder
acc = Builder
"\\{" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'}' Builder
acc = Builder
"\\}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'\'' Builder
acc = Builder
"\\string'|" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'`' Builder
acc = Builder
"\\string`" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'"' Builder
acc = Builder
"\\string\"" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
'-' Builder
acc = Builder
"\\string-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc
escapeChar Char
c Builder
acc = Char -> Builder
B.singleton Char
c Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
acc