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.Arrow (first)
9 import Control.Monad (Monad(..), (=<<), forM_, when)
11 import Data.Eq (Eq(..))
12 import Data.Foldable (foldr, null, foldMap, foldl', any)
13 import Data.Function (($), (.), flip, id)
14 import Data.Functor (Functor(..), (<$>))
15 import Data.Map.Strict (Map)
16 import Data.Maybe (Maybe(..))
17 import Data.Monoid (Monoid(..))
18 import Data.Semigroup (Semigroup(..))
19 import Data.Sequence (ViewL(..), ViewR(..), (<|), (|>))
20 import Data.String (String)
21 import Data.Text (Text)
22 import GHC.Exts (toList)
23 import Text.Blaze ((!))
24 import Text.Show (Show(..))
25 import qualified Data.Char as Char
26 import qualified Data.Map.Strict as Map
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 as B
31 import qualified Text.Blaze.Internal as B
33 import Language.TCT.Tree
34 import Language.TCT.Token
35 import Language.TCT.Elem hiding (trac,dbg)
36 import qualified Language.TCT.Write.Text as Write
37 import Text.Blaze.Utils
38 import Text.Blaze.DTC (DTC)
39 import qualified Text.Blaze.DTC as D
40 import qualified Text.Blaze.DTC.Attributes as DA
42 import Debug.Trace (trace)
43 trac :: String -> a -> a
45 -- trac m x = trace m x
46 dbg :: Show a => String -> a -> a
47 dbg m x = trac (m <> ": " <> show x) x
52 { inh_dtc_para :: DTC -> DTC
53 , inh_dtc_figure :: Bool
58 , inh_dtc_figure = False
61 mimetype :: Text -> Maybe Text
62 mimetype "sh" = Just "text/x-shellscript"
63 mimetype "shell" = Just "text/x-shellscript"
64 mimetype "shellscript" = Just "text/x-shellscript"
67 dtc :: Trees Key Tokens -> DTC
70 D.xmlModel "./schema/dtc.rnc"
71 D.xmlStylesheet $ "./xsl/document.html5."<>lang<>".xsl"
72 D.html5Stylesheet $ "./xsl/document.html5."<>lang<>".xsl"
73 D.atomStylesheet $ "./xsl/document.atom."<>lang<>".xsl"
77 (Seq.viewl -> Tree0 (Write.t_Tokens -> TL.toStrict -> title) :< head)
79 d_Trees inh_dtc (mangleHead title head)
81 inh_dtc { inh_dtc_figure = True }
85 inh_dtc { inh_dtc_figure = True }
92 mangleHead title head =
94 (`Seq.findIndexL` head) $ \case
95 TreeN (KeyColon "about" _) _ -> True
99 TreeN (KeyColon "about" "")
102 Just i -> Seq.adjust f i head
104 f (TreeN c about) = TreeN c $ Seq.fromList names <> about
107 names = name <$> Text.splitOn "\n" title
109 TreeN (KeyColon "name" "") .
110 Seq.singleton . Tree0 .
113 d_Trees :: Inh_DTC -> Trees Key Tokens -> DTC
116 TreeN (KeyBar n _) _ :< _
117 | (content,ts') <- gatherBar n ts -> do
118 D.artwork !?? (mimetype n, DA.type_ . attrValue) $
119 d_Trees inh{inh_dtc_para=id} content
122 TreeN KeyBrackets{} _ :< _
123 | (refs,ts') <- gatherBrackets ts, not (null refs) -> do
125 forM_ refs $ d_Tree inh
128 TreeN key@(KeyColon n _) cs :< ts'
129 | (cs',ts'') <- gatherColon n ts'
131 d_Trees inh $ TreeN key (cs<>cs') <| ts''
133 _ | (ul,ts') <- gatherLI (==KeyDash) ts, not (null ul) -> do
134 D.ul ! DA.style "format —" $
135 forM_ ul $ d_Tree inh
138 _ | (ol,ts') <- gatherLI (\case KeyDot{} -> True; _ -> False) ts, not (null ol) -> do
139 D.ol $ forM_ ol $ d_Tree inh
149 gatherBar :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
150 gatherBar name = first unKeyBar . spanBar
152 unKeyBar :: Trees Key Tokens -> Trees Key Tokens
153 unKeyBar = (=<<) $ \case
154 TreeN KeyBar{} ts -> ts
158 TreeN (KeyBar n _) _ | n == name -> True
161 gatherColon :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
164 TreeN (KeyBar n _) _ -> n == name
165 TreeN (KeyGreat n _) _ -> n == name
168 gatherBrackets :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
171 TreeN KeyBrackets{} _ -> True
175 gatherColon :: Trees Key Tokens -> Maybe (Name, Tokens, Trees Key Tokens, Trees Key Tokens)
178 TreeN (KeyColon name _) (toList -> [Tree0 head]) :< (spanBar name -> (body,ts')) ->
179 Just (name,head,body,ts')
184 TreeN (KeyBar n _) _ | n == name -> True
191 (Trees Key Tokens, Trees Key Tokens)
193 let (lis, ts') = spanLIs ts in
194 foldl' accumLIs (mempty,ts') lis
196 spanLIs = Seq.spanl $ \case
197 TreeN (liKey -> True) _ -> True
198 Tree0 (Tokens toks) ->
200 TokenPair (PairElem "li" _) _ -> True
203 accumLIs acc@(oks,kos) t =
205 TreeN (liKey -> True) _ -> (oks|>t,kos)
206 Tree0 (Tokens toks) ->
207 let mk = Tree0 . Tokens in
209 (`Seq.spanl` toks) $ \case
210 TokenPair (PairElem "li" _) _ -> True
211 TokenPlain txt -> Char.isSpace`Text.all`txt
213 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
214 , if null ko then kos else mk ko<|kos )
218 TokenPlain{} -> False
223 (Name, Tokens, Attributes, Trees Key Tokens)
224 gatherName ts = dbg "gatherName" $
225 case Seq.viewl children of
226 Tree0 (toList -> [TokenPlain name]) :< body ->
227 case Text.splitOn "\n" name of
228 n:[] -> (n,mempty,attrs,body)
229 n:ns -> (n,tokens [TokenPlain $ Text.intercalate "\n" ns],attrs,body)
230 [] -> (name,mempty,attrs,body)
231 Tree0 name :< body -> ("",name,attrs,body)
232 _ -> ("",mempty,attrs,children)
234 (attrs,children) = partitionAttributesChildren ts
236 d_Tree :: Inh_DTC -> Tree Key Tokens -> DTC
237 d_Tree inh (TreeN KeySection{} ts) =
239 { inh_dtc_para = D.para
241 case gatherName ts of
242 ("",Tokens (null->True),attrs,body) ->
244 D.section $ d_Trees inh' body
245 ("",names,attrs,body) ->
246 d_Attributes (setAttrId (TL.toStrict $ Write.t_Tokens names) attrs) $
248 D.name $ d_Tokens names
250 (name,names,attrs,body) ->
251 d_Attributes (setAttrId name attrs) $
252 D.section ! DA.name (attrValue name) $ do
253 when (not $ null $ unTokens names) $
254 D.name $ d_Tokens names
256 d_Tree inh (TreeN key@(KeyColon typ _) ts) =
257 if inh_dtc_figure inh
259 case gatherName ts of
260 ("",names,attrs,body) ->
262 D.figure ! DA.type_ (attrValue typ) $ do
263 when (not $ null $ unTokens names) $
264 D.name $ d_Tokens names
266 (name,names,attrs,body) ->
268 D.figure ! DA.type_ (attrValue typ)
269 ! DA.name (attrValue name) $ do
270 when (not $ null $ unTokens names) $
271 D.name $ d_Tokens names
274 let (attrs,body) = partitionAttributesChildren ts in
277 d_Tree path (TreeN key ts) = d_Key path key ts
278 d_Tree inh (Tree0 ts) =
280 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens ts
281 _ -> inh_dtc_para inh $ d_Tokens ts
283 setAttrId :: Text -> Attributes -> Attributes
284 setAttrId = Map.insertWith (\_new old -> old) "id"
286 d_Key :: Inh_DTC -> Key -> Trees Key Tokens -> DTC
287 d_Key inh key ts = do
289 KeyColon n _wh -> d_key n
290 KeyGreat n _wh -> d_key n
291 KeyEqual n _wh -> d_key n
292 KeyBar n _wh -> d_key n
293 KeyDot _n -> D.li $ d_Trees inh ts
294 KeyDash -> D.li $ d_Trees inh ts
295 KeyDashDash -> B.Comment (B.Text $ TL.toStrict com) ()
298 Write.text Write.config_text $
299 mapTreeKey cell1 (\_path -> cell1) <$> ts
301 D.artwork $ d_Trees inh{inh_dtc_para = id} ts
303 case gatherName ts of
304 ("",Tokens (null->True),attrs,body) ->
305 d_Attributes (setAttrId n attrs) $
306 D.reference $ d_Trees inh body
307 ("",names,attrs,body) ->
308 d_Attributes (setAttrId n attrs) $
310 D.name $ d_Tokens names
312 (name,names,attrs,body) ->
313 d_Attributes (setAttrId n attrs) $
314 D.reference ! DA.name (attrValue name) $ do
315 when (not $ null $ unTokens names) $
316 D.name $ d_Tokens names
320 d_key name | null ts =
321 B.CustomLeaf (B.Text name) True mempty
323 B.CustomParent (B.Text name) $
326 d_Tokens :: Tokens -> DTC
327 d_Tokens tok = goTokens tok
329 -- indent = Text.replicate (columnPos pos - 1) " "
331 go (TokenPlain t) = B.toMarkup t
332 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
333 go (TokenEscape c) = B.toMarkup c
334 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
335 go (TokenPair PairBracket ts)
336 | to <- Write.t_Tokens ts
337 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to =
338 D.rref ! DA.to (attrValue $ TL.toStrict to) $ mempty
339 go (TokenPair PairStar ts) = D.b $ goTokens ts
340 go (TokenPair PairSlash ts) = D.i $ goTokens ts
341 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
342 go (TokenPair PairFrenchquote toks@(Tokens ts)) =
345 (Seq.viewl -> TokenPlain l :< ls) ->
349 TokenPlain (Text.dropWhile Char.isSpace l)
350 <|(m|>TokenPlain (Text.dropWhileEnd Char.isSpace r))
353 TokenPlain (Text.dropAround Char.isSpace l) <| ls
354 (Seq.viewr -> rs :> TokenPlain r) ->
356 rs |> TokenPlain (Text.dropAround Char.isSpace r)
358 go (TokenPair PairHash (toList -> [TokenPlain ts])) =
359 D.ref mempty ! DA.to (attrValue ts)
360 go (TokenPair (PairElem name attrs) ts) =
363 Tokens s | Seq.null s ->
364 B.CustomLeaf (B.Text name) True mempty
365 _ -> B.CustomParent (B.Text name) $ goTokens ts
366 go (TokenPair p ts) = do
367 let (o,c) = pairBorders p ts
371 goTokens :: Tokens -> DTC
372 goTokens (Tokens toks) =
373 case Seq.viewl toks of
374 TokenPair PairParen b :< (Seq.viewl -> TokenPair PairBracket p :< ts) -> do
376 Tokens (toList -> [TokenLink lnk]) ->
377 D.eref ! DA.to (attrValue lnk) $ goTokens b
378 _ -> D.rref ! DA.to (attrValue $ TL.toStrict $ Write.t_Tokens p) $ goTokens b
380 t :< ts -> go t <> goTokens (Tokens ts)
383 d_Attrs :: Attrs -> DTC -> DTC
384 d_Attrs = flip $ foldl' d_Attr
386 d_Attr :: DTC -> (Text,Attr) -> DTC
387 d_Attr acc (_,Attr{..}) =
393 -- attr_id :: Text -> [(Text,Text)] -> [(Text,Text)]
394 -- attr_id title = ("id",title)
396 -- * Type 'Attributes'
397 type Attributes = Map Name Text
399 d_Attributes :: Attributes -> DTC -> DTC
400 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
401 B.AddCustomAttribute (B.Text n) (B.Text v)
403 partitionAttributesChildren ::
405 (Attributes, Trees Key Tokens)
406 partitionAttributesChildren ts = (attrs,children)
413 TreeN (KeyEqual n _wh) a -> Map.insert n v acc
416 Write.text Write.config_text{Write.config_text_escape = False} $
417 mapTreeKey cell1 (\_path -> cell1) <$> a
418 -- Write.treeRackUpLeft <$> a
421 children = Seq.filter (\t ->
424 TreeN KeyEqual{} _cs -> False