This tool turns the markdown and literate Haskell into the HTML that makes up the website and the README.md for GitHub and for Hackage (based on the index.md for the website) and the test suite based on the tutorial.
The tool is self-testing: run it with no arguments (or cabal test
).
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Main
( mainwhere
)
import Control.Applicative
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as LBS
import Data.IORef
import qualified Data.List as L
import Data.Maybe
import qualified Data.Monoid as M
import qualified Data.Text as T
import Network.HTTP.Conduit
import Prelude.Compat
import qualified Shelly as SH
import System.Directory
import System.Environment
import System.FilePath
import System.IO
import TestKit
import Text.Heredoc
import Text.RE.Replace
import Text.RE.TDFA.ByteString.Lazy
import qualified Text.RE.TDFA.String as TS
import Text.RE.Tools.Grep
import Text.RE.Tools.Sed
main :: IO ()
= do
main <- getArgs
as case as of
-> test
[] "test"] -> test
["doc",fn,fn'] | is_file fn -> doc fn fn'
["gen",fn,fn'] | is_file fn -> gen fn fn'
["badges"] -> badges
["blog-badge"] -> blog_badge
["pages"] -> pages
["all"] -> gen_all
[-> usage
_ where
= not . (== "--") . take 2
is_file
= prepare_tutorial Doc fn fn'
doc fn fn' = genMode >>= \gm -> prepare_tutorial gm fn fn'
gen fn fn'
= do
usage <- getProgName
pnm let prg = ((" "++pnm++" ")++)
$ unlines
hPutStr stderr "usage:"
[ "--help"
, prg "[test]"
, prg "badges"
, prg "blog-badge"
, prg "pages"
, prg "all"
, prg "doc (-|<in-file>) (-|<out-file>)"
, prg "gen (-|<in-file>) (-|<out-file>)"
, prg ]
gen_all :: IO ()
= do
gen_all -- prepare HTML docs for the (literate) tools
"re-gen-cabals"
pd "re-gen-modules"
pd "re-include"
pd "re-nginx-log-processor"
pd "re-prep"
pd "re-sort-imports"
pd "re-top"
pd "re-tests"
pd "TestKit"
pd "RE/REOptions"
pd "RE/Tools/Edit"
pd "RE/Tools/Grep"
pd "RE/Tools/Sed"
pd "RE/ZeInternals/NamedCaptures"
pd "RE/ZeInternals/Replace"
pd "RE/ZeInternals/TestBench"
pd "RE/ZeInternals/Tools/Lex"
pd "RE/ZeInternals/Types/IsRegex"
pd "RE/ZeInternals/Types/Matches"
pd "RE/ZeInternals/Types/Match"
pd "RE/ZeInternals/Types/Capture"
pd -- render the tutorial in HTML
False "tmp"
createDirectoryIfMissing "tutorial"
gen_tutorial "tutorial-options"
gen_tutorial "tutorial-replacing"
gen_tutorial "tutorial-testbench"
gen_tutorial "tutorial-tools"
gen_tutorial
pageswhere
= case (mtch !$$? [cp|fdr|],mtch !$$? [cp|mnm|]) of
pd fnm Nothing ,Just mnm) -> pandoc_lhs ("Text.RE." ++mnm) ("Text/" ++fnm++".lhs") ("docs/"++mnm++".html")
(Just fdr,Just mnm) -> pandoc_lhs ("Text.RE."++fdr++"."++mnm) ("Text/" ++fnm++".lhs") ("docs/"++mnm++".html")
(-> pandoc_lhs ("examples/"++fnm++".lhs" ) ("examples/"++fnm++".lhs") ("docs/"++fnm++".html")
_ where
= fnm TS.?=~ [re|^RE/(${fdr}([a-zA-Z/]+)/)?${mnm}(@{%id})|] mtch
gen_tutorial :: String -> IO ()
= do
gen_tutorial nm Doc ("examples" </> mst) ("tmp" </> tgt)
prepare_tutorial
pandoc_lhs' tgt"examples" </> tgt)
("tmp" </> tgt)
("docs" </> htm)
(-- generate the tutorial-based tests
<- genMode
gm "examples" </> mst) ("examples" </> tgt)
prepare_tutorial gm (putStrLn $ ">> " ++ ("examples" </> tgt)
where
= "re-" ++ nm ++ ".lhs"
tgt = "re-" ++ nm ++ ".html"
htm = "re-" ++ nm ++ "-master.lhs" mst
-- | the MODE determines whether we are generating documentation
-- or a Haskell testsuite and includes any IO-accessible state
-- needed by the relevant processor
data MODE
= Doc -- ^ generating mardown+lhs input for pandoc
| Gen GenState -- ^ adjusting-the-program-for-testing state
The DocState
is initialised to Outside
and flips though the different states as it traverses a code block, so that we can wrap code blocks in special <div class="replcodeblock">
blocks when their first line indicates that it contains a REPL calculation, which the style sheet can pick up and present accordingly.
-- | the state is the accumulated test function identifiers for
-- generating the list of them gets added to the end of the programme
type GenState = IORef [String]
genMode :: IO MODE
= Gen <$> newIORef [] genMode
prepare_tutorial :: MODE -> FilePath -> FilePath -> IO ()
=
prepare_tutorial mode fp_in fp_out >>= prep_tutorial_pp mode >>= incld >>=
LBS.readFile fp_in . sortImports
LBS.writeFile fp_out where
= case mode of
incld Doc -> include_code_pp
Gen _ -> return
prep_tutorial_pp :: MODE -> LBS.ByteString -> IO LBS.ByteString
=
prep_tutorial_pp mode $ Select
sed' LineEdit [re|^%main ${arg}(top|bottom)$|] $ main_ mode
[ LineEdit [re|^import *TestKit$|] $ hide mode
, LineEdit [re|^\{-# OPTIONS_GHC -fno-warn-missing-signatures *#-\}$|] $ hide mode
, Function [re|^${fn}(evalme@{%id}) += +(checkThis|checkThisWith +@{%id}) +${arg}(@{%string}) +\(${ans}([^)]+)\) +\$ +\(${exp}(.*)\)$|]
, TOP $ evalme mode
Function [re|^${fn}(evalme@{%id}) += +(checkThis|checkThisWith +@{%id}) +${arg}(@{%string}) +\(${ans}([^)]+)\) +\$ +${exp}(.*)$|]
, TOP $ evalme mode
Function [re|^.*$|] TOP $ passthru
, ]
evalme :: MODE
-> LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
Doc = evalmeDoc
evalme Gen gs) = evalmeGen gs
evalme (
main_ :: MODE
-> LineNo
-> Matches LBS.ByteString
-> IO (LineEdit LBS.ByteString)
Doc = delete
main_ Gen gs) = mainGen gs
main_ (
hide :: MODE
-> LineNo
-> Matches LBS.ByteString
-> IO (LineEdit LBS.ByteString)
Doc = delete
hide Gen _) = passthru_ hide (
evalmeDoc :: LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
= return $ Just $ flip replace mtch $ LBS.intercalate "\n"
evalmeDoc _ mtch _ _ "ghci> ${exp}"
[ "${ans}"
, ]
evalmeGen :: GenState
-> LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
= Just <$>
evalmeGen gs _ mtch0 _ _ ALL f mtch0
replaceCapturesM replaceMethods where
=
f mtch loc _ case locationCapture loc == arg_i of
True -> do
:)
modifyIORef gs (idereturn $ Just $ LBS.pack $ show ide
where
= LBS.unpack $ captureText [cp|fn|] mtch
ide False -> return Nothing
= either oops id $ findCaptureID [cp|arg|] $ captureNames mtch0
arg_i
= error "evalmeGen: confused captures!" oops
How are we doing?
mainGen :: GenState
-> LineNo
-> Matches LBS.ByteString
-> IO (LineEdit LBS.ByteString)
= case allMatches mtchs of
mainGen gs _ mtchs ->
[mtch] case captureText [cp|arg|] $ mtch of
"top" -> return $ ReplaceWith $ LBS.unlines $
[ begin_code"module Main(main) where"
,
, end_code""
, "*********************************************************"
, "*"
, "* WARNING: this is generated from pp-tutorial-master.lhs "
, "*"
, "*********************************************************"
,
]"bottom" -> do
<- readIORef gs
fns return $ ReplaceWith $ LBS.unlines $
[ begin_code"main :: IO ()"
, "main = runTheTests"
, ++ mk_list fns ++
]
[ end_code
]-> error "mainGen (b)"
_ -> error "mainGen (a)" _
We cannot place these strings inline without confusing pandoc so we use these definitions instead.
end_code :: LBS.ByteString
begin_code,= "\\" M.<> "begin{code}"
begin_code = "\\" M.<> "end{code}" end_code
mk_list :: [String] -> [LBS.ByteString]
= [" []"]
mk_list [] :ides) = f "[" ide0 $ foldr (f ",") [" ]"] ides
mk_list (ide0where
= (" " M.<> pfx M.<> " " M.<> LBS.pack ide) : t f pfx ide t
include_code_pp :: LBS.ByteString -> IO LBS.ByteString
=
include_code_pp $ Select
sed' Function [re|^%include ${file}(@{%string}) ${rex}(@{%string})$|] TOP inc_code
[ Function [re|^.*$|] TOP passthru
, ]
inc_code :: LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
= fmap Just $
inc_code _ mtch _ _ =<< compileRegex re_s
extract fp where
= prs_s $ captureText [cp|file|] mtch
fp = prs_s $ captureText [cp|rex|] mtch
re_s
= maybe (error "include_code") T.unpack . parseString prs_s
passthru :: LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
= return Nothing
passthru _ _ _ _
passthru_ :: LineNo
-> Matches LBS.ByteString
-> IO (LineEdit LBS.ByteString)
= return NoEdit
passthru_ _ _
delete :: LineNo
-> Matches LBS.ByteString
-> IO (LineEdit LBS.ByteString)
= return Delete delete _ _
extract :: FilePath -> RE -> IO LBS.ByteString
= extr . LBS.lines <$> LBS.readFile fp
extract fp rex where
=
extr lns case parse $ scan rex lns of
Nothing -> oops
Just (lno,n) -> LBS.unlines $ (hdr :) $ (take n $ drop i lns) ++ [ftr]
where
= getZeroBasedLineNo lno
i
= error $ concat
oops "failed to locate fragment matching "
[ show $ reSource rex
, " in file "
, show fp
,
]
= "<div class='includedcodeblock'>"
hdr = "</div>" ftr
parse :: [Token] -> Maybe (LineNo,Int)
= Nothing
parse [] :tks) = case (tk,tks) of
parse (tkBra b_ln,Hit:Ket k_ln:_) -> Just (b_ln,count_lines_incl b_ln k_ln)
(-> parse tks _
count_lines_incl :: LineNo -> LineNo -> Int
=
count_lines_incl b_ln k_ln + 1 - getZeroBasedLineNo b_ln getZeroBasedLineNo k_ln
data Token = Bra LineNo | Hit | Ket LineNo deriving (Show)
scan :: RE -> [LBS.ByteString] -> [Token]
= grepWithScript
scan rex $ \i -> chk $ Bra i
[ (,) [re|\\begin\{code\}|] $ \_ -> chk Hit
, (,) rex $ \i -> chk $ Ket i
, (,) [re|\\end\{code\}|]
]where
= case anyMatches mtchs of
chk x mtchs True -> Just x
False -> Nothing
badges :: IO ()
= do
badges mapM_ collect
"license" "https://img.shields.io/badge/license-BSD3-brightgreen.svg"
[ (,) "unix-build" "https://img.shields.io/travis/iconnect/regex.svg?label=Linux%2BmacOS"
, (,) "windows-build" "https://img.shields.io/appveyor/ci/cdornan/regex.svg?label=Windows"
, (,) "coverage" "https://img.shields.io/coveralls/iconnect/regex.svg"
, (,) "build-status" "https://img.shields.io/travis/iconnect/regex.svg?label=Build%20Status"
, (,) "maintainers-contact" "https://img.shields.io/badge/email-maintainers%40regex.uk-blue.svg"
, (,) "feedback-contact" "https://img.shields.io/badge/email-feedback%40regex.uk-blue.svg"
, (,)
]where
= do
collect (nm,url) putStrLn $ "updating badge: " ++ nm
>>= LBS.writeFile (badge_fn nm)
simpleHttp url
= "docs/badges/"++nm++".svg" badge_fn nm
blog_badge :: IO ()
= do
blog_badge <- L.sortBy (flip compare) . map (take 10) <$>
dts "../regex-blog/posts"
getDirectoryContents case dts of
-> error "No posts found!"
[] :_ -> case matched $ dt_lbs ?=~ date_re of
dtFalse -> error $ "Post date format not recognised: " ++ dt
True -> do
putStrLn $ "Latest blog is: " ++ dt
<- lbsReadFile badges_file
lbs $ replaceAll dt_lbs $ lbs *=~ date_re
LBS.writeFile badges_file where
= LBS.pack dt
dt_lbs where
= [re|[0-9]{4}-[0-9]{2}-[0-9]{2}|]
date_re = "docs/badges/blog.svg" badges_file
pages :: IO ()
= do
pages "regex" MM_hackage "lib/md/index.md" "lib/README-regex.md"
prep_page "regex-examples" MM_hackage "lib/md/index.md" "lib/README-regex-examples.md"
prep_page "regex" MM_github "lib/md/index.md" "README.md"
prep_page mapM_ pandoc_page [minBound..maxBound]
data Page
= PG_index
| PG_about
| PG_reblog
| PG_contact
| PG_build_status
| PG_installation
| PG_tutorial
| PG_examples
| PG_roadmap
| PG_macros
| PG_directory
| PG_changelog
deriving (Bounded,Enum,Eq,Ord,Show)
page_root :: Page -> String
= map tr . drop 3 . show
page_root where
'_' = '-'
tr = c
tr c
page_docs_file :: Page -> FilePath
page_master_file,= "lib/md/" ++ page_root pg ++ ".md"
page_master_file pg = "docs/" ++ page_root pg ++ ".html"
page_docs_file pg
page_address :: Page -> LBS.ByteString
PG_reblog = "blog"
page_address = LBS.pack $ page_root pg
page_address pg
page_title :: Page -> LBS.ByteString
= case pg of
page_title pg PG_index -> "Home"
PG_about -> "About"
PG_reblog -> "Blog"
PG_contact -> "Contact"
PG_build_status -> "Build Status"
PG_installation -> "Installation"
PG_tutorial -> "Tutorial"
PG_examples -> "Examples"
PG_roadmap -> "Roadmap"
PG_macros -> "Macro Tables"
PG_directory -> "Directory"
PG_changelog -> "Change Log"
pandoc_page :: Page -> IO ()
= do
pandoc_page pg <- setup_ttl <$> LBS.readFile (page_master_file pg)
mt_lbs <- prep_page' MM_pandoc mt_lbs
(hdgs,md_lbs) "tmp/metadata.markdown" $ LBS.unlines ["---","title: " M.<> page_title pg,"---"]
LBS.writeFile "tmp/heading.markdown" $ page_heading pg
LBS.writeFile "tmp/page_pre_body.html" $ mk_pre_body_html pg hdgs
LBS.writeFile "tmp/page_pst_body.html" pst_body_html
LBS.writeFile "tmp/page.markdown" md_lbs
LBS.writeFile $ SH.verbosely $
SH.shelly "pandoc"
SH.run_ "-f", "markdown+grid_tables+autolink_bare_uris"
[ "-t", "html5"
, "-T", "regex"
, "-s"
, "-H", "lib/favicons.html"
, "-B", "tmp/page_pre_body.html"
, "-A", "tmp/page_pst_body.html"
, "-c", "lib/styles.css"
, "-o", T.pack $ page_docs_file pg
, "tmp/metadata.markdown"
, "tmp/heading.markdown"
, "tmp/page.markdown"
,
]where
= case pg of
setup_ttl PG_index -> set_title "regex"
-> id
_
data Heading =
Heading
_hdg_id :: LBS.ByteString
{ _hdg_title :: LBS.ByteString
,
}deriving (Show)
data MarkdownMode
= MM_github
| MM_hackage
| MM_pandoc
deriving (Eq,Show)
page_heading :: Page -> LBS.ByteString
PG_index = ""
page_heading =
page_heading pg "<p class='pagebc'><a href='.' title='Home'>Home</a> » **" M.<> page_title pg M.<> "**</p>\n"
prep_page :: LBS.ByteString -> MarkdownMode -> FilePath -> FilePath -> IO ()
= do
prep_page ttl mmd in_fp out_fp <- set_title ttl <$> LBS.readFile in_fp
lbs <- prep_page' mmd lbs
(_,lbs')
LBS.writeFile out_fp lbs'
set_title :: LBS.ByteString -> LBS.ByteString -> LBS.ByteString
= fromMaybe oops $ flip sed' lbs $ Pipe
set_title ttl lbs Function [re|<<\$title\$>>|] TOP $ \_ _ _ _->return $ Just ttl
[
]where
-- runIdentity added to base in 4.9 only
= error "set_title"
oops
prep_page' :: MarkdownMode -> LBS.ByteString -> IO ([Heading],LBS.ByteString)
= do
prep_page' mmd lbs <- newIORef []
rf_h <- newIORef False
rf_t <- fmap (tweak_md mmd) $ sed' (scr rf_h rf_t) =<< include lbs
lbs1 <- fromMaybe "" <$> fin_task_list' mmd rf_t
lbs2 <- reverse <$> readIORef rf_h
hdgs return (hdgs,lbs1 M.<> lbs2)
where
= Select
scr rf_h rf_t Function [re|^%heading#${ide}(@{%id}) +${ttl}([^ ].*)$|] TOP $ heading mmd rf_t rf_h
[ Function [re|^- \[ \] +${itm}(.*)$|] TOP $ task_list mmd rf_t False
, Function [re|^- \[[Xx]\] +${itm}(.*)$|] TOP $ task_list mmd rf_t True
, Function [re|^.*$|] TOP $ fin_task_list mmd rf_t
,
]
heading :: MarkdownMode
-> IORef Bool
-> IORef [Heading]
-> LineNo
-> Match LBS.ByteString
-> RELocation
-> Capture LBS.ByteString
-> IO (Maybe LBS.ByteString)
= do
heading mmd rf_t rf_h _ mtch _ _ <- fromMaybe "" <$> fin_task_list' mmd rf_t
lbs Heading ide ttl:)
modifyIORef rf_h (return $ Just $ lbs M.<> h2
where
= case mmd of
h2 MM_github -> "## " M.<> ttl
MM_hackage -> "## " M.<> ttl
MM_pandoc -> "<h2 id='" M.<> ide M.<> "'>" M.<> ttl M.<> "</h2>"
= mtch !$$ [cp|ide|]
ide = mtch !$$ [cp|ttl|]
ttl
mk_pre_body_html :: Page -> [Heading] -> LBS.ByteString
= hdr M.<> LBS.concat (map nav [minBound..maxBound]) M.<> ftr
mk_pre_body_html pg hdgs where
hdr :: LBS.ByteString
= [here| <div id="container">
hdr
<div id="sidebar">
<div id="corner">M.<> branding M.<> [here|
|]
</div>
<div class="widget" id="pages">
<ul class="page-nav">
|]
= LBS.unlines $
nav dst_pg " " pg_cls pg_adr pg_ttl :
nav_li " " ["secnav"] ("#" M.<> _hdg_id) _hdg_title
[ nav_li | Heading{..} <- hdgs
, is_moi
]where
= ["pagenav",if is_moi then "moi" else "toi"]
pg_cls = page_address dst_pg
pg_adr = page_title dst_pg
pg_ttl = pg == dst_pg
is_moi
= LBS.concat
nav_li pfx cls dst title
[ pfx"<li class='"
,
, LBS.unwords cls"'><a href='"
,
, dst"'>"
,
, title"</a></li>"
,
]
= [here| </ul>
ftr
</div>
<div class="supplementary widget" id="github">
<a href="http://code.regex.uk"><img src="images/code.svg" alt="github code" /> Code</a>
</div>
<div class="supplementary widget" id="github-issues">
<a href="http://issues.regex.uk"><img src="images/issue-opened.svg" alt="github issues" /> Issues</a>
</div>
<div class="widget-divider"> </div>
<div class="supplementary widget" id="blog-badge">
<a href="http://blog.regex.uk">
<img src="badges/blog.svg" alt="regex blog" />
</a>
</div>
<div class="supplementary widget" id="hackage-badge">
<a href="https://hackage.haskell.org/package/regex">
<img src="badges/hackage.svg" alt="hackage version" />
</a>
</div>
<div class="supplementary widget" id="build-status-badge">
<a href="build-status">
<img src="badges/build-status.svg" alt="build status" />
</a>
</div>
<div class="supplementary widget" id="maintainers-contact">
<a href="mailto:maintainers@regex.uk">
<img src="badges/maintainers-contact.svg" alt="maintainers contact" />
</a>
</div>
<div class="supplementary widget" id="feedback-contact">
<a href="mailto:feedback@regex.uk">
<img src="badges/feedback-contact.svg" alt="deedback contact" />
</a>
</div>
<div class="supplementary widget twitter">
<iframe style="width:162px; height:20px;" src="https://platform.twitter.com/widgets/follow_button.html?screen_name=hregex&show_count=false">
</iframe>
</div>
</div>
<div id="content">
|]
pst_body_html :: LBS.ByteString
= [here| </div>
pst_body_html
</div>M.<> tracking |]
-- | replacement function to convert GFM task list line into HTML if we
-- aren't writing GFM (i.e., generating markdown for GitHub)
task_list :: MarkdownMode -- ^ what flavour of md are we generating
-> IORef Bool -- ^ will contain True iff we have already entered a task list
-> Bool -- ^ true if this is a checjed line
-> LineNo -- ^ line no of the replacement redex (unused)
-> Match LBS.ByteString -- ^ the matched task-list line
-> RELocation -- ^ which match and capure (unused)
-> Capture LBS.ByteString -- ^ the capture weare replacing (unsuded)
-> IO (Maybe LBS.ByteString) -- ^ the replacement text, or Nothing to indicate no change to this line
=
task_list mmd rf chk _ mtch _ _ case mmd of
MM_github -> return Nothing
MM_hackage -> return $ Just $ " " M.<> cb M.<> " " M.<> itm M.<> "\n"
MM_pandoc -> do
<- readIORef rf
in_tl True
writeIORef rf return $ tl_line in_tl chk
where
= Just $ LBS.concat
tl_line in_tl enbl if in_tl then "" else "<ul class='contains-task-list'>\n"
[ " <li class='task-list-item'>"
, "<input type='checkbox' class='task-list-item-checkbox'"
, if enbl then " checked=''" else ""
, " disabled=''/>"
,
, itm"</li>"
,
]
= if chk then "☒" else "☐"
cb
= mtch !$$ [cp|itm|]
itm
-- | replacement function used for 'other' lines -- terminate any task
-- list that was being generated
fin_task_list :: MarkdownMode -- ^ what flavour of md are we generating
-> IORef Bool -- ^ will contain True iff we have already entered a task list
-> LineNo -- ^ line no of the replacement redex (unused)
-> Match LBS.ByteString -- ^ the matched task-list line
-> RELocation -- ^ which match and capure (unused)
-> Capture LBS.ByteString -- ^ the capture weare replacing (unsuded)
-> IO (Maybe LBS.ByteString) -- ^ the replacement text, or Nothing to indicate no change to this line
=
fin_task_list mmd rf_t _ mtch _ _ fmap ( M.<> matchSource mtch) <$> fin_task_list' mmd rf_t
-- | close any task list being processed, returning the closing text
-- as necessary
fin_task_list' :: MarkdownMode -- ^ what flavour of md are we generating
-> IORef Bool -- ^ will contain True iff we have already entered a task list
-> IO (Maybe LBS.ByteString) -- ^ task-list closure HTML, if task-list HTML needs closing
= do
fin_task_list' mmd rf <- readIORef rf
in_tl False
writeIORef rf case mmd==MM_github || not in_tl of
True -> return Nothing
False -> return $ Just $ "</ul>\n"
pandoc_lhs :: String -> String -> String -> IO ()
= pandoc_lhs' title in_file in_file
pandoc_lhs title in_file
pandoc_lhs' :: String -> String -> String -> String -> IO ()
= do
pandoc_lhs' title repo_path in_file out_file >>= include_code_pp >>= LBS.writeFile int_file
lbsReadFile in_file "tmp/metadata.markdown" $
LBS.writeFile
LBS.unlines"---"
[ "title: " M.<> LBS.pack title
, "---"
,
]"tmp/bc.html" bc
LBS.writeFile "tmp/ft.html" ft
LBS.writeFile fmap (const ()) $
$ SH.verbosely $
SH.shelly "pandoc"
SH.run "-f", "markdown+lhs+grid_tables"
[ "-t", "html5"
, "-T", "regex"
, "-s"
, "-H", "lib/favicons.html"
, "-B", "tmp/bc.html"
, "-A", "tmp/ft.html"
, "-c", "lib/lhs-styles.css"
, "-c", "lib/bs.css"
, "-o", T.pack out_file
, "tmp/metadata.markdown"
,
, T.pack int_file
]where
= LBS.unlines
bc -- [ "<div class='brandingdiv'>"
-- , " " M.<> branding
-- , "</div>"
"<div class='bcdiv'>"
[ " <ol class='breadcrumb'>"
, " <li>" M.<> branding M.<> "</li>"
, " <li><a title='source file' href='" M.<>
, M.<> "'>" M.<> (LBS.pack title) M.<> "</a></li>"
repo_url "</ol>"
, "</div>"
, "<div class='litcontent'>"
,
]
= LBS.concat
ft "</div>"
[ M.<> tracking
]
= LBS.concat
repo_url "https://github.com/iconnect/regex/blob/master/"
[
, LBS.pack repo_path
]
= "tmp/pandoc-int.lhs" int_file
tweak_md :: MarkdownMode -> LBS.ByteString -> LBS.ByteString
= case mm of
tweak_md mm lbs MM_github -> lbs
MM_pandoc -> awk
Template [ed|<https?://${rest}([^)]+)>///[${rest}]($0)|]
[
]MM_hackage -> awk
Template [ed|<br/>$///\n|]
[
]where
= fromMaybe oops . flip sed' lbs . Pipe
awk
-- runIdentity added to base in 4.9 only
= error "tweak_md" oops
branding :: LBS.ByteString
= [here|<a href="." style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;" id="branding">[<span style='color:red;'>re</span>|${<span style='color:red;'>gex</span>}(.*)|<span></span>]</a>|] branding
tracking :: LBS.ByteString
= [here| <script>
tracking
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-92650418-1', 'auto');
ga('send', 'pageview');
</script> |]
test :: IO ()
= do
test "re-prep doc" (prepare_tutorial Doc) "data/pp-test.lhs" "data/pp-result-doc.lhs"
test_pp <- genMode
gm "re-prep gen" (prepare_tutorial gm ) "data/pp-test.lhs" "data/pp-result-gen.lhs"
test_pp putStrLn "tests passed"
lbsReadFile :: FilePath -> IO LBS.ByteString
= LBS.fromStrict <$> B.readFile fp lbsReadFile fp