packages feed

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

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

import Control.Applicative

#if (__GLASGOW_HASKELL__ < 609)
import Control.Exception hiding (IOException)
#else
import Control.Exception
#endif

import Control.Monad (when)
import Data.Char (ord)
import Data.Digest.OpenSSL.MD5 (md5sum)
import Data.ByteString (pack)
import Data.List (intercalate)
import System.IO
import System.IO.Unsafe
import System.Posix.Files (getFileStatus, isRegularFile)
import System.Process (runInteractiveProcess, waitForProcess, runProcess)
import Text.ParserCombinators.Parsec hiding (many, optional, (<|>), try)

import Network.Protocol.Uri ((/+))
import Text.Document.Parser.WikiHelper
import Text.Document.Core.Type
import Text.Document.Plugin
import Misc.Commons (trim)
import qualified Text.Xhtml.Xhtml as H
import qualified Text.Xml.Xml     as X

#if (__GLASGOW_HASKELL__ < 609)
type IOException = Exception
#endif

-------- 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}"