-- | Defines types and functions to help generate common LaTeX preamble.
module Language.Drasil.TeX.Preamble (genPreamble) where

import Data.List (nub)

import Language.Drasil.Config (hyperSettings, fontSize, bibFname)
import Language.Drasil.Printing.Helpers (sq)
import Language.Drasil.Printing.LayoutObj (LayoutObj(..))
import Language.Drasil.TeX.Monad (D, vcat, (%%), nest)
import Language.Drasil.TeX.Helpers (docclass, command, command1o, command2, command3,
  usepackage, lbrace, rbrace)

-- FIXME: this really shouldn't be in code, it should be data!
-- | LaTeX packages.
data Package = AMSMath      -- ^ Improves information structure for mathematical formulas.
             | BookTabs     -- ^ Enhances quality of tables in the document.
             | Caption      -- ^ Customize the captions in floating environments.
             | FullPage     -- ^ Sets margins and page style.
             | Graphics     -- ^ Manipulate graphical elements.
             | HyperRef     -- ^ Handles cross-referencing within the document.
             | Listings     -- ^ Source code printer for LaTeX.
             | Tikz         -- ^ Create graphical elements.
             | Dot2Tex      -- ^ Create better graphs.
             | AdjustBox    -- ^ Adjustable boxed content.
             | AMSsymb      -- ^ Displays bold math sets (reals, naturals, etc.).
--           | Breqn --line breaks long equations automatically
             | FileContents -- ^ Creates .bib file within .tex file.
             | BibLaTeX     -- ^ Reimplementation of bibliography elements.
             | Tabularray   -- ^ Adds auto column width feature for tables.
             | TabularX     -- ^ Adds \arraybackslash
             | Mathtools    -- ^ Line breaks for long fractions and cases.
             | URL          -- ^ Allows for hyperlinks.
             | FontSpec     -- ^ For utf-8 encoding in lualatex.
             | Unicode      -- ^ For unicode-math in lualatex.
             | EnumItem     -- ^ Contol basic list environments.
             | SVG          -- ^ For rendering svg diagrams.
             | Float        -- ^ For enhanced control over placement of figures and tables.
             deriving Package -> Package -> Bool
(Package -> Package -> Bool)
-> (Package -> Package -> Bool) -> Eq Package
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Package -> Package -> Bool
== :: Package -> Package -> Bool
$c/= :: Package -> Package -> Bool
/= :: Package -> Package -> Bool
Eq

-- | Adds a 'Package' to the LaTeX document.
addPackage :: Package -> D
addPackage :: Package -> D
addPackage Package
AMSMath   = String -> D
usepackage String
"amsmath"
addPackage Package
BookTabs  = String -> D
usepackage String
"booktabs"
addPackage Package
Caption   = String -> D
usepackage String
"caption"
addPackage Package
FullPage  = String -> D
usepackage String
"fullpage"
addPackage Package
Graphics  = String -> D
usepackage String
"graphics"
addPackage Package
HyperRef  = String -> D
usepackage String
"hyperref" D -> D -> D
%%
                       String -> String -> D
command String
"hypersetup" String
hyperSettings
addPackage Package
Listings  = String -> D
usepackage String
"listings"
addPackage Package
Tikz      = String -> D
usepackage String
"tikz" D -> D -> D
%%
                       String -> String -> D
command String
"usetikzlibrary" String
"arrows.meta, shapes"
addPackage Package
Dot2Tex   = String -> D
usepackage String
"dot2texi"
addPackage Package
AdjustBox = String -> D
usepackage String
"adjustbox"
addPackage Package
AMSsymb   = String -> D
usepackage String
"amssymb"
--addPackage Breqn     = usepackage "breqn"
addPackage Package
FileContents = String -> D
usepackage String
"filecontents"
addPackage Package
BibLaTeX  = String -> Maybe String -> String -> D
command1o String
"usepackage" (String -> Maybe String
forall a. a -> Maybe a
Just String
"backend=bibtex") String
"biblatex"
addPackage Package
Tabularray = String -> D
usepackage String
"tabularray"
addPackage Package
TabularX  = String -> D
usepackage String
"tabularx"
addPackage Package
Mathtools = String -> D
usepackage String
"mathtools"
addPackage Package
URL       = String -> D
usepackage String
"url"
-- Discussed in issue #1819
-- Because we are using LuaLatex, we use fontspec here instead of fontenc
addPackage Package
FontSpec  = String -> D
usepackage String
"fontspec"
addPackage Package
Unicode   = String -> D
usepackage String
"unicode-math"
addPackage Package
EnumItem  = String -> D
usepackage String
"enumitem"
addPackage Package
SVG       = String -> D
usepackage String
"svg"
addPackage Package
Float     = String -> D
usepackage String
"float"

-- | Common LaTeX commands.
data Def = Bibliography
         | GreaterThan
         | LessThan
         | SetMathFont
         | SymbDescriptionP1
         | SymbDescriptionP2
         | ResizeExpr
         deriving Def -> Def -> Bool
(Def -> Def -> Bool) -> (Def -> Def -> Bool) -> Eq Def
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Def -> Def -> Bool
== :: Def -> Def -> Bool
$c/= :: Def -> Def -> Bool
/= :: Def -> Def -> Bool
Eq

-- | Define common LaTeX commands.
addDef :: Def -> D
addDef :: Def -> D
addDef Def
Bibliography  = String -> String -> D
command String
"bibliography" String
bibFname
addDef Def
GreaterThan   = String -> String -> String -> D
command2 String
"newcommand" String
"\\gt" String
"\\ensuremath >"
addDef Def
LessThan      = String -> String -> String -> D
command2 String
"newcommand" String
"\\lt" String
"\\ensuremath <"
addDef Def
SetMathFont   = String -> String -> D
command String
"setmathfont" String
"Latin Modern Math"
addDef Def
SymbDescriptionP1 = String -> String -> String -> String -> D
command3 String
"newlist" String
"symbDescription" String
"description" String
"1"
addDef Def
SymbDescriptionP2 = String -> Maybe String -> String -> D
command1o String
"setlist" (String -> Maybe String
forall a. a -> Maybe a
Just String
"symbDescription") String
"noitemsep, topsep=0pt, parsep=0pt, partopsep=0pt"
addDef Def
ResizeExpr = [D] -> D
vcat [
    String -> String -> D
command String
"newcommand" String
"\\resizeExpression" D -> D -> D
forall a. Semigroup a => a -> a -> a
<> Doc -> D
forall a. a -> PrintLaTeX a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Doc
sq String
"1") D -> D -> D
forall a. Semigroup a => a -> a -> a
<> D
lbrace,
    Int -> D -> D
nest Int
2 (D -> D) -> D -> D
forall a b. (a -> b) -> a -> b
$ String -> String -> String -> D
command2 String
"adjustbox" String
"max width=\\linewidth" String
"$#1$",
    D
rbrace
  ]

-- | Generates LaTeX document preamble.
genPreamble :: [LayoutObj] -> D
genPreamble :: [LayoutObj] -> D
genPreamble [LayoutObj]
los = let ([Package]
pkgs, [Def]
defs) = [LayoutObj] -> ([Package], [Def])
parseDoc [LayoutObj]
los
  in String -> String -> D
docclass (Int -> String
forall a. Show a => a -> String
show Int
fontSize String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"pt") String
"article" D -> D -> D
%%
     [D] -> D
vcat ((Package -> D) -> [Package] -> [D]
forall a b. (a -> b) -> [a] -> [b]
map Package -> D
addPackage [Package]
pkgs) D -> D -> D
%% [D] -> D
vcat ((Def -> D) -> [Def] -> [D]
forall a b. (a -> b) -> [a] -> [b]
map Def -> D
addDef [Def]
defs)

-- | Helper to gather all preamble information.
parseDoc :: [LayoutObj] -> ([Package], [Def])
parseDoc :: [LayoutObj] -> ([Package], [Def])
parseDoc [LayoutObj]
los' =
  ([Package
FontSpec, Package
FullPage, Package
HyperRef, Package
AMSMath, Package
AMSsymb, Package
Mathtools, Package
Unicode] [Package] -> [Package] -> [Package]
forall a. [a] -> [a] -> [a]
++
   [Package] -> [Package]
forall a. Eq a => [a] -> [a]
nub ((([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res)
  , [Def
SetMathFont, Def
GreaterThan, Def
LessThan] [Def] -> [Def] -> [Def]
forall a. [a] -> [a] -> [a]
++ [Def] -> [Def]
forall a. Eq a => [a] -> [a]
nub ((([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res))
  where
    res :: [([Package], [Def])]
res = (LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' [LayoutObj]
los'
    parseDoc' :: LayoutObj -> ([Package], [Def])
    parseDoc' :: LayoutObj -> ([Package], [Def])
parseDoc' Table{} = ([Package
Tabularray,Package
TabularX,Package
BookTabs,Package
Caption], [])
    parseDoc' (HDiv Tags
_ [LayoutObj]
slos Label
_) =
      let res1 :: [([Package], [Def])]
res1 = (LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' [LayoutObj]
slos in
      let pp :: [Package]
pp = (([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res1 in
      let dd :: [Def]
dd = (([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res1 in
      ([Package]
pp, [Def]
dd)
    parseDoc' (Definition DType
_ [(String, [LayoutObj])]
ps Label
_) =
      let res1 :: [([Package], [Def])]
res1 = ((String, [LayoutObj]) -> [([Package], [Def])])
-> [(String, [LayoutObj])] -> [([Package], [Def])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((LayoutObj -> ([Package], [Def]))
-> [LayoutObj] -> [([Package], [Def])]
forall a b. (a -> b) -> [a] -> [b]
map LayoutObj -> ([Package], [Def])
parseDoc' ([LayoutObj] -> [([Package], [Def])])
-> ((String, [LayoutObj]) -> [LayoutObj])
-> (String, [LayoutObj])
-> [([Package], [Def])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, [LayoutObj]) -> [LayoutObj]
forall a b. (a, b) -> b
snd) [(String, [LayoutObj])]
ps in
      let pp :: [Package]
pp = (([Package], [Def]) -> [Package])
-> [([Package], [Def])] -> [Package]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Package]
forall a b. (a, b) -> a
fst [([Package], [Def])]
res1 in
      let dd :: [Def]
dd = (([Package], [Def]) -> [Def]) -> [([Package], [Def])] -> [Def]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Package], [Def]) -> [Def]
forall a b. (a, b) -> b
snd [([Package], [Def])]
res1 in
      (Package
TabularrayPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:Package
TabularXPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:Package
BookTabsPackage -> [Package] -> [Package]
forall a. a -> [a] -> [a]
:[Package]
pp,Def
SymbDescriptionP1Def -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:Def
SymbDescriptionP2Def -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:[Def]
dd)
    parseDoc' Figure{}     = ([Package
Graphics,Package
Caption, Package
SVG, Package
Float],[])
    parseDoc' Graph{}      = ([Package
Caption,Package
Tikz,Package
Dot2Tex,Package
AdjustBox],[])
    parseDoc' Bib{}        = ([Package
FileContents,Package
BibLaTeX,Package
URL],[Def
Bibliography])
    parseDoc' Header{}     = ([], [])
    parseDoc' Paragraph{}  = ([], [])
    parseDoc' List{}       = ([Package
EnumItem], [])
    parseDoc' EqnBlock{}   = ([Package
AdjustBox], [Def
ResizeExpr])
    parseDoc' Cell{}       = ([], [])
    parseDoc' CodeBlock{}  = ([], [])