haskintex 0.2.0.0 → 0.3.0.0
raw patch · 6 files changed
+195/−83 lines, 6 filesdep +hintdep ~HaTeX
Dependencies added: hint
Dependency ranges changed: HaTeX
Files
- Main.hs +124/−62
- examples/fact.htex +14/−0
- examples/fact.tex +0/−14
- examples/hatex.htex +24/−0
- examples/sine.htex +22/−0
- haskintex.cabal +11/−7
Main.hs view
@@ -8,6 +8,7 @@ import System.Environment (getArgs) import System.FilePath import System.Directory+import System.IO (hFlush,stdout) -- Text import Data.Text (pack,unpack) import qualified Data.Text as T@@ -29,16 +30,21 @@ import Data.Version (showVersion) -- Lists import Data.List (intersperse)+-- GHC+import Language.Haskell.Interpreter -- Syntax -- | The 'Syntax' datatype describes how haskintex see a LaTeX -- file. When haskintex processes an input file, it parsers--- to this structure. It differentiates three things:+-- to this structure. It differentiates between these parts: -- -- * writehaskell environments (WriteHaskell), either marked -- visible or not. --+-- * Haskell expression of type 'LaTeX' (InsertHaTeX).+-- See the HaTeX package for details about this type.+-- -- * evalhaskell commands and environments (EvalHaskell). -- -- * Anything else (WriteLaTeX).@@ -46,6 +52,7 @@ data Syntax = WriteLaTeX Text | WriteHaskell Bool Text -- False for Hidden, True for Visible+ | InsertHaTeX Text | EvalHaskell Bool Text -- False for Command, True for Environment | Sequence [Syntax] deriving Show -- Show instance for debugging.@@ -53,7 +60,7 @@ -- Parsing parseSyntax :: Bool -> Parser Syntax-parseSyntax v = fmap Sequence $ many $ choice [ p_writehaskell v, p_evalhaskell, p_writelatex ]+parseSyntax v = fmap Sequence $ many $ choice [ p_writehaskell v, p_inserthatex, p_evalhaskell, p_writelatex ] p_writehaskell :: Bool -> Parser Syntax p_writehaskell v = do@@ -64,6 +71,12 @@ h <- manyTill anyChar $ string "\\end{writehaskell}" return $ WriteHaskell b $ pack h +p_inserthatex :: Parser Syntax+p_inserthatex = do+ _ <- string "\\hatex{"+ h <- p_haskell 0+ return $ InsertHaTeX $ pack h+ p_evalhaskell :: Parser Syntax p_evalhaskell = choice [ p_evalhaskellenv, p_evalhaskellcomm ] @@ -89,6 +102,8 @@ else ('}':) <$> p_haskell (n-1) , do _ <- char '\"' liftA2 (++) (('\"':) <$> p_string) (p_haskell n)+ , string "'{'" >> return "'{'"+ , string "'}'" >> return "'}'" , liftA2 (:) anyChar (p_haskell n) ] @@ -97,7 +112,7 @@ liftA2 (++) (char '\\' >> char '\"' >> return "\\\"") p_string , liftA2 (:) (char '\"') (return []) , liftA2 (:) anyChar p_string- ] + ] p_writelatex :: Parser Syntax p_writelatex = (WriteLaTeX . pack) <$>@@ -105,6 +120,7 @@ where p_other = choice [ string "\\begin{writehaskell}" >> return False -- starts p_writehaskell+ , string "\\hatex" >> return False -- starts p_inserthatex , string "\\begin{evalhaskell}" >> return False -- starts p_evalhaskellenv , string "\\evalhaskell" >> return False -- starts p_evalhaskellcomm , return True@@ -119,7 +135,10 @@ -- PASS 2: Evaluate Haskell expressions from processed Syntax. -evalCode :: String -> Bool -> Bool -> Syntax -> Haskintex Text+evalCode :: String -- ^ Auxiliary module name+ -> Bool -- ^ Is manual flag on?+ -> Bool -- ^ Is lhs2tex flag on?+ -> Syntax -> Haskintex Text evalCode modName mFlag lhsFlag = go where go (WriteLaTeX t) = return t@@ -130,6 +149,21 @@ | lhsFlag = TeXEnv "code" [] $ raw x | otherwise = verbatim x in return $ render $ f t+ go (InsertHaTeX t) = do+ let e = unpack $ T.strip t+ int = do+ loadModules [modName]+ setTopLevelModules [modName]+ setImports ["Prelude"]+ interpret e (as :: LaTeX)+ outputStr $ "Evaluation (LaTeX): " ++ e+ r <- runInterpreter int+ case r of+ Left err -> do+ outputStr $ "Warning: Error while evaluating the expression.\n"+ ++ errorString err+ return mempty+ Right l -> return $ render l go (EvalHaskell env t) = let f :: Text -> LaTeX f x | mFlag = raw x -- Manual flag overrides lhs2tex flag behavior@@ -160,33 +194,43 @@ in l : go (r:ts) else t : go ts +-- Errors++errorString :: InterpreterError -> String+errorString (UnknownError e) = "Unknown error: " ++ e+errorString (WontCompile es) = "Compiler error:\n" ++ init (unlines $ fmap errMsg es)+errorString (NotAllowed e) = "Not allowed:" ++ e+errorString (GhcException e) = "GHC exception: " ++ e+ -- Configuration data Conf = Conf- { keepFlag :: Bool- , visibleFlag :: Bool- , verboseFlag :: Bool- , manualFlag :: Bool- , helpFlag :: Bool- , lhs2texFlag :: Bool- , stdoutFlag :: Bool- , unknownFlags :: [String]- , inputs :: [FilePath]+ { keepFlag :: Bool+ , visibleFlag :: Bool+ , verboseFlag :: Bool+ , manualFlag :: Bool+ , helpFlag :: Bool+ , lhs2texFlag :: Bool+ , stdoutFlag :: Bool+ , overwriteFlag :: Bool+ , unknownFlags :: [String]+ , inputs :: [FilePath] } supportedFlags :: [(String,Conf -> Bool)] supportedFlags =- [ ("keep", keepFlag)- , ("visible", visibleFlag)- , ("verbose", verboseFlag)- , ("manual", manualFlag)- , ("help", helpFlag)- , ("lhs2tex", lhs2texFlag)- , ("stdout", stdoutFlag)+ [ ("keep" , keepFlag)+ , ("visible" , visibleFlag)+ , ("verbose" , verboseFlag)+ , ("manual" , manualFlag)+ , ("help" , helpFlag)+ , ("lhs2tex" , lhs2texFlag)+ , ("stdout" , stdoutFlag)+ , ("overwrite" , overwriteFlag) ] readConf :: [String] -> Conf-readConf = go $ Conf False False False False False False False [] []+readConf = go $ Conf False False False False False False False False [] [] where go c [] = c go c (x:xs) =@@ -194,14 +238,15 @@ -- Arguments starting with '-' are considered a flag. ('-':flag) -> case flag of- "keep" -> go (c {keepFlag = True}) xs- "visible" -> go (c {visibleFlag = True}) xs- "verbose" -> go (c {verboseFlag = True}) xs- "manual" -> go (c {manualFlag = True}) xs- "help" -> go (c {helpFlag = True}) xs- "lhs2tex" -> go (c {lhs2texFlag = True}) xs- "stdout" -> go (c {stdoutFlag = True}) xs- _ -> go (c {unknownFlags = unknownFlags c ++ [flag]}) xs+ "keep" -> go (c {keepFlag = True}) xs+ "visible" -> go (c {visibleFlag = True}) xs+ "verbose" -> go (c {verboseFlag = True}) xs+ "manual" -> go (c {manualFlag = True}) xs+ "help" -> go (c {helpFlag = True}) xs+ "lhs2tex" -> go (c {lhs2texFlag = True}) xs+ "stdout" -> go (c {stdoutFlag = True}) xs+ "overwrite" -> go (c {overwriteFlag = True}) xs+ _ -> go (c {unknownFlags = unknownFlags c ++ [flag]}) xs -- Otherwise, an input file. _ -> go (c {inputs = inputs c ++ [x]}) xs @@ -222,12 +267,14 @@ haskintex :: Haskintex () haskintex = do flags <- ask- if helpFlag flags+ if -- If the help flag is passed, ignore everything else+ -- and just print the help.+ helpFlag flags then lift $ putStr help- else do let xs = inputs flags- if null xs- then lift $ putStr noFiles- else mapM_ haskintexFile xs+ else let xs = inputs flags+ in if null xs+ then lift $ putStr noFiles+ else mapM_ haskintexFile xs commas :: [String] -> String commas = concat . intersperse ", "@@ -249,9 +296,9 @@ haskintexFile :: FilePath -> Haskintex () haskintexFile fp_ = do- -- If the given file does not exist, try adding '.tex'.+ -- If the given file does not exist, try adding '.htex'. b <- lift $ doesFileExist fp_- let fp = if b then fp_ else fp_ ++ ".tex"+ let fp = if b then fp_ else fp_ ++ ".htex" -- Report enabled flags showEnabledFlags -- Warnings@@ -279,13 +326,25 @@ lhsFlag <- lhs2texFlag <$> ask l <- evalCode modName mFlag lhsFlag s -- Write final output.+ let fp' = dropExtension (takeFileName fp) ++ ".tex"+ writeit = do outputStr $ "Writing final file at " ++ fp' ++ "..."+ lift $ T.writeFile fp' l outFlag <- stdoutFlag <$> ask- if outFlag- then do outputStr "Sending final output to stdout..."- lift $ T.putStr l- else do let fp' = "haskintex_" ++ fp- outputStr $ "Writing final file at " ++ fp' ++ "..."- lift $ T.writeFile fp' l+ overFlag <- overwriteFlag <$> ask+ nonew <- lift $ doesFileExist fp'+ let finalOutput+ | outFlag = do outputStr "Sending final output to stdout..."+ lift $ T.putStr l+ | overFlag = writeit+ | nonew = do lift $ putStr $ "File " ++ fp' ++ " already exists. Overwrite?"+ ++ " (use -overwrite to overwrite by default) "+ lift $ hFlush stdout -- To immediately show the text on Windows systems.+ resp <- lift getLine+ if resp `elem` ["","y","yes"]+ then writeit+ else outputStr "No file was written."+ | otherwise = writeit+ finalOutput -- If the keep flag is not set, remove the haskell source file. kFlag <- keepFlag <$> ask unless kFlag $ do@@ -308,32 +367,35 @@ , "will be processed with the same set of flags, which will include all the" , "flags passed in the call. This is the list of flags supported by haskintex:" , ""- , " -keep haskintex creates an intermmediate Haskell file before"- , " evaluating any expressions. By default, this file is "- , " eliminated after processing the file. Pass this flag to"- , " keep the file."+ , " -keep haskintex creates an intermmediate Haskell file before"+ , " evaluating any expressions. By default, this file is "+ , " eliminated after processing the file. Pass this flag to"+ , " keep the file." , ""- , " -visible By default, code written inside a writehaskell environment"- , " is not shown in the LaTeX output. This flag changes the"- , " default."+ , " -visible By default, code written inside a writehaskell environment"+ , " is not shown in the LaTeX output. This flag changes the"+ , " default." , ""- , " -verbose If this flag is enabled, haskintex will print information"- , " about its own execution while running."+ , " -verbose If this flag is enabled, haskintex will print information"+ , " about its own execution while running." , ""- , " -manual By default, Haskell expressions, either from writehaskell "- , " or evalhaskell, appear in the LaTeX output inside verb or"- , " verbatim declarations. If this flag is passed, neither verb"- , " nor verbatim will be used. The code will be written as text "- , " as it is. The user will decide how to handle it."+ , " -manual By default, Haskell expressions, either from writehaskell "+ , " or evalhaskell, appear in the LaTeX output inside verb or"+ , " verbatim declarations. If this flag is passed, neither verb"+ , " nor verbatim will be used. The code will be written as text "+ , " as it is. The user will decide how to handle it." , ""- , " -help This flags cancels any other flag or input file and makes"- , " the program simply show this help message."+ , " -help This flags cancels any other flag or input file and makes"+ , " the program simply show this help message." , ""- , " -stdout Instead of writing the output to a file, send it to the"- , " standard output stream (stdout)."+ , " -stdout Instead of writing the output to a file, send it to the"+ , " standard output stream (stdout)." , ""- , " -lhs2tex Instead of using verb or verbatim declarations, format the"- , " output using the syntax accepted by lhs2TeX."+ , " -lhs2tex Instead of using verb or verbatim declarations, format the"+ , " output using the syntax accepted by lhs2TeX."+ , ""+ , " -overwrite Overwrite the output file if it already exists. If this flag"+ , " is not set, the program will ask before overwriting." , "" , "Any unsupported flag will be ignored." ]
+ examples/fact.htex 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}
− examples/fact.tex
@@ -1,14 +0,0 @@-\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}
+ examples/hatex.htex view
@@ -0,0 +1,24 @@+\documentclass{article}+\usepackage{tikz}+\usepackage[utf8]{inputenc}+\author{Daniel Díaz}+\title{Embedding HaTeX in \emph{haskintex}}+\begin{document}+\maketitle+Below is the \emph{Spira Mirabilis} inserted using the HaTeX+package.+\begin{writehaskell}+import Text.LaTeX+import Text.LaTeX.Packages.TikZ.Simple++spiral :: Figure+spiral = LineWidth (Pt 2) $+ pathImage 0.01 (0,4) $+ \t -> ( a * exp t * cos (b*t)+ , a * exp t * sin (b*t)+ )+ where+ a = 0.1 ; b = 4+\end{writehaskell}+\hatex{center $ tikzpicture $ figuretikz spiral}+\end{document}
+ examples/sine.htex view
@@ -0,0 +1,22 @@+\documentclass{article}+\author{Mr. Trigonometric}+\title{The sine function}+\usepackage{tikz}+\begin{document}+\maketitle+\begin{writehaskell}+import Text.LaTeX+import Text.LaTeX.Packages.TikZ.Simple++graphLength :: Double+graphLength = 3*pi++sineGraph :: Figure+sineGraph = Figures [+ Colored (BasicColor Red) $ Line [ (-1,0) , (graphLength,0) ]+ , Colored (BasicColor Red) $ Line [ (0,-1) , (0,1) ]+ , LineWidth (Pt 2) $ pathImage 0.01 (0,graphLength) $ \x -> (x,sin x)+ ]+\end{writehaskell}+\hatex{tikzpicture $ figuretikz sineGraph}+\end{document}
haskintex.cabal view
@@ -1,12 +1,13 @@ name: haskintex-version: 0.2.0.0+version: 0.3.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+ The /haskintex/ (Haskell in LaTeX) 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.+ extension and, in brief, anything you can do within Haskell.+ Additionally, it is possible to include expressions of 'LaTeX' type (see /HaTeX/ package) and render them as LaTeX code.+ 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@@ -17,7 +18,9 @@ build-type: Simple extra-source-files: README.md -- examples- examples/fact.tex+ examples/fact.htex+ examples/hatex.htex+ examples/sine.htex cabal-version: >=1.10 executable haskintex@@ -29,7 +32,8 @@ , 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+ , HaTeX >= 3.9 && < 3.10 , attoparsec >= 0.10.2.0 && < 0.11+ , hint default-language: Haskell2010 ghc-options: -Wall