haskintex (empty) → 0.1.0.0
raw patch · 6 files changed
+278/−0 lines, 6 filesdep +HaTeXdep +attoparsecdep +basesetup-changed
Dependencies added: HaTeX, attoparsec, base, directory, filepath, process, text, transformers
Files
- LICENSE +30/−0
- Main.hs +188/−0
- README.md +10/−0
- Setup.hs +2/−0
- examples/fact.tex +14/−0
- haskintex.cabal +34/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Daniel Díaz++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Daniel Díaz nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Main.hs view
@@ -0,0 +1,188 @@++{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++-- System+import System.Process+import System.Environment (getArgs)+import System.FilePath+import System.Directory+-- Text+import Data.Text (pack,unpack)+import qualified Data.Text as T+import qualified Data.Text.IO as T+-- Parser+import Data.Attoparsec.Text+-- Transformers+import Control.Monad (when,unless)+import Control.Monad.Trans.Class+import Control.Monad.Trans.Reader+-- LaTeX+import Text.LaTeX+-- Utils+import Control.Applicative+import Data.Foldable (foldMap)++-- Syntax++data Syntax =+ WriteLaTeX Text+ | WriteHaskell Bool Text -- False for Hidden, True for Visible+ | EvalHaskell Bool Text -- False for Command, True for Environment+ | Sequence [Syntax]++-- Parsing++parseSyntax :: Bool -> Parser Syntax+parseSyntax v = fmap Sequence $ many $ choice [ p_writehaskell v, p_evalhaskell, p_writelatex ]++p_writehaskell :: Bool -> Parser Syntax+p_writehaskell v = do+ _ <- string "\\begin{writehaskell}"+ b <- choice [ string "[hidden]" >> return False+ , string "[visible]" >> return True+ , return v ]+ h <- manyTill anyChar $ try $ string "\\end{writehaskell}"+ return $ WriteHaskell b $ pack h++p_evalhaskell :: Parser Syntax+p_evalhaskell = choice [ p_evalhaskellenv, p_evalhaskellcomm ]++p_evalhaskellenv :: Parser Syntax+p_evalhaskellenv = do+ _ <- string "\\begin{evalhaskell}"+ h <- manyTill anyChar $ try $ string "\\end{evalhaskell}"+ return $ EvalHaskell True $ pack h++p_evalhaskellcomm :: Parser Syntax+p_evalhaskellcomm = do+ _ <- string "\\evalhaskell{"+ h <- manyTill anyChar $ char '}'+ return $ EvalHaskell False $ pack h++p_writelatex :: Parser Syntax+p_writelatex = (WriteLaTeX . pack) <$>+ many1 (p_other >>= \b -> if b then anyChar else fail "stop write latex")+ where+ p_other =+ choice [ string "\\begin{writehaskell}" >> return False+ , string "\\begin{evalhaskell}" >> return False+ , string "\\evalhaskell" >> return False+ , return True+ ]++-- PASS 1: Extract code from processed Syntax.++extractCode :: Syntax -> Text+extractCode (WriteHaskell _ t) = t+extractCode (Sequence xs) = foldMap extractCode xs+extractCode _ = mempty++-- PASS 2: Evaluate Haskell expressions from processed Syntax.++evalCode :: String -> Syntax -> Haskintex Text+evalCode modName = go+ where+ go (WriteLaTeX t) = return t+ go (WriteHaskell b t) =+ return $ if b then render (verbatim t :: LaTeX)+ else mempty+ go (EvalHaskell b t) =+ let f :: Text -> LaTeX+ f = if b then verbatim . layout else verb+ in (render . f . pack) <$> ghc modName t+ go (Sequence xs) = mconcat <$> mapM go xs++ghc :: String -> Text -> Haskintex String+ghc modName e = do+ let e' = unpack $ T.strip e+ outputStr $ "Evaluation: " ++ e'+ lift $ init <$> readProcess "ghc" [ "-e", e', modName ++ ".hs" ] []++maxLineLength :: Int+maxLineLength = 60++-- | Break lines longer than 'maxLineLenght'.+layout :: Text -> Text+layout = T.unlines . go . T.lines+ where+ go [] = []+ go (t:ts) =+ if T.length t > maxLineLength+ then let (l,r) = T.splitAt maxLineLength t+ in l : go (r:ts)+ else t : go ts++-- Configuration++data Conf = Conf+ { keepFlag :: Bool+ , visibleFlag :: Bool+ , verboseFlag :: Bool+ , inputs :: [FilePath]+ }++isArg :: String -> Bool+isArg [] = False+isArg (x:_) = x == '-'++readConf :: [String] -> Conf+readConf xs =+ Conf ("-keep" `elem` xs)+ ("-visible" `elem` xs)+ ("-verbose" `elem` xs)+ (filter (not . isArg) xs)++-- Haskintex++type Haskintex = ReaderT Conf IO++outputStr :: String -> Haskintex ()+outputStr str = do+ b <- verboseFlag <$> ask+ when b $ lift $ putStrLn str++-- MAIN++main :: IO ()+main = (readConf <$> getArgs) >>= runReaderT haskintex++haskintex :: Haskintex ()+haskintex = ask >>= mapM_ haskintexFile . inputs++haskintexFile :: FilePath -> Haskintex ()+haskintexFile fp_ = do+ -- If the given file does not exist, try adding '.tex'.+ b <- lift $ doesFileExist fp_+ let fp = if b then fp_ else fp_ ++ ".tex"+ -- Read visible flag. It will be required in the file parsing.+ vFlag <- visibleFlag <$> ask+ outputStr $ "Visible flag: " ++ (if vFlag then "enabled" else "disabled") ++ "."+ -- File parsing.+ outputStr $ "Reading " ++ fp ++ "..."+ t <- lift $ T.readFile fp+ case parseOnly (parseSyntax vFlag) t of+ Left err -> outputStr $ "Reading of " ++ fp ++ " failed: " ++ err+ Right s -> do+ -- First pass: Create haskell source from the code obtained with 'extractCode'.+ let modName = ("Haskintex_" ++) $ dropExtension $ takeFileName fp+ outputStr $ "Creating Haskell source file " ++ modName ++ ".hs..."+ let hs = extractCode s+ moduleHeader = pack $ "module " ++ modName ++ " where\n\n"+ lift $ T.writeFile (modName ++ ".hs") $ moduleHeader <> hs+ -- Second pass: Evaluate expressions using 'evalCode'.+ outputStr $ "Evaluating expressions in " ++ fp ++ "..."+ l <- evalCode modName s+ let fp' = "haskintex_" ++ fp+ -- Write final output.+ outputStr $ "Writing final file at " ++ fp' ++ "..."+ lift $ T.writeFile fp' l+ -- If the keep flag is not set, remove the haskell source file.+ kFlag <- keepFlag <$> ask+ unless kFlag $ do+ outputStr $ "Removing Haskell source file " ++ modName ++ ".hs "+ ++ "(use -keep to avoid this)..."+ lift $ removeFile $ modName ++ ".hs"+ -- End.+ outputStr $ "End of processing of file " ++ fp ++ "."
+ README.md view
@@ -0,0 +1,10 @@+# The *haskintex* program++The *haskintex* program is a tool that reads a LaTeX file and evaluates Haskell expressions contained+in some specific commands and environments. It allows you to define your own functions, use any GHC Haskell language+extension and, in brief, anything you can do within Haskell. You can freely add any Haskell code you need, and make+this code appear *optionally* in the LaTeX output. It is a tiny program, and therefore, easy to understand, use and+predict.++For more details, read the+[homepage of the project](http://daniel-diaz.github.io/projects/haskintex).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ examples/fact.tex view
@@ -0,0 +1,14 @@+\documentclass{article}+\begin{document}++Recursive definition of the factorial function in Haskell.++\begin{writehaskell}[visible]+fact :: Int -> Int+fact 0 = 1+fact n = n * fact (n-1)+\end{writehaskell}++The factorial function grows really fast. While 5 factorial is+\evalhaskell{fact 5}, 10 factorial is \evalhaskell{fact 10}.+\end{document}
+ haskintex.cabal view
@@ -0,0 +1,34 @@+name: haskintex+version: 0.1.0.0+synopsis: Haskell Evaluation inside of LaTeX code.+description:+ The /haskintex/ program is a tool that reads a LaTeX file and evaluates Haskell expressions contained+ in some specific commands and environments. It allows you to define your own functions, use any GHC Haskell language+ extension and, in brief, anything you can do within Haskell. You can freely add any Haskell code you need, and make+ this code appear /optionally/ in the LaTeX output. It is a tiny program, and therefore, easy to understand, use and+ predict.+homepage: http://daniel-diaz.github.io/projects/haskintex+bug-reports: https://github.com/Daniel-Diaz/haskintex/issues+license: BSD3+license-file: LICENSE+author: Daniel Díaz+maintainer: dhelta.diaz@gmail.com+category: LaTeX+build-type: Simple+extra-source-files: README.md+ -- examples+ examples/fact.tex+cabal-version: >=1.10++executable haskintex+ main-is: Main.hs+ build-depends: base >= 4.6 && < 4.7+ , transformers == 0.3.*+ , text >= 0.11.2.3 && < 0.12+ , directory >= 1.2.0.0 && < 1.3+ , filepath >= 1.1.0.0 && < 1.4+ , process >= 1.1.0.2 && < 1.2+ , HaTeX >= 3.6 && < 3.9+ , attoparsec >= 0.10.2.0 && < 0.11+ default-language: Haskell2010+ ghc-options: -Wall