BlogLiterately-diagrams (empty) → 0.1.0.0
raw patch · 5 files changed
+288/−0 lines, 5 filesdep +BlogLiteratelydep +BlogLiterately-diagramsdep +basesetup-changed
Dependencies added: BlogLiterately, BlogLiterately-diagrams, base, containers, diagrams-builder, diagrams-cairo, diagrams-lib, filepath, pandoc, safe
Files
- BlogLiterately-diagrams.cabal +87/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- src/Text/BlogLiterately/Diagrams.hs +164/−0
- src/tools/BlogLiteratelyD.hs +5/−0
+ BlogLiterately-diagrams.cabal view
@@ -0,0 +1,87 @@+name: BlogLiterately-diagrams+version: 0.1.0.0+synopsis: Include images in blog posts with inline diagrams code+description: A plugin for @BlogLiterately@ (<http://hackage.haskell.org/package/BlogLiterately>) which turns inline diagrams+ code into images.+ This library also provides an executable,+ @BlogLiteratelyD@, providing a standard instance+ of @BlogLiterately@ extended with support for+ inline diagrams code (and also including a pass+ to center block-level images). For most users it+ should suffice to simply use @BlogLiteratelyD@ in+ place of @BlogLiterately@.+ .+ To use it, include code blocks with the @dia@ or+ @dia-def@ class (using pandoc's special extended+ Markdown syntax+ (<http://johnmacfarlane.net/pandoc/demo/example9/pandocs-markdown.html>),+ or BlogLiterately's extended syntax for tagged+ code blocks+ (<http://byorgey.wordpress.com/blogliterately/>)),+ like so:+ .+ > [dia-def]+ > -- This block produces no output but its+ > -- declarations will be in scope in all the+ > -- rest of the diagram blocks.+ >+ > gSq = square 1 # fc green+ >+ > NOTE: Square brackets below should be replaced+ > by curly braces. Haddock chokes on curly+ > braces.+ >+ > Here is a green square:+ > + > ```[.dia width='200']+ > dia = gSq+ > ```+ > + > Green squares like `gSq`[.dia height='16']+ > and blue circles like `circle 1 # fc blue`[.dia height='16']+ > are extremely important.+ .+ Note that attributes like width and height can+ also be specified, but be sure to put the numbers+ in quotes or else they will not parse properly.+ .+ Running this through @BlogLiteratelyD@ (after+ replacing square brackets with curly braces)+ should result in HTML that looks something like+ this:+ .+ <<http://projects.haskell.org/diagrams/hosted/BLD-post-result.png>>+license: BSD3+license-file: LICENSE+author: Brent Yorgey+maintainer: byorgey@cis.upenn.edu+copyright: Copyright 2012 Brent Yorgey+category: Web+build-type: Simple+cabal-version: >=1.10++source-repository head+ type: darcs+ location: http://code.haskell.org/~byorgey/code/BlogLiterately-diagrams++library+ default-language: Haskell2010+ exposed-modules: Text.BlogLiterately.Diagrams+ build-depends: base >= 4.3 && < 4.6,+ containers,+ filepath,+ diagrams-cairo >= 0.5 && < 0.6,+ diagrams-builder ==0.2.*,+ diagrams-lib ==0.5.*,+ BlogLiterately ==0.5.*,+ pandoc ==1.9.*,+ safe ==0.3.*+ hs-source-dirs: src++executable BlogLiteratelyD+ build-depends: base,+ BlogLiterately >= 0.5.2 && < 0.6,+ BlogLiterately-diagrams+ main-is: BlogLiteratelyD.hs+ hs-source-dirs: src/tools+ default-language: Haskell2010
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, Brent Yorgey++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 Brent Yorgey 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Text/BlogLiterately/Diagrams.hs view
@@ -0,0 +1,164 @@+-----------------------------------------------------------------------------+-- |+-- Module : Text.BlogLiterately.Diagrams+-- Copyright : (c) Brent Yorgey 2012+-- License : BSD-style (see LICENSE)+-- Maintainer : Brent Yorgey <byorgey@gmail.com>+--+-- Custom transformation passes for the @BlogLiterately@ blog-writing+-- tool (<http://hackage.haskell.org/package/BlogLiterately>),+-- allowing inclusion of inline code using the @diagrams@ framework+-- (<http://projects.haskell.org/diagrams>) which are compiled into+-- images. See "Text.BlogLiterately.Run" for more information.+--+-- Note that this package provides an executable, @BlogLiteratelyD@,+-- which uses the transformation pipeline+--+-- > (diagramsInlineXF : diagramsXF : centerImagesXF : standardTransforms)+-----------------------------------------------------------------------------++module Text.BlogLiterately.Diagrams+ ( diagramsXF, diagramsInlineXF+ ) where++import Control.Arrow+import Data.List (isPrefixOf)+import qualified Data.Map as M+import Safe (readMay, headDef)+import System.FilePath+import System.IO (stderr, hPutStrLn)++import Diagrams.Backend.Cairo+import Diagrams.Backend.Cairo.Internal+import Diagrams.Builder+import Diagrams.Prelude (R2, zeroV)+import Diagrams.TwoD.Size ( SizeSpec2D(Dims), mkSizeSpec )+import Text.BlogLiterately+import Text.Pandoc++-- | Transform a blog post by looking for code blocks with class+-- @dia@, and replacing them with images generated by evaluating the+-- identifier @dia@ and rendering the resulting diagram. In+-- addition, blocks with class @dia-def@ are collected (and deleted+-- from the output) and provided as additional definitions that will+-- be in scope during evaluation of all @dia@ blocks.+--+-- Be sure to use this transform /before/ the standard+-- 'Text.BlogLiterately.Transform.highlightXF' transform, /i.e./+-- with the 'Text.BlogLiterately.Run.blogLiteratelyCustom' function.+-- For example,+--+-- > main = blogLiteratelyCustom (diagramsXF : standardTransforms)+--+-- It also works well in conjunction with+-- 'Text.BlogLiterately.Transform.centerImagesXF' (which, of course,+-- should be placed after @diagramsXF@ in the pipeline). This+-- package provides an executable @BlogLiteratelyD@ which+-- includes @diagramsInlineXF@, @diagramsXF@, and @centerImagesXF@.+diagramsXF :: Transform+diagramsXF = Transform (\bl -> Kleisli $ renderBlockDiagrams bl) (const True)++renderBlockDiagrams :: BlogLiterately -> Pandoc -> IO Pandoc+renderBlockDiagrams _ p = bottomUpM (renderBlockDiagram defs) p+ where+ defs = queryWith extractDiaDef p++-- | Transform a blog post by looking for /inline/ code snippets with+-- class @dia@, and replacing them with images generated by+-- evaluating the contents of each code snippet as a Haskell+-- expression representing a diagram. Any code blocks with class+-- @dia-def@ will be in scope for the evaluation of these+-- expressions (such code blocks are unaffected).+--+-- Because @diagramsXF@ and @diagramsInlineXF@ both use blocks with+-- class @dia-def@, but @diagramsInlineXF@ leaves them alone whereas+-- @diagramsXF@ deletes them, @diagramsInlineXF@ must be placed+-- before @diagramsXF@ in the pipeline.+diagramsInlineXF :: Transform+diagramsInlineXF = Transform (\bl -> Kleisli $ renderInlineDiagrams bl) (const True)++renderInlineDiagrams :: BlogLiterately -> Pandoc -> IO Pandoc+renderInlineDiagrams _ p = bottomUpM (renderInlineDiagram defs) p+ where+ defs = queryWith extractDiaDef p++extractDiaDef :: Block -> [String]+extractDiaDef (CodeBlock (_, as, _) s)+ = [src | "dia-def" `elem` (maybe id (:) tag) as]+ where+ (tag, src) = unTag s++extractDiaDef b = []++diaDir = "diagrams" -- XXX make this configurable++-- | Given some code with declarations, some attributes, and an+-- expression to render, render it and return the filename of the+-- generated image (or an error message).+renderDiagram :: [String] -- ^ Declarations+ -> String -- ^ Expression to render+ -> Attr -- ^ Code attributes+ -> IO (Either String FilePath)+renderDiagram decls expr attr@(ident, cls, fields) = do+ res <- buildDiagram+ Cairo+ (zeroV :: R2)+ (CairoOptions "default.png" size PNG)+ decls+ (expr ++ " {- " ++ show attr ++ " -}")+ -- the above hack is to make sure that changing+ -- attributes results in the diagram being recompiled.+ []+ ["Diagrams.Backend.Cairo"]+ (hashedRegenerate+ (\hash opts -> opts { cairoFileName = mkFile hash })+ diaDir+ )+ case res of+ ParseErr err -> do+ let errStr = "\nParse error:\n" ++ err+ putErrLn errStr+ return (Left errStr)+ InterpErr ierr -> do+ let errStr = "\nInterpreter error:\n" ++ ppInterpError ierr+ putErrLn errStr+ return (Left errStr)+ Skipped hash -> return (Right $ mkFile hash)+ OK hash (act,_) -> act >> return (Right $ mkFile hash)++ where+ size = mkSizeSpec+ (lookup "width" fields >>= readMay)+ (lookup "height" fields >>= readMay)+ mkFile base = diaDir </> base <.> "png"++renderBlockDiagram :: [String] -> Block -> IO Block+renderBlockDiagram defs c@(CodeBlock attr@(_, cls, _) s)+ | "dia-def" `elem` tags = return Null+ | "dia" `elem` tags = do+ res <- renderDiagram (src : defs) "pad 1.1 dia" attr+ case res of+ Left err -> return (CodeBlock attr (s ++ err))+ Right file -> return $ Para [Image [] (file, "")]++ | otherwise = return c++ where+ (tag, src) = unTag s+ tags = (maybe id (:) tag) cls++renderBlockDiagram _ b = return b++renderInlineDiagram :: [String] -> Inline -> IO Inline+renderInlineDiagram defs c@(Code attr@(_, cls, _) expr)+ | "dia" `elem` cls = do+ res <- renderDiagram defs expr attr+ case res of+ Left err -> return (Code attr (expr ++ err))+ Right file -> return $ Image [] (file, "")+ | otherwise = return c++renderInlineDiagram _ i = return i++putErrLn :: String -> IO ()+putErrLn = hPutStrLn stderr
+ src/tools/BlogLiteratelyD.hs view
@@ -0,0 +1,5 @@+import Text.BlogLiterately+import Text.BlogLiterately.Diagrams++main = blogLiteratelyCustom+ (diagramsInlineXF : diagramsXF : centerImagesXF : standardTransforms)