pencil 0.1.2 → 0.1.3
raw patch · 4 files changed
+77/−40 lines, 4 filesdep −feeddep ~doctestdep ~hsassdep ~pandoc
Dependencies removed: feed
Dependency ranges changed: doctest, hsass, pandoc, yaml
Files
- CHANGELOG.md +5/−0
- README.md +13/−3
- pencil.cabal +9/−8
- src/Pencil/Internal/Pencil.hs +50/−29
CHANGELOG.md view
@@ -4,6 +4,11 @@ ## [Unreleased] +## [0.1.3]++### Changed+- Updated dependencies. Should be able to use with recent versions of Stack LTS releases and Nix channels.+ ## [0.1.2] ### Added
README.md view
@@ -1,4 +1,4 @@-[](https://travis-ci.org/elben/pencil)+[](https://circleci.com/gh/elben/pencil/tree/master) # Pencil @@ -14,13 +14,23 @@ > marble topped tables, the smell of early morning... and luck were all you > needed. — Ernest Hemingway, A Moveable Feast +# Setup++First, make sure you have `nix` installed:++```bash+curl https://nixos.org/nix/install | sh+nix-channel --add https://nixos.org/channels/nixos-18.09 nixpkgs+nix-channel --update+```+ # Examples Checkout the [examples provided](https://github.com/elben/pencil/tree/master/examples). To run the [Simple](https://github.com/elben/pencil/tree/master/examples/Simple) example: ```-stack build-stack exec pencil-example-simple+nix-shell --attr env+[nix-shell]$ cabal new-run pencil-example-simple ``` Open the `examples/Simple/out/` folder to see the rendered web pages. To serve
pencil.cabal view
@@ -1,5 +1,5 @@ name: pencil-version: 0.1.2+version: 0.1.3 synopsis: Static site generator description: Pencil is a static site generator. Use it to generate your personal website!@@ -29,12 +29,11 @@ , data-default >= 0.7 && < 1 , directory >= 1.2.5.0 && < 1.4 , edit-distance >= 0.2.2.1 && < 0.3- , feed >= 0.3.12.0 && < 1 , filepath >= 1.4 && < 1.5 , hashable >= 1.2.6.0 && < 1.3- , hsass >= 0.4.0 && < 0.5+ , hsass >= 0.8 && < 1 , mtl >= 2.2 && < 3- , pandoc >= 1.19.2.4 && < 2+ , pandoc >= 2.0 && < 3 , semigroups >= 0.18.2 && < 0.19 , parsec >= 3.1 && < 3.2 , text >= 1.2.2 && < 1.3@@ -42,7 +41,7 @@ , unordered-containers >= 0.2.7.2 && < 0.3 , vector >= 0.12.0 && < 0.13 , xml >= 1.3.10 && < 1.4- , yaml >= 0.8.23 && < 0.9+ , yaml >= 0.8.32 && < 0.12 default-language: Haskell2010 test-suite pencil-test@@ -51,11 +50,12 @@ main-is: Spec.hs build-depends: base >= 4.8 && < 5 , pencil- , doctest >= 0.11.4 && < 0.12+ , doctest >= 0.16.0.1 && < 1 ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N default-language: Haskell2010 -executable pencil-example-simple+test-suite pencil-example-simple+ type: exitcode-stdio-1.0 hs-source-dirs: examples/Simple main-is: Main.hs ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N@@ -63,7 +63,8 @@ , pencil default-language: Haskell2010 -executable pencil-example-blog+test-suite pencil-example-blog+ type: exitcode-stdio-1.0 hs-source-dirs: examples/Blog main-is: Main.hs ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
src/Pencil/Internal/Pencil.hs view
@@ -32,6 +32,8 @@ import qualified System.Directory as D import qualified System.FilePath as FP import qualified Text.Pandoc as P+import qualified Text.Pandoc.Highlighting+import Text.Pandoc.Extensions (enableExtension, Extension(..)) import qualified Text.Sass as Sass -- | The main monad transformer stack for a Pencil application.@@ -76,8 +78,10 @@ -- , 'configEnv' = HashMap.empty -- , 'configDisplayValue' = 'toText' -- , 'configSassOptions' = Text.Sass.Options.defaultSassOptions--- , 'configPandocReaderOptions' = Text.Pandoc.def--- , 'configPandocWriterOptions' = Text.Pandoc.def { Text.Pandoc.writerHighlight = True }+-- , 'configPandocReaderOptions' = Text.Pandoc.def {+-- Text.Pandoc.readerExtensions = Text.Pandoc.Extensions.getDefaultExtensions "markdown"+-- }+-- , 'configPandocWriterOptions' = Text.Pandoc.def { Text.Pandoc.writerHighlightStyle = Just Text.Pandoc.Highlighting.monochrome } -- , 'configDisplayValue = 'toText' -- } -- @@@ -88,8 +92,15 @@ , configOutputDir = "out/" , configEnv = H.empty , configSassOptions = Text.Sass.Options.defaultSassOptions- , configPandocReaderOptions = P.def- , configPandocWriterOptions = P.def { P.writerHighlight = True }++ -- For markdown reader. We use getDefaultExtensions "markdown" here to get default Markdown extensions.+ -- See https://hackage.haskell.org/package/pandoc-2.5/docs/Text-Pandoc-Extensions.html#v:getDefaultExtensions+ , configPandocReaderOptions = P.def {+ P.readerExtensions = P.getDefaultExtensions "markdown"+ }+ , configPandocWriterOptions = P.def {+ P.writerHighlightStyle = Just Text.Pandoc.Highlighting.monochrome+ } , configDisplayValue = toText } @@ -188,34 +199,38 @@ run app config = do e <- runExceptT $ runReaderT app config case e of- Left err ->- case err of- FileNotFound mfp ->- case mfp of- Just fp -> do- e2 <- runExceptT $ runReaderT (mostSimilarFile fp) config- case e2 of- Left _ -> return ()- Right mBest ->- case mBest of- Just best -> putStrLn ("Maybe you mean this: " ++ best)- Nothing -> return ()- Nothing -> return ()- VarNotInEnv var fp ->- putStrLn ("Variable ${" ++ T.unpack var ++ "}" ++ " not found in the environment when rendering file " ++ fp ++ ".")+ Left (VarNotInEnv var fp) ->+ putStrLn ("Variable ${" ++ T.unpack var ++ "}" ++ " not found in the environment when rendering file " ++ fp ++ ".")+ Left (FileNotFound (Just fp)) -> do+ e2 <- runExceptT $ runReaderT (mostSimilarFiles fp) config+ case e2 of+ Right closestFiles ->+ if not (null closestFiles)+ then do+ putStrLn ("File " ++ fp ++ " not found. Maybe you meant: ")+ printAsList (take 3 closestFiles)+ else putStrLn ("File " ++ fp ++ " not found.") _ -> return ()- Right _ -> return ()+ _ -> return () +-- Print the list of Strings, one line at a time, prefixed with "-".+printAsList :: [String] -> IO ()+printAsList [] = return ()+printAsList (a:as) = do+ putStr "- "+ putStrLn a+ printAsList as+ -- | Given a file path, look at all file paths and find the one that seems most -- similar.-mostSimilarFile :: FilePath -> PencilApp (Maybe FilePath)-mostSimilarFile fp = do+mostSimilarFiles :: FilePath -> PencilApp [FilePath]+mostSimilarFiles fp = do sitePrefix <- asks getSourceDir fps <- listDir True "" let fps' = map (sitePrefix ++) fps -- add site prefix for distance search let costs = map (\f -> (f, levenshteinDistance defaultEditCosts fp f)) fps' let sorted = L.sortBy (\(_, d1) (_, d2) -> compare d1 d2) costs- return $ fst <$> M.listToMaybe sorted+ return $ map fst sorted -- | Known Pencil errors that we know how to either recover from or quit -- gracefully.@@ -425,6 +440,11 @@ isNoSuchFile :: IOError -> Bool isNoSuchFile e = ioe_type e == NoSuchThing +readMarkdownWriteHtml :: P.PandocMonad m => P.ReaderOptions -> P.WriterOptions -> T.Text -> m T.Text+readMarkdownWriteHtml readerOptions writerOptions content = do+ pandoc <- P.readMarkdown readerOptions content+ P.writeHtml5String writerOptions pandoc+ -- | Loads and parses the given file path. Converts 'Markdown' files to HTML, -- compiles 'Sass' files into CSS, and leaves everything else alone. parseAndConvertTextFiles :: FilePath -> PencilApp (T.Text, [PNode])@@ -435,9 +455,10 @@ Markdown -> do pandocReaderOptions <- asks getPandocReaderOptions pandocWriterOptions <- asks getPandocWriterOptions- case P.readMarkdown pandocReaderOptions (T.unpack content) of+ result <- liftIO $ P.runIO (readMarkdownWriteHtml pandocReaderOptions pandocWriterOptions content)+ case result of Left _ -> return content- Right pandoc -> return $ T.pack $ P.writeHtmlString pandocWriterOptions pandoc+ Right text -> return text Sass -> do sassOptions <- asks getSassOptions sitePrefix <- asks getSourceDir@@ -589,7 +610,7 @@ -> FilePath -> PencilApp [FilePath] listDir recursive dir = do- let dir' = FP.addTrailingPathSeparator dir+ let dir' = if null dir then dir else FP.addTrailingPathSeparator dir fps <- listDir_ recursive dir' return $ map (dir' ++) fps @@ -770,7 +791,7 @@ -- wasn't a text file, then return a Passthroguh resource. This is where we -- finally handle the "checked" exception; that is, converting the Left error -- case (NotTextFile) into a Right case (Passthrough).- liftM Single (load fpf fp)+ fmap Single (load fpf fp) `catchError` handle -- 'handle' requires FlexibleContexts where handle e = case e of@@ -814,13 +835,13 @@ let env = findEnv nodes let fp' = "/" ++ fpf fp let env' = H.insert "this.url" (VText (T.pack fp')) env- return $ Page nodes env' ("/" ++ fpf fp)+ return $ Page nodes env' fp' -- | Find preamble node, and load as an Env. If no preamble is found, return a -- blank Env. findEnv :: [PNode] -> Env findEnv nodes =- aesonToEnv $ M.fromMaybe H.empty (findPreambleText nodes >>= (A.decode . encodeUtf8 . T.strip))+ aesonToEnv $ M.fromMaybe H.empty (findPreambleText nodes >>= (A.decodeThrow . encodeUtf8 . T.strip)) -- | Loads and renders file as CSS. --