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.Lazy as TL
27 import qualified Text.Blaze as B
28 import qualified Text.Blaze.Internal as B
30 import Language.TCT.Tree
31 import Language.TCT.Token
32 import Language.TCT.Elem hiding (trac,dbg)
33 import qualified Language.TCT.Write.Text as Write
34 import Text.Blaze.Utils
35 import Text.Blaze.DTC (DTC)
36 import qualified Text.Blaze.DTC as D
37 import qualified Text.Blaze.DTC.Attributes as DA
39 import Debug.Trace (trace)
40 trac :: String -> a -> a
43 dbg :: Show a => String -> a -> a
44 dbg m x = trac (m <> ": " <> show x) x
46 dtc :: Trees (Cell Key) (Cell Tokens) -> DTC
49 D.xmlModel "./schema/dtc.rnc"
50 D.xmlStylesheet $ "./xsl/document.html5."<>lang<>".xsl"
51 D.html5Stylesheet $ "./xsl/document.html5."<>lang<>".xsl"
52 D.atomStylesheet $ "./xsl/document.atom."<>lang<>".xsl"
55 TreeN (unCell -> KeySection{})
56 (Seq.viewl -> Tree0 (unCell -> Write.t_Tokens -> title) :< head)
58 d_Trees [] (mangleHead title head)
65 Trees (Cell Key) (Cell Tokens) ->
66 Trees (Cell Key) (Cell Tokens)
67 mangleHead title head =
69 (`Seq.findIndexL` head) $ \case
70 TreeN (unCell -> KeyColon "about" _) _ -> True
74 TreeN (cell0 (KeyColon "about" ""))
77 Just i -> Seq.adjust f i head
79 f (TreeN c about) = TreeN c $ Seq.fromList names <> about
82 names = name <$> TL.splitOn "\n" title
84 TreeN (cell0 (KeyColon "name" "")) .
87 Tokens . Seq.singleton . TokenPlain
89 d_Trees :: [Key] -> Trees (Cell Key) (Cell 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
105 Trees (Cell Key) (Cell Tokens) ->
106 ( Trees (Cell Key) (Cell Tokens)
107 , Trees (Cell Key) (Cell Tokens) )
109 let (lis, ts') = spanLIs ts in
110 foldl' accumLIs (mempty,ts') lis
112 spanLIs = Seq.spanl $ \case
113 TreeN (unCell -> KeyDash) _ -> True
114 Tree0 (unCell -> Tokens toks) ->
116 TokenPair (PairElem "li" _) _ -> True
119 accumLIs acc@(oks,kos) t =
121 TreeN (unCell -> KeyDash) _ -> (oks|>t,kos)
122 Tree0 (Cell pos posEnd (Tokens toks)) ->
123 let mk = Tree0 . Cell pos posEnd . Tokens in
125 (`Seq.spanl` toks) $ \case
126 TokenPair (PairElem "li" _) _ -> True
127 TokenPlain txt -> Char.isSpace`TL.all`txt
129 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
130 , if null ko then kos else mk ko<|kos )
134 TokenPlain{} -> False
138 Trees (Cell Key) (Cell Tokens) ->
139 ( Trees (Cell Key) (Cell Tokens)
140 , Trees (Cell Key) (Cell Tokens) )
142 let (lis, ts') = spanLIs ts in
143 foldl' accumLIs (mempty,ts') lis
145 spanLIs = Seq.spanl $ \case
146 TreeN (unCell -> KeyDot{}) _ -> True
147 Tree0 (unCell -> Tokens toks) ->
149 TokenPair (PairElem "li" _) _ -> True
152 accumLIs acc@(oks,kos) t =
154 TreeN (unCell -> KeyDot{}) _ -> (oks|>t,kos)
155 Tree0 (Cell pos posEnd (Tokens toks)) ->
156 let mk = Tree0 . Cell pos posEnd . Tokens in
158 (`Seq.spanl` toks) $ \case
159 TokenPair (PairElem "li" _) _ -> True
160 TokenPlain txt -> Char.isSpace`TL.all`txt
162 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
163 , if null ko then kos else mk ko<|kos )
167 TokenPlain{} -> False
170 d_Tree :: [Key] -> Tree (Cell Key) (Cell Tokens) -> DTC
171 d_Tree path (TreeN (unCell -> key@KeySection{}) ts) =
172 case Seq.viewl children of
173 Tree0 (Cell _posTitle _ (toList -> [TokenPlain title])) :< body ->
174 d_attrs (mangleAttrs title attrs) $
175 case TL.splitOn "\n" title of
177 D.section ! DA.name (attrValue t0) $ do
178 let st = TL.intercalate "\n" t1
179 when (not (TL.null st)) $
180 D.name $ B.toMarkup st
183 D.section ! DA.name (attrValue title) $
185 Tree0 (Cell _posTitle _ title) :< body ->
186 d_attrs (mangleAttrs (Write.t_Tokens title) attrs) $
188 D.name $ d_Tokens (key:path) title
192 D.section $ d_content children
194 (attrs,children) = partitionAttributesChildren ts
195 d_content cs = d_Trees (key:path) cs
196 mangleAttrs :: TL.Text -> Attributes -> Attributes
197 mangleAttrs title = Map.insertWith (\_new old -> old) "id" title
198 d_Tree path (Tree0 cell) = d_CellTokens path cell
199 d_Tree path (TreeN cell@(unCell -> KeyColon{}) ts) =
200 let (attrs,children) = partitionAttributesChildren ts in
201 d_attrs attrs $ d_CellKey path cell children
202 d_Tree path (TreeN cell ts) = d_CellKey path cell ts
204 d_CellKey :: [Key] -> Cell Key -> Trees (Cell Key) (Cell Tokens) -> DTC
205 d_CellKey path (Cell _pos _posEnd key) cells = do
207 KeyColon n _wh -> d_Key n
208 KeyGreat n _wh -> d_Key n
209 KeyEqual n _wh -> d_Key n
210 KeyBar n _wh -> d_Key n
211 KeyDot _n -> D.li $ d_Trees (key:path) cells
212 KeyDash -> D.li $ d_Trees (key:path) cells
214 KeyLower name attrs -> do
215 B.Content $ "<"<>B.toMarkup name
217 forM_ cells $ d_Tree path
221 d_Key name | null cells =
222 B.CustomLeaf (B.Text name) True mempty
224 B.CustomParent (B.Text name) $
225 d_Trees (key:path) cells
227 d_CellTokens :: [Key] -> Cell Tokens -> DTC
228 d_CellTokens path (Cell _pos _posEnd ts) =
229 -- case L.find (\case KeySection{} -> True; _ -> False) $ dbg "d_CellTokens: path:" path of
230 case dbg "d_CellTokens: path" path of
233 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens path ts
234 _ -> D.para $ d_Tokens path ts
237 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens path ts
238 _ -> D.para $ d_Tokens path ts
239 _ -> d_Tokens path ts
241 d_Tokens :: [Key] -> Tokens -> DTC
242 d_Tokens _path tok = goTokens tok
244 -- indent = Text.replicate (columnPos pos - 1) " "
246 go (TokenPlain t) = B.toMarkup t
247 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
248 go (TokenEscape c) = B.toMarkup c
249 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
250 go (TokenPair PairSlash ts) = D.i $ goTokens ts
251 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
252 go (TokenPair PairFrenchquote ts) = D.q $ goTokens ts
253 go (TokenPair PairHash (toList -> [TokenPlain ts])) =
254 D.ref mempty ! DA.to (attrValue ts)
255 go (TokenPair (PairElem name attrs) ts) =
258 Tokens s | Seq.null s ->
259 B.CustomLeaf (B.Text name) True mempty
260 _ -> B.CustomParent (B.Text name) $ goTokens ts
261 go (TokenPair p ts) = do
262 let (o,c) = pairBorders p ts
266 goTokens :: Tokens -> DTC
267 goTokens (Tokens ts) = foldMap go ts
269 d_Attrs :: Attrs -> DTC -> DTC
270 d_Attrs = flip $ foldl' d_Attr
272 d_Attr :: DTC -> (Text,Attr) -> DTC
273 d_Attr acc (_,Attr{..}) =
279 -- attr_id :: Text -> [(Text,Text)] -> [(Text,Text)]
280 -- attr_id title = ("id",title)
282 -- * Type 'Attributes'
283 type Attributes = Map Name TL.Text
285 d_attrs :: Attributes -> DTC -> DTC
286 d_attrs = flip $ Map.foldrWithKey $ \n v ->
287 B.AddCustomAttribute (B.Text n) (B.Text $ TL.toStrict v)
289 partitionAttributesChildren ::
290 Trees (Cell Key) (Cell Tokens) ->
291 (Attributes, Trees (Cell Key) (Cell Tokens))
292 partitionAttributesChildren ts = (attrs,children)
299 TreeN (unCell -> KeyEqual n _wh) a -> Map.insert n v acc
302 Write.text Write.config_text{Write.config_text_escape = False} $
303 Write.treeRackUpLeft <$> a
306 children = Seq.filter (\t ->
309 TreeN (unCell -> KeyEqual{}) _cs -> False