HaTeX 3.8.0.0 → 3.9.0.0
raw patch · 16 files changed
+460/−349 lines, 16 filesdep ~base
Dependency ranges changed: base
Files
- Examples/parser.hs +31/−0
- Examples/tikzsimple.hs +5/−5
- HaTeX.cabal +10/−6
- README.md +15/−7
- Text/LaTeX/Base.hs +3/−5
- Text/LaTeX/Base/Parser.hs +286/−299
- Text/LaTeX/Base/Render.hs +2/−0
- Text/LaTeX/Base/Syntax.hs +4/−0
- Text/LaTeX/Base/Warnings.hs +1/−1
- Text/LaTeX/Packages/AMSMath.hs +14/−13
- Text/LaTeX/Packages/Color.hs +9/−1
- Text/LaTeX/Packages/TikZ/Simple.hs +9/−6
- Text/LaTeX/Packages/TikZ/Syntax.hs +30/−6
- parsertest/example1.tex +7/−0
- parsertest/example2.tex +8/−0
- parsertest/parsertest.hs +26/−0
+ Examples/parser.hs view
@@ -0,0 +1,31 @@++{-# LANGUAGE OverloadedStrings #-}++import Text.LaTeX+import Text.LaTeX.Base.Parser+import Data.Text (unlines)+import qualified Data.Text.IO as T++main :: IO ()+main = case parseLaTeX example of+ Left err -> putStrLn err+ Right l -> do+ putStrLn "Printing LaTeX AST..."+ print l+ putStrLn "Checking that (render . parse == id)..."+ let t = render l+ print $ example == t+ putStrLn "All done."++example :: Text+example = Data.Text.unlines+ [ "\\documentclass{article}"+ , "\\usepackage[utf8]{inputenc}"+ , "\\author{Daniel Díaz}"+ , "\\title{LaTeX parser}"+ , "\\begin{document}"+ , "\\maketitle"+ , "This is an example of how to parse LaTeX using the"+ , "\\HaTeX library."+ , "\\end{document}"+ ]
Examples/tikzsimple.hs view
@@ -21,16 +21,16 @@ myFigure :: Figure myFigure = Scale 3 $ Figures [ RectangleFilled (0,0) 1 1- , Colored Green $ RectangleFilled (-1,1) 1 1- , Colored Red $ RectangleFilled ( 0,2) 1 1- , Colored Blue $ RectangleFilled ( 1,1) 1 1+ , Colored (BasicColor Green) $ RectangleFilled (-1,1) 1 1+ , Colored (BasicColor Red) $ RectangleFilled ( 0,2) 1 1+ , Colored (BasicColor Blue) $ RectangleFilled ( 1,1) 1 1 ] myFigure2 :: Figure myFigure2 = Scale 2 $ Figures- [ Colored Blue $ PolygonFilled [(-2,-1),(0,1),(2,-1)]+ [ Colored (RGBColor 100 35 150) $ PolygonFilled [(-2,-1),(0,1),(2,-1)] , Text (0,1.4) $ "Is this a " <> textit "blue" <> " triangle?"- , Rotate (pi/9) $ Colored Yellow $ Text (-0.2,-0.2) "Yes, it is!"+ , Rotate (pi/9) $ Colored (BasicColor Yellow) $ Text (-0.2,-0.2) "Yes, it is!" ] myFigure3 :: Figure
HaTeX.cabal view
@@ -1,5 +1,5 @@ Name: HaTeX -Version: 3.8.0.0 +Version: 3.9.0.0 Author: Daniel Díaz Category: Text, LaTeX Build-type: Simple @@ -7,26 +7,30 @@ License-file: license Maintainer: Daniel Díaz (dhelta `dot` diaz `at` gmail `dot` com) Bug-reports: https://github.com/Daniel-Diaz/HaTeX/issues +homepage: http://daniel-diaz.github.io/projects/hatex Synopsis: The Haskell LaTeX library. -Description: The LaTeX project site states: \"LaTeX is a high-quality typesetting system\". This library provides - a bridge between LaTeX and Haskell, implementing the LaTeX syntax in Haskell. +Description: This library provides a bridge between LaTeX and Haskell, implementing the LaTeX /syntax/ + in Haskell. . - Some of the things you can do are: + Some of the things you can do with HaTeX are: . Write LaTeX documents with all the advantages you already have in Haskell (recursion, type system, high order functions, ...), create a LaTeX backend for your own program, - make analysis of LaTeX code through its Abstract Syntax Tree (AST), pretty-print Haskell + parse a LaTeX file and obtain its Abstract Syntax Tree (AST), pretty-print Haskell values in LaTeX, generate TikZ scripts easily, ... . See the @examples@ directory in the source distribution to look some simple examples. It would be good to get you started. The HaTeX User's Guide is available at - <https://github.com/Daniel-Diaz/hatex-guide>. + <https://github.com/Daniel-Diaz/hatex-guide/blob/master/README.md>. Cabal-version: >= 1.10 Extra-source-files: ReleaseNotes README.md -- Examples Examples/*.hs + -- Tests + parsertest/*.tex + parsertest/parsertest.hs Extra-doc-files: -- TikZ docfiles/tikz/*.png
README.md view
@@ -1,10 +1,10 @@-# HaTeX ReadMe +# The HaTeX library HaTeX is a Haskell library that implements the *LaTeX syntax*. -Check a list of examples of usage in the [examples](Examples/) directory. -A good starting point may be [simple.hs](Examples/simple.hs). -Run the script using the ``main`` function. +Check a list of examples of usage in the [Examples](https://github.com/Daniel-Diaz/HaTeX/tree/master/Examples) directory. +A good starting point may be [simple.hs](https://github.com/Daniel-Diaz/HaTeX/blob/master/Examples/simple.hs). +Run any example script executing the ``main`` function. ## Installation notes @@ -39,16 +39,22 @@ To be sure that you are reading the last version, go to the github repository of the guide and follow instructions to build it. It is fairly easy. -## Contributing +## Community and Contributions -To contribute to HaTeX, please, visit our code repository in GitHub: +There are many ways to get involved in the HaTeX project. -https://github.com/Daniel-Diaz/HaTeX +* Fork the [GitHub repository](https://github.com/Daniel-Diaz/HaTeX). +* Report bugs or make suggestions opening a ticket in the [Issue Tracker](https://github.com/Daniel-Diaz/HaTeX/issues). +* Help us to improve and extend our [hatex-guide](https://github.com/Daniel-Diaz/hatex-guide). +* Join the [Mailing List](http://projects.haskell.org/cgi-bin/mailman/listinfo/hatex) for help or announcements of the +last developments. +* Drop by the IRC channel at `#hatex`. ## TODO list * Add more examples. * More testing on the parser (See [#15](https://github.com/Daniel-Diaz/HaTeX/issues/15)). + This includes adding more test cases to the [parsertest folder](https://github.com/Daniel-Diaz/HaTeX/tree/master/parsertest). * Add more documentation. * BibTeX support. @@ -60,3 +66,5 @@ * [TeX-my-math](https://github.com/leftaroundabout/Symbolic-math-HaTeX): Experimental library to ease the production of mathematical expressions using HaTeX. +* [haskintex](http://daniel-diaz.github.io/projects/haskintex): Tool to use Haskell and in particular the HaTeX library +within a LaTeX file.
Text/LaTeX/Base.hs view
@@ -34,14 +34,12 @@ , module Text.LaTeX.Base.Commands , module Text.LaTeX.Base.Writer , module Text.LaTeX.Base.Texy - -- * External re-exports + -- * Monoids -- -- | Since the 'Monoid' instance is the only way to append 'LaTeX' - -- values, a re-export of "Data.Monoid" is given here. - , module Data.Monoid -#if __GLASGOW_HASKELL__ < 704 + -- values, a re-export of the 'Monoid' class is given here for convenience. + , Monoid (..) , (<>) -#endif ) where -- Internal modules
Text/LaTeX/Base/Parser.hs view
@@ -1,299 +1,286 @@-{-# LANGUAGE CPP #-} -{-# LANGUAGE OverloadedStrings #-} -------------------------------------------------------------------------------- --- | --- Module : Text/LaTeX/Base/Parser.hs --- Copyright : (c) Tobias Schoofs --- License : LGPL --- Stability : experimental --- Portability: portable --- --- LaTeX Parser based on Attoparsec -------------------------------------------------------------------------------- -module Text.LaTeX.Base.Parser ( - latexParser, - latexBlockParser, - latexAtOnce, - latexDocParser, - isMainDoc -#ifdef _TEST - , specials -#endif - ) -where - - import Data.Attoparsec.Text hiding (take, takeTill) - import qualified Data.Attoparsec.Text as A (takeTill) - import Data.Char (toLower) - import Data.Monoid - import Data.Maybe (fromMaybe) - import Data.Text (Text) - import qualified Data.Text as T - - import Control.Applicative ((<|>), (<$>)) - import Control.Monad (unless) - - import Text.LaTeX.Base.Syntax - - ------------------------------------------------------------------------ - -- | Parses a Text sequence at once; - -- may fail or conclude. - ------------------------------------------------------------------------ - latexAtOnce :: Text -> Either String LaTeX - latexAtOnce t | T.null t = return TeXEmpty - | otherwise = - case parse latexParser t of - Fail _ _ e -> Left e - Done _ r -> Right r - rx@(Partial _) -> -- Left "incomplete input" - case feed rx T.empty of - Fail _ _ e -> Left e - Partial _ -> Left "incomplete input" - Done _ r -> Right r - - ------------------------------------------------------------------------ - -- | The incremental LaTeX Parser - ------------------------------------------------------------------------ - latexParser :: Parser LaTeX - latexParser = blocks - - ------------------------------------------------------------------------ - -- | Incremental Parser for single blocks of LaTeX - ------------------------------------------------------------------------ - latexBlockParser :: Parser LaTeX - latexBlockParser = block - - ------------------------------------------------------------------------ - -- | Incremental Parser that terminates after the /document/ envionment - ------------------------------------------------------------------------ - latexDocParser :: Parser LaTeX - latexDocParser = blockTillDoc - - ------------------------------------------------------------------------ - -- Blocks - ------------------------------------------------------------------------ - blocks :: Parser LaTeX - blocks = mconcat <$> block `manyTill` endOfInput - - blockTillDoc :: Parser LaTeX - blockTillDoc = do - b <- block - if isMainDoc b then return b - else mappend b <$> blockTillDoc - - -- | Test if a 'LaTeX' block is a @document@ environment. - isMainDoc :: LaTeX -> Bool - isMainDoc b = case b of - TeXEnv "document" _ _ -> True - _ -> False - - ------------------------------------------------------------------------ - -- Block - -- Note: text stops on ']'; - -- if the other parser fail on the rest - -- text2 handles it, starting with ']' - ------------------------------------------------------------------------ - block :: Parser LaTeX - block = foldr1 (<|>) [text, dolMath, comment, text2, command, environment] - - ------------------------------------------------------------------------ - -- Text - ------------------------------------------------------------------------ - text :: Parser LaTeX - text = do - mbC <- peekChar - case mbC of - Nothing -> return TeXEmpty - Just c | c `elem` "$%\\{]}" -> fail "not text" - | otherwise -> TeXRaw <$> A.takeTill (`elem` "$%\\{]}") - - ------------------------------------------------------------------------ - -- Text without stopping on ']' - ------------------------------------------------------------------------ - text2 :: Parser LaTeX - text2 = do - _ <- char ']' - t <- try (text <|> return (TeXRaw T.empty)) - return $ TeXRaw (T.pack "]") <> t - - ------------------------------------------------------------------------ - -- Environment - ------------------------------------------------------------------------ - environment :: Parser LaTeX - environment = anonym <|> env - - anonym :: Parser LaTeX - anonym = char '{' >> - TeXBraces . mconcat <$> block `manyTill` char '}' - - env :: Parser LaTeX - env = do - _ <- char '\\' - n <- envName "begin" - as <- fmap (fromMaybe []) cmdArgs - b <- envBody n - return $ TeXEnv (T.unpack n) as b - - envName :: Text -> Parser Text - envName k = do - _ <- string k - _ <- char '{' - n <- A.takeTill (== '}') - _ <- char '}' - return n - - envBody :: Text -> Parser LaTeX - envBody n = mconcat <$> (bodyBlock n) `manyTill` endenv - where endenv = try $ string ("\\end{" <> n <> "}") - - bodyBlock :: Text -> Parser LaTeX - bodyBlock n = do - c <- peekChar - case c of - Just _ -> block - _ -> fail $ "Environment '" <> T.unpack n <> "' not finalized." - - ------------------------------------------------------------------------ - -- Command - ------------------------------------------------------------------------ - command :: Parser LaTeX - command = do - _ <- char '\\' - mbX <- peekChar - case mbX of - Nothing -> return TeXEmpty - Just x -> if isSpecial x - then special - else do - c <- A.takeTill endCmd - if c `elem` ["begin","end"] - then fail $ "Command not allowed: " ++ T.unpack c - else maybe (TeXCommS $ T.unpack c) (TeXComm $ T.unpack c) <$> cmdArgs - - ------------------------------------------------------------------------ - -- Command Arguments - ------------------------------------------------------------------------ - cmdArgs :: Parser (Maybe [TeXArg]) - cmdArgs = try (string "{}" >> return (Just [])) - <|> fmap Just (many1 cmdArg) - <|> return Nothing - - cmdArg :: Parser TeXArg - cmdArg = do - c <- char '[' <|> char '{' - let e = case c of - '[' -> "]" - '{' -> "}" - _ -> error "this cannot happen!" - b <- mconcat <$> block `manyTill` string e - case c of - '[' -> return $ OptArg b - '{' -> return $ FixArg b - _ -> error "this cannot happen!" - - ------------------------------------------------------------------------ - -- Special commands (consisting of one char) - ------------------------------------------------------------------------ - special :: Parser LaTeX - special = do - x <- anyChar - case x of - '(' -> math Parentheses "\\)" - '[' -> math Square "\\]" - '{' -> lbrace - '}' -> rbrace - '|' -> vert - '\\' -> lbreak - _ -> commS [x] - - ------------------------------------------------------------------------ - -- line break - ------------------------------------------------------------------------ - lbreak :: Parser LaTeX - lbreak = do - y <- try (char '[' <|> char '*' <|> return ' ') - case y of - '[' -> linebreak False - '*' -> do z <- try (char '[' <|> return ' ') - case z of - '[' -> linebreak True - _ -> return (TeXLineBreak Nothing True) - _ -> return (TeXLineBreak Nothing False) - - linebreak :: Bool -> Parser LaTeX - linebreak t = do m <- measure - _ <- char ']' - s <- try (char '*' <|> return ' ') - return $ TeXLineBreak (Just m) (t || s == '*') - - measure :: Parser Measure - measure = try (double >>= unit) - <|> CustomMeasure <$> block - - unit :: Double -> Parser Measure - unit f = do - u1 <- anyChar - u2 <- anyChar - case map toLower [u1, u2] of - "pt" -> return $ Pt f - "mm" -> return $ Mm f - "cm" -> return $ Cm f - "in" -> return $ In f - "ex" -> return $ Ex f - "em" -> return $ Em f - _ -> fail "NaN" - - ------------------------------------------------------------------------ - -- right or left brace or vertical - ------------------------------------------------------------------------ - rbrace, lbrace,vert :: Parser LaTeX - lbrace = brace "{" - rbrace = brace "}" - vert = brace "|" - - brace :: String -> Parser LaTeX - brace = return . TeXCommS - - commS :: String -> Parser LaTeX - commS = return . TeXCommS - - ------------------------------------------------------------------------ - -- Math - ------------------------------------------------------------------------ - dolMath :: Parser LaTeX - dolMath = do - _ <- char '$' - b <- mconcat <$> block `manyTill` char '$' - return $ TeXMath Dollar b -- [] - - math :: MathType -> Text -> Parser LaTeX - math t eMath = do - b <- mconcat <$> block `manyTill` try (string eMath) - return $ TeXMath t b -- [] - - ------------------------------------------------------------------------ - -- Comment - ------------------------------------------------------------------------ - comment :: Parser LaTeX - comment = do - _ <- char '%' - c <- A.takeTill (== '\n') - e <- atEnd - unless e (char '\n' >>= \_ -> return ()) - return $ TeXComment c - - ------------------------------------------------------------------------ - -- Helpers - ------------------------------------------------------------------------ - isSpecial :: Char -> Bool - isSpecial = (`elem` specials) - - endCmd :: Char -> Bool - endCmd c = notLowercaseAlph && notUppercaseAlph - where c' = fromEnum c - notLowercaseAlph = c' < fromEnum 'a' || c' > fromEnum 'z' - notUppercaseAlph = c' < fromEnum 'A' || c' > fromEnum 'Z' - - - specials :: String - specials = "'(),.-\"!^$&#{}%~|/:;=[]\\` " +{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+-------------------------------------------------------------------------------+-- |+-- Module : Text/LaTeX/Base/Parser.hs+-- Copyright : (c) Tobias Schoofs+-- License : LGPL +-- Stability : experimental+-- Portability: portable+--+-- LaTeX Parser based on Attoparsec+-------------------------------------------------------------------------------+module Text.LaTeX.Base.Parser (+ parseLaTeX+ , latexParser+ , latexBlockParser+ , latexAtOnce+ , latexDocParser+#ifdef _TEST+ , specials+#endif+ ) where++import Data.Attoparsec.Text hiding (take, takeTill)+import qualified Data.Attoparsec.Text as A (takeTill)+import Data.Char (toLower)+import Data.Monoid+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import qualified Data.Text as T ++import Control.Applicative ((<|>), (<$>))+import Control.Monad (unless)++import Text.LaTeX.Base.Syntax++-- | Parse a 'Text' sequence as a 'LaTeX' block. If it fails, it returns+-- an error string.+parseLaTeX :: Text -> Either String LaTeX+parseLaTeX t | T.null t = return TeXEmpty+ | otherwise = + case parse latexParser t of+ Fail _ _ e -> Left e+ Done _ r -> Right r+ rx@(Partial _) -> -- Left "incomplete input"+ case feed rx T.empty of+ Fail _ _ e -> Left e+ Partial _ -> Left "incomplete input"+ Done _ r -> Right r++{-# DEPRECATED latexAtOnce "Use parseLaTeX instead." #-}++latexAtOnce :: Text -> Either String LaTeX+latexAtOnce = parseLaTeX++------------------------------------------------------------------------+-- | Incremental Parser that terminates after the /document/ envionment+------------------------------------------------------------------------+latexDocParser :: Parser LaTeX+latexDocParser = blockTillDoc++------------------------------------------------------------------------+-- | Incremental 'LaTeX' parser.+------------------------------------------------------------------------+latexParser :: Parser LaTeX+latexParser = mconcat <$> latexBlockParser `manyTill` endOfInput ++blockTillDoc :: Parser LaTeX+blockTillDoc = do+ b <- latexBlockParser+ if isMainDoc b then return b+ else mappend b <$> blockTillDoc++-- | Test if a 'LaTeX' block is a @document@ environment.+isMainDoc :: LaTeX -> Bool+isMainDoc (TeXEnv "document" _ _) = True+isMainDoc _ = False++-- | Parser of a single 'LaTeX' constructor, no appending blocks.+latexBlockParser :: Parser LaTeX+latexBlockParser = foldr1 (<|>) [text, dolMath, comment, text2, environment, command]+-- Note: text stops on ']'; if the other parsers fail on the rest+-- text2 handles it, starting with ']' + +------------------------------------------------------------------------+-- Text+------------------------------------------------------------------------+text :: Parser LaTeX+text = do+ mbC <- peekChar+ case mbC of+ Nothing -> fail "text: Empty input."+ Just c | c `elem` "$%\\{]}" -> fail "not text"+ | otherwise -> TeXRaw <$> A.takeTill (`elem` "$%\\{]}")++------------------------------------------------------------------------+-- Text without stopping on ']'+------------------------------------------------------------------------+text2 :: Parser LaTeX+text2 = do+ _ <- char ']'+ t <- try (text <|> return (TeXRaw T.empty))+ return $ TeXRaw (T.pack "]") <> t++------------------------------------------------------------------------+-- Environment+------------------------------------------------------------------------+environment :: Parser LaTeX+environment = anonym <|> env++anonym :: Parser LaTeX+anonym = char '{' >> + TeXBraces . mconcat <$> latexBlockParser `manyTill` char '}'++env :: Parser LaTeX+env = do+ _ <- char '\\'+ n <- envName "begin"+ skipSpace+ as <- fmap (fromMaybe []) cmdArgs+ b <- envBody n + return $ TeXEnv (T.unpack n) as b++envName :: Text -> Parser Text+envName k = do+ _ <- string k+ _ <- char '{'+ n <- A.takeTill (== '}')+ _ <- char '}'+ return n++envBody :: Text -> Parser LaTeX+envBody n = mconcat <$> (bodyBlock n) `manyTill` endenv+ where endenv = try $ string ("\\end") >> skipSpace >> string ("{" <> n <> "}")++bodyBlock :: Text -> Parser LaTeX+bodyBlock n = do+ c <- peekChar+ case c of + Just _ -> latexBlockParser+ _ -> fail $ "Environment '" <> T.unpack n <> "' not finalized."++------------------------------------------------------------------------+-- Command+------------------------------------------------------------------------+command :: Parser LaTeX+command = do+ _ <- char '\\'+ mbX <- peekChar+ case mbX of+ Nothing -> return TeXEmpty+ Just x -> if isSpecial x+ then special+ else do+ c <- A.takeTill endCmd+ -- if c `elem` ["begin","end"]+ -- then fail $ "Command not allowed: " ++ T.unpack c+ -- else maybe (TeXCommS $ T.unpack c) (TeXComm $ T.unpack c) <$> cmdArgs+ maybe (TeXCommS $ T.unpack c) (TeXComm $ T.unpack c) <$> cmdArgs++------------------------------------------------------------------------+-- Command Arguments+------------------------------------------------------------------------+cmdArgs :: Parser (Maybe [TeXArg])+cmdArgs = try (string "{}" >> return (Just []))+ <|> fmap Just (many1 cmdArg)+ <|> return Nothing++cmdArg :: Parser TeXArg+cmdArg = do+ c <- char '[' <|> char '{'+ let e = case c of+ '[' -> "]"+ '{' -> "}"+ _ -> error "this cannot happen!"+ b <- mconcat <$> latexBlockParser `manyTill` string e+ case c of + '[' -> return $ OptArg b+ '{' -> return $ FixArg b+ _ -> error "this cannot happen!"++------------------------------------------------------------------------+-- Special commands (consisting of one char)+------------------------------------------------------------------------+special :: Parser LaTeX+special = do+ x <- anyChar+ case x of+ '(' -> math Parentheses "\\)"+ '[' -> math Square "\\]"+ '{' -> lbrace+ '}' -> rbrace+ '|' -> vert+ '\\' -> lbreak+ _ -> commS [x]++------------------------------------------------------------------------+-- Line break+------------------------------------------------------------------------+lbreak :: Parser LaTeX+lbreak = do+ y <- try (char '[' <|> char '*' <|> return ' ') + case y of+ '[' -> linebreak False+ '*' -> do z <- try (char '[' <|> return ' ')+ case z of+ '[' -> linebreak True+ _ -> return (TeXLineBreak Nothing True)+ _ -> return (TeXLineBreak Nothing False)++linebreak :: Bool -> Parser LaTeX+linebreak t = do m <- measure+ _ <- char ']'+ s <- try (char '*' <|> return ' ')+ return $ TeXLineBreak (Just m) (t || s == '*')++measure :: Parser Measure+measure = try (double >>= unit) <|> CustomMeasure <$> latexBlockParser++unit :: Double -> Parser Measure+unit f = do+ u1 <- anyChar+ u2 <- anyChar+ case map toLower [u1, u2] of+ "pt" -> return $ Pt f+ "mm" -> return $ Mm f+ "cm" -> return $ Cm f+ "in" -> return $ In f+ "ex" -> return $ Ex f+ "em" -> return $ Em f+ _ -> fail "NaN"++------------------------------------------------------------------------+-- Right or left brace or vertical+------------------------------------------------------------------------+rbrace, lbrace,vert :: Parser LaTeX+lbrace = brace "{"+rbrace = brace "}"+vert = brace "|"++brace :: String -> Parser LaTeX+brace = return . TeXCommS++commS :: String -> Parser LaTeX+commS = return . TeXCommS++------------------------------------------------------------------------+-- Math+------------------------------------------------------------------------+dolMath :: Parser LaTeX+dolMath = do+ _ <- char '$' + b <- mconcat <$> latexBlockParser `manyTill` char '$'+ return $ TeXMath Dollar b++math :: MathType -> Text -> Parser LaTeX+math t eMath = do+ b <- mconcat <$> latexBlockParser `manyTill` try (string eMath)+ return $ TeXMath t b++------------------------------------------------------------------------+-- Comment +------------------------------------------------------------------------+comment :: Parser LaTeX+comment = do+ _ <- char '%'+ c <- A.takeTill (== '\n')+ e <- atEnd+ unless e (char '\n' >>= \_ -> return ())+ return $ TeXComment c++------------------------------------------------------------------------+-- Helpers+------------------------------------------------------------------------+isSpecial :: Char -> Bool+isSpecial = (`elem` specials)++endCmd :: Char -> Bool+endCmd c = notLowercaseAlph && notUppercaseAlph+ where c' = fromEnum c+ notLowercaseAlph = c' < fromEnum 'a' || c' > fromEnum 'z'+ notUppercaseAlph = c' < fromEnum 'A' || c' > fromEnum 'Z'+++specials :: String+specials = "'(),.-\"!^$&#{}%~|/:;=[]\\` "
Text/LaTeX/Base/Render.hs view
@@ -27,6 +27,7 @@ import Data.Text.Encoding import Data.List (intersperse) import qualified Data.ByteString as B +import Data.Word (Word8) -- | Class of values that can be transformed to 'Text'. -- You mainly will use this to obtain the 'Text' output @@ -151,6 +152,7 @@ instance Render Integer where instance Render Float where instance Render Double where +instance Render Word8 where instance Render a => Render [a] where render xs = "[" <> renderCommas xs <> "]"
Text/LaTeX/Base/Syntax.hs view
@@ -32,6 +32,7 @@ import Data.String import Control.Applicative import Data.Functor.Identity (runIdentity) +import Data.Typeable -- | Measure units defined in LaTeX. Use 'CustomMeasure' to use commands like 'textwidth'. -- For instance: @@ -126,6 +127,9 @@ protectChar '\\' = "\\textbackslash{}" protectChar '_' = "\\_{}" protectChar x = [x] + +instance Typeable LaTeX where + typeOf _ = mkTyConApp (mkTyCon3 "HaTeX" "Text.LaTeX.Base.Syntax" "LaTeX") [] -- Syntax analysis
Text/LaTeX/Base/Warnings.hs view
@@ -4,7 +4,7 @@ -- | This module provides functionality for check a 'LaTeX' value for -- possibly undesired things (like the call to an undefined label), -- returning 'Warning's. These are called 'Warning's because they --- never terminates the program execution. +-- never terminate the program execution. module Text.LaTeX.Base.Warnings ( -- * Warnings datatype Warning (..)
Text/LaTeX/Packages/AMSMath.hs view
@@ -89,6 +89,7 @@ , to , mapsto , forall , exists , dagger, ddagger + , infty -- * Fonts , mathdefault , mathbf @@ -394,7 +395,8 @@ ---- Sum/Integral symbols --- | Sigma sumation symbol. +-- | Sigma sumation symbol. Use 'sumFromTo' instead if you want to +-- specify the limits of the sum. tsum :: LaTeXC l => l tsum = comm0 "sum" @@ -403,9 +405,10 @@ => l -- ^ Expression below the sigma. -> l -- ^ Expression above the sigma. -> l -sumFromTo x y = tsum !: x ^: y +sumFromTo x y = commS "sum" !: x ^: y --- | Pi product symbol. +-- | Pi product symbol. Use 'prodFromTo' if you want to specify the +-- limits of the product. prod :: LaTeXC l => l prod = comm0 "prod" @@ -414,9 +417,10 @@ => l -- ^ Expression below the pi. -> l -- ^ Expression above the pi. -> l -prodFromTo x y = prod !: x ^: y +prodFromTo x y = commS "prod" !: x ^: y --- | Integral symbol. +-- | Integral symbol. Use 'integralFromTo' if you want to specify +-- the limits of the integral. integral :: LaTeXC l => l integral = comm0 "int" @@ -425,7 +429,7 @@ => l -- ^ Lower limit of integration. -> l -- ^ Upper limit of integration. -> l -integralFromTo x y = integral !: x ^: y +integralFromTo x y = commS "int" !: x ^: y ---- Operator symbols @@ -437,7 +441,6 @@ \l1 l2 -> (l1 <> commS "not") `op` l2 - -- | Plus-or-minus operator (±). pm :: LaTeXC l => l -> l -> l pm = between $ comm0 "pm" @@ -528,7 +531,6 @@ equiv :: LaTeXC l => l -> l -> l equiv = between $ comm0 "equiv" - -- | Element-of (∈). in_ :: LaTeXC l => l -> l -> l in_ = between $ comm0 "in" @@ -561,7 +563,6 @@ setminus :: LaTeXC l => l -> l -> l setminus = between $ comm0 "setminus" - -- | Angle pointing downwards (∨). vee :: LaTeXC l => l -> l -> l vee = between $ comm0 "vee" @@ -570,7 +571,6 @@ wedge :: LaTeXC l => l -> l -> l wedge = between $ comm0 "wedge" - -- | Circled plus operator (⊕). oplus :: LaTeXC l => l -> l -> l oplus = between $ comm0 "oplus" @@ -591,9 +591,6 @@ odot :: LaTeXC l => l -> l -> l odot = between $ comm0 "odot" - - - ---- Greek alphabet -- | /α/ symbol. @@ -781,6 +778,10 @@ -- | Double dagger symbol, ‡. ddagger :: LaTeXC l => l ddagger = comm0 "ddagger" + +-- | Infinity symbol. +infty :: LaTeXC l => l +infty = comm0 "infty" ------------------------------------- ------------ Math Fonts -------------
Text/LaTeX/Packages/Color.hs view
@@ -18,6 +18,10 @@ , ColorName (..) , ColorModel (..) , ColSpec (..) + -- * Words + -- | RGB255 colors are determined by three parameters of the 'Word8' type. + -- Values of type 'Word8' lie within 0 and 255. + , Word8 -- * Commands , pagecolor , color @@ -32,6 +36,7 @@ import Text.LaTeX.Base.Types -- import Data.Text (toLower) +import Data.Word (Word8) -- | The 'pcolor' package. -- @@ -75,8 +80,11 @@ -- | Specify your own color using one of the different color models. data ColorModel = RGB Float Float Float - | RGB255 Int Int Int + -- ^ Each parameter determines the proportion of red, green and + -- blue, with a value within the [0,1] interval. + | RGB255 Word8 Word8 Word8 | GrayM Float + -- ^ Grayscale, from 0 (black) to 1 (white). | HTML String | CMYK Float Float Float Float deriving Show
Text/LaTeX/Packages/TikZ/Simple.hs view
@@ -19,9 +19,9 @@ -- > myFigure :: Figure -- > myFigure = Scale 2 $ Figures -- > [ RectangleFilled (0,0) 1 1--- > , Colored Green $ RectangleFilled (-1,1) 1 1--- > , Colored Red $ RectangleFilled ( 0,2) 1 1--- > , Colored Blue $ RectangleFilled ( 1,1) 1 1+-- > , Colored (BasicColor Green) $ RectangleFilled (-1,1) 1 1+-- > , Colored (BasicColor Red) $ RectangleFilled ( 0,2) 1 1+-- > , Colored (BasicColor Blue) $ RectangleFilled ( 1,1) 1 1 -- > ] -- module Text.LaTeX.Packages.TikZ.Simple (@@ -30,8 +30,9 @@ -- * Figures , Figure (..) , Point- -- | /In the future we will accept colors other than the basic ones./+ , TikZColor (..) , Color (..)+ , Word8 -- * Additional functions , pathImage -- * Figure scripting@@ -42,7 +43,9 @@ import Text.LaTeX.Base.Syntax (LaTeX) import Text.LaTeX.Base.Types (Measure)-import Text.LaTeX.Packages.TikZ (TikZ,Color,tikzpicture,emptytikz,tikz)+import Text.LaTeX.Packages.TikZ+ ( TikZ, TikZColor, Color, Word8+ , tikzpicture, emptytikz, tikz ) import qualified Text.LaTeX.Packages.TikZ as T -- | A point in the plane.@@ -64,7 +67,7 @@ | EllipseFilled Point Double Double -- ^ Same as 'Ellipse', but filled with some color. | Text Point LaTeX -- ^ Insert some 'LaTeX' code, centered at the given 'Point'. -- The text should not be very complex to fit nicely in the picture.- | Colored Color Figure -- ^ Color for the given 'Figure'.+ | Colored TikZColor Figure -- ^ Color for the given 'Figure'. | LineWidth Measure Figure -- ^ Line width for the given 'Figure'. | Scale Double Figure -- ^ Scaling of the given 'Figure' by a factor. | Rotate Double Figure -- ^ Rotate a 'Figure' by a given angle (in radians).
Text/LaTeX/Packages/TikZ/Syntax.hs view
@@ -27,7 +27,9 @@ , (->-) -- * Parameters , Parameter (..)+ , TikZColor (..) , Color (..)+ , Word8 -- * TikZ , TikZ , emptytikz@@ -44,14 +46,14 @@ import Text.LaTeX.Base.Render import Text.LaTeX.Base.Syntax import Text.LaTeX.Packages.Color--- TODO: Extend colors to anything accepted in TikZ. import Data.Monoid import Data.Foldable (foldMap) import qualified Data.Sequence as S+import Numeric (showFFloat) -- POINTS --- | A point in TikZ.+-- | A point in Ti/k/Z. data TPoint = DimPoint Measure Measure | XYPoint Double Double@@ -60,23 +62,35 @@ | RelPoint_ TPoint deriving Show +-- | Newtype of double with a custom 'Show' instance.+newtype TikZDouble = TikZDouble Double++instance Show TikZDouble where+ show (TikZDouble x) = showFFloat (Just 5) x []++instance Render TikZDouble where+ render = fromString . show+ instance Render TPoint where render (DimPoint x y) = "(" <> renderCommas [x,y] <> ")"- render (XYPoint x y) = "(" <> renderCommas [x,y] <> ")"- render (XYZPoint x y z) = "(" <> renderCommas [x,y,z] <> ")"+ render (XYPoint x y) = "(" <> renderCommas [TikZDouble x,TikZDouble y] <> ")"+ render (XYZPoint x y z) = "(" <> renderCommas [TikZDouble x,TikZDouble y,TikZDouble z] <> ")" render (RelPoint p) = "++" <> render p render (RelPoint_ p) = "+" <> render p +-- | Point using 'Measure's for coordinantes. pointAt :: Measure -> Measure -> TPoint pointAt = DimPoint +-- | Point using numbers as coordinates. pointAtXY :: Double -> Double -> TPoint pointAtXY = XYPoint +-- | Three-dimensional point. pointAtXYZ :: Double -> Double -> Double -> TPoint pointAtXYZ = XYZPoint --- | Makes a point relative to the previous one.+-- | Makes a point relative to the previous. relPoint :: TPoint -> TPoint relPoint (RelPoint x) = RelPoint x relPoint (RelPoint_ x) = RelPoint x@@ -206,11 +220,21 @@ -- Parameters +-- | Color models accepted by Ti/k/Z.+data TikZColor =+ BasicColor Color+ | RGBColor Word8 Word8 Word8+ deriving Show++instance Render TikZColor where+ render (BasicColor c) = render c+ render (RGBColor r g b) = "{rgb,255:red," <> render r <> ";green," <> render g <> ";blue," <> render b <> "}"+ -- | Parameters to use in a 'scope' to change how things -- are rendered within that scope. data Parameter = TWidth Measure- | TColor Color+ | TColor TikZColor | TScale Double | TRotate Double -- ^ Angle is in degrees. deriving Show
+ parsertest/example1.tex view
@@ -0,0 +1,7 @@+\documentclass{article}++\newenvironment{foo}{\begin{center}}{\end{center}}++\begin{document}++\end{document}
+ parsertest/example2.tex view
@@ -0,0 +1,8 @@+\documentclass{article}+\usepackage{amsmath}++\begin{document}++$A \\cap [j_n, \\omega)$++\end{document}
+ parsertest/parsertest.hs view
@@ -0,0 +1,26 @@++import Text.LaTeX+import Text.LaTeX.Base.Parser+import qualified Data.Text.IO as T++testNumbers :: [Int]+testNumbers = [1 .. 2]++testFile :: Int -> IO Bool+testFile i = do+ putStr $ "Parsing example " ++ show i ++ "... "+ t <- T.readFile $ "example" ++ show i ++ ".tex"+ case parseLaTeX t of+ Left err -> do putStrLn "Failed."+ putStrLn $ "The error was: " ++ err+ return False+ Right _ -> putStrLn "Succeed." >> return True+ +main :: IO ()+main = do+ putStrLn "Running Parser Test..."+ bs <- mapM testFile testNumbers+ let b = and bs+ putStrLn $ "Parser Test Passed: " ++ show b+ if b then return ()+ else putStrLn $ "Number of errors: " ++ show (length $ filter (==False) bs)