hyakko 0.6.4 → 0.6.5
raw patch · 6 files changed
+215/−184 lines, 6 files
Files
- hyakko.cabal +4/−2
- src/Hyakko.lhs +54/−166
- src/Hyakko/Text/Markdown.hs +16/−0
- src/Hyakko/Text/Templates.hs +98/−0
- src/Hyakko/Types.hs +43/−0
- src/Text/Markdown.hs +0/−16
hyakko.cabal view
@@ -1,5 +1,5 @@ name: hyakko-version: 0.6.4+version: 0.6.5 cabal-version: >= 1.6 build-type: Simple license: MIT@@ -50,7 +50,9 @@ resources/parallel/public/fonts/novecento-bold.ttf resources/parallel/public/fonts/novecento-bold.woff extra-source-files:- src/Text/Markdown.hs+ src/Hyakko/Text/Markdown.hs+ src/Hyakko/Text/Templates.hs+ src/Hyakko/Types.hs source-repository head type: git
src/Hyakko.lhs view
@@ -30,14 +30,15 @@ fairly easily via a [separate languages file](https://github.com/sourrust/hyakko/blob/master/resources/languages.json). -> {-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}+> {-# LANGUAGE OverloadedStrings #-} > module Main where -> import Text.Markdown+> import Hyakko.Text.Markdown+> import Hyakko.Text.Templates+> import Hyakko.Types -> import Data.Aeson-> import Data.HashMap.Strict (HashMap)+> import Data.Aeson (decode') > import qualified Data.HashMap.Strict as M > import Data.ByteString.Lazy.Char8 (ByteString) > import qualified Data.ByteString.Lazy.Char8 as L@@ -47,7 +48,7 @@ > import Data.List (sort) > import Data.Maybe (fromJust, isNothing) > import Data.Version (showVersion)-> import Control.Applicative ((<$>), (<*>), empty)+> import Control.Applicative ((<$>)) > import Control.Monad (filterM, (>=>), forM, forM_, unless) > import qualified Text.Blaze.Html as B > import Text.Blaze.Html.Renderer.Utf8 (renderHtml)@@ -81,25 +82,26 @@ > generateDocumentation :: Hyakko -> [FilePath] -> IO () > generateDocumentation _ [] = > putStrLn "hyakko: no files or options given (try --help)"-> generateDocumentation opts xs = mapM_ generate xs-> where generate :: FilePath -> IO ()-> generate x = do-> code <- T.readFile x-> dataDir <- getDataDir-> let sections = parse (getLanguage x) code-> opts' = configHyakko opts dataDir-> unless (isNothing $ layout opts') $ do-> let layoutDir = fromJust $ layout opts'-> copyDirectory opts'$ dataDir </> "resources"-> </> layoutDir-> </> "public"-> if null sections then-> putStrLn $ "hyakko doesn't support the language extension "-> ++ takeExtension x-> else do-> let highlighted = highlight x sections-> y = mapSections sections highlighted-> generateHTML opts' x y+> generateDocumentation opts xs = do+> dataDir <- getDataDir+> let opts' = configHyakko opts dataDir+> dirout = output opts'+> style <- hyakkoStyles opts'+> T.writeFile (dirout </> "hyakko.css") style+> unless (isNothing $ layout opts') $ do+> let layoutDir = fromJust $ layout opts'+> copyDirectory opts' $ dataDir </> "resources" </> layoutDir+> </> "public"+> forM_ xs $ \x -> do+> code <- T.readFile x+> let sections = parse (getLanguage x) code+> if null sections then+> putStrLn $ "hyakko doesn't support the language extension "+> ++ takeExtension x+> else do+> let highlighted = highlight x sections+> y = mapSections sections highlighted+> generateHTML opts' x y Given a string of source code, parse out eacg block of prose and the code that follows it — by detecting which is which, line by line — then create an@@ -111,20 +113,24 @@ > let sections = sectionOff "" "" xs > in map M.fromList sections -> where sectionOff :: Text -> Text -> [Text] -> [[(String, Text)]]-> sectionOff code docs [] = [ ("codeText", code)-> , ("docsText", docs)-> ] : []+> where save :: Text -> Text -> [(String, Text)]+> save code docs = [ ("codeText", code)+> , ("docsText", docs)+> ]++> sectionOff :: Text -> Text -> [Text] -> [[(String, Text)]]+> sectionOff code docs [] = save code docs : [] > sectionOff code docs (y:ys) =-> if T.unpack y =~ r then-> handleDocs code-> else-> sectionOff (code ++. y ++. "\n") docs ys+> let line = T.unpack y+> shebang = L.pack "(^#![/]|^\\s*#\\{)"+> in if line =~ r && (not $ line =~ shebang) then+> handleDocs code+> else+> sectionOff (code ++. y ++. "\n") docs ys > where handleDocs "" = handleHeaders code (newdocs docs) ys-> handleDocs _ = [ ("codeText", code)-> , ("docsText", docs)-> ] : handleHeaders "" (newdocs "") ys+> handleDocs _ = save code docs+> : handleHeaders "" (newdocs "") ys > newdocs d = d ++. (replace r y "") ++. "\n" @@ -133,9 +139,7 @@ > handleHeaders c d zs = > if T.unpack d =~ L.pack "^(---|===)+" then-> [ ("codeText", c)-> , ("docsText", d)-> ] : sectionOff "" "" zs+> save c d : sectionOff "" "" zs > else > sectionOff c d zs @@ -146,19 +150,17 @@ > parse :: Maybe Language -> Text -> Sections > parse Nothing _ = [] > parse (Just src) code =-> inSections (newlines line (literate src) True)+> inSections (fromLiterate (T.lines code) (literate src) True) > ("^\\s*" ++* symbol src ++* "\\s?")-> where line :: [Text]-> line = filter ((/=) "#!" . T.take 2) $ T.lines code Transforms a literate style language file into its normal, non-literate-style language. If it is normal, `newlines` for returns the same list of+style language. If it is normal, `fromLiterate` for returns the same list of `Text` that was passed in. -> newlines :: [Text] -> Maybe Bool -> Bool -> [Text]-> newlines [] _ _ = []-> newlines xs Nothing _ = xs-> newlines (x:xs) lit isText =+> where fromLiterate :: [Text] -> Maybe Bool -> Bool -> [Text]+> fromLiterate [] _ _ = []+> fromLiterate xs Nothing _ = xs+> fromLiterate (x:xs) lit isText = > let s = symbol src > r = "^" ++* (fromJust $ litSymbol src) ++* "\\s?" > r1 = L.pack "^\\s*$"@@ -167,7 +169,7 @@ > else > insert (T.unpack x =~ r1) isText > ((T.pack $ L.unpack s) ++. " " ++. x)-> in x': newlines xs lit y+> in x': fromLiterate xs lit y Inserts a comment symbol and a single space into the documentation line and check if the last line was code and documentation. If the previous line was@@ -206,80 +208,6 @@ > M.insert "codeHtml" (codeText x) sect > in map intoMap [0 .. sectLength] -Determine whether or not there is a `Jump to` section.--> multiTemplate :: Int -> [(String, String)]-> multiTemplate 1 = []-> multiTemplate _ = [("multi", "1")]--Produces a list of anchor tags to different files in docs. This will only-show up if the template support it and there are more than one source file-generated.--> sourceTemplate :: Hyakko -> [FilePath] -> [(String, String)]-> sourceTemplate opts = map source-> where source x = ("source", concat-> [ "<a class=\"source\" href=\""-> , takeFileName $ destination (output opts) x-> , "\">"-> , takeFileName x-> , "</a>"-> ])--Depending on the layout type, `sectionTemplate` will produce the HTML that-will be hooked into the templates layout theme.--> sectionTemplate :: Sections-> -> Maybe String-> -> [Int]-> -> [(String, String)]-> sectionTemplate section layoutType count =-> let isLayout = not $ isNothing layoutType-> sections = if isLayout then layoutFn $ fromJust layoutType-> else undefined-> in map sections count-> where layoutFn "parallel" = parallel-> layoutFn "linear" = linear-> layoutFn _ = undefined-> parallel x =-> let x' = x + 1-> sect = section !! x-> docsHtml = T.unpack $ sect M.! "docsHtml"-> codeHtml = T.unpack $ sect M.! "codeHtml"-> codeText = T.unpack $ sect M.! "codeText"-> header = docsHtml =~ L.pack "^\\s*<(h\\d)"-> isBlank = T.null $ replace "\\s" (T.pack codeText) ""-> in ("section", concat-> [ "<li id=\"section-"-> , show x'-> , "\"><div class=\"annotation\">"-> , "<div class=\"pilwrap"-> , if null header then "" else " for-" ++ tail header-> , "\"><a class=\"pilcrow\" href=\""-> , show x'-> , "\">λ</a></div>"-> , docsHtml-> , "</div>"-> , if isBlank then "" else "<div class=\"content\">"-> ++ codeHtml ++ "</div>"-> ])-> linear x =-> let sect = section !! x-> codeText = T.unpack $ sect M.! "codeText"-> isText = not $ null codeText-> in ("section", concat-> [ T.unpack $ sect M.! "docsHtml"-> , if isText then T.unpack $ sect M.! "codeHtml" else []-> ])--> cssTemplate :: Hyakko -> [(String, String)]-> cssTemplate opts =-> let maybeLayout = layout opts-> normalize = "public" </> "stylesheets" </> "normalize.css"-> otherFile = if isNothing maybeLayout then id else-> ([normalize] ++)-> in zip ["css", "css"] $ otherFile ["hyakko.css"]- Once all of the code is finished highlighting, we can generate the HTML file and write out the documentation. Pass the completed sections into the template found in `resources/linear/hyakko.html` or@@ -324,33 +252,6 @@ Helpers & Setup --------------- -The `Sections` type is just an alias to keep type signatures short.--> type Sections = [HashMap String Text]--Alias `Languages`, for the multiple different languages inside the-`languages.json` file.--> type Languages = HashMap String Language--Better data type for language info — compared to the `Object` data type in-`Aeson`.--> data Language =-> Language { name_ :: ByteString-> , symbol :: ByteString-> , literate :: Maybe Bool-> , litSymbol :: Maybe ByteString-> }--> instance FromJSON Language where-> parseJSON (Object o) = Language-> <$> o .: "name"-> <*> o .: "symbol"-> <*> o .:? "literate"-> <*> o .:? "litSymbol"-> parseJSON _ = empty- Infix functions for easier concatenation with Text and ByteString. > (++.) :: Text -> Text -> Text@@ -432,7 +333,7 @@ > files <- forM file $ \x -> do > isDir <- doesDirectoryExist x > if isDir then-> unpackDirectories x >>= return . fst+> fst <$> unpackDirectories x > else > return [x] > return . sort $ concat files@@ -443,12 +344,12 @@ > unpackDirectories :: FilePath -> IO ([FilePath], [FilePath]) > unpackDirectories d = do > let reg = L.pack "[^(^\\.{1,2}$)]"-> content <- getDirectoryContents d >>= return . filter (=~ reg)+> content <- filter (=~ reg) <$> getDirectoryContents d > let content' = map (d </>) content > files <- filterM doesFileExist content' > subdir <- filterM doesDirectoryExist content'-> subcontent <- mapM unpackDirectories subdir >>= \x ->-> return (concatMap fst x, concatMap snd x)+> subcontent <- fmap (\x -> (concatMap fst x, concatMap snd x))+> (mapM unpackDirectories subdir) > return (files ++ fst subcontent, subdir ++ snd subcontent) > copyDirectory :: Hyakko -> FilePath -> IO ()@@ -478,16 +379,6 @@ Configuration ------------- -Data structure for command line argument parsing.--> data Hyakko =-> Hyakko { layout :: Maybe String-> , output :: FilePath-> , css :: Maybe FilePath-> , template :: Maybe FilePath-> , dirOrFiles :: [FilePath]-> } deriving (Show, Data, Typeable)- Default configuration **options**. If no arguments for these flags are specifed, it will just use the ones in `defaultConfig`. @@ -524,9 +415,6 @@ > main :: IO () > main = do > opts <- cmdArgs defaultConfig-> style <- hyakkoStyles opts > source <- sources $ dirOrFiles opts-> let dirout = output opts-> createDirectoryIfMissing False dirout-> T.writeFile (dirout </> "hyakko.css") style+> createDirectoryIfMissing False $ output opts > generateDocumentation opts source
+ src/Hyakko/Text/Markdown.hs view
@@ -0,0 +1,16 @@+module Hyakko.Text.Markdown (toHTML) where++import Text.Pandoc ( readMarkdown+ , writeHtmlString+ , def+ )++import Data.Text (Text, pack)++-- Function for translating Markdown to HTML since `Pandoc` has several+-- different generators for other markup languages.+toHTML :: String -> Text+toHTML = pack . writeHTMLStr . parse+ where parse = readMarkdown def+ writeHTMLStr = writeHtmlString def+{-# INLINE toHTML #-}
+ src/Hyakko/Text/Templates.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE OverloadedStrings #-}++module Hyakko.Text.Templates where++import Hyakko.Types++import Data.ByteString.Lazy.Char8 (ByteString)+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.HashMap.Strict as M+import Data.Maybe (fromJust, isNothing)+import qualified Data.Text as T+import Data.Text (Text)+import System.FilePath (takeFileName, takeBaseName, (</>))+import Text.Regex.PCRE ((=~))++-- Determine whether or not there is a `Jump to` section.+multiTemplate :: Int -> [(String, String)]+multiTemplate 1 = []+multiTemplate _ = [("multi", "1")]++-- Produces a list of anchor tags to different files in docs. This will+-- only show up if the template support it and there are more than one+-- source file generated.+sourceTemplate :: Hyakko -> [FilePath] -> [(String, String)]+sourceTemplate opts = map source+ where source x = ("source", concat+ [ "<a class=\"source\" href=\""+ , takeFileName $ (output opts) </> (takeBaseName x) ++ ".html"+ , "\">"+ , takeFileName x+ , "</a>"+ ])++-- Depending on the layout type, `sectionTemplate` will produce the HTML+-- that will be hooked into the templates layout theme.+sectionTemplate :: Sections+ -> Maybe String+ -> [Int]+ -> [(String, String)]+sectionTemplate section layoutType count =+ let isLayout = not $ isNothing layoutType+ sections = if isLayout then layoutFn $ fromJust layoutType+ else undefined+ in map sections count+ where layoutFn "parallel" = parallel+ layoutFn "linear" = linear+ layoutFn _ = undefined++ -- Whenever the layout is sepecifed as **parallel**, this is the+ -- function that will generate the mapping for variable name and+ -- replacment value.+ parallel x =+ let x' = x + 1+ sect = section !! x+ docsHtml = T.unpack $ sect M.! "docsHtml"+ codeHtml = T.unpack $ sect M.! "codeHtml"+ codeText = T.unpack $ sect M.! "codeText"+ header = docsHtml =~ L.pack "^\\s*<(h\\d)"+ isBlank = T.null $ replace "\\s" (T.pack codeText) ""+ sectnum = "section-" ++ show x'+ in ("section", concat+ [ "<li id=\""+ , sectnum+ , "\"><div class=\"annotation\">"+ , "<div class=\"pilwrap"+ , if null header then "" else " for-" ++ tail header+ , "\"><a class=\"pilcrow\" href=\"#"+ , sectnum+ , "\">λ</a></div>"+ , docsHtml+ , "</div>"+ , if isBlank then "" else "<div class=\"content\">"+ ++ codeHtml ++ "</div>"+ ])+ where replace :: ByteString -> Text -> Text -> Text+ replace reg orig replacer =+ let str = T.unpack orig+ (_, _, rp) = str =~ reg :: (String, String, String)+ in T.append replacer (T.pack rp)++ -- Far simpler layout compared to **parallel**. This function gets+ -- called when the layout is marked as **linear**.+ linear x =+ let sect = section !! x+ codeText = T.unpack $ sect M.! "codeText"+ isText = not $ null codeText+ in ("section", concat+ [ T.unpack $ sect M.! "docsHtml"+ , if isText then T.unpack $ sect M.! "codeHtml" else []+ ])++cssTemplate :: Hyakko -> [(String, String)]+cssTemplate opts =+ let maybeLayout = layout opts+ normalize = "public" </> "stylesheets" </> "normalize.css"+ otherFile = if isNothing maybeLayout then id else+ ([normalize] ++)+ in zip ["css", "css"] $ otherFile ["hyakko.css"]
+ src/Hyakko/Types.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}++module Hyakko.Types where++import Control.Applicative ((<$>), (<*>), empty)+import Data.Aeson+import Data.ByteString.Lazy (ByteString)+import Data.HashMap.Strict (HashMap)+import Data.Text (Text)+import System.Console.CmdArgs++-- The `Sections` type is just an alias to keep type signatures short.+type Sections = [HashMap String Text]++-- Alias `Languages`, for the multiple different languages inside the+-- `languages.json` file.+type Languages = HashMap String Language++-- Better data type for language info — compared to the `Object` data type+-- in `Aeson`.+data Language =+ Language { name_ :: ByteString+ , symbol :: ByteString+ , literate :: Maybe Bool+ , litSymbol :: Maybe ByteString+ }++instance FromJSON Language where+ parseJSON (Object o) = Language+ <$> o .: "name"+ <*> o .: "symbol"+ <*> o .:? "literate"+ <*> o .:? "litSymbol"+ parseJSON _ = empty++-- Data structure for command line argument parsing.+data Hyakko =+ Hyakko { layout :: Maybe String+ , output :: FilePath+ , css :: Maybe FilePath+ , template :: Maybe FilePath+ , dirOrFiles :: [FilePath]+ } deriving (Show, Data, Typeable)
− src/Text/Markdown.hs
@@ -1,16 +0,0 @@-module Text.Markdown (toHTML) where--import Text.Pandoc ( readMarkdown- , writeHtmlString- , def- )--import Data.Text (Text, pack)---- Function for translating Markdown to HTML since `Pandoc` has several--- different generators for other markup languages.-toHTML :: String -> Text-toHTML = pack . writeHTMLStr . parse- where parse = readMarkdown def- writeHTMLStr = writeHtmlString def-{-# INLINE toHTML #-}