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
177 (Trees Key Tokens, Trees Key Tokens)
179 let (lis, ts') = spanLIs ts in
180 foldl' accumLIs (mempty,ts') lis
182 spanLIs = Seq.spanl $ \case
183 TreeN (liKey -> True) _ -> True
184 Tree0 (Tokens toks) ->
186 TokenPair (PairElem "li" _) _ -> True
189 accumLIs acc@(oks,kos) t =
191 TreeN (liKey -> True) _ -> (oks|>t,kos)
192 Tree0 (Tokens toks) ->
193 let mk = Tree0 . Tokens in
195 (`Seq.spanl` toks) $ \case
196 TokenPair (PairElem "li" _) _ -> True
197 TokenPlain txt -> Char.isSpace`Text.all`txt
199 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
200 , if null ko then kos else mk ko<|kos )
204 TokenPlain{} -> False
209 (Name, Tokens, Attributes, Trees Key Tokens)
210 gatherName ts = dbg "gatherName" $
211 case Seq.viewl children of
212 Tree0 (toList -> [TokenPlain name]) :< body ->
213 case Text.splitOn "\n" name of
214 n:[] -> (n,mempty,attrs,body)
215 n:ns -> (n,tokens [TokenPlain $ Text.intercalate "\n" ns],attrs,body)
216 [] -> (name,mempty,attrs,body)
217 Tree0 name :< body -> ("",name,attrs,body)
218 _ -> ("",mempty,attrs,children)
220 (attrs,children) = partitionAttributesChildren ts
222 d_Tree :: Inh_DTC -> Tree Key Tokens -> DTC
223 d_Tree inh (TreeN KeySection{} ts) =
225 { inh_dtc_para = D.para
227 case gatherName ts of
228 ("",Tokens (null->True),attrs,body) ->
230 D.section $ d_Trees inh' body
231 ("",names,attrs,body) ->
232 d_Attributes (setAttrId (TL.toStrict $ Write.t_Tokens names) attrs) $
234 D.name $ d_Tokens names
236 (name,names,attrs,body) ->
237 d_Attributes (setAttrId name attrs) $
238 D.section ! DA.name (attrValue name) $ do
239 when (not $ null $ unTokens names) $
240 D.name $ d_Tokens names
242 d_Tree inh (TreeN key@(KeyColon typ _) ts) =
243 if inh_dtc_figure inh
245 case gatherName ts of
246 ("",names,attrs,body) ->
248 D.figure ! DA.type_ (attrValue typ) $ do
249 when (not $ null $ unTokens names) $
250 D.name $ d_Tokens names
252 (name,names,attrs,body) ->
254 D.figure ! DA.type_ (attrValue typ)
255 ! DA.name (attrValue name) $ do
256 when (not $ null $ unTokens names) $
257 D.name $ d_Tokens names
260 let (attrs,body) = partitionAttributesChildren ts in
263 d_Tree path (TreeN key ts) = d_Key path key ts
264 d_Tree inh (Tree0 ts) =
266 (toList -> [TokenPair PairElem{} _ts]) -> d_Tokens ts
267 _ -> inh_dtc_para inh $ d_Tokens ts
269 setAttrId :: Text -> Attributes -> Attributes
270 setAttrId = Map.insertWith (\_new old -> old) "id"
272 d_Key :: Inh_DTC -> Key -> Trees Key Tokens -> DTC
273 d_Key inh key ts = do
275 KeyColon n _wh -> d_key n
276 KeyGreat n _wh -> d_key n
277 KeyEqual n _wh -> d_key n
278 KeyBar n _wh -> d_key n
279 KeyDot _n -> D.li $ d_Trees inh ts
280 KeyDash -> D.li $ d_Trees inh ts
281 KeyDashDash -> B.Comment (B.Text $ TL.toStrict com) ()
284 Write.text Write.config_text $
285 mapTreeKey cell1 (\_path -> cell1) <$> ts
287 D.artwork $ d_Trees inh{inh_dtc_para = id} ts
289 case gatherName ts of
290 ("",Tokens (null->True),attrs,body) ->
291 d_Attributes (setAttrId n attrs) $
292 D.reference $ d_Trees inh body
293 ("",names,attrs,body) ->
294 d_Attributes (setAttrId n attrs) $
296 D.name $ d_Tokens names
298 (name,names,attrs,body) ->
299 d_Attributes (setAttrId n attrs) $
300 D.reference ! DA.name (attrValue name) $ do
301 when (not $ null $ unTokens names) $
302 D.name $ d_Tokens names
306 d_key name | null ts =
307 B.CustomLeaf (B.Text name) True mempty
309 B.CustomParent (B.Text name) $
312 d_Tokens :: Tokens -> DTC
313 d_Tokens tok = goTokens tok
315 -- indent = Text.replicate (columnPos pos - 1) " "
317 go (TokenPlain t) = B.toMarkup t
318 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
319 go (TokenEscape c) = B.toMarkup c
320 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
321 go (TokenPair PairBracket ts)
322 | to <- Write.t_Tokens ts
323 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to =
324 D.rref ! DA.to (attrValue $ TL.toStrict to) $ mempty
325 go (TokenPair PairStar ts) = D.b $ goTokens ts
326 go (TokenPair PairSlash ts) = D.i $ goTokens ts
327 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
328 go (TokenPair PairFrenchquote toks@(Tokens ts)) =
331 (Seq.viewl -> TokenPlain l :< ls) ->
335 TokenPlain (Text.dropWhile Char.isSpace l)
336 <|(m|>TokenPlain (Text.dropWhileEnd Char.isSpace r))
339 TokenPlain (Text.dropAround Char.isSpace l) <| ls
340 (Seq.viewr -> rs :> TokenPlain r) ->
342 rs |> TokenPlain (Text.dropAround Char.isSpace r)
344 go (TokenPair PairHash (toList -> [TokenPlain ts])) =
345 D.ref mempty ! DA.to (attrValue ts)
346 go (TokenPair (PairElem name attrs) ts) =
349 Tokens s | Seq.null s ->
350 B.CustomLeaf (B.Text name) True mempty
351 _ -> B.CustomParent (B.Text name) $ goTokens ts
352 go (TokenPair p ts) = do
353 let (o,c) = pairBorders p ts
357 goTokens :: Tokens -> DTC
358 goTokens (Tokens toks) =
359 case Seq.viewl toks of
360 TokenPair PairParen b :< (Seq.viewl -> TokenPair PairBracket p :< ts) -> do
362 Tokens (toList -> [TokenLink lnk]) ->
363 D.eref ! DA.to (attrValue lnk) $ goTokens b
364 _ -> D.rref ! DA.to (attrValue $ TL.toStrict $ Write.t_Tokens p) $ goTokens b
366 t :< ts -> go t <> goTokens (Tokens ts)
369 d_Attrs :: Attrs -> DTC -> DTC
370 d_Attrs = flip $ foldl' d_Attr
372 d_Attr :: DTC -> (Text,Attr) -> DTC
373 d_Attr acc (_,Attr{..}) =
379 -- attr_id :: Text -> [(Text,Text)] -> [(Text,Text)]
380 -- attr_id title = ("id",title)
382 -- * Type 'Attributes'
383 type Attributes = Map Name Text
385 d_Attributes :: Attributes -> DTC -> DTC
386 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
387 B.AddCustomAttribute (B.Text n) (B.Text v)
389 partitionAttributesChildren ::
391 (Attributes, Trees Key Tokens)
392 partitionAttributesChildren ts = (attrs,children)
399 TreeN (KeyEqual n _wh) a -> Map.insert n v acc
402 Write.text Write.config_text{Write.config_text_escape = False} $
403 mapTreeKey cell1 (\_path -> cell1) <$> a
404 -- Write.treeRackUpLeft <$> a
407 children = Seq.filter (\t ->
410 TreeN KeyEqual{} _cs -> False