never executed always true always false
    1 {-# LANGUAGE OverloadedStrings   #-}
    2 {-# LANGUAGE ScopedTypeVariables #-}
    3 module Reanimate.LaTeX
    4   ( latex
    5   , latexWithHeaders
    6   , latexChunks
    7   , xelatex
    8   , xelatexWithHeaders
    9   , ctex
   10   , ctexWithHeaders
   11   , latexAlign
   12   )
   13 where
   14 
   15 import qualified Data.ByteString               as B
   16 import           Data.Text                                ( Text )
   17 import qualified Data.Text                     as T
   18 import qualified Data.Text.Encoding            as T
   19 import           Graphics.SvgTree                         ( Tree(..)
   20                                                           , parseSvgFile
   21                                                           )
   22 import           Reanimate.Cache
   23 import           Reanimate.Misc
   24 import           Reanimate.Svg
   25 import           Reanimate.Parameters
   26 import           System.FilePath                          ( replaceExtension
   27                                                           , takeFileName
   28                                                           , (</>)
   29                                                           )
   30 import           System.IO.Unsafe                         ( unsafePerformIO )
   31 
   32 -- | Invoke latex and import the result as an SVG object. SVG objects are
   33 --   cached to improve performance.
   34 --
   35 --   Example:
   36 --
   37 --   > latex "$e^{i\\pi}+1=0$"
   38 --
   39 --   <<docs/gifs/doc_latex.gif>>
   40 latex :: T.Text -> Tree
   41 latex = latexWithHeaders []
   42 
   43 latexWithHeaders :: [T.Text] -> T.Text -> Tree
   44 latexWithHeaders = someTexWithHeaders "latex" "dvi" []
   45 
   46 someTexWithHeaders :: String -> String -> [String] -> [T.Text] -> T.Text -> Tree
   47 someTexWithHeaders _exec _dvi _args _headers tex | pNoExternals = mkText tex
   48 someTexWithHeaders exec dvi args headers tex =
   49   (unsafePerformIO . (cacheMem . cacheDiskSvg) (latexToSVG dvi exec args))
   50     script
   51  where
   52   script = mkTexScript exec args headers tex
   53 
   54 latexChunks :: [T.Text] -> [Tree]
   55 latexChunks chunks | pNoExternals = map mkText chunks
   56 latexChunks chunks                = worker (svgGlyphs $ latex $ T.concat chunks) chunks
   57  where
   58   merge lst = mkGroup [ fmt svg | (fmt, _, svg) <- lst ]
   59   worker [] [] = []
   60   worker _ [] = error "latex chunk mismatch"
   61   worker everything (x : xs) =
   62     let width = length $ svgGlyphs (latex x)
   63     in merge (take width everything) : worker (drop width everything) xs
   64 
   65 -- | Invoke xelatex and import the result as an SVG object. SVG objects are
   66 --   cached to improve performance. Xelatex has support for non-western scripts.
   67 xelatex :: Text -> Tree
   68 xelatex = xelatexWithHeaders []
   69 
   70 xelatexWithHeaders :: [T.Text] -> T.Text -> Tree
   71 xelatexWithHeaders = someTexWithHeaders "xelatex" "xdv" ["-no-pdf"]
   72 
   73 -- | Invoke xelatex with "\usepackage[UTF8]{ctex}" and import the result as an
   74 --   SVG object. SVG objects are cached to improve performance. Xelatex has
   75 --   support for non-western scripts.
   76 --
   77 --   Example:
   78 --
   79 --   > ctex "中文"
   80 --
   81 --   <<docs/gifs/doc_ctex.gif>>
   82 ctex :: T.Text -> Tree
   83 ctex = ctexWithHeaders []
   84 
   85 ctexWithHeaders :: [T.Text] -> T.Text -> Tree
   86 ctexWithHeaders headers = xelatexWithHeaders ("\\usepackage[UTF8]{ctex}" : headers)
   87 
   88 -- | Invoke latex and import the result as an SVG object. SVG objects are
   89 --   cached to improve performance. This wraps the TeX code in an 'align*'
   90 --   context.
   91 --
   92 --   Example:
   93 --
   94 --   > latexAlign "R = \\frac{{\\Delta x}}{{kA}}"
   95 --
   96 --   <<docs/gifs/doc_latexAlign.gif>>
   97 latexAlign :: Text -> Tree
   98 latexAlign tex = latex $ T.unlines ["\\begin{align*}", tex, "\\end{align*}"]
   99 
  100 postprocess :: Tree -> Tree
  101 postprocess = simplify
  102 
  103 -- executable, arguments, header, tex
  104 latexToSVG :: String -> String -> [String] -> Text -> IO Tree
  105 latexToSVG dviExt latexExec latexArgs tex = do
  106   latexBin <- requireExecutable latexExec
  107   dvisvgm  <- requireExecutable "dvisvgm"
  108   withTempDir $ \tmp_dir -> withTempFile "tex" $ \tex_file ->
  109     withTempFile "svg" $ \svg_file -> do
  110       let dvi_file =
  111             tmp_dir </> replaceExtension (takeFileName tex_file) dviExt
  112       B.writeFile tex_file (T.encodeUtf8 tex)
  113       runCmd
  114         latexBin
  115         (  latexArgs
  116         ++ [ "-interaction=nonstopmode"
  117            , "-halt-on-error"
  118            , "-output-directory=" ++ tmp_dir
  119            , tex_file
  120            ]
  121         )
  122       runCmd
  123         dvisvgm
  124         [ dvi_file
  125         , "--precision=5"
  126         , "--exact"    -- better bboxes.
  127         , "--no-fonts" -- use glyphs instead of fonts.
  128         , "--scale=0.1,-0.1"
  129         , "--verbosity=0"
  130         , "-o"
  131         , svg_file
  132         ]
  133       svg_data <- B.readFile svg_file
  134       case parseSvgFile svg_file svg_data of
  135         Nothing  -> error "Malformed svg"
  136         Just svg -> return $ postprocess $ unbox $ replaceUses svg
  137 
  138 mkTexScript :: String -> [String] -> [Text] -> Text -> Text
  139 mkTexScript latexExec latexArgs texHeaders tex =
  140   T.unlines
  141     $  [ "% " <> T.pack (unwords (latexExec : latexArgs))
  142        , "\\documentclass[preview]{standalone}"
  143        , "\\usepackage{amsmath}"
  144        , "\\usepackage{gensymb}"
  145        ]
  146     ++ texHeaders
  147     ++ [ "\\usepackage[english]{babel}"
  148        , "\\linespread{1}"
  149        , "\\begin{document}"
  150        , tex
  151        , "\\end{document}"
  152        ]
  153 
  154 {- Packages used by manim.
  155 
  156 \\\usepackage{amsmath}\n\
  157 \\\usepackage{amssymb}\n\
  158 \\\usepackage{dsfont}\n\
  159 \\\usepackage{setspace}\n\
  160 \\\usepackage{relsize}\n\
  161 \\\usepackage{textcomp}\n\
  162 \\\usepackage{mathrsfs}\n\
  163 \\\usepackage{calligra}\n\
  164 \\\usepackage{wasysym}\n\
  165 \\\usepackage{ragged2e}\n\
  166 \\\usepackage{physics}\n\
  167 \\\usepackage{xcolor}\n\
  168 \\\usepackage{textcomp}\n\
  169 \\\usepackage{xfrac}\n\
  170 \\\usepackage{microtype}\n\
  171 -}