packages feed

mathblog-0.2: src/MB/Processing.hs

module MB.Processing
    ( processPost
    )
where

import Control.Monad
    ( forM
    )
import Data.List
    ( intercalate
    )
import Data.Digest.Pure.SHA
    ( showDigest
    , sha1
    )
import Data.ByteString.Lazy.Char8
    ( pack
    )
import System.Directory
    ( doesFileExist
    )
import System.Process
    ( readProcessWithExitCode
    )
import System.Exit
    ( ExitCode(..)
    )
import qualified Text.Pandoc as Pandoc
import MB.Types
import qualified MB.Files as Files

processPost :: Config -> Post -> IO Post
processPost = renderGnuPlot

renderGnuPlot :: Config -> Post -> IO Post
renderGnuPlot config post = do
  let Pandoc.Pandoc m blocks = postAst post
  newBlocks <- forM blocks $ \blk ->
               case blk of
                 Pandoc.CodeBlock (preambleName, classes, _) s ->
                     renderGnuPlotScript config preambleName s classes
                 b -> return b

  return $ post { postAst = Pandoc.Pandoc m newBlocks }

loadPreamble :: Config -> String -> IO (Maybe String)
loadPreamble config preambleName = do
  let filename = Files.eqPreambleFile config $ preambleName ++ ".txt"
  e <- doesFileExist filename
  case e of
    False -> return Nothing
    True -> do
           s <- readFile filename
           s `seq` return ()
           return $ Just s

renderGnuPlotScript :: Config
                    -> String
                    -> String
                    -> [String]
                    -> IO Pandoc.Block
renderGnuPlotScript config preambleName rawScript classes = do
  putStrLn $ "Rendering equation graph, type=" ++ preambleName

  mPreamble <- loadPreamble config preambleName

  case mPreamble of
    Nothing -> do
      putStrLn $ "Error: no such gnuplot preamble: " ++ preambleName
      return $ Pandoc.Para [Pandoc.Str "[[COULD NOT DRAW EQUATION]]"]
    Just preamble -> do

      let scriptLines = lines rawScript
          preambleLines = lines preamble
          digestInput = preambleName ++ rawScript

      -- Generate an image name in the images/ directory of the blog
      -- data directory.  Use a hash of the preamble name and script
      -- contents so we can avoid rendering the image again if it
      -- already exists.
      let hash = showDigest $ sha1 $ pack digestInput
          imageFilename = preambleName ++ "-" ++ hash ++ ".png"
          imagePath = Files.imageFilename config imageFilename
          outputLines = [ "set term png enhanced"
                        , "set output \"" ++ imagePath ++ "\""
                        ]
          fullScript = intercalate "; " $ outputLines ++ preambleLines ++ scriptLines

      -- Invoke gnuplot to render the image
      (status, out, err) <- readProcessWithExitCode "gnuplot" ["-e", fullScript] ""

      case status of
        ExitSuccess -> return ()
        ExitFailure _ -> do
                       putStrLn "Could not render equation:"
                       putStrLn "Equation was:"
                       putStrLn rawScript
                       putStrLn "gnuplot output:"
                       putStrLn out
                       putStrLn err

      return $ Pandoc.Para [Pandoc.HtmlInline $ concat [ "<img src=\"" ++ baseUrl config ++ "/generated-images/"
                                                       , imageFilename
                                                       , "\" class=\""
                                                       , intercalate " " classes
                                                       , "\">"
                                                       ]
                           ]