hyakko 0.2.1 → 0.3.0
raw patch · 3 files changed
+58/−35 lines, 3 filesdep +bytestring
Dependencies added: bytestring
Files
- hyakko.cabal +3/−2
- src/Hyakko.hs +52/−31
- src/Text/Markdown.hs +3/−2
hyakko.cabal view
@@ -1,5 +1,5 @@ name: hyakko-version: 0.2.1+version: 0.3.0 cabal-version: >= 1.6 build-type: Simple license: MIT@@ -39,7 +39,8 @@ regex-pcre >= 0.9, containers >= 0.4, directory >= 1,- pandoc >= 1.8.2+ pandoc >= 1.8.2,+ bytestring >= 0.9 hs-source-dirs: src ghc-options: -O2 -Wall main-is: Hyakko.hs
src/Hyakko.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} -- **Hyakko** is a Haskell port of [docco](http://jashkenas.github.com/docco/): -- the original quick-and-dirty, hundred-line-line, literate-programming-style -- documentation generator. It produces HTML that displays your comments@@ -19,12 +20,19 @@ -- git clone git://github.com/sourrust/hyakko.git -- cd hyakko -- cabal install+--+-- or+--+-- cabal update+-- cabal install hyakko module Main where import Text.Markdown import Data.Map (Map) import qualified Data.Map as M+import Data.ByteString.Lazy.Char8 (ByteString)+import qualified Data.ByteString.Lazy.Char8 as L import Data.List (sort, groupBy) import Data.Maybe (fromJust) import Control.Monad (filterM)@@ -41,15 +49,19 @@ -- Make type signature more readable with these two `Callback` types. type Callback = IO ()-type Callback' = [Map String String] -> IO ()+type Callback' = [Map String ByteString] -> IO () +(><) :: ByteString -> ByteString -> ByteString+(><) = L.append+{-# INLINE (><) #-}+ -- Generate the documentation for a source file by reading it in, splitting it -- up into comment/code sections, highlighting them for the appropriate language, -- and merging them into an HTML template. generateDocumentation :: [FilePath] -> IO () generateDocumentation [] = return () generateDocumentation (x:xs) = do- code <- readFile x+ code <- L.readFile x let sections = parse (getLanguage x) code if null sections then putStrLn $ "hyakko doesn't support the language extension " ++ takeExtension x@@ -69,17 +81,19 @@ -- ("codeHtml", ...) -- ] ---inSections :: [String] -> String -> [Map String String]+inSections :: [ByteString] -> ByteString -> [Map String ByteString] inSections xs r = let mkRegex' = mkRegex . (=~ r) -- Generalized function used to section off code and comments groupBy' t t1 = groupBy $ \x y -> and $ map (t1 . (=~ r)) [t x, t y] -- Replace the beggining comment symbol with nothing- replace = unlines . map (\y -> subRegex (mkRegex' y) y "")+ replace = L.unlines . map (\y ->+ let y' = L.unpack y+ in L.pack $ subRegex (mkRegex' y') y' "") -- Clump sectioned off lines into doc and code text. clump [] = [] clump [x] = clump $ ensurePair [x]- clump (x:y:ys) = [("docsText", replace x),("codeText", unlines y)] : clump ys+ clump (x:y:ys) = [("docsText", replace x),("codeText", L.unlines y)] : clump ys -- Make sure the result is in the right pairing order ensurePair ys = if even $ length ys then ys else if (head . head) ys =~ r then ys ++ [[""]] else [""]:ys@@ -93,10 +107,10 @@ s3 = ensurePair $ map concat s2 in [M.fromList l | l <- clump s3] -parse :: Maybe (Map String String) -> String -> [Map String String]+parse :: Maybe (Map String ByteString) -> ByteString -> [Map String ByteString] parse Nothing _ = [] parse (Just src) code =- let line = filter ((/=) "#!" . take 2) $ lines code+ let line = filter ((/=) "#!" . L.take 2) $ L.lines code in inSections line $ src M.! "comment" -- Highlights a single chunk of Haskell code, using **Pygments** over stdio,@@ -106,26 +120,30 @@ -- We process the entire file in a single call to Pygments by inserting little -- marker comments between each section and then splitting the result string -- wherever our markers occur.-highlight :: FilePath -> [Map String String] -> Callback' -> IO ()+highlight :: FilePath -> [Map String ByteString] -> Callback' -> IO () highlight src section cb = do let language = fromJust $ getLanguage src- options = ["-l", language M.! "name", "-f", "html", "-O", "encoding=utf-8"]- input = concatMap (\x -> x M.! "codeText"++(language M.! "dividerText")) section+ options = ["-l", L.unpack $ language M.! "name", "-f",+ "html", "-O", "encoding=utf-8"]+ input = concatMap (\x ->+ let codeText = L.unpack $ x M.! "codeText"+ divider = L.unpack $ language M.! "dividerText"+ in codeText ++ divider) section output <- readProcess "pygmentize" options input let output' = subRegex (mkRegex highlightReplace) output ""- fragments = splitRegex (mkRegex $ language M.! "dividerHtml") output'+ fragments = splitRegex (mkRegex . L.unpack $ language M.! "dividerHtml") output' cb $ map (\x -> let s = section !! x- in M.insert "docsHtml" (toHTML $ s M.! "docsText") $- M.insert "codeHtml" (highlightStart ++ (fragments !! x) +++ in M.insert "docsHtml" (toHTML . L.unpack $ s M.! "docsText") $+ M.insert "codeHtml" (highlightStart >< (L.pack $ fragments !! x) >< highlightEnd) s) [0..(length section) - 1] -- 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/hyakko.html`-generateHTML :: FilePath -> [Map String String] -> IO ()+generateHTML :: FilePath -> [Map String ByteString] -> IO () generateHTML src section = do let title = takeFileName src dest = destination src@@ -142,22 +160,22 @@ " <div class='pilwrap'>", " <a class='pilcrow' href='#section-"++show (x + 1)++"'>λ</a>", " </div>",- (section !! x) M.! "docsHtml",+ L.unpack $ (section !! x) M.! "docsHtml", " </td>", " <td class='code'>",- (section !! x) M.! "codeHtml",+ L.unpack $ (section !! x) M.! "codeHtml", " </td>", "</tr>" ])) [0..(length section) - 1] ] putStrLn $ "hyakko: " ++ src ++ " -> " ++ dest- writeFile dest html+ L.writeFile dest html -- ### Helpers & Setup -- A list of the languages that Hyakko supports, mapping the file extension to -- the name of the Pygments lexer and the symbol that indicates a comment. To -- add another language to Hyakko's repertoire, add it here.-languages :: Map String (Map String String)+languages :: Map String (Map String ByteString) languages = let hashSymbol = ("symbol", "#") l = M.fromList [@@ -175,17 +193,17 @@ -- Build out the appropriate matchers and delimiters for each language. in M.map (\x -> let s = x M.! "symbol" -- Does the line begin with a comment?- in M.insert "comment" ("^\\s*"++s++"\\s?") $+ in M.insert "comment" ("^\\s*"><s><"\\s?") $ -- The dividing token we feed into Pygments, to delimit the boundaries -- between sections.- M.insert "dividerText" ("\n"++s++"DIVIDER\n") $+ M.insert "dividerText" ("\n"><s><"DIVIDER\n") $ -- The mirror of `divider_text` that we expect Pygments to return. We can -- split on this to recover the original sections. -- Note: the class is "c" for Python and "c1" for the other languages- M.insert "dividerHtml" ("\n*<span class=\"c1?\">"++s++"DIVIDER</span>\n") x) l+ M.insert "dividerHtml" ("\n*<span class=\"c1?\">"><s><"DIVIDER</span>\n") x) l -- Get the current language we're documenting, based on the extension.-getLanguage :: FilePath -> Maybe (Map String String)+getLanguage :: FilePath -> Maybe (Map String ByteString) getLanguage src = M.lookup (takeExtension src) languages -- Compute the destination HTML path for an input source file path. If the source@@ -198,23 +216,25 @@ ensureDirectory cb = system "mkdir -p docs" >> cb -- Create the template that we will use to generate the Hyakko HTML page.-hyakkoTemplate :: [(String, String)] -> IO String+hyakkoTemplate :: [(String, String)] -> IO ByteString hyakkoTemplate var = readDataFile "resources/hyakko.html" >>=- return . renderTemplate var+ return . renderTemplate var . L.unpack -- The CSS styles we'd like to apply to the documentation.-hyakkoStyles :: IO String+hyakkoStyles :: IO ByteString hyakkoStyles = readDataFile "resources/hyakko.css" -- The start and end of each Pygments highlight block.-highlightStart, highlightEnd, highlightReplace :: String+highlightStart, highlightEnd :: ByteString highlightStart = "<div class=\"highlight\"><pre>" highlightEnd = "</pre></div>"-highlightReplace = highlightStart ++ "|" ++ highlightEnd +highlightReplace :: String+highlightReplace = L.unpack highlightStart ++ "|" ++ L.unpack highlightEnd+ -- Reads from resource path given in cabal package-readDataFile :: FilePath -> IO String-readDataFile f = getDataFileName f >>= readFile+readDataFile :: FilePath -> IO ByteString+readDataFile f = getDataFileName f >>= L.readFile -- For each source file passed in as an argument, generate the documentation. sources :: IO [FilePath]@@ -228,7 +248,8 @@ -- in sub-directories. unpackDirectories :: FilePath -> IO [FilePath] unpackDirectories d = do- content <- getDirectoryContents d >>= return . filter (=~ "[^\\.{1,2}]")+ let reg = "[^(^\\.{1,2}$)]" :: ByteString+ content <- getDirectoryContents d >>= return . filter (=~ reg) let content' = map (d </>) content files <- filterM doesFileExist content' subdir <- filterM doesDirectoryExist content'@@ -241,5 +262,5 @@ style <- hyakkoStyles source <- sources ensureDirectory $ do- writeFile "docs/hyakko.css" style+ L.writeFile "docs/hyakko.css" style generateDocumentation source
src/Text/Markdown.hs view
@@ -6,10 +6,11 @@ , defaultParserState , defaultWriterOptions )+import Data.ByteString.Lazy.Char8 (ByteString, pack) -- Function for translating Markdown to HTML since `Pandoc` has several -- different generators for other markup languages.-toHTML :: String -> String-toHTML = writeHtmlString defaultWriterOptions . parse+toHTML :: String -> ByteString+toHTML = pack . writeHtmlString defaultWriterOptions . parse where parse = readMarkdown defaultParserState {-# INLINE toHTML #-}