module Text.LaTeX.Guide.Backend.HTML (
backend
) where
import Text.LaTeX.Guide.Syntax
import Text.LaTeX.Guide.Info hiding (LaTeX)
import Text.LaTeX.Guide.Auto
import Text.Blaze.Html5 (Html,toHtml,preEscapedToHtml,preEscapedToValue,(!))
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Data.Text.Lazy.IO
import Data.Monoid
import Control.Monad.Trans.State
import Data.List (intersperse)
import Data.Version (showVersion)
import Data.Time
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
resURL :: Text -> Text
resURL t = "https://raw.github.com/Daniel-Diaz/hatex-guide/master/res/" <> t
sectFromInt :: Int -> Html -> Html
sectFromInt 1 = H.h1
sectFromInt 2 = H.h2
sectFromInt 3 = H.h3
sectFromInt 4 = H.h4
sectFromInt 5 = H.h5
sectFromInt 6 = H.h6
sectFromInt n = error $ "Subsection with hierarchy of " ++ show n ++ " is not available in the HTML backend."
type SectionNumber = [Int]
showSN :: SectionNumber -> String
showSN = mconcat . intersperse "." . fmap show
mapLast :: (a -> a) -> [a] -> [a]
mapLast _ [] = []
mapLast f [x] = [f x]
mapLast f (x:xs) = x : mapLast f xs
upgradeSN :: Int -> SectionNumber -> SectionNumber
upgradeSN n [] = replicate (n1) 0 ++ [1]
upgradeSN n sn = mapLast (+1) $ take n $ sn ++ repeat 0
sectiondots :: Int -> Html
sectiondots 1 = mempty
sectiondots n = toHtml $ (mconcat $ replicate (n1) str) ++ " "
where
str :: String
str = ".........."
data HtmlState =
HState { fnIndex :: Int
, sectionNumber :: SectionNumber
, htmlBody :: Html
, fnHtml :: Html
, tocHtml :: Html
}
defaultState :: HtmlState
defaultState = HState 1 [] mempty mempty mempty
type HtmlM = State HtmlState
ihtml :: Html -> HtmlM ()
ihtml h = modify $ \s -> s { htmlBody = htmlBody s <> h }
ihtmlf :: (Html -> Html) -> HtmlM () -> HtmlM ()
ihtmlf f hm = do
s0 <- get
let s1 = execState hm $ s0 { htmlBody = mempty }
put $ s1 { htmlBody = htmlBody s0 <> f (htmlBody s1) }
execHtmlM :: HtmlM a -> Html
execHtmlM hm =
do let s = execState hm defaultState
H.h1 "Table of contents"
tocHtml s
H.br
H.a ! A.href "#footnotes" $ "Footnotes"
H.hr
htmlBody s
H.hr
H.a ! A.id "footnotes" $ H.h1 "Footnotes"
fnHtml s
htmlSyntax :: Syntax -> HtmlM ()
htmlSyntax (Raw t) = ihtml $ toHtml t
htmlSyntax (Section n s) = do
t <- sectionNumber <$> get
let t' = upgradeSN n t
a = "s" ++ showSN t'
ihtmlf (sectFromInt n . (H.a ! A.id (preEscapedToValue a))) $ do
ihtml $ toHtml $ (++". ") $ showSN t'
htmlSyntax s
let fortoc = do
sectiondots n
H.a ! A.href (preEscapedToValue $ '#' : a) $ do
toHtml $ showSN t'
toHtml (". " :: String)
htmlBody $ execState (htmlSyntax s) defaultState
modify $ \st -> st { sectionNumber = t'
, tocHtml = tocHtml st <> H.br <> fortoc
}
htmlSyntax (Bold s) = ihtmlf H.b $ htmlSyntax s
htmlSyntax (Italic s) = ihtmlf H.i $ htmlSyntax s
htmlSyntax (Code b t) =
let f = if b then H.code else H.pre
in ihtml $ f $ preEscapedToHtml t
htmlSyntax (URL t) = ihtml $ H.a ! A.href (preEscapedToValue t) $ toHtml t
htmlSyntax (IMG t) = ihtml $ H.img ! A.src (preEscapedToValue $ resURL t) ! A.width "50%"
htmlSyntax LaTeX = ihtml $ H.i "LaTeX"
htmlSyntax HaTeX = ihtml $ H.i "HaTeX"
htmlSyntax (Math t) = ihtml $ H.i $ toHtml t
htmlSyntax (Append s1 s2) = htmlSyntax s1 >> htmlSyntax s2
htmlSyntax Empty = return ()
htmlSyntax (Footnote x) = do
s0 <- get
let i = fnIndex s0
str = '[' : (show i ++ "]")
s1 = execState (htmlSyntax x) $ s0 { htmlBody = mempty }
fn = H.p $ do H.a ! A.id (preEscapedToValue $ 'f' : show i) $ toHtml str
toHtml (" - " :: String)
htmlBody s1
h = H.a ! A.href (preEscapedToValue $ "#f" ++ show i) $ toHtml str
modify $ \s -> s { fnIndex = fnIndex s + 1
, fnHtml = fnHtml s <> fn
, htmlBody = htmlBody s <> h
}
htmlSyntax (Paragraph s) = do
ihtmlf H.p $ htmlSyntax s
ihtml $ toHtml ("\n\n" :: String)
htmlTitle :: Day -> Html
htmlTitle d = do
H.h1 ! A.class_ "title" $ "The HaTeX User's Guide"
let vstr = "Version " ++ showVersion guideVersion
H.p ! A.class_ "centered" $ H.i $ do
toHtml vstr
toHtml (" using " :: String)
H.a ! A.href "http://hackage.haskell.org/package/blaze-html" $ "blaze-html"
toHtml ("." :: String)
H.p ! A.class_ "centered" $ H.i $ toHtml $ "Generated on " ++ showGregorian d ++ "."
H.p ! A.class_ "centered" $ toHtml $ mconcat $ intersperse ", " $ "Daniel Díaz" : contributors
htmlConfig :: Html -> IO Html
htmlConfig h = do
d <- utctDay <$> getCurrentTime
return $ H.docTypeHtml $ do
H.head $ do
H.title "The HaTeX User's Guide"
H.link ! A.rel "stylesheet" ! A.href "https://rawgithub.com/Daniel-Diaz/hatex-guide/master/hatex.css"
H.body $ htmlTitle d <> H.hr <> h
createManual :: IO Html
createManual = fmap (execHtmlM . sequence_ . fmap htmlSyntax) parseSections >>= htmlConfig
backend :: IO ()
backend = do
Prelude.putStrLn "Creating guide..."
m <- createManual
Prelude.putStrLn "Writing guide file..."
let fp = outputName ".html"
Data.Text.Lazy.IO.writeFile fp $ renderHtml m
Prelude.putStrLn $ "Guide written in " <> fp <> "."