1 {-# LANGUAGE FlexibleInstances #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ViewPatterns #-}
4 -- | Render TCT as HTML5.
5 module Language.TCT.Write.HTML5 where
7 import Control.Monad (Monad(..), forM_, mapM_, mapM, when)
9 import Data.Eq (Eq(..))
10 import Data.Foldable (Foldable(..))
11 import Data.Function (($))
13 import Data.Maybe (Maybe(..))
14 import Data.Monoid (Monoid(..))
15 import Data.Ord (Ord(..))
16 import Data.Semigroup (Semigroup(..))
17 import Data.Sequence (ViewL(..))
18 import Data.String (IsString(..))
19 import Data.Text (Text)
20 import Data.TreeSeq.Strict (Tree(..),Trees)
21 import Prelude (Num(..), undefined)
22 import Text.Blaze ((!))
23 import Text.Blaze.Html (Html)
24 import Text.Show (Show(..))
25 import qualified Control.Monad.Trans.State as S
26 import qualified Data.List as L
27 import qualified Data.Sequence as Seq
28 import qualified Data.Text as Text
29 import qualified Data.Text.Lazy as TL
30 import qualified Text.Blaze.Html5 as H
31 import qualified Text.Blaze.Html5.Attributes as HA
33 import Text.Blaze.Utils
35 import qualified Language.TCT.Write.Plain as Plain
38 class Html5ify a where
40 instance Html5ify Text where
42 instance Html5ify TCTs where
47 H.meta ! HA.httpEquiv "Content-Type"
48 ! HA.content "text/html; charset=UTF-8"
49 whenJust (tokensTitle tct) $ \ts ->
50 H.title $ H.toMarkup $ L.head $
51 TL.lines (Plain.textify ts) <> [""]
52 -- link ! rel "Chapter" ! title "SomeTitle">
53 H.link ! HA.rel "stylesheet"
55 ! HA.href "style/tct-html5.css"
57 H.a ! HA.id ("line-1") $ return ()
58 html5ify (Plain.treePosLastCell tct)
59 instance Html5ify (Trees (Pos,Cell Key) (Pos,Tokens)) where
60 html5ify = mapM_ html5ify
61 instance Html5ify (Tree (Pos,Cell Key) (Pos,Tokens)) where
62 html5ify (TreeN (posEnd, Cell pos _ (KeySection lvl)) ts) = do
63 html5ifyIndentCell (posEnd,pos)
65 H.span ! HA.class_ "section-title" $ do
66 H.span $ html5ify $ Text.replicate lvl "#" <> " "
68 Tree0 (_,title) :< _ -> h lvl $ html5ify title
71 case Seq.viewl ts of {Tree0{} :< ts' -> ts'; _ -> ts}
79 h n | n > 0 = H.span ! HA.class_ ("h h"<>attrify n)
81 html5ify (Tree0 (posEnd,toks)) =
82 case Seq.viewl toks of
83 EmptyL -> html5ify toks
84 t0:<_ -> html5ifyIndentCell (posEnd,posTree t0) <> html5ify toks
85 html5ify (TreeN (posEnd,cell@(Cell pos _ _)) cs) =
86 html5ifyIndentCell (posEnd,pos) <>
88 instance Html5ify (Cell Key, Trees (Pos,Cell Key) (Pos,Tokens)) where
89 html5ify (Cell _pos _posEnd key, ts) = do
91 KeyColon n wh -> html5Key "" "" n wh ":" "" "colon"
92 KeyGreat n wh -> html5Key "" "" n wh ">" "" "great"
93 KeyEqual n wh -> html5Key "" "" n wh "=" "" "equal"
94 KeyBar n wh -> html5Key "" "" n wh "|" "" "bar"
95 KeyDot n -> html5Key "" "" n "" "." "" "dot"
96 KeyDash -> html5Key "" "" "" "" "-" " " "dash"
97 KeyDashDash -> html5Key "" "" "" "" "--" " " "dashdash"
98 KeyBrackets n -> html5Key "[" "" n "" "]" "" "dashdash"
99 KeyLower name attrs -> do
100 H.span ! HA.class_ (mconcat ["key key-lower"," key-name-",attrify name]) $ do
101 H.span ! HA.class_ "key-mark" $ H.toMarkup '<'
102 H.span ! HA.class_ "key-name" $ H.toMarkup name
106 html5Key :: Text -> White -> Text -> White -> Text -> White -> H.AttributeValue -> Html
107 html5Key markBegin whmb name whn markEnd whme cl = do
108 -- html5Spaces $ colPos posEnd - (colPos pos + Text.length name + 1)
109 H.span ! HA.class_ (mconcat ["key key-",cl," key-name-",attrify name]) $ do
110 when (markBegin/="") $
111 H.span ! HA.class_ "key-mark" $ H.toMarkup markBegin
114 H.span ! HA.class_ "key-name" $ H.toMarkup name
117 H.span ! HA.class_ "key-mark" $ H.toMarkup markEnd
119 H.span ! HA.class_ "key-value" $
121 instance Html5ify Tokens where
123 case Seq.viewl toks of
126 goTokens toks `S.evalState` linePos pos
129 indent = Text.replicate (columnPos pos - 1) " "
130 go :: Token -> S.State Int Html
131 go (TreeN (unCell -> p) ts) =
133 PairElem name attrs -> do
136 let cl = mconcat ["pair-PairElem", " pair-elem-", attrify name]
137 H.span ! HA.class_ cl $ do
138 whenMarkup o $ H.span ! HA.class_ "pair-open" $ o
139 whenMarkup h $ H.span ! HA.class_ "pair-content" $ h
140 whenMarkup c $ H.span ! HA.class_ "pair-close" $ c
142 html5name = H.span ! HA.class_ "elem-name" $ H.toMarkup name
147 ( "<"<>html5name<>html5ify attrs<>"/>"
150 ( "<"<>html5name<>html5ify attrs<>">"
151 , "</"<>html5name<>">" )
155 let (o,c) = pairBorders p ts
156 H.span ! HA.class_ (mconcat ["pair-", fromString $ show p]) $ do
157 H.span ! HA.class_ "pair-open" $ H.toMarkup o
158 H.span ! HA.class_ "pair-content" $ h
159 H.span ! HA.class_ "pair-close" $ H.toMarkup c
160 go (Tree0 (unCell -> tok)) =
164 let lines = Text.splitOn "\n" txt
165 let lnums = H.toMarkup :
168 H.a ! HA.id ("line-"<>attrify lnum) $ return ()
173 S.put (lin - 1 + L.length lines)
174 return $ mconcat $ L.zipWith ($) lnums lines
177 H.span ! HA.class_ "tag" $ do
178 H.span ! HA.class_ "tag-open" $ H.toMarkup '#'
180 TokenEscape c -> return $ H.toMarkup ['\\',c]
183 H.a ! HA.href (attrify lnk) $
185 goTokens :: Tokens -> S.State Int Html
188 return $ foldr (<>) mempty ts'
189 instance Html5ify Attrs where
190 html5ify = mapM_ html5ify
191 instance Html5ify (Text,Attr) where
192 html5ify (attr_white,Attr{..}) = do
193 H.toMarkup attr_white
194 H.span ! HA.class_ "attr-name" $
197 H.span ! HA.class_ "attr-value" $
198 H.toMarkup attr_value
199 H.toMarkup attr_close
203 tokensTitle :: Trees (Cell Key) Tokens -> Maybe Tokens
206 TreeN (unCell -> KeySection{}) _ts -> True
209 TreeN (unCell -> KeySection _lvl) (Seq.viewl -> Tree0 title:<_) -> Just title
212 html5Spaces :: Int -> Html
213 html5Spaces 0 = return ()
214 html5Spaces sp = H.span $ html5ify $ Text.replicate sp " "
216 html5ifyIndentCell :: (Pos,Pos) -> Html
217 html5ifyIndentCell (Pos lineLast colLast,Pos line col)
218 | lineLast < line = do
219 forM_ [lineLast+1..line] $ \lnum -> do
221 H.a ! HA.id ("line-"<>attrify lnum) $ return ()
222 H.toMarkup $ Text.replicate (col - 1) " "
224 && colLast <= col = H.toMarkup $ Text.replicate (col - colLast) " "
225 | otherwise = undefined