diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Math.hs | 63 | ||||
| -rw-r--r-- | src/Site.hs | 53 |
2 files changed, 80 insertions, 36 deletions
diff --git a/src/Math.hs b/src/Math.hs index e927fdd..db01f75 100644 --- a/src/Math.hs +++ b/src/Math.hs | |||
| @@ -2,40 +2,61 @@ module Math | |||
| 2 | ( compileMath | 2 | ( compileMath |
| 3 | ) where | 3 | ) where |
| 4 | 4 | ||
| 5 | import System.IO (stdout, stderr, hPutStrLn, writeFile, readFile) | ||
| 5 | import System.IO.Temp (withSystemTempDirectory) | 6 | import System.IO.Temp (withSystemTempDirectory) |
| 6 | import System.Process (callProcess) | 7 | import System.Process (callProcess, readProcessWithExitCode) |
| 7 | import System.Directory (copyFile, getCurrentDirectory, setCurrentDirectory) | 8 | import System.Directory (copyFile, getCurrentDirectory, setCurrentDirectory) |
| 8 | import System.FilePath (takeFileName, FilePath(..), (</>)) | 9 | import System.FilePath (takeFileName, FilePath(..), (</>)) |
| 10 | import System.Exit (ExitCode(..)) | ||
| 9 | 11 | ||
| 10 | import Control.Monad | 12 | import Control.Monad (when) |
| 11 | import Control.Exception (bracket) | 13 | import Control.Exception (bracket, throwIO) |
| 14 | import Data.Maybe (fromMaybe, listToMaybe) | ||
| 15 | |||
| 16 | import Control.Monad.Writer.Strict (WriterT(..), execWriterT, tell) | ||
| 17 | import Control.Monad.Trans (liftIO) | ||
| 12 | 18 | ||
| 13 | import Control.DeepSeq (($!!)) | 19 | import Control.DeepSeq (($!!)) |
| 14 | 20 | ||
| 15 | compileMath :: String -> IO String | 21 | import Text.Regex.TDFA ((=~)) |
| 22 | |||
| 23 | instance Monoid ExitCode where | ||
| 24 | mempty = ExitSuccess | ||
| 25 | (ExitFailure a) `mappend` _ = ExitFailure a | ||
| 26 | ExitSuccess `mappend` x@(ExitFailure _) = x | ||
| 27 | ExitSuccess `mappend` ExitSuccess = ExitSuccess | ||
| 28 | |||
| 29 | |||
| 30 | compileMath :: String -> IO (String, String) | ||
| 16 | compileMath = withSystemTempDirectory "math" . compileMath' | 31 | compileMath = withSystemTempDirectory "math" . compileMath' |
| 17 | 32 | ||
| 18 | compileMath' :: String -> FilePath -> IO String | 33 | compileMath' :: String -> FilePath -> IO (String, String) |
| 19 | compileMath' input tmpDir = do | 34 | compileMath' input tmpDir = do |
| 20 | mapM_ (copyToTmp . ("tex" </>)) [ "preamble.tex" | 35 | mapM_ (copyToTmp . ("tex" </>)) [ "preamble.tex" |
| 21 | , "preview.dtx" | 36 | , "preview.dtx" |
| 22 | , "preview.ins" | 37 | , "preview.ins" |
| 23 | ] | 38 | ] |
| 24 | withCurrentDirectory tmpDir $ do | 39 | (exitCode, out, err) <- withCurrentDirectory tmpDir $ execWriterT $ do |
| 25 | callProcess "latex" [ "-interaction=batchmode" | 40 | run "latex" [ "-interaction=batchmode" |
| 26 | , "preview.ins" | 41 | , "preview.ins" |
| 27 | ] | 42 | ] "" |
| 28 | writeFile (tmpDir </> "image.tex") input | 43 | liftIO $ writeFile (tmpDir </> "image.tex") input |
| 29 | callProcess "latex" [ "-interaction=batchmode" | 44 | run "latex" [ "-interaction=batchmode" |
| 30 | , "image.tex" | 45 | , "image.tex" |
| 31 | ] | 46 | ] "" |
| 32 | callProcess "dvisvgm" [ "--exact" | 47 | run "dvisvgm" [ "--exact" |
| 33 | , "--no-fonts" | 48 | , "--no-fonts" |
| 34 | , tmpDir </> "image.dvi" | 49 | , tmpDir </> "image.dvi" |
| 35 | ] | 50 | ] "" |
| 36 | (\x -> return $!! x) =<< (readFile $ tmpDir </> "image.svg") | 51 | when (exitCode /= ExitSuccess) $ do |
| 52 | hPutStrLn stdout out | ||
| 53 | hPutStrLn stderr err | ||
| 54 | throwIO exitCode | ||
| 55 | (\x -> return $!! (x, extractAlignment err)) =<< (readFile $ tmpDir </> "image.svg") | ||
| 37 | where | 56 | where |
| 38 | copyToTmp fp = copyFile fp (tmpDir </> takeFileName fp) | 57 | copyToTmp fp = copyFile fp (tmpDir </> takeFileName fp) |
| 58 | run :: String -> [String] -> String -> WriterT (ExitCode, String, String) IO () | ||
| 59 | run bin args stdin = tell =<< liftIO (readProcessWithExitCode bin args stdin) | ||
| 39 | 60 | ||
| 40 | withCurrentDirectory :: FilePath -- ^ Directory to execute in | 61 | withCurrentDirectory :: FilePath -- ^ Directory to execute in |
| 41 | -> IO a -- ^ Action to be executed | 62 | -> IO a -- ^ Action to be executed |
| @@ -44,3 +65,9 @@ withCurrentDirectory dir action = | |||
| 44 | bracket getCurrentDirectory setCurrentDirectory $ \ _ -> do | 65 | bracket getCurrentDirectory setCurrentDirectory $ \ _ -> do |
| 45 | setCurrentDirectory dir | 66 | setCurrentDirectory dir |
| 46 | action | 67 | action |
| 68 | |||
| 69 | extractAlignment :: String -> String | ||
| 70 | extractAlignment = fromMaybe "0pt" . extract . (=~ "depth=([^\\s]+)") | ||
| 71 | where | ||
| 72 | extract :: (String, String, String, [String]) -> Maybe String | ||
| 73 | extract (_, _, _, xs) = listToMaybe xs | ||
diff --git a/src/Site.hs b/src/Site.hs index e821322..dcb9a7d 100644 --- a/src/Site.hs +++ b/src/Site.hs | |||
| @@ -13,18 +13,19 @@ import Data.List (take, reverse, nub, groupBy, concatMap) | |||
| 13 | import Data.Function (on) | 13 | import Data.Function (on) |
| 14 | import Data.Default | 14 | import Data.Default |
| 15 | import Text.Pandoc | 15 | import Text.Pandoc |
| 16 | import Text.Pandoc.Walk (query) | 16 | import Text.Pandoc.Walk (query, walkM) |
| 17 | import Text.Pandoc.Error | 17 | import Text.Pandoc.Error |
| 18 | import Control.Applicative (Alternative(..), Applicative(..)) | 18 | import Control.Applicative (Alternative(..), Applicative(..)) |
| 19 | 19 | ||
| 20 | import System.FilePath (takeBaseName, (</>), (<.>)) | ||
| 21 | |||
| 20 | import qualified Crypto.Hash.SHA256 as SHA256 (hash) | 22 | import qualified Crypto.Hash.SHA256 as SHA256 (hash) |
| 21 | import qualified Data.ByteString.Char8 as CBS | 23 | import qualified Data.ByteString.Char8 as CBS |
| 22 | import Data.Hex | 24 | import Data.Hex (hex) |
| 23 | import Data.Char (toLower) | 25 | import Data.Char (toLower) |
| 24 | 26 | ||
| 25 | import System.FilePath (takeBaseName, (</>), (<.>)) | ||
| 26 | |||
| 27 | import Math (compileMath) | 27 | import Math (compileMath) |
| 28 | import Text.Printf (printf) | ||
| 28 | 29 | ||
| 29 | main :: IO () | 30 | main :: IO () |
| 30 | main = hakyllWith config $ do | 31 | main = hakyllWith config $ do |
| @@ -34,24 +35,24 @@ main = hakyllWith config $ do | |||
| 34 | route idRoute | 35 | route idRoute |
| 35 | compile copyFileCompiler | 36 | compile copyFileCompiler |
| 36 | 37 | ||
| 38 | math <- getMath "posts/*" mathTranslation' | ||
| 39 | forM_ math $ \(_, mathStr) -> create [mathTranslation' mathStr] $ do | ||
| 40 | route idRoute | ||
| 41 | compile $ do | ||
| 42 | item <- makeItem mathStr | ||
| 43 | >>= loadAndApplyTemplate "templates/math.tex" defaultContext | ||
| 44 | >>= withItemBody (unsafeCompiler . compileMath) | ||
| 45 | saveSnapshot "alignment" $ fmap snd item | ||
| 46 | return $ fmap fst item | ||
| 47 | |||
| 37 | match "posts/*" $ do | 48 | match "posts/*" $ do |
| 38 | route $ setExtension ".html" | 49 | route $ setExtension ".html" |
| 39 | compile $ do | 50 | compile $ do |
| 40 | getResourceBody >>= saveSnapshot "content" | 51 | getResourceBody >>= saveSnapshot "content" |
| 41 | pandocCompiler | 52 | pandocCompilerWithTransformM defaultHakyllReaderOptions defaultHakyllWriterOptions mathTransform |
| 42 | >>= loadAndApplyTemplate "templates/default.html" defaultContext | 53 | >>= loadAndApplyTemplate "templates/default.html" defaultContext |
| 43 | >>= relativizeUrls | 54 | >>= relativizeUrls |
| 44 | 55 | ||
| 45 | math <- getMath "posts/*" mathTranslation' | ||
| 46 | forM_ math $ \(deps, mathStr) -> | ||
| 47 | rulesExtraDependencies (map IdentifierDependency deps) $ | ||
| 48 | create [mathTranslation' mathStr] $ do | ||
| 49 | route idRoute | ||
| 50 | compile $ do | ||
| 51 | makeItem mathStr | ||
| 52 | >>= loadAndApplyTemplate "templates/math.tex" defaultContext | ||
| 53 | >>= withItemBody (unsafeCompiler . compileMath) | ||
| 54 | |||
| 55 | tags <- buildTags "posts/*" tagTranslation' >>= addTag "All Posts" "posts/*" | 56 | tags <- buildTags "posts/*" tagTranslation' >>= addTag "All Posts" "posts/*" |
| 56 | 57 | ||
| 57 | tagsRules tags $ \tag pattern -> do | 58 | tagsRules tags $ \tag pattern -> do |
| @@ -143,14 +144,14 @@ tagTranslation = mapMaybe charTrans | |||
| 143 | | isAlphaNum c = Just $ toLower c | 144 | | isAlphaNum c = Just $ toLower c |
| 144 | | otherwise = Nothing | 145 | | otherwise = Nothing |
| 145 | 146 | ||
| 146 | mathTranslation' :: String -> Identifier | ||
| 147 | mathTranslation' = fromCapture "math/*.svg" . map toLower . CBS.unpack . hex . SHA256.hash . CBS.pack | ||
| 148 | |||
| 149 | addTag :: MonadMetadata m => String -> Pattern -> Tags -> m Tags | 147 | addTag :: MonadMetadata m => String -> Pattern -> Tags -> m Tags |
| 150 | addTag name pattern tags = do | 148 | addTag name pattern tags = do |
| 151 | ids <- getMatches pattern | 149 | ids <- getMatches pattern |
| 152 | return $ tags { tagsMap = tagsMap tags ++ [(name, ids)] } | 150 | return $ tags { tagsMap = tagsMap tags ++ [(name, ids)] } |
| 153 | 151 | ||
| 152 | mathTranslation' :: String -> Identifier | ||
| 153 | mathTranslation' = fromCapture "math/*.svg" . map toLower . CBS.unpack . hex . SHA256.hash . CBS.pack | ||
| 154 | |||
| 154 | getMath :: Pattern -> (String -> Identifier) -> Rules [([Identifier], String)] | 155 | getMath :: Pattern -> (String -> Identifier) -> Rules [([Identifier], String)] |
| 155 | getMath pattern makeId = do | 156 | getMath pattern makeId = do |
| 156 | ids <- getMatches pattern | 157 | ids <- getMatches pattern |
| @@ -193,6 +194,22 @@ readPandoc' path = readFile path >>= either fail return . result' | |||
| 193 | 194 | ||
| 194 | addExt ro e = ro {readerExtensions = Set.insert e $ readerExtensions ro} | 195 | addExt ro e = ro {readerExtensions = Set.insert e $ readerExtensions ro} |
| 195 | 196 | ||
| 197 | mathTransform :: Pandoc -> Compiler Pandoc | ||
| 198 | mathTransform = walkM mathTransform' | ||
| 199 | where | ||
| 200 | mathTransform' :: Inline -> Compiler Inline | ||
| 201 | mathTransform' (Math mathType tex) = do | ||
| 202 | alignment <- loadSnapshotBody texId "alignment" | ||
| 203 | let | ||
| 204 | html = printf "<object data=\"/%s\" type=\"image/svg+xml\" style=\"vertical-align:-%s\">%s</object>" | ||
| 205 | (toFilePath texId) (alignment :: String) tex | ||
| 206 | return $ Span ("", [classOf mathType], []) [RawInline (Format "html") html] | ||
| 207 | where | ||
| 208 | texId = mathTranslation' tex | ||
| 209 | classOf DisplayMath = "display-math" | ||
| 210 | classOf InlineMath = "inline-math" | ||
| 211 | mathTransform' x = return x | ||
| 212 | |||
| 196 | toFilePath' :: Identifier -> FilePath | 213 | toFilePath' :: Identifier -> FilePath |
| 197 | toFilePath' = (providerDirectory config </>) . toFilePath | 214 | toFilePath' = (providerDirectory config </>) . toFilePath |
| 198 | 215 | ||
