1 {-# LANGUAGE OverloadedStrings #-}
2 {-# LANGUAGE RecordWildCards #-}
3 {-# LANGUAGE ViewPatterns #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 -- | Render a TCT file in DTC.
6 module Language.TCT.Write.DTC where
8 import Control.Monad (Monad(..), forM_, when)
10 import Data.Foldable (foldr, null, foldMap, foldl', any)
11 import Data.Function (($), (.), flip)
12 import Data.Functor ((<$>))
13 import Data.Map.Strict (Map)
14 import Data.Maybe (Maybe(..))
15 import Data.Monoid (Monoid(..))
16 import Data.Semigroup (Semigroup(..))
17 import Data.Sequence (ViewL(..), (<|), (|>))
18 import Data.String (String)
19 import Data.Text (Text)
20 import GHC.Exts (toList)
21 import Text.Blaze ((!))
22 import Text.Show (Show(..))
23 import qualified Data.Char as Char
24 import qualified Data.Map.Strict as Map
25 import qualified Data.Sequence as Seq
26 import qualified Data.Text as Text
27 import qualified Data.Text.Lazy as TL
28 import qualified Text.Blaze as B
29 import qualified Text.Blaze.Internal as B
31 import Language.TCT.Tree
32 import Language.TCT.Token
33 import Language.TCT.Elem hiding (trac,dbg)
34 import qualified Language.TCT.Write.Text as Write
35 import Text.Blaze.Utils
36 import Text.Blaze.DTC (DTC)
37 import qualified Text.Blaze.DTC as D
38 import qualified Text.Blaze.DTC.Attributes as DA
40 import Debug.Trace (trace)
41 trac :: String -> a -> a
44 dbg :: Show a => String -> a -> a
45 dbg m x = trac (m <> ": " <> show x) x
47 dtc :: Trees Key Tokens -> DTC
50 D.xmlModel "./schema/dtc.rnc"
51 D.xmlStylesheet $ "./xsl/document.html5."<>lang<>".xsl"
52 D.html5Stylesheet $ "./xsl/document.html5."<>lang<>".xsl"
53 D.atomStylesheet $ "./xsl/document.atom."<>lang<>".xsl"
57 (Seq.viewl -> Tree0 (Write.t_Tokens -> TL.toStrict -> title) :< head)
59 d_Trees [] (mangleHead title head)
68 mangleHead title head =
70 (`Seq.findIndexL` head) $ \case
71 TreeN (KeyColon "about" _) _ -> True
75 TreeN (KeyColon "about" "")
78 Just i -> Seq.adjust f i head
80 f (TreeN c about) = TreeN c $ Seq.fromList names <> about
83 names = name <$> Text.splitOn "\n" title
85 TreeN (KeyColon "name" "") .
86 Seq.singleton . Tree0 . Tokens .
87 Seq.singleton . TokenPlain
89 d_Trees :: [Key] -> Trees Key Tokens -> DTC
92 _ | (ul,ts') <- gatherUL ts, not (null ul) -> do
93 D.ul $ forM_ ul $ d_Tree path
95 _ | (ol,ts') <- gatherOL ts, not (null ol) -> do
96 D.ol $ forM_ ol $ d_Tree path
98 _ | t:<ts' <- Seq.viewl ts -> do
104 gatherUL :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
106 let (lis, ts') = spanLIs ts in
107 foldl' accumLIs (mempty,ts') lis
109 spanLIs = Seq.spanl $ \case
110 TreeN KeyDash _ -> True
111 Tree0 (Tokens toks) ->
113 TokenPair (PairElem "li" _) _ -> True
116 accumLIs acc@(oks,kos) t =
118 TreeN KeyDash _ -> (oks|>t,kos)
119 Tree0 (Tokens toks) ->
120 let mk = Tree0 . Tokens in
122 (`Seq.spanl` toks) $ \case
123 TokenPair (PairElem "li" _) _ -> True
124 TokenPlain txt -> Char.isSpace`Text.all`txt
126 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
127 , if null ko then kos else mk ko<|kos )
131 TokenPlain{} -> False
134 gatherOL :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
136 let (lis, ts') = spanLIs ts in
137 foldl' accumLIs (mempty,ts') lis
139 spanLIs = Seq.spanl $ \case
140 TreeN KeyDot{} _ -> True
141 Tree0 (Tokens toks) ->
143 TokenPair (PairElem "li" _) _ -> True
146 accumLIs acc@(oks,kos) t =
148 TreeN KeyDot{} _ -> (oks|>t,kos)
149 Tree0 (Tokens toks) ->
150 let mk = Tree0 . Tokens in
152 (`Seq.spanl` toks) $ \case
153 TokenPair (PairElem "li" _) _ -> True
154 TokenPlain txt -> Char.isSpace`Text.all`txt
156 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
157 , if null ko then kos else mk ko<|kos )
161 TokenPlain{} -> False
164 d_Tree :: [Key] -> Tree Key Tokens -> DTC
165 d_Tree path (TreeN key@KeySection{} ts) =
166 case Seq.viewl children of
167 Tree0 (toList -> [TokenPlain title]) :< body ->
168 d_attrs (mangleAttrs title attrs) $
169 case Text.splitOn "\n" title of
171 D.section ! DA.name (attrValue t0) $ do
172 let st = Text.intercalate "\n" t1
173 when (not (Text.null st)) $
174 D.name $ B.toMarkup st
177 D.section ! DA.name (attrValue title) $
179 Tree0 title :< body ->
180 d_attrs (mangleAttrs (TL.toStrict $ Write.t_Tokens title) attrs) $
182 D.name $ d_Tokens (key:path) title
186 D.section $ d_content children
188 (attrs,children) = partitionAttributesChildren ts
189 d_content cs = d_Trees (key:path) cs
190 mangleAttrs :: Text -> Attributes -> Attributes
191 mangleAttrs title = Map.insertWith (\_new old -> old) "id" title
192 d_Tree path (Tree0 ts) =
196 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens path ts
197 _ -> D.para $ d_Tokens path ts
200 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens path ts
201 _ -> D.para $ d_Tokens path ts
202 _ -> d_Tokens path ts
203 d_Tree path (TreeN cell@KeyColon{} ts) =
204 let (attrs,children) = partitionAttributesChildren ts in
205 d_attrs attrs $ d_Key path cell children
206 d_Tree path (TreeN cell ts) = d_Key path cell ts
208 d_Key :: [Key] -> Key -> Trees Key Tokens -> DTC
209 d_Key path key cells = do
211 KeyColon n _wh -> d_key n
212 KeyGreat n _wh -> d_key n
213 KeyEqual n _wh -> d_key n
214 KeyBar n _wh -> d_key n
215 KeyDot _n -> D.li $ d_Trees (key:path) cells
216 KeyDash -> D.li $ d_Trees (key:path) cells
218 KeyLower name attrs -> do
219 B.Content $ "<"<>B.toMarkup name
221 forM_ cells $ d_Tree path
225 d_key name | null cells =
226 B.CustomLeaf (B.Text name) True mempty
228 B.CustomParent (B.Text name) $
229 d_Trees (key:path) cells
231 d_Tokens :: [Key] -> Tokens -> DTC
232 d_Tokens _path tok = goTokens tok
234 -- indent = Text.replicate (columnPos pos - 1) " "
236 go (TokenPlain t) = B.toMarkup t
237 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
238 go (TokenEscape c) = B.toMarkup c
239 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
240 go (TokenPair PairSlash ts) = D.i $ goTokens ts
241 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
242 go (TokenPair PairFrenchquote ts) = D.q $ goTokens ts
243 go (TokenPair PairHash (toList -> [TokenPlain ts])) =
244 D.ref mempty ! DA.to (attrValue ts)
245 go (TokenPair (PairElem name attrs) ts) =
248 Tokens s | Seq.null s ->
249 B.CustomLeaf (B.Text name) True mempty
250 _ -> B.CustomParent (B.Text name) $ goTokens ts
251 go (TokenPair p ts) = do
252 let (o,c) = pairBorders p ts
256 goTokens :: Tokens -> DTC
257 goTokens (Tokens ts) = foldMap go ts
259 d_Attrs :: Attrs -> DTC -> DTC
260 d_Attrs = flip $ foldl' d_Attr
262 d_Attr :: DTC -> (Text,Attr) -> DTC
263 d_Attr acc (_,Attr{..}) =
269 -- attr_id :: Text -> [(Text,Text)] -> [(Text,Text)]
270 -- attr_id title = ("id",title)
272 -- * Type 'Attributes'
273 type Attributes = Map Name Text
275 d_attrs :: Attributes -> DTC -> DTC
276 d_attrs = flip $ Map.foldrWithKey $ \n v ->
277 B.AddCustomAttribute (B.Text n) (B.Text v)
279 partitionAttributesChildren ::
281 (Attributes, Trees Key Tokens)
282 partitionAttributesChildren ts = (attrs,children)
289 TreeN (KeyEqual n _wh) a -> Map.insert n v acc
292 Write.text Write.config_text{Write.config_text_escape = False} $
293 mapTreeKey cell1 (\_path -> cell1) <$> a
294 -- Write.treeRackUpLeft <$> a
297 children = Seq.filter (\t ->
300 TreeN KeyEqual{} _cs -> False