packages feed

heckle 2.0.1.9 → 2.0.2.0

raw patch · 7 files changed

+305/−333 lines, 7 filesdep −optparse-applicativedep −optparse-genericdep ~directoryPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: optparse-applicative, optparse-generic

Dependency ranges changed: directory

API changes (from Hackage documentation)

- Heckle: April :: Month
- Heckle: August :: Month
- Heckle: December :: Month
- Heckle: February :: Month
- Heckle: January :: Month
- Heckle: July :: Month
- Heckle: June :: Month
- Heckle: March :: Month
- Heckle: May :: Month
- Heckle: November :: Month
- Heckle: October :: Month
- Heckle: September :: Month
- Heckle: data Month
- Heckle: instance GHC.Classes.Eq Heckle.Month
- Heckle: instance GHC.Enum.Bounded Heckle.Month
- Heckle: instance GHC.Enum.Enum Heckle.Month
- Heckle: instance GHC.Show.Show Heckle.Month
- Heckle: month :: Int -> Month

Files

heckle.cabal view
@@ -1,5 +1,5 @@ name:                heckle-version:             2.0.1.9+version:             2.0.2.0 synopsis:            Jekyll in Haskell (feat. LaTeX) description:         A static site generator that supports LaTeX-PDF and Markdown-HTML posts. Care has been taken to make it configurable, easy to use, and unopinionated. @@ -18,12 +18,12 @@   location: https://github.com/2016rshah/heckle.git  library-  hs-source-dirs:    src+  hs-source-dirs:    lib   exposed-modules:   Heckle   build-depends:     base >= 4.8 && <5                    , filepath >= 1.4.0.0                    , blaze-html >= 0.8.1.1-                   , directory >=1.2 && <1.3+                   , directory >=1.2 && <1.4                    , process >= 1.2.0.0                    , split >=0.2 && <0.3                    , tagsoup >= 0.13.3@@ -33,16 +33,16 @@   default-language:  Haskell2010  executable heckle-  hs-source-dirs:    heckle+  hs-source-dirs:    src   main-is:           Main.hs   other-modules:     Files   build-depends:     base >=4.8 && <5                    , heckle-                   , directory >=1.2 && <1.3+                   , directory >=1.2 && <1.4                    , filepath >= 1.4.0.0                    , process >= 1.2.0.0                    , split >=0.2 && <0.3-                   , optparse-applicative >= 0.12.0.0 && <0.13.0.0-                   , optparse-generic ==1.1.*+                   --, optparse-applicative >= 0.12.0.0 && <0.14.0.0+                   --, optparse-generic ==1.1.*   other-extensions:  OverloadedStrings   default-language:  Haskell2010
− heckle/Files.hs
@@ -1,52 +0,0 @@-module Files where---exampleTeXPost :: String-exampleTeXPost = unlines-                 [ "\\documentclass{article}"-                 , "\\author{Rushi Shah}"-                 , "\\date{1 January 2015}"-                 , "\\title{Example LaTeX Post}"-                 , "\\begin{document}"-                 , "\\maketitle"-                 , "This is an example LaTeX/PDF post."-                 , "\\end{document}"-                 ]--exampleMDPost :: String-exampleMDPost = unlines -                [ "% Example MD Post"-                , "% Rushi Shah"-                , "% 1 January 2016"-                , ""-                , "This is an example MD/HTML post"-                ]- -exampleIndexFile :: String-exampleIndexFile = unlines-                  [ "<ul id='blog-posts'></ul>"]--exampleResFile :: String-exampleResFile = unlines-    ["<ul id=\"blog-posts\">"-    ,"    <li class=\"blog-post\">"-    ,"        <a class=\"post-link\" href=\"posts/example-markdown.html\">"-    ,"            Example MD Post"-    ,"        </a>"-    ,"        <div class=\"post-date\">"-    ,"            1 January 2016"-    ,"        </div>"-    ,"    </li>"-    ,"    <li class=\"blog-post\">"-    ,"        <a class=\"post-link\" href=\"posts/example-latex.pdf\">"-    ,"            Example Post"-    ,"        </a>"-    ,"        <div class=\"post-date\">"-    ,"            1 January 2015"-    ,"        </div>"-    ,"    </li>"-    ,"</ul>"]--exampleTemplateFile :: String-exampleTemplateFile = unlines-                  [ "<div id='blog-post'></div>"]
− heckle/Main.hs
@@ -1,102 +0,0 @@-module Main where--import Control.Exception-import Data.Either-import Data.List-import Data.Maybe-import Options.Applicative-import System.Directory-import System.FilePath-import System.Environment (getArgs)-import System.Process     (readProcess)--import Paths_heckle (version)-import Data.Version (showVersion)---import Heckle-import Files--data Command-  = Build-  | Init-  | Version--withInfo :: InfoMod a -> Parser a -> ParserInfo a-withInfo im p = info (helper <*> p) im--infixr 1 ==>-(==>) = withInfo . progDesc--mainFlags :: ParserInfo Command-mainFlags = withInfo (fullDesc <> progDesc "heckle: a simple, configurable static site generator") parser-  where-    parser :: Parser Command-    parser = subparser $ mconcat-      [ command "build" $ "Generate site"-        ==> pure Build-      , command "init" $ "Make new site template"-        ==> pure Init-      , command "version" $ "Get the package version"-        ==> pure Version-      ]--buildSite :: IO ()-buildSite = do-  putStrLn "Reading directory and turning into native posts"-  postsToBeCreated <- mapM fileToPost =<< getDirectoryContents "posts"-  let posts = reverse . sort . rights $ postsToBeCreated-  putStrLn $ "Number of posts found: " ++ show (length posts)--  putStrLn "Writing markdown files into template HTML"-  template <- readFile "template.html.hkl"-  sequence $ mapMaybe (writeHTML template) posts--  putStrLn "Creating HTML <ul> element for index file"-  let generatedHtml = postsToHtml posts--  putStrLn "Inserting HTML <ul> element into layout file"-  layoutFile <- readFile "index.html.hkl"-  let injectedOutput = layoutFile `injectIndex` generatedHtml-  case injectedOutput of-    Nothing -> putStrLn "Error with templating"-    Just s  -> do-      writeFile "index.html" s-      putStrLn "Success building!"--initSite :: IO ()-initSite = do--  -- Create the basic layout file-  writeFile "index.html.hkl" exampleIndexFile -- Change to layout when testing, index when deploying"-  writeFile "template.html.hkl" exampleTemplateFile-  writeFile "index.html" exampleResFile--  -- Create directory for posts and basic post-  createDirectoryIfMissing True "posts"-  setCurrentDirectory "posts"-  writeFile "example-markdown.md" exampleMDPost--  -- Compile the LaTeX file into a PDF-  -- Could do this for every .tex file if wanted to-  writeFile "example-latex.tex" exampleTeXPost-  x <- try (readProcess "pdflatex" ["example-latex.tex"] "")-  case x of-    Left e -> do-      let err = show (e :: IOException)-      putStrLn "Warning: LaTeX installation not found, removing LaTeX post"-      removeFile "example-latex.tex"-      return "LaTeX not found"-    Right r -> return "Success"--  putStrLn "Success initializing!"--versionOfSite :: IO ()-versionOfSite = putStrLn ("heckle " ++ showVersion version)--main = do-    command <- execParser mainFlags-    case command of-      Build -> buildSite-      Init  -> initSite-      Version -> versionOfSite
+ lib/Heckle.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE RecordWildCards            #-}+{-# LANGUAGE TypeSynonymInstances       #-}++module Heckle where++import Control.Applicative+import Control.Monad+import Data.Either+import Data.Function (on)+import Data.List.Split (splitOn)+import Data.String (IsString)+import Data.Monoid+import System.FilePath++import Text.Blaze.Html5 as H hiding (main, map)+import Text.Blaze.Html5.Attributes as A+import Text.Blaze.Html.Renderer.Pretty++import qualified Text.HTML.TagSoup as TagSoup++import Data.Time++import Text.Pandoc.Definition       hiding (Format)+import Text.Pandoc.Options          (def)+import Text.Pandoc.Readers.LaTeX    (readLaTeX)+import Text.Pandoc.Readers.Markdown (readMarkdown)+import Text.Pandoc.Shared           (stringify)+import Text.Pandoc.Writers.HTML     (writeHtmlString)++instance Show Html where+  show = renderHtml++displayDate :: UTCTime -> String+displayDate = formatTime defaultTimeLocale "%-d %B %Y"++postsToHtml :: [Post] -> Html+postsToHtml xs = do+  ul ! A.id "blog-posts" $+    forM_ xs postToHtml++postToHtml :: Post -> Html+postToHtml Post{..} = li ! class_ "blog-post" $ do+  a ! class_ "post-link" ! href (stringValue ("posts/" ++ fileName ++ ext)) $ toHtml postTitle+  H.div ! class_ "post-date" $ toHtml (displayDate postDate)+  where+    ext = getOutputExtension format++data Format = LaTeX | Markdown+  deriving (Show, Eq)++getOutputExtension :: Format -> String+getOutputExtension LaTeX    = ".pdf"+getOutputExtension Markdown = ".html"++newtype Title = Title { getTitle :: String } +  deriving (Show, Eq, IsString, ToMarkup)++data Post = Post+  { fileName    :: String  -- TODO make this more typed+  , postTitle   :: Title+  , postDate    :: UTCTime+  , format      :: Format+  , pd          :: Pandoc+  }  +  deriving (Show, Eq)++instance Ord Post where+  compare = compare `on` postDate++parseAbsoluteDate :: String -> Either String UTCTime+parseAbsoluteDate s = case parseAbsoluteDate' s of+  Just a -> Right a+  Nothing -> Left "Date does not match valid formats"+++-- | Valid formats:+-- | 6 January 2012+-- | January 6, 2012+-- | 9:47AM 6 January 2012+-- | 9:47AM January 6, 2012+parseAbsoluteDate' :: String -> Maybe UTCTime +parseAbsoluteDate' s = foldr (<|>) Nothing results  +  where+    results = map ($ s) options+    options = map (parseTimeM True defaultTimeLocale) formats+    formats = ["%-d %B %Y", "%B %-d, %Y", "%-l:%M%p %-d %B %Y", "%-l:%M%p %B %-d, %Y"]++getMeta :: (Meta -> [Inline]) -> Pandoc -> Either String String+getMeta f (Pandoc m _) = case f m of+  [] -> Left "Couldn't find it"+  xs -> Right (stringify xs)++-- | Creates a post given a constructor for a post+createPost+  :: Show a+  => Format+  -> String+  -> Either a Pandoc+  -> Either String Post+createPost _ _ (Left e) = Left (show e)+createPost format fileName (Right pd) = do+  postTitle <- Title <$> getMeta docTitle pd+  postDate  <- getMeta docDate pd >>= parseAbsoluteDate+  return Post{..}++fileToPost :: String -> IO (Either String Post)+fileToPost fileName =+  case splitExtension fileName of+    (name, ".pdf") ->+      return . createPost LaTeX name . readLaTeX def =<< readFile ("posts/" <> name <> ".tex")+    (name, ".md") ->+      return . createPost Markdown name . readMarkdown def =<< readFile ("posts/" <> fileName)+    _ -> pure (Left "Not a LaTeX or MD file")++injectIndex :: String -> Html -> Maybe String+injectIndex layout ul = injectAt [ TagSoup.TagOpen "ul" [("id","blog-posts")]+                                 , TagSoup.TagClose "ul"]+                                 layout (show ul)++injectTemplate :: String -> Post -> Maybe String+injectTemplate layout post+  | format post == Markdown = injectAt tags layout inp+  | otherwise = Nothing+  where+    tags = [TagSoup.TagOpen "div" [("id","blog-post")], TagSoup.TagClose "div"]+    inp  = "<div id='blog-post'>" <> writeHtmlString def (pd post) <> "</div>"++injectAt :: [TagSoup.Tag String] -> String -> String -> Maybe String+injectAt p layout insert = case splitOn p (TagSoup.parseTags layout) of+  [beg, end] -> Just $ TagSoup.renderTags (beg <> TagSoup.parseTags insert <> end)+  _          -> Nothing++writeHTML :: String -> Post -> Maybe (IO ())+writeHTML template p@Post{..} =+  writeFile ("posts/" <> fileName <> ".html") <$> injectTemplate template p
+ src/Files.hs view
@@ -0,0 +1,52 @@+module Files where+++exampleTeXPost :: String+exampleTeXPost = unlines+                 [ "\\documentclass{article}"+                 , "\\author{Rushi Shah}"+                 , "\\date{1 January 2015}"+                 , "\\title{Example LaTeX Post}"+                 , "\\begin{document}"+                 , "\\maketitle"+                 , "This is an example LaTeX/PDF post."+                 , "\\end{document}"+                 ]++exampleMDPost :: String+exampleMDPost = unlines +                [ "% Example MD Post"+                , "% Rushi Shah"+                , "% 1 January 2016"+                , ""+                , "This is an example MD/HTML post"+                ]+ +exampleIndexFile :: String+exampleIndexFile = unlines+                  [ "<ul id='blog-posts'></ul>"]++exampleResFile :: String+exampleResFile = unlines+    ["<ul id=\"blog-posts\">"+    ,"    <li class=\"blog-post\">"+    ,"        <a class=\"post-link\" href=\"posts/example-markdown.html\">"+    ,"            Example MD Post"+    ,"        </a>"+    ,"        <div class=\"post-date\">"+    ,"            1 January 2016"+    ,"        </div>"+    ,"    </li>"+    ,"    <li class=\"blog-post\">"+    ,"        <a class=\"post-link\" href=\"posts/example-latex.pdf\">"+    ,"            Example Post"+    ,"        </a>"+    ,"        <div class=\"post-date\">"+    ,"            1 January 2015"+    ,"        </div>"+    ,"    </li>"+    ,"</ul>"]++exampleTemplateFile :: String+exampleTemplateFile = unlines+                  [ "<div id='blog-post'></div>"]
− src/Heckle.hs
@@ -1,172 +0,0 @@-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings          #-}-{-# LANGUAGE RecordWildCards            #-}-{-# LANGUAGE TypeSynonymInstances       #-}--module Heckle where--import Control.Applicative-import Control.Monad-import Data.Bifunctor-import Data.Either-import Data.Function (on)-import Data.List-import Data.List.Split (splitOn)-import Data.String (IsString)-import Data.Monoid-import System.FilePath--import Text.Blaze.Html5 as H hiding (main, map)-import Text.Blaze.Html5.Attributes as A-import Text.Blaze.Html.Renderer.Pretty--import qualified Text.HTML.TagSoup as TagSoup--import Data.Time--- parseTimeM True defaultTimeLocale "%d %B %Y" "12 January 2016" :: Maybe UTCTime----https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Maybe.html figure out how to optionally match either with hh:mm:ss or without it---https://hackage.haskell.org/package/time-1.7/docs/Data-Time-Format.html---http://hackage.haskell.org/package/time-1.7/docs/Data-Time-Clock.html#t:UTCTime---https://hackage.haskell.org/package/time-1.7/docs/Data-Time-Format.html---https://lotz84.github.io/haskellbyexample/ex/time-formatting-parsing--- ---import Text.Pandoc.Definition hiding (Format)-import Text.Pandoc.Options          (def)-import Text.Pandoc.Readers.LaTeX    (readLaTeX)-import Text.Pandoc.Readers.Markdown (readMarkdown)-import Text.Pandoc.Shared           (stringify)-import Text.Pandoc.Writers.HTML     (writeHtmlString)--instance Show Html where-  show = renderHtml--data Month-  = January-  | February-  | March-  | April-  | May-  | June-  | July-  | August-  | September-  | October-  | November-  | December-  deriving (Show, Eq, Bounded, Enum)--month :: Int -> Month-month n = toEnum (n-1)--displayDate :: UTCTime -> String-displayDate t = formatTime defaultTimeLocale "%-d %B %Y" t---postsToHtml :: [Post] -> Html-postsToHtml xs = do-  ul ! A.id "blog-posts" $-    forM_ xs postToHtml--postToHtml :: Post -> Html-postToHtml Post{..} = li ! class_ "blog-post" $ do-  a ! class_ "post-link" ! href (stringValue ("posts/" ++ fileName ++ ext)) $ toHtml postTitle-  H.div ! class_ "post-date" $ toHtml (displayDate postDate)-  where-    ext = getOutputExtension format----data InputFormat =-data Format = LaTeX | Markdown-  deriving (Show, Eq)--getOutputExtension :: Format -> String-getOutputExtension LaTeX    = ".pdf"-getOutputExtension Markdown = ".html"---- data FileName = FileName { getFileName :: String, getExtension ::  }-newtype Title = Title { getTitle :: String } -  deriving (Show, Eq, IsString, ToMarkup)--data Post = Post-  { fileName    :: String  -- TODO make this more typed-  , postTitle   :: Title-  , postDate    :: UTCTime-  , format      :: Format-  , pd          :: Pandoc-  }  -  deriving (Show, Eq)--instance Ord Post where-  compare = compare `on` postDate--parseAbsoluteDate :: String -> Either String UTCTime-parseAbsoluteDate s = case parseAbsoluteDate' s of-  Just a -> Right a-  Nothing -> Left "Date does not match valid formats"---{---Valid formats:-6 January 2012-January 6, 2012-9:47AM 6 January 2012-9:47AM January 6, 2012---}-parseAbsoluteDate' :: String -> Maybe UTCTime -parseAbsoluteDate' s = foldr (<|>) Nothing results  -  where-    results = map ($ s) options-    options = map (parseTimeM True defaultTimeLocale) formats-    formats = ["%-d %B %Y", "%B %-d, %Y", "%-l:%M%p %-d %B %Y", "%-l:%M%p %B %-d, %Y"]--getMeta :: (Meta -> [Inline]) -> Pandoc -> Either String String-getMeta f (Pandoc m _) = case f m of-  [] -> Left "Couldn't find it"-  xs -> Right (stringify xs)---- | Creates a post given a constructor for a post-createPost-  :: Show a-  => Format-  -> String-  -> Either a Pandoc-  -> Either String Post-createPost _ _ (Left e) = Left (show e)-createPost format fileName (Right pd) = do-  postTitle <- Title <$> getMeta docTitle pd-  postDate  <- getMeta docDate pd >>= parseAbsoluteDate-  return Post{..}--fileToPost :: String -> IO (Either String Post)-fileToPost fileName =-  case splitExtension fileName of-    (name, ".pdf") ->-      return . createPost LaTeX name . readLaTeX def =<< readFile ("posts/" <> name <> ".tex")-    (name, ".md") ->-      return . createPost Markdown name . readMarkdown def =<< readFile ("posts/" <> fileName)-    _ -> pure (Left "Not a LaTeX or MD file")--injectIndex :: String -> Html -> Maybe String-injectIndex layout ul = injectAt [ TagSoup.TagOpen "ul" [("id","blog-posts")]-                                 , TagSoup.TagClose "ul"]-                                 layout (show ul)--injectTemplate :: String -> Post -> Maybe String-injectTemplate layout post-  | format post == Markdown = injectAt tags layout inp-  | otherwise = Nothing-  where-    tags = [TagSoup.TagOpen "div" [("id","blog-post")], TagSoup.TagClose "div"]-    inp  = "<div id='blog-post'>" <> writeHtmlString def (pd post) <> "</div>"--injectAt :: [TagSoup.Tag String] -> String -> String -> Maybe String-injectAt p layout insert = case splitOn p (TagSoup.parseTags layout) of-  [beg, end] -> Just $ TagSoup.renderTags (beg <> TagSoup.parseTags insert <> end)-  _          -> Nothing--writeHTML :: String -> Post -> Maybe (IO ())-writeHTML template p@Post{..} =-  writeFile ("posts/" <> fileName <> ".html") <$> injectTemplate template p
+ src/Main.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE CPP #-}+module Main where++import Control.Exception+import Data.Either+import Data.List+import Data.Maybe+--import Options.Applicative+import System.Directory+import System.FilePath+import System.Environment (getArgs)+import System.Process     (readProcess)++import Paths_heckle (version)+import Data.Version (showVersion)+-- #if MIN_VERSION_optparse_applicative(0,13,0)+-- versions before optparse-applicative-0.13 reexported (<>) themselves+import Data.Monoid ((<>))+-- #endif++import Heckle+import Files++-- data Command+--   = Build+--   | Init+--   | Version++-- withInfo :: InfoMod a -> Parser a -> ParserInfo a+-- withInfo im p = info (helper <*> p) im++-- infixr 1 ==>+-- (==>) = withInfo . progDesc++-- mainFlags :: ParserInfo Command+-- mainFlags = withInfo (fullDesc <> progDesc "heckle: a simple, configurable static site generator") parser+--   where+--     parser :: Parser Command+--     parser = subparser $ mconcat+--       [ command "build" $ "Generate site"+--         ==> pure Build+--       , command "init" $ "Make new site template"+--         ==> pure Init+--       , command "version" $ "Get the package version"+--         ==> pure Version+--       ]++buildSite :: IO ()+buildSite = do+  putStrLn "Reading directory and turning into native posts"+  postsToBeCreated <- mapM fileToPost =<< getDirectoryContents "posts"+  let posts = reverse . sort . rights $ postsToBeCreated+  putStrLn $ "Number of posts found: " ++ show (length posts)++  putStrLn "Writing markdown files into template HTML"+  template <- readFile "template.html.hkl"+  sequence $ mapMaybe (writeHTML template) posts++  putStrLn "Creating HTML <ul> element for index file"+  let generatedHtml = postsToHtml posts++  putStrLn "Inserting HTML <ul> element into layout file"+  layoutFile <- readFile "index.html.hkl"+  let injectedOutput = layoutFile `injectIndex` generatedHtml+  case injectedOutput of+    Nothing -> putStrLn "Error with templating"+    Just s  -> do+      writeFile "index.html" s+      putStrLn "Success building!"++initSite :: IO ()+initSite = do++  -- Create the basic layout file+  writeFile "index.html.hkl" exampleIndexFile -- Change to layout when testing, index when deploying"+  writeFile "template.html.hkl" exampleTemplateFile+  writeFile "index.html" exampleResFile++  -- Create directory for posts and basic post+  createDirectoryIfMissing True "posts"+  setCurrentDirectory "posts"+  writeFile "example-markdown.md" exampleMDPost++  -- Compile the LaTeX file into a PDF+  -- Could do this for every .tex file if wanted to+  writeFile "example-latex.tex" exampleTeXPost+  x <- try (readProcess "pdflatex" ["example-latex.tex"] "")+  case x of+    Left e -> do+      let err = show (e :: IOException)+      putStrLn "Warning: LaTeX installation not found, removing LaTeX post"+      removeFile "example-latex.tex"+      return "LaTeX not found"+    Right r -> return "Success"++  putStrLn "Success initializing!"++versionOfSite :: IO ()+versionOfSite = putStrLn ("heckle " ++ showVersion version)++main = do+    --command <- execParser mainFlags+  args <- getArgs+  case args of+      "build":[] -> buildSite+      "init":[] -> initSite+      "version":[] -> versionOfSite+      otherwise -> putStrLn "Command not recognized"