lambdatex (empty) → 0.1.0.0
raw patch · 18 files changed
+1126/−0 lines, 18 filesdep +HaTeXdep +QuickCheckdep +basesetup-changed
Dependencies added: HaTeX, QuickCheck, base, containers, directory, hspec, lambdatex, mtl, text, transformers
Files
- LICENSE +339/−0
- Setup.hs +2/−0
- lambdatex.cabal +65/−0
- src/Text/LaTeX/LambdaTeX.hs +127/−0
- src/Text/LaTeX/LambdaTeX/Error.hs +6/−0
- src/Text/LaTeX/LambdaTeX/Package.hs +21/−0
- src/Text/LaTeX/LambdaTeX/Package/Internal.hs +27/−0
- src/Text/LaTeX/LambdaTeX/Package/Types.hs +14/−0
- src/Text/LaTeX/LambdaTeX/Part.hs +15/−0
- src/Text/LaTeX/LambdaTeX/Reference.hs +81/−0
- src/Text/LaTeX/LambdaTeX/Reference/Internal.hs +43/−0
- src/Text/LaTeX/LambdaTeX/Reference/Types.hs +16/−0
- src/Text/LaTeX/LambdaTeX/Selection.hs +46/−0
- src/Text/LaTeX/LambdaTeX/Selection/Internal.hs +82/−0
- src/Text/LaTeX/LambdaTeX/Selection/Types.hs +10/−0
- src/Text/LaTeX/LambdaTeX/Types.hs +209/−0
- src/Text/LaTeX/LambdaTeX/Utils.hs +14/−0
- test/Spec.hs +9/−0
+ LICENSE view
@@ -0,0 +1,339 @@+ GNU GENERAL PUBLIC LICENSE+ Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The licenses for most software are designed to take away your+freedom to share and change it. By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users. This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it. (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.) You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++ To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have. You must make sure that they, too, receive or can get the+source code. And you must show them these terms so they know their+rights.++ We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++ Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software. If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++ Finally, any free program is threatened constantly by software+patents. We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary. To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++ The precise terms and conditions for copying, distribution and+modification follow.++ GNU GENERAL PUBLIC LICENSE+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++ 0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License. The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language. (Hereinafter, translation is included without limitation in+the term "modification".) Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope. The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++ 1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++ 2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++ a) You must cause the modified files to carry prominent notices+ stating that you changed the files and the date of any change.++ b) You must cause any work that you distribute or publish, that in+ whole or in part contains or is derived from the Program or any+ part thereof, to be licensed as a whole at no charge to all third+ parties under the terms of this License.++ c) If the modified program normally reads commands interactively+ when run, you must cause it, when started running for such+ interactive use in the most ordinary way, to print or display an+ announcement including an appropriate copyright notice and a+ notice that there is no warranty (or else, saying that you provide+ a warranty) and that users may redistribute the program under+ these conditions, and telling the user how to view a copy of this+ License. (Exception: if the Program itself is interactive but+ does not normally print such an announcement, your work based on+ the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole. If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works. But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++ 3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++ a) Accompany it with the complete corresponding machine-readable+ source code, which must be distributed under the terms of Sections+ 1 and 2 above on a medium customarily used for software interchange; or,++ b) Accompany it with a written offer, valid for at least three+ years, to give any third party, for a charge no more than your+ cost of physically performing source distribution, a complete+ machine-readable copy of the corresponding source code, to be+ distributed under the terms of Sections 1 and 2 above on a medium+ customarily used for software interchange; or,++ c) Accompany it with the information you received as to the offer+ to distribute corresponding source code. (This alternative is+ allowed only for noncommercial distribution and only if you+ received the program in object code or executable form with such+ an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it. For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable. However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++ 4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License. Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++ 5. You are not required to accept this License, since you have not+signed it. However, nothing else grants you permission to modify or+distribute the Program or its derivative works. These actions are+prohibited by law if you do not accept this License. Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++ 6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions. You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++ 7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all. For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices. Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++ 8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded. In such case, this License incorporates+the limitation as if written in the body of this License.++ 9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number. If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation. If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++ 10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission. For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this. Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++ NO WARRANTY++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ {description}+ Copyright (C) {year} {fullname}++ This program is free software; you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation; either version 2 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License along+ with this program; if not, write to the Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++ Gnomovision version 69, Copyright (C) year name of author+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary. Here is a sample; alter the names:++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program+ `Gnomovision' (which makes passes at compilers) written by James Hacker.++ {signature of Ty Coon}, 1 April 1989+ Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs. If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library. If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ lambdatex.cabal view
@@ -0,0 +1,65 @@+name: lambdatex+version: 0.1.0.0+synopsis: Type-Safe LaTeX EDSL+description: + ΛTeX, pronounced 'LambdaTeX' is a Haskell EDSL that adds type-safety to LaTeX.+ ΛTeX-generated LaTeX code should compile without errors.++ TODO(kerckhove) big fancy example+homepage: http://github.com/NorfairKing/lambdatex+license: GPL+license-file: LICENSE+author: Tom Sydney Kerckhove+maintainer: syd.kerckhove@gmail.com+copyright: 2015 Tom Sydney Kerckhove+category: Text+build-type: Simple+-- extra-source-files:+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Text.LaTeX.LambdaTeX+ Text.LaTeX.LambdaTeX.Error+ Text.LaTeX.LambdaTeX.Package+ Text.LaTeX.LambdaTeX.Package.Internal+ Text.LaTeX.LambdaTeX.Package.Types+ Text.LaTeX.LambdaTeX.Part+ Text.LaTeX.LambdaTeX.Reference+ Text.LaTeX.LambdaTeX.Reference.Internal+ Text.LaTeX.LambdaTeX.Reference.Types+ Text.LaTeX.LambdaTeX.Selection+ Text.LaTeX.LambdaTeX.Selection.Internal+ Text.LaTeX.LambdaTeX.Selection.Types+ Text.LaTeX.LambdaTeX.Types+ Text.LaTeX.LambdaTeX.Utils+ build-depends: base >= 4.6 && < 5.0+ , HaTeX >= 3.16 && < 3.17+ , mtl >= 2.2 && < 2.3+ , text >= 1.2 && < 1.3+ , containers >= 0.5 && < 0.6+ , transformers >= 0.4 && < 0.5+ , directory >= 1.2 && < 1.3+ ghc-options: -Wall+ -fwarn-unused-imports+ -fwarn-incomplete-patterns+ -fno-warn-unused-do-bind+ -fno-warn-name-shadowing+ -fno-warn-orphans+ -fforce-recomp+ default-language: Haskell2010++test-suite lambdatex-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ build-depends: base+ , lambdatex+ , hspec+ , QuickCheck+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/NorfairKing/lambdatex
+ src/Text/LaTeX/LambdaTeX.hs view
@@ -0,0 +1,127 @@+-- |+-- TODO(kerckhove) big example here!+--+{-# LANGUAGE OverloadedStrings #-}+module Text.LaTeX.LambdaTeX (+ -- * Building ΛTeX+ module Text.LaTeX.LambdaTeX++ -- ** Selections+ , module Text.LaTeX.LambdaTeX.Selection++ -- ** References+ , module Text.LaTeX.LambdaTeX.Reference++ -- ** Packages dependencies+ , module Text.LaTeX.LambdaTeX.Package++ -- ** Re-exports+ , module Text.LaTeX.LambdaTeX.Types++ ) where++import Control.Monad.IO.Class (MonadIO (..))++import qualified Data.Set as S+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Text.LaTeX.Base (LaTeX, renderFile)++import Text.LaTeX.LambdaTeX.Package+import Text.LaTeX.LambdaTeX.Package.Internal+import Text.LaTeX.LambdaTeX.Reference+import Text.LaTeX.LambdaTeX.Reference.Internal+import Text.LaTeX.LambdaTeX.Reference.Types+import Text.LaTeX.LambdaTeX.Selection+import Text.LaTeX.LambdaTeX.Selection.Types+import Text.LaTeX.LambdaTeX.Types+import Text.LaTeX.LambdaTeX.Utils++-- | Build all the files for a LaTeX project given by a ΛTeXT generator+-- This either returns Left with an error or Right () to signify success.+--+-- This function takes care of some of the LaTeX tediousness:+--+-- * LaTeX file generation+-- * Automatic bibtex file generation+-- * All safety provided by 'execLambdaTeXT' (in the form of textual errors)+-- * TODO(kerckhove) Automatic asynchronic resolution of figure dependencies on graphviz or tikz figures+buildLaTeXProject :: MonadIO m => ΛTeXT m a -> ProjectConfig -> m (Either [ΛError] ())+buildLaTeXProject func conf = do+ (errs, (latex, refs)) <- execLambdaTeXT func $ projectGenerationConfig conf++ -- Render tex file+ let mainTexFile = projectTexFileName conf ++ ".tex"+ liftIO $ renderFile mainTexFile latex++ -- Render bib file+ let mainBibFile = projectBibFileName conf ++ ".bib"+ liftIO $ removeIfExists mainBibFile+ liftIO $ T.appendFile mainBibFile $ renderReferences refs++ return $ if null errs+ then Right ()+ else Left errs++-- | Execute a ΛTeXT generation+-- This either returns a tuple of the errors and a tuple of the resulting LaTeX value and a list of external references that need to be put into a bibtex file.+--+-- This function takes care of a lot of safety issues:+--+-- * Subset selection. This allows you to build large documents in parts.+-- * External dependency selection. No more '??' for external references in the output pdf.+-- * Internal dependency safety. No more '??' for external references in the internal pdf.+-- * Package dependency resolution, TODO(kerckhove) with packages in the right order+-- * Dependency selection of figure dependencies on graphviz or tikz figures+execLambdaTeXT :: Monad m => ΛTeXT m a -> GenerationConfig -> m ([ΛError], (LaTeX, [Reference]))+execLambdaTeXT func conf = do+ ((_,latex), _, output) <- runΛTeX func (ΛConfig $ generationSelection conf) initState+ let result = injectPackageDependencies (S.toList $ outputPackageDependencies output) latex+ let refs = S.toList $ outputExternalReferences output++ -- Check reference errors+ let made = outputLabelsMade output+ needed = outputLabelsNeeded output+ diff = S.difference needed made++ let referss = map ReferenceMissing $ S.toList diff++ return (referss, (result, refs))++ where+ initState :: ΛState+ initState = ΛState { stateCurrentPart = emptyPart }+++-- * Configuration++-- | Configuration of a ΛTeX project+data ProjectConfig = ProjectConfig {+ projectGenerationConfig :: GenerationConfig+ , projectBibFileName :: String+ , projectTexFileName :: String+ }++-- | Default project configuration.+--+-- Modify this instead of building your own 'ProjectConfig'+defaultProjectConfig :: ProjectConfig+defaultProjectConfig = ProjectConfig {+ projectGenerationConfig = defaultGenerationConfig+ , projectBibFileName = "main"+ , projectTexFileName = "main"+ }++-- | Configuration of ΛTeX generation+data GenerationConfig = GenerationConfig {+ generationSelection :: Selection+ }++-- | Default generation config.+--+-- Modify this instead of building your own 'GenerationConfig'+defaultGenerationConfig :: GenerationConfig+defaultGenerationConfig = GenerationConfig {+ generationSelection = [All]+ }
+ src/Text/LaTeX/LambdaTeX/Error.hs view
@@ -0,0 +1,6 @@+module Text.LaTeX.LambdaTeX.Error where++import Data.Text (Text)++data ΛError = ReferenceMissing Text+ deriving (Show, Eq)
+ src/Text/LaTeX/LambdaTeX/Package.hs view
@@ -0,0 +1,21 @@+-- | This module allows you to automatically resolve LaTeX package dependencies in your document.+--+-- Note: If you want different arguments to a package, you have to specify this by making a 'manual' 'packageDep' declaration before your document.+module Text.LaTeX.LambdaTeX.Package where++import Text.LaTeX.Base.Syntax++import qualified Data.Set as S++import Text.LaTeX.LambdaTeX.Package.Types+import Text.LaTeX.LambdaTeX.Types++-- | Declare a dependency to a package, with given arguments+packageDep :: Monad m => [LaTeX] -- ^ Arguments+ -> Text -- ^ Name of the LaTeX package+ -> ΛTeXT m ()+packageDep args name = λtell $ mempty { outputPackageDependencies = S.singleton (PackageDep name args) }++-- | Declare a dependency to a package without any arguments+packageDep_ :: Monad m => Text -> ΛTeXT m ()+packageDep_ name = packageDep [] name
+ src/Text/LaTeX/LambdaTeX/Package/Internal.hs view
@@ -0,0 +1,27 @@+module Text.LaTeX.LambdaTeX.Package.Internal where++import Text.LaTeX.Base.Syntax++import Text.LaTeX.LambdaTeX.Package.Types+import Text.LaTeX.LambdaTeX.Types++-- | Inject package dependencies into a given LaTeX document.+-- This is done by top-level functions in @Text.LaTeX.LambdaTeX@ automatically+injectPackageDependencies :: [PackageDep] -> LaTeX -> LaTeX+injectPackageDependencies ps = go+ -- We're looking for this: TeXComm "documentclass" ...+ where+ -- We have to go looking through the LaTeX :(+ go t@(TeXComm "documentclass" _) = TeXSeq t packages+ go (TeXSeq t1 t2) = TeXSeq (go t1) (go t2)+ go c = c++ packages :: LaTeX+ packages = mconcat $ map (\(PackageDep name args) -> usepackage args name) ps+++-- | Redefinition of @usepackage@ to use Text+-- Don't use this directly, use the packageDep instead!+usepackage :: [LaTeX] -> Text -> LaTeX+usepackage ls pn = TeXComm "usepackage" [MOptArg ls, FixArg $ TeXRaw pn]+
+ src/Text/LaTeX/LambdaTeX/Package/Types.hs view
@@ -0,0 +1,14 @@+module Text.LaTeX.LambdaTeX.Package.Types where++import Data.Ord (comparing)+import Data.Text (Text)++import Text.LaTeX.Base.Syntax (LaTeX)++data PackageDep = PackageDep {+ packageDepName :: Text+ , packageDepOptions :: [LaTeX]+ } deriving (Show, Eq)++instance Ord PackageDep where+ compare = comparing packageDepName
+ src/Text/LaTeX/LambdaTeX/Part.hs view
@@ -0,0 +1,15 @@+module Text.LaTeX.LambdaTeX.Part where++import Data.Text (Text)++newtype Part = Part { unPart :: [Text] }++emptyPart :: Part+emptyPart = Part { unPart = [] }++pushPart :: Part -> Text -> Part+pushPart p t = Part { unPart = unPart p ++ [t] }++popPart :: Part -> Part+popPart p = Part { unPart = init $ unPart p }+
+ src/Text/LaTeX/LambdaTeX/Reference.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE OverloadedStrings #-}+module Text.LaTeX.LambdaTeX.Reference where++import Text.LaTeX.Base.Class+import Text.LaTeX.Base.Syntax++import qualified Text.LaTeX.Base.Commands as H (label, pageref,+ ref)++import Text.LaTeX.LambdaTeX.Reference.Internal+import Text.LaTeX.LambdaTeX.Reference.Types+import Text.LaTeX.LambdaTeX.Types++-- * Internal references+-- An internal references point is defined by a label+-- It is then referenced with @ref label@+--+-- ΛTeX automatically ensures that those references are always internally consistent+-- BUT you have to make sure that you use these functions instead of the regular ones.++-- ** Labels++-- | Label a part+label :: Monad m => Text -> ΛTeXT m ()+label l = do+ fromLaTeX $ H.label $ TeXRaw l+ addLabelMade l++-- | The safe version of LaTeX's @ref@+ref :: Monad m => Text -> ΛTeXT m ()+ref l = do+ fromLaTeX $ H.ref $ TeXRaw l+ addLabelNeeded l++-- | The safe version of LaTeX's @pageref@+pageref :: Monad m => Text -> ΛTeXT m ()+pageref l = do+ fromLaTeX $ H.pageref $ TeXRaw l+ addLabelNeeded l++-- * External references+-- ** Defining references++-- TODO(kerckhove) Check for duplicate fields?++-- | Define an external reference.+-- Use 'cite' or 'nocite' to use this in your document.+makeReference :: ReferenceType -> Text -> [(Text, Text)] -> Reference+makeReference = Reference++-- ** Using references++-- | Refer to an external reference.+cite :: Monad m => Reference -> ΛTeXT m ()+cite ref = do+ fromLaTeX $ comm1 "cite" $ TeXRaw $ referenceName ref+ addReference ref++-- | Put an external reference in your list of references without using it.+nocite :: Monad m => Reference -> ΛTeXT m ()+nocite ref = do+ fromLaTeX $ comm1 "nocite" $ TeXRaw $ referenceName ref+ addReference ref++-- ** Reference Types+--+-- See [The Wiki article on which fields each of them requires](https://en.wikibooks.org/wiki/LaTeX/Bibliography_Management)+--+-- TODO(kerckhove) Generate these!+unpublished :: ReferenceType+unpublished = "unpublished"++lectureSlides :: ReferenceType+lectureSlides = "unpublished"++online :: ReferenceType+online = "online"++article :: ReferenceType+article = "article"+
+ src/Text/LaTeX/LambdaTeX/Reference/Internal.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+module Text.LaTeX.LambdaTeX.Reference.Internal where++import qualified Data.Set as S+import qualified Data.Text as T++import Text.LaTeX.LambdaTeX.Reference.Types+import Text.LaTeX.LambdaTeX.Types++-- * Internal references++-- | Declare that a label has been made+addLabelMade :: Monad m => Text -> ΛTeXT m ()+addLabelMade label = λtell $ mempty { outputLabelsMade = S.singleton label }++-- | Declare that a label is needed+addLabelNeeded :: Monad m => Text -> ΛTeXT m ()+addLabelNeeded label = λtell $ mempty { outputLabelsNeeded = S.singleton label }++-- * External references++-- | Render references to bib(La)TeX format+renderReferences :: [Reference] -> Text+renderReferences rs = (`mappend` "\n\n") . T.intercalate ",\n\n" $ map showRef rs+ where+ showRef :: Reference -> Text+ showRef r = mconcat+ [+ "@"+ , referenceType r+ , "{"+ , referenceName r+ , ",\n"+ , T.intercalate ",\n" (map showField $ referenceFields r)+ , "\n}"+ ]++ showField :: (Text, Text) -> Text+ showField (a, b) = mconcat [" ", a, " = {", b, "}"]++-- | Add a reference to a ΛTeX generator+addReference :: Monad m => Reference -> ΛTeXT m ()+addReference ref = λtell $ mempty { outputExternalReferences = S.singleton ref }
+ src/Text/LaTeX/LambdaTeX/Reference/Types.hs view
@@ -0,0 +1,16 @@+module Text.LaTeX.LambdaTeX.Reference.Types where++import Data.Ord (comparing)+import Data.Text (Text)++type ReferenceType = Text+data Reference = Reference {+ referenceType :: ReferenceType+ , referenceName :: Text+ , referenceFields :: [(Text, Text)]+ } deriving (Show, Eq)++instance Ord Reference where+ compare = comparing referenceName++
+ src/Text/LaTeX/LambdaTeX/Selection.hs view
@@ -0,0 +1,46 @@+module Text.LaTeX.LambdaTeX.Selection where++import Control.Monad (when)++import qualified Data.Text as T++import Text.LaTeX.LambdaTeX.Selection.Internal+import Text.LaTeX.LambdaTeX.Selection.Types+import Text.LaTeX.LambdaTeX.Types++-- * Making selections++-- | Construct a selection from a space-separated list of strings representing selectors+--+-- > constructSelection = map constructSelector . words+constructSelection :: String -> Selection+constructSelection = map constructSelector . words++-- | Construct a selector from a string+--+-- >>> constructSelector "all"+-- > All+--+-- >>> constructSelector "mySection.mySubsection"+-- > Match ["mySection", "mySubsection"]+--+-- >>> constructSelector "+mySection.mySubsection"+-- > Match ["mySection", "mySubsection"]+--+-- >>> constructSelector "-mySection.mySubsection"+-- > Ignore ["mySection", "mySubsection"]+constructSelector :: String -> Selector+constructSelector "all" = All+constructSelector ('+':s) = Match $ map T.pack $ split s+constructSelector ('-':s) = Ignore $ map T.pack $ split s+constructSelector s = Match $ map T.pack $ split s++-- * Using selections++-- | Declare a sub-part of the document with a name.+-- This allows you to use the subset-selection feature later.+note :: Monad m => Text -> ΛTeXT m () -> ΛTeXT m ()+note partname func = inPart partname $ do+ s <- isSelected+ when s func+
+ src/Text/LaTeX/LambdaTeX/Selection/Internal.hs view
@@ -0,0 +1,82 @@+module Text.LaTeX.LambdaTeX.Selection.Internal where++import Data.List (isPrefixOf)++import Text.LaTeX.LambdaTeX.Selection.Types+import Text.LaTeX.LambdaTeX.Types++-- | Whether a part is selected by a given list of selectors.+--+-- A part is selected if:+--+-- All parts are selected or+-- It it is matched and not ignored.+selects :: Part -> [Selector] -> Bool+selects (Part ps) ss = go ps ss False+ where+ go :: [Text] -> [Selector] -> Bool -> Bool+ go _ [] b = b+ go ps (All:ss) _ = go ps ss True+ go ps ((Match s):ss) b = if ps `matches` s+ then go ps ss True+ else go ps ss b+ go ps ((Ignore s):ss) True = if ps `matches` s+ then go ps ss False+ else go ps ss True+ go ps ((Ignore _):ss) False = go ps ss False++-- | Whether the current part is selected to be generated+isSelected :: Monad m => ΛTeXT m Bool+isSelected = do+ part <- currentPart+ sels <- λasks configSelection+ return $ selects part sels++-- * Current part Helpers++-- | Returns the current part from the ΛTeX state+currentPart :: Monad m => ΛTeXT m Part+currentPart = λgets stateCurrentPart++-- | Execute the following function with a given sub-part name+inPart :: Monad m => Text -> ΛTeXT m () -> ΛTeXT m ()+inPart partname func = do+ pushCurrentPart partname+ func+ popCurrentPart++-- | Push a new part name onto the current part stack+--+-- WARNING: This should never be used outside of 'inPart'+pushCurrentPart :: Monad m => Text -> ΛTeXT m ()+pushCurrentPart partname = λmodify (\s -> s { stateCurrentPart = pushPart (stateCurrentPart s) partname})++-- | Pop a part name off the current part stack+--+-- WARNING: This should never be used outside of 'inPart'+popCurrentPart :: Monad m => ΛTeXT m ()+popCurrentPart = λmodify (\s -> s { stateCurrentPart = popPart $ stateCurrentPart s })+++-- * Text Helpers++-- | Split a string on a dot.+-- This can be useful to convert from a 'Selector's textual representation back to a selector+--+-- > split = splitOn '.'+split :: String -> [String]+split = splitOn '.'++-- | Split a string on a specific character+splitOn :: Char -> String -> [String]+splitOn c s = go s []+ where+ go :: String -> String -> [String]+ go [] s = [s]+ go (sc:ss) acc | sc == c = acc : go [] ss+ | otherwise = go ss (acc ++ [sc])+++-- | Tests whether a given part matches a given selector's part specification+matches :: [Text] -> [Text] -> Bool+matches = flip isPrefixOf
+ src/Text/LaTeX/LambdaTeX/Selection/Types.hs view
@@ -0,0 +1,10 @@+module Text.LaTeX.LambdaTeX.Selection.Types where++import Data.Text (Text)++type Selection = [Selector]+data Selector = All+ | Match [Text]+ | Ignore [Text]+ deriving (Show, Eq)+
+ src/Text/LaTeX/LambdaTeX/Types.hs view
@@ -0,0 +1,209 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++module Text.LaTeX.LambdaTeX.Types (+ module Text.LaTeX.LambdaTeX.Types+ , module Text.LaTeX.LambdaTeX.Part+ , module Text.LaTeX.LambdaTeX.Error+ , module Text.LaTeX.LambdaTeX.Package.Types+ , module Text.LaTeX.LambdaTeX.Reference.Types+ , module Text.LaTeX.LambdaTeX.Selection.Types++#if !MIN_VERSION_base(4,8,0)+ , module Control.Applicative+ , module Data.Monoid+#endif+ , Text+ ) where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative+import Data.Monoid hiding (All)+#endif++import Control.Monad (liftM)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Reader (MonadReader (..), asks)+import Control.Monad.RWS (RWST (..))+import Control.Monad.State (MonadState (..), gets,+ modify)+import Control.Monad.Trans (MonadTrans (..), lift)+import Control.Monad.Writer (MonadWriter (..))++import Data.Set (Set)+import qualified Data.Set as S+import Data.String (IsString (..))+import Data.Text (Text)++import Text.LaTeX.Base (LaTeX, LaTeXT, runLaTeXT)+import Text.LaTeX.Base.Class (LaTeXC (..), fromLaTeX)+import Text.LaTeX.Base.Writer (extractLaTeX, textell)++import Text.LaTeX.Packages.AMSMath ()++import Text.LaTeX.LambdaTeX.Error+import Text.LaTeX.LambdaTeX.Package.Types+import Text.LaTeX.LambdaTeX.Part+import Text.LaTeX.LambdaTeX.Reference.Types+import Text.LaTeX.LambdaTeX.Selection.Types++-- * The ΛTeX Monad+type LambdaTeXT = ΛTeXT+type LambdaTeXT_ m = ΛTeXT_ m++type ΛTeXT_ m = ΛTeXT m ()++newtype ΛTeXT m a =+ ΛTeXT { unwrapΛTeXT :: LaTeXT (RWST ΛConfig ΛOutput ΛState m) a }+ deriving (Functor, Applicative, Monad)++-- TODO(kerckhove) Move and add amsmath dependency+instance (Monad m, a ~ ()) => Num (ΛTeXT m a) where+ (+) a b = ΛTeXT $ unwrapΛTeXT a + unwrapΛTeXT b+ (-) a b = ΛTeXT $ unwrapΛTeXT a - unwrapΛTeXT b+ (*) a b = ΛTeXT $ unwrapΛTeXT a * unwrapΛTeXT b+ negate = ΛTeXT . negate . unwrapΛTeXT+ fromInteger = fromLaTeX . fromInteger+ abs = ΛTeXT . abs . unwrapΛTeXT+ -- Non-defined methods+ signum = ΛTeXT . signum . unwrapΛTeXT+++-- TODO(kerckhove) Move and add amsmath dependency+instance (Monad m, a ~ ()) => Fractional (ΛTeXT m a) where+ (/) a b = ΛTeXT $ unwrapΛTeXT a / unwrapΛTeXT b+ fromRational = fromLaTeX . fromRational++-- TODO(kerckhove) Also instantiate floating?++runΛTeX :: Monad m => ΛTeXT m a -> ΛConfig -> ΛState -> m ((a, LaTeX), ΛState, ΛOutput)+runΛTeX func conf state = runRWST (runLaTeXT $ unwrapΛTeXT func) conf state++instance MonadTrans ΛTeXT where+ lift = ΛTeXT . lift . lift++instance MonadIO m => MonadIO (ΛTeXT m) where+ liftIO = lift . liftIO++instance (Monad m, a ~ ()) => LaTeXC (ΛTeXT m a) where+ liftListL f xs = mapM extractΛLaTeX_ xs >>= λtextell . f++instance (Monad m, a ~ ()) => IsString (ΛTeXT m a) where+ fromString = λtextell . fromString++instance (Monad m, a ~ ()) => Monoid (ΛTeXT m a) where+ mempty = return ()+ mappend = (>>)++λtextell :: Monad m => LaTeX -> ΛTeXT m ()+λtextell = ΛTeXT . textell++λtell :: Monad m => ΛOutput -> ΛTeXT m ()+λtell = ΛTeXT . tell++λask :: Monad m => ΛTeXT m ΛConfig+λask = λasks id++λasks :: Monad m => (ΛConfig -> a) -> ΛTeXT m a+λasks = ΛTeXT . asks++λget :: Monad m => ΛTeXT m ΛState+λget = λgets id++λgets :: Monad m => (ΛState -> a) -> ΛTeXT m a+λgets = ΛTeXT . gets++λmodify :: Monad m => (ΛState -> ΛState) -> ΛTeXT m ()+λmodify = ΛTeXT . modify++-- | This function run a 'LaTeXT' computation,+-- lifting the result again in the monad.+extractΛLaTeX :: Monad m => ΛTeXT m a -> ΛTeXT m (a,LaTeX)+extractΛLaTeX = ΛTeXT . extractLaTeX . unwrapΛTeXT++-- | Like 'extractΛLaTeX' but without the result+extractΛLaTeX_ :: Monad m => ΛTeXT m a -> ΛTeXT m LaTeX+extractΛLaTeX_ = liftM snd . extractΛLaTeX++-- | Internal ΛTeXT configration+data ΛConfig = ΛConfig {+ configSelection :: Selection+ }++-- | Internal ΛTeXT configration output+data ΛOutput = ΛOutput {+ outputPackageDependencies :: Set PackageDep+ , outputExternalReferences :: Set Reference+ , outputLabelsMade :: Set Text+ , outputLabelsNeeded :: Set Text+ }++instance Monoid ΛOutput where+ mempty = ΛOutput {+ outputPackageDependencies = S.empty+ , outputExternalReferences = S.empty+ , outputLabelsMade = S.empty+ , outputLabelsNeeded = S.empty+ }++ mappend o1 o2 = ΛOutput {+ outputPackageDependencies =+ S.union+ (outputPackageDependencies o1)+ (outputPackageDependencies o2)+ , outputExternalReferences =+ S.union+ (outputExternalReferences o1)+ (outputExternalReferences o2)+ , outputLabelsMade =+ S.union+ (outputLabelsMade o1)+ (outputLabelsMade o2)+ , outputLabelsNeeded =+ S.union+ (outputLabelsNeeded o1)+ (outputLabelsNeeded o2)+ }++-- | Internal ΛTeXT configration state+data ΛState = ΛState {+ stateCurrentPart :: Part+ }++-- Orphan Monad Transformer instances for LaTeXT+instance MonadReader r m => MonadReader r (LaTeXT m) where+ ask = lift ask+ local = local+ reader = lift . reader++instance MonadState s m => MonadState s (LaTeXT m) where+ get = lift get+ put = lift . put+ state = lift . state++instance MonadWriter w m => MonadWriter w (LaTeXT m) where+ tell = lift . tell+ listen = listen+ pass = pass+++-- Monad Transformer instances for ΛTeXT+instance MonadReader r m => MonadReader r (ΛTeXT m) where+ ask = lift ask+ local = local+ reader = lift . reader++instance MonadState s m => MonadState s (ΛTeXT m) where+ get = lift get+ put = lift . put+ state = lift . state++instance MonadWriter w m => MonadWriter w (ΛTeXT m) where+ tell = lift . tell+ listen = listen+ pass = pass+
+ src/Text/LaTeX/LambdaTeX/Utils.hs view
@@ -0,0 +1,14 @@+-- | ΛTeX utilities+module Text.LaTeX.LambdaTeX.Utils where++import Control.Exception+import System.Directory (removeFile)+import System.IO.Error (isDoesNotExistError)++-- | Remove the given file if it exists+removeIfExists :: FilePath -> IO ()+removeIfExists fileName = removeFile fileName `catch` handleExists+ where handleExists e+ | isDoesNotExistError e = return ()+ | otherwise = throwIO e+
+ test/Spec.hs view
@@ -0,0 +1,9 @@+import Control.Exception (evaluate)+import Test.Hspec+import Test.QuickCheck++main :: IO ()+main = hspec $ do+ describe "unfinished test suite" $ do+ it "is not finished yet, so here's a dummy test" $ do+ True