1 {-# LANGUAGE FlexibleInstances #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ViewPatterns #-}
4 module Language.TCT.Write.HTML5 where
6 import Control.Monad (Monad(..), forM_, mapM_, when)
8 import Data.Char (Char)
9 import Data.Default.Class (Default(..))
10 import Data.Eq (Eq(..))
11 import Data.Foldable (Foldable(..))
12 import Data.Function (($), (.), id)
13 import Data.Functor ((<$>))
14 import Data.Functor.Compose (Compose(..))
15 import Data.Maybe (Maybe(..))
16 import Data.Monoid (Monoid(..))
17 import Data.Ord (Ord(..))
18 import Data.Semigroup (Semigroup(..))
19 import Data.Sequence (ViewL(..))
20 import Data.String (String, IsString(..))
21 import Data.Text (Text)
22 import Data.TreeSeq.Strict (Tree(..),Trees)
23 import Prelude (Num(..), undefined, error)
24 import Text.Blaze ((!))
25 import Text.Blaze.Html (Html)
26 import Text.Show (Show(..))
27 import qualified Control.Monad.Trans.State as S
28 import qualified Data.List as List
29 import qualified Data.Sequence as Seq
30 import qualified Data.Text as Text
31 import qualified Data.Text.Lazy as TL
32 import qualified Text.Blaze.Html5 as H
33 import qualified Text.Blaze.Html5.Attributes as HA
34 -- import Debug.Trace (trace)
36 import Text.Blaze.Utils
38 import qualified Language.TCT.Write.Plain as Plain
41 type Html5 = StateMarkup State ()
48 instance Default State where
54 class Html5ify a where
55 html5ify :: a -> Html5
56 instance Html5ify H.Markup where
57 html5ify = Compose . return
58 instance Html5ify Html5 where
60 instance Html5ify () where
62 instance Html5ify Char where
63 html5ify = html5ify . H.toMarkup
64 instance Html5ify Text where
65 html5ify = html5ify . H.toMarkup
66 instance Html5ify TL.Text where
67 html5ify = html5ify . H.toMarkup
68 instance Html5ify String where
69 html5ify = html5ify . H.toMarkup
70 html5Document :: TCTs -> Html
71 html5Document body = do
75 H.meta ! HA.httpEquiv "Content-Type"
76 ! HA.content "text/html; charset=UTF-8"
77 whenJust (tokensTitle body) $ \ts ->
79 H.toMarkup $ Plain.text def $ List.head $ toList ts
80 -- link ! rel "Chapter" ! title "SomeTitle">
81 H.link ! HA.rel "stylesheet"
83 ! HA.href "style/tct-html5.css"
84 let (html5Body, State{}) =
88 H.a ! HA.id ("line-1") $ return ()
90 instance Html5ify (Trees (Cell Key) Tokens) where
91 html5ify = mapM_ html5ify
92 instance Html5ify (Tree (Cell Key) Tokens) where
94 TreeN (Cell bp ep k) ts -> html5ify (Cell bp ep (k,ts))
95 Tree0 ts -> html5ify ts
96 instance Html5ify a => Html5ify (Cell a) where
97 html5ify (Cell next@(Pos line col) ep a) = do
98 prev@(Pos lineLast colLast) <- liftStateMarkup $ S.gets state_pos
100 _ | lineLast < line -> do
101 forM_ [lineLast+1..line] $ \lnum -> do
103 H.a ! HA.id ("line-"<>attrify lnum) $$ return ()
104 html5ify $ Text.replicate (col - 1) " "
105 _ | lineLast == line && colLast <= col -> do
106 html5ify $ Text.replicate (col - colLast) " "
107 _ -> error $ "html5ify: non-ascending positions: "
108 <> "\n prev: " <> show prev
109 <> "\n next: " <> show next
110 -- liftStateMarkup $ S.modify $ \s -> s{state_pos=bp}
111 liftStateMarkup $ S.modify $ \s -> s{state_pos=ep}
113 instance Html5ify (Key, Trees (Cell Key) Tokens) where
116 KeyPara -> html5ify ts
117 KeyColon n wh -> html5Key "" "" n wh ":" "" "colon"
118 KeyGreat n wh -> html5Key "" "" n wh ">" "" "great"
119 KeyEqual n wh -> html5Key "" "" n wh "=" "" "equal"
120 KeyBar n wh -> html5Key "" "" n wh "|" "" "bar"
121 KeyDot n -> html5Key "" "" n "" "." "" "dot"
122 KeyDash -> html5Key "" "" "" "" "-" " " "dash"
123 KeyDashDash -> html5Key "" "" "" "" "--" " " "dashdash"
124 KeyBrackets n -> html5Key "[" "" n "" "]" "" "dashdash"
125 KeyLower name attrs -> do
126 H.span ! HA.class_ (mconcat ["key key-lower"," key-name-",attrify name]) $$ do
127 H.span ! HA.class_ "key-mark" $$ html5ify '<'
128 H.span ! HA.class_ "key-name" $$ html5ify name
133 H.span ! HA.class_ "section-title" $$ do
134 H.span ! HA.class_ "section-mark" $$ do
135 html5ify $ Text.replicate lvl "#"
137 Tree0 title :< _ -> h lvl $$ html5ify title
141 Tree0{} :< ts' -> ts'
150 h n | n > 6 = H.span ! HA.class_ ("h h"<>attrify n)
153 html5Key :: Text -> White -> Text -> White -> Text -> White -> H.AttributeValue -> Html5
154 html5Key markBegin whmb name whn markEnd whme cl = do
155 H.span ! HA.class_ (mconcat ["key key-",cl," key-name-",attrify name]) $$ do
156 when (markBegin/="") $
157 H.span ! HA.class_ "key-mark" $$ html5ify markBegin
160 H.span ! HA.class_ "key-name" $$ html5ify name
163 H.span ! HA.class_ "key-mark" $$ html5ify markEnd
165 H.span ! HA.class_ "key-value" $$
167 instance Html5ify Tokens where
168 html5ify = mapM_ html5ify
169 instance Html5ify Token where
170 html5ify (TreeN (Cell bp ep p) ts) = do
172 PairElem name attrs -> do
173 H.span ! HA.class_ ("pair-PairElem" <> " pair-elem-"<>attrify name) $$ do
174 html5ify $ Cell bp bp{columnPos = columnPos bp + lenO} ()
176 H.span ! HA.class_ "pair-open" $$ o
177 when (not $ Seq.null ts) $
178 H.span ! HA.class_ "pair-content" $$ html5ify ts
179 html5ify $ Cell ep{columnPos = columnPos ep - lenC} ep ()
181 H.span ! HA.class_ "pair-close" $$ c
184 H.span ! HA.class_ "elem-name" $$
186 lenName = Text.length name
187 lenAttrs = sum $ (<$> attrs) $ \(attr_white,Attr{..}) ->
188 Text.length attr_white +
189 Text.length attr_name +
190 Text.length attr_open +
191 Text.length attr_value +
192 Text.length attr_close
193 (lenO,lenC) | Seq.null ts = (1+lenName+lenAttrs+2,0)
194 | otherwise = (1+lenName+lenAttrs+1,2+lenName+1)
196 (o,c) | Seq.null ts =
197 ( "<"<>html5Name<>html5ify attrs<>"/>"
200 ( "<"<>html5Name<>html5ify attrs<>">"
201 , "</"<>html5Name<>">" )
203 let (o,c) = pairBorders p ts
204 H.span ! HA.class_ ("pair-"<>fromString (show p)) $$ do
205 html5ify $ Cell bp bp{columnPos = columnPos bp + Text.length o} ()
206 H.span ! HA.class_ "pair-open" $$ html5ify o
207 H.span ! HA.class_ "pair-content" $$ html5ify ts
208 html5ify $ Cell ep{columnPos = columnPos ep - Text.length c} ep ()
209 H.span ! HA.class_ "pair-close" $$ html5ify c
210 html5ify (Tree0 (Cell bp ep t)) = do
211 html5ify $ Cell bp ep ()
213 TokenPlain txt -> html5ify txt
216 let lines = Text.splitOn "\n" txt
217 let lnums = html5ify :
220 H.a ! HA.id ("line-"<>attrify lnum) $$ return ()
225 S.put (lin - 1 + List.length lines)
226 return $ mconcat $ List.zipWith ($) lnums lines
229 H.span ! HA.class_ "tag" $$ do
230 H.span ! HA.class_ "tag-open" $$
233 TokenEscape c -> html5ify ['\\',c]
235 H.a ! HA.href (attrify lnk) $$
237 instance Html5ify Attrs where
238 html5ify = mapM_ html5ify
239 instance Html5ify (White,Attr) where
240 html5ify (attr_white,Attr{..}) = do
242 H.span ! HA.class_ "attr-name" $$
245 H.span ! HA.class_ "attr-value" $$
251 tokensTitle :: Trees (Cell Key) Tokens -> Maybe Tokens
254 TreeN (unCell -> KeySection{}) _ts -> True
257 TreeN (unCell -> KeySection _lvl) (Seq.viewl -> Tree0 title:<_) -> Just title
260 html5Spaces :: Column -> Html5
261 html5Spaces 0 = return ()
262 html5Spaces sp = H.span $$ html5ify $ Text.replicate sp " "