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.Applicative (Applicative(..))
9 import Control.Arrow (first)
10 import Control.Monad (Monad(..), (=<<), mapM, sequence_)
12 import Data.Eq (Eq(..))
13 import Data.Foldable (foldr, null, foldl', any)
14 import Data.Function (($), (.), flip, id)
15 import Data.Functor ((<$>))
16 import Data.Map.Strict (Map)
17 import Data.Maybe (Maybe(..))
18 import Data.Monoid (Monoid(..))
19 import Data.Semigroup (Semigroup(..))
20 import Data.Sequence (ViewL(..), ViewR(..), (<|), (|>))
21 import Data.String (String)
22 import Data.Text (Text)
23 import GHC.Exts (toList)
24 import Text.Blaze ((!))
25 import Text.Show (Show(..))
26 import qualified Control.Monad.Trans.State as S
27 import qualified Data.Char as Char
28 import qualified Data.List as List
29 import qualified Data.Map.Strict as Map
30 import qualified Data.Sequence as Seq
31 import qualified Data.Text as Text
32 import qualified Data.Text.Lazy as TL
33 import qualified System.FilePath as FP
34 import qualified Text.Blaze as B
35 import qualified Text.Blaze.Internal as B
37 import Language.TCT.Elem hiding (trac,dbg)
38 import Language.TCT.Token
39 import Language.TCT.Tree
40 import Text.Blaze.DTC (DTC)
41 import Text.Blaze.Utils
42 import qualified Language.TCT.Write.Text as Write
43 import qualified Text.Blaze.DTC as D
44 import qualified Text.Blaze.DTC.Attributes as DA
46 -- import Debug.Trace (trace)
47 trac :: String -> a -> a
49 -- trac m x = trace m x
50 dbg :: Show a => String -> a -> a
51 dbg m x = trac (m <> ": " <> show x) x
56 { inh_dtc_figure :: Bool
57 , inh_dtc_tree0 :: [(DTC -> DTC)]
61 { inh_dtc_figure = False
68 { chan_dtc_tree0 :: [(DTC -> DTC)]
76 mimetype :: Text -> Maybe Text
77 mimetype "sh" = Just "text/x-shellscript"
78 mimetype "shell" = Just "text/x-shellscript"
79 mimetype "shellscript" = Just "text/x-shellscript"
82 (<>=) :: (Monad m, Semigroup a) => m a -> m a -> m a
83 (<>=) m n = (<>) <$> m <*> n
86 dtc :: Trees Key Tokens -> DTC
89 D.xmlModel "./schema/dtc.rnc"
90 D.xmlStylesheet $ "./xsl/document.html5."<>lang<>".xsl"
91 D.html5Stylesheet $ "./xsl/document.html5."<>lang<>".xsl"
92 D.atomStylesheet $ "./xsl/document.atom."<>lang<>".xsl"
94 (`S.evalState` chan_dtc) $
96 TreeN KeySection{} (spanlTree0 -> (title, head)) :< body ->
97 d_Trees inh_dtc (mangleHead title head) <>=
98 d_Trees inh_dtc{inh_dtc_figure = True} body
99 _ -> d_Trees inh_dtc{inh_dtc_figure = True} ts
105 mangleHead title head =
107 (`Seq.findIndexL` head) $ \case
108 TreeN (KeyColon "about" _) _ -> True
111 Nothing -> TreeN (KeyColon "about" "") title <| head
112 Just i -> Seq.adjust f i head
114 f (TreeN c about) = TreeN c $ title <> about
117 d_Trees :: Inh_DTC -> Trees Key Tokens -> S.State Chan_DTC DTC
118 d_Trees inh_orig = go inh_orig
121 case Seq.viewl trs of
122 TreeN (KeyBar n _) _ :< _
123 | (body,ts) <- spanlBar n trs
125 ((D.artwork !?? (mimetype n, DA.type_ . attrValue)) . sequence_ <$>
126 d_Tree inh{inh_dtc_tree0=[]} `mapM` body) <>=
129 TreeN KeyBrackets{} _ :< _
130 | (refs,ts) <- spanlBrackets trs
132 (D.references . sequence_ <$> d_Tree inh_orig `mapM` refs) <>=
135 TreeN key@(KeyColon n _) cs :< ts
136 | (cs',ts') <- spanlKeyName n ts
138 go inh $ TreeN key (cs<>cs') <| ts'
140 _ | (ul,ts) <- spanlItems (==KeyDash) trs
142 ((D.ul ! DA.style "format —") . sequence_ <$> d_Tree inh_orig `mapM` ul) <>=
145 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trs
147 (D.ol . sequence_ <$> d_Tree inh_orig `mapM` ol) <>=
150 t@(Tree0 toks) :< ts | isTokenElem toks ->
151 d_Tree inh_orig t <>=
154 case inh_dtc_tree0 inh of
156 d_Tree inh_orig t <>=
157 go inh{inh_dtc_tree0=[]} ts
159 (d <$> d_Tree inh_orig t) <>=
160 go inh{inh_dtc_tree0=ds} ts
163 d_Tree inh_orig t <>=
166 _ -> return $ return ()
168 d_Tree :: Inh_DTC -> Tree Key Tokens -> S.State Chan_DTC DTC
171 TreeN KeySection{} ts -> do
172 let (attrs,body) = partitionAttributesChildren ts
173 let inh' = inh{inh_dtc_tree0 = D.name : List.repeat D.para}
174 d_Attributes (setAttrId (getAttrId body) attrs) . D.section <$>
176 TreeN key@(KeyColon kn _) ts -> do
177 let (attrs,body) = partitionAttributesChildren ts
178 let inh' = inh{inh_dtc_tree0 =
180 "about" -> D.name : D.name : List.repeat D.para
181 "reference" -> D.name : D.name : List.repeat D.para
182 "author" -> List.repeat D.name
185 if inh_dtc_figure inh && not (kn`List.elem`D.elems)
187 d_Attributes attrs . (D.figure ! DA.type_ (attrValue kn)) <$>
189 [Tree0{}] -> d_Trees inh'{inh_dtc_tree0 = List.repeat D.para} body
190 _ -> d_Trees inh'{inh_dtc_tree0 = D.name : List.repeat D.para} body
191 else d_Attributes attrs <$> d_Key inh' key body
192 TreeN key ts -> d_Key inh key ts
193 Tree0 ts -> return $ d_Tokens ts
195 d_Key :: Inh_DTC -> Key -> Trees Key Tokens -> S.State Chan_DTC DTC
198 KeyColon n _wh -> d_key n
199 KeyGreat n _wh -> d_key n
200 KeyEqual n _wh -> d_key n
201 KeyBar n _wh -> d_key n
202 KeyDot _n -> D.li <$> d_Trees inh ts
203 KeyDash -> D.li <$> d_Trees inh ts
204 KeyDashDash -> return $ B.Comment (B.Text $ TL.toStrict com) ()
206 Write.text Write.config_text $
207 mapTreeKey cell1 (\_path -> cell1) <$> ts
209 S.modify $ \chan -> chan{chan_dtc_tree0=[]}
210 D.artwork <$> d_Trees inh ts
211 KeyBrackets ident -> do
212 let (attrs,body) = partitionAttributesChildren ts
213 let inh' = inh{inh_dtc_figure = False}
214 S.modify $ \chan -> chan{chan_dtc_tree0 =
215 D.name : D.name : List.repeat D.para
217 d_Attributes (setAttrId ident attrs) .
218 D.reference <$> d_Trees inh' body
220 return (D.include True $ attrValue $ FP.replaceExtension p "dtc") <>=
223 d_key :: Text -> S.State Chan_DTC DTC
224 d_key n | null ts = return $ B.CustomLeaf (B.Text n) True mempty
225 d_key n = B.CustomParent (B.Text n) <$> d_Trees inh ts
227 d_Tokens :: Tokens -> DTC
228 d_Tokens tok = goTokens tok
231 go (TokenPlain t) = B.toMarkup t
232 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
233 go (TokenEscape c) = B.toMarkup c
234 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
235 go (TokenPair PairBracket ts)
236 | to <- Write.t_Tokens ts
237 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to =
238 D.rref ! DA.to (attrValue $ TL.toStrict to) $ mempty
239 go (TokenPair PairStar ts) = D.b $ goTokens ts
240 go (TokenPair PairSlash ts) = D.i $ goTokens ts
241 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
242 go (TokenPair PairFrenchquote toks@(Tokens ts)) =
245 (Seq.viewl -> TokenPlain l :< ls) ->
249 TokenPlain (Text.dropWhile Char.isSpace l)
250 <|(m|>TokenPlain (Text.dropWhileEnd Char.isSpace r))
253 TokenPlain (Text.dropAround Char.isSpace l) <| ls
254 (Seq.viewr -> rs :> TokenPlain r) ->
256 rs |> TokenPlain (Text.dropAround Char.isSpace r)
258 go (TokenPair PairHash (toList -> [TokenPlain ts])) =
259 D.ref mempty ! DA.to (attrValue ts)
260 go (TokenPair (PairElem name attrs) ts) =
264 B.CustomLeaf (B.Text name) True mempty
265 _ -> B.CustomParent (B.Text name) $ goTokens ts
266 go (TokenPair p ts) = do
267 let (o,c) = pairBorders p ts
272 goTokens :: Tokens -> DTC
273 goTokens (Tokens toks) =
274 case Seq.viewl toks of
275 TokenPair PairParen b :< (Seq.viewl -> TokenPair PairBracket p :< ts) -> do
277 Tokens (toList -> [TokenLink lnk]) ->
278 D.eref ! DA.to (attrValue lnk) $ goTokens b
279 _ -> D.rref ! DA.to (attrValue $ TL.toStrict $ Write.t_Tokens p) $ goTokens b
281 t :< ts -> go t <> goTokens (Tokens ts)
284 spanlTree0 :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
290 spanlBar :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
291 spanlBar name = first unKeyBar . spanBar
293 unKeyBar :: Trees Key Tokens -> Trees Key Tokens
294 unKeyBar = (=<<) $ \case
295 TreeN KeyBar{} ts -> ts
299 TreeN (KeyBar n _) _ | n == name -> True
302 spanlKeyName :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
305 TreeN (KeyBar n _) _ -> n == name
306 TreeN (KeyGreat n _) _ -> n == name
309 spanlBrackets :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
312 TreeN KeyBrackets{} _ -> True
318 (Trees Key Tokens, Trees Key Tokens)
319 spanlItems liKey ts =
320 let (lis, ts') = spanLIs ts in
321 foldl' accumLIs (mempty,ts') lis
323 spanLIs = Seq.spanl $ \case
324 TreeN (liKey -> True) _ -> True
325 Tree0 (Tokens toks) ->
327 TokenPair (PairElem "li" _) _ -> True
330 accumLIs acc@(oks,kos) t =
332 TreeN (liKey -> True) _ -> (oks|>t,kos)
333 Tree0 (Tokens toks) ->
334 let mk = Tree0 . Tokens in
336 (`Seq.spanl` toks) $ \case
337 TokenPair (PairElem "li" _) _ -> True
338 TokenPlain txt -> Char.isSpace`Text.all`txt
340 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
341 , if null ko then kos else mk ko<|kos )
345 TokenPlain{} -> False
348 getAttrId :: Trees Key Tokens -> (Text)
350 case Seq.index ts <$> Seq.findIndexL isTree0 ts of
351 Just (Tree0 toks) -> TL.toStrict $ Write.t_Tokens toks
355 setAttrId :: Text -> Attributes -> Attributes
356 setAttrId ident | Text.null ident = id
357 setAttrId ident = Map.insertWith (\_new old -> old) "id" ident
359 d_Attrs :: Attrs -> DTC -> DTC
360 d_Attrs = flip $ foldl' d_Attr
362 d_Attr :: DTC -> (Text,Attr) -> DTC
363 d_Attr acc (_,Attr{..}) =
369 -- * Type 'Attributes'
370 type Attributes = Map Name Text
372 d_Attributes :: Attributes -> DTC -> DTC
373 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
374 B.AddCustomAttribute (B.Text n) (B.Text v)
376 partitionAttributesChildren ::
378 (Attributes, Trees Key Tokens)
379 partitionAttributesChildren ts = (attrs,children)
386 TreeN (KeyEqual n _wh) a -> Map.insert n v acc
389 Write.text Write.config_text{Write.config_text_escape = False} $
390 mapTreeKey cell1 (\_path -> cell1) <$> a
391 -- Write.treeRackUpLeft <$> a
394 children = Seq.filter (\t ->
397 TreeN KeyEqual{} _cs -> False