packages feed

orchid-0.0.7: src/Text/Document/Plugin/Formula.hs

module Text.Document.Plugin.Formula (formulaPlugin) where

import Control.Applicative
import Control.Exception.Extensible
import Control.Monad (when)
import Data.ByteString (pack)
import Data.Char (ord)
import Data.Digest.OpenSSL.MD5 (md5sum)
import Data.List (intercalate)
import Misc.Commons (trim)
import Network.Protocol.Uri ((/+))
import System.IO
import System.IO.Unsafe
import System.Posix.Files (getFileStatus, isRegularFile)
import System.Process (runInteractiveProcess, waitForProcess, runProcess)
import Text.Document.Core.Type
import Text.Document.Parser.WikiHelper
import Text.Document.Plugin
import Text.ParserCombinators.Parsec hiding (many, optional, (<|>), try)
import qualified Text.Xhtml.Xhtml as H
import qualified Text.Xml.Xml     as X

-------- hscolour plugin ------------------------------------------------------

formulaPlugin :: Plugin Document Syn_Document
formulaPlugin = makePlugin "formula"
  [(Wiki,  pFormula)]
  [(XHTML, ppXHTML), (LaTeX, ppCodeLaTeX), (ADT, ppADT)]
  [(XHTML, ioXHTML)]

-------- parsers --------------------------------------------------------------

pFormula (Just (ContextWiki n)) = do
   (m, i) <- pIndent n
   (string "@@" <* many (oneOf ws) <* string "formula")
     *> many pEmptyLineEol
     *> (trimCode
    <$> pLevel (m + 1))

-------- pretty printers ------------------------------------------------------

ppXHTML formula doc = OutputXML
  $ X.attribute "class" "formula"
  $ H.img ("_images" /+ generateFileName formula) "formula"

generateFileName :: String -> String
generateFileName formula = md5sum (pack $ map (fromIntegral . ord) formula) ++ ".png"

-------- processors -----------------------------------------------------------

ioXHTML :: String -> FilePath -> Document -> Syn_Document -> IO ()
ioXHTML formula workDir doc sem = do

  let image = generateFileName formula

  exist <- try (isRegularFile <$> getFileStatus (workDir /+ image)) :: IO (Either IOException Bool)
  case exist of
    Right True -> return ()
    Left _  -> do

      -- Save formula pulled through template as tex file.
      writeFile ("/tmp/tex-formula-" ++ image++ ".tex") (texTemplate formula)

      -- Create DVI file from tex.
      runProcess "latex" [
          "-interaction=nonstopmode"
        , "/tmp/tex-formula-" ++ image ++ ".tex"
        ] (Just "/tmp") Nothing Nothing Nothing Nothing
        >>= waitForProcess

      -- Convert DVI file to PNG image.
      runProcess "dvipng" [
          "-q", "-T", "tight", "-bg", "Transparent"
        , "-D", "180", "/tmp/tex-formula-" ++ image ++ ".dvi"
        , "-o", workDir /+ "_images" /+ image
        ] Nothing Nothing Nothing Nothing Nothing
        >>= waitForProcess
      return ()

ppCodeLaTeX s doc = OutputPlain s

ppADT s doc = OutputPlain $ show s

texTemplate :: String -> String
texTemplate s = concat [header, s, footer]
  where
    header = intercalate "\n" [
        "\\documentclass[fleqn]{article}"
      , "\\usepackage{amssymb,amsmath,bm,color}"
      , "\\usepackage[utf8]{inputenc}"
      , "\\begin{document}"
      , "\\thispagestyle{empty}"
      , "\\mathindent0cm"
      , "\\parindent0cm"
      , ""
      ]
    footer = "\n\\end{document}"