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(..), (=<<), forM_)
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 Data.Char as Char
27 import qualified Data.List as List
28 import qualified Data.Map.Strict as Map
29 import qualified Data.Sequence as Seq
30 import qualified Data.Text as Text
31 import qualified Data.Text.Lazy as TL
32 import qualified System.FilePath as FP
33 import qualified Text.Blaze as B
34 import qualified Text.Blaze.Internal as B
36 import Language.TCT.Elem hiding (trac,dbg)
37 import Language.TCT.Token
38 import Language.TCT.Tree
39 import Text.Blaze.DTC (DTC)
40 import Text.Blaze.Utils
41 import qualified Language.TCT.Write.Text as Write
42 import qualified Text.Blaze.DTC as D
43 import qualified Text.Blaze.DTC.Attributes as DA
45 -- import Debug.Trace (trace)
46 trac :: String -> a -> a
48 -- trac m x = trace m x
49 dbg :: Show a => String -> a -> a
50 dbg m x = trac (m <> ": " <> show x) x
55 { inh_dtc_figure :: Bool
56 , inh_dtc_tree0 :: [(DTC -> DTC)]
60 { inh_dtc_figure = False
64 mimetype :: Text -> Maybe Text
65 mimetype "hs" = Just "text/x-haskell"
66 mimetype "sh" = Just "text/x-shellscript"
67 mimetype "shell" = Just "text/x-shellscript"
68 mimetype "shellscript" = Just "text/x-shellscript"
71 dtc :: Trees Key Tokens -> DTC
74 D.xmlModel "./schema/dtc.rnc"
75 D.xmlStylesheet $ "./xsl/document.html5."<>lang<>".xsl"
76 D.html5Stylesheet $ "./xsl/document.html5."<>lang<>".xsl"
77 D.atomStylesheet $ "./xsl/document.atom."<>lang<>".xsl"
80 TreeN KeySection{} (spanlTree0 -> (title, head)) :< body -> do
81 d_Trees inh_dtc (mangleHead title head)
82 d_Trees inh_dtc{inh_dtc_figure = True} body
83 _ -> d_Trees inh_dtc{inh_dtc_figure = True} ts
89 mangleHead title head =
91 (`Seq.findIndexL` head) $ \case
92 TreeN (KeyColon "about" _) _ -> True
95 Nothing -> TreeN (KeyColon "about" "") title <| head
96 Just i -> Seq.adjust f i head
98 f (TreeN c about) = TreeN c $ title <> about
101 d_Trees :: Inh_DTC -> Trees Key Tokens -> DTC
102 d_Trees inh_orig = go inh_orig
105 case Seq.viewl trs of
106 TreeN (KeyBar n _) _ :< _
107 | (body,ts) <- spanlBar n trs
108 , not (null body) -> do
109 (D.artwork !?? (mimetype n, DA.type_ . attrValue)) $
110 forM_ body $ d_Tree inh{inh_dtc_tree0=[]}
113 TreeN KeyBrackets{} _ :< _
114 | (refs,ts) <- spanlBrackets trs
115 , not (null refs) -> do
117 forM_ refs $ d_Tree inh_orig
120 TreeN key@(KeyColon n _) cs :< ts
121 | (cs',ts') <- spanlKeyName n ts
123 go inh $ TreeN key (cs<>cs') <| ts'
125 _ | (ul,ts) <- spanlItems (==KeyDash) trs
126 , not (null ul) -> do
127 D.ul ! DA.style "format —" $
128 forM_ ul $ d_Tree inh{inh_dtc_tree0=List.repeat D.para}
131 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trs
132 , not (null ol) -> do
134 forM_ ol $ d_Tree inh{inh_dtc_tree0=List.repeat D.para}
137 t@(Tree0 toks) :< ts | isTokenElem toks -> do
142 case inh_dtc_tree0 inh of
145 go inh{inh_dtc_tree0=[]} ts
147 d $ d_Tree inh_orig t
148 go inh{inh_dtc_tree0=ds} ts
156 d_Tree :: Inh_DTC -> Tree Key Tokens -> DTC
159 TreeN KeySection{} ts -> do
160 let (attrs,body) = partitionAttributesChildren ts
161 let inh' = inh{inh_dtc_tree0 = D.name : List.repeat D.para}
162 d_Attributes (setAttrId (getAttrId body) attrs) . D.section $
164 TreeN key@(KeyColon kn _) ts -> do
165 let (attrs,body) = partitionAttributesChildren ts
166 let inh' = inh{inh_dtc_tree0 =
168 "about" -> D.name : D.name : List.repeat D.para
169 "reference" -> D.name : D.name : List.repeat D.para
170 "author" -> List.repeat D.name
173 if inh_dtc_figure inh && not (kn`List.elem`D.elems)
176 D.figure ! DA.type_ (attrValue kn) $
178 [Tree0{}] -> d_Trees inh'{inh_dtc_tree0 = List.repeat D.para} body
179 _ -> d_Trees inh'{inh_dtc_tree0 = D.name : List.repeat D.para} body
180 else d_Attributes attrs $ d_Key inh' key body
181 TreeN key ts -> d_Key inh key ts
182 Tree0 ts -> d_Tokens ts
184 d_Key :: Inh_DTC -> Key -> Trees Key Tokens -> DTC
187 KeyColon n _wh -> d_key n
188 KeyGreat n _wh -> d_key n
189 KeyEqual n _wh -> d_key n
190 KeyBar n _wh -> d_key n
191 KeyDot _n -> D.li $ d_Trees inh ts
192 KeyDash -> D.li $ d_Trees inh ts
193 KeyDashDash -> B.Comment (B.Text $ TL.toStrict com) ()
195 Write.text Write.config_text $
196 mapTreeKey cell1 (\_path -> cell1) <$> ts
198 D.artwork $ d_Trees inh ts
199 KeyBrackets ident -> do
200 let (attrs,body) = partitionAttributesChildren ts
201 let inh' = inh{inh_dtc_figure = False}
202 d_Attributes (setAttrId ident attrs) $
203 D.reference $ d_Trees inh' body
205 D.include True $ attrValue $ FP.replaceExtension p "dtc"
209 d_key n | null ts = B.CustomLeaf (B.Text n) True mempty
210 d_key n = B.CustomParent (B.Text n) $ d_Trees inh ts
212 d_Tokens :: Tokens -> DTC
213 d_Tokens tok = goTokens tok
216 go (TokenPlain t) = B.toMarkup t
217 go (TokenTag t) = D.ref mempty ! DA.to (attrValue t)
218 go (TokenEscape c) = B.toMarkup c
219 go (TokenLink lnk) = D.eref (B.toMarkup lnk) ! DA.to (attrValue lnk)
220 go (TokenPair PairBracket ts)
221 | to <- Write.t_Tokens ts
222 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to =
223 D.rref ! DA.to (attrValue $ TL.toStrict to) $ mempty
224 go (TokenPair PairStar ts) = D.b $ goTokens ts
225 go (TokenPair PairSlash ts) = D.i $ goTokens ts
226 go (TokenPair PairBackquote ts) = D.code $ goTokens ts
227 go (TokenPair PairFrenchquote toks@(Tokens ts)) =
230 (Seq.viewl -> TokenPlain l :< ls) ->
234 TokenPlain (Text.dropWhile Char.isSpace l)
235 <|(m|>TokenPlain (Text.dropWhileEnd Char.isSpace r))
238 TokenPlain (Text.dropAround Char.isSpace l) <| ls
239 (Seq.viewr -> rs :> TokenPlain r) ->
241 rs |> TokenPlain (Text.dropAround Char.isSpace r)
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 | null s -> B.CustomLeaf (B.Text name) True mempty
249 _ -> B.CustomParent (B.Text name) $ goTokens ts
250 go (TokenPair p ts) = do
251 let (o,c) = pairBorders p ts
256 goTokens :: Tokens -> DTC
257 goTokens (Tokens toks) =
258 case Seq.viewl toks of
259 TokenPair PairParen b :< (Seq.viewl -> TokenPair PairBracket p :< ts) -> do
261 Tokens (toList -> [TokenLink lnk]) ->
262 D.eref ! DA.to (attrValue lnk) $ goTokens b
263 _ -> D.rref ! DA.to (attrValue $ TL.toStrict $ Write.t_Tokens p) $ goTokens b
265 t :< ts -> go t <> goTokens (Tokens ts)
268 spanlTree0 :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
274 spanlBar :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
275 spanlBar name = first unKeyBar . spanBar
277 unKeyBar :: Trees Key Tokens -> Trees Key Tokens
278 unKeyBar = (=<<) $ \case
279 TreeN KeyBar{} ts -> ts
283 TreeN (KeyBar n _) _ | n == name -> True
286 spanlKeyName :: Name -> Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
289 TreeN (KeyBar n _) _ -> n == name
290 TreeN (KeyGreat n _) _ -> n == name
293 spanlBrackets :: Trees Key Tokens -> (Trees Key Tokens, Trees Key Tokens)
296 TreeN KeyBrackets{} _ -> True
302 (Trees Key Tokens, Trees Key Tokens)
303 spanlItems liKey ts =
304 let (lis, ts') = spanLIs ts in
305 foldl' accumLIs (mempty,ts') lis
307 spanLIs = Seq.spanl $ \case
308 TreeN (liKey -> True) _ -> True
309 Tree0 (Tokens toks) ->
311 TokenPair (PairElem "li" _) _ -> True
314 accumLIs acc@(oks,kos) t =
316 TreeN (liKey -> True) _ -> (oks|>t,kos)
317 Tree0 (Tokens toks) ->
318 let mk = Tree0 . Tokens in
320 (`Seq.spanl` toks) $ \case
321 TokenPair (PairElem "li" _) _ -> True
322 TokenPlain txt -> Char.isSpace`Text.all`txt
324 ( if null ok then oks else oks|>mk (rmTokenPlain ok)
325 , if null ko then kos else mk ko<|kos )
329 TokenPlain{} -> False
332 getAttrId :: Trees Key Tokens -> (Text)
334 case Seq.index ts <$> Seq.findIndexL isTree0 ts of
335 Just (Tree0 toks) -> TL.toStrict $ Write.t_Tokens toks
339 setAttrId :: Text -> Attributes -> Attributes
340 setAttrId ident | Text.null ident = id
341 setAttrId ident = Map.insertWith (\_new old -> old) "id" ident
343 d_Attrs :: Attrs -> DTC -> DTC
344 d_Attrs = flip $ foldl' d_Attr
346 d_Attr :: DTC -> (Text,Attr) -> DTC
347 d_Attr acc (_,Attr{..}) =
353 -- * Type 'Attributes'
354 type Attributes = Map Name Text
356 d_Attributes :: Attributes -> DTC -> DTC
357 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
358 B.AddCustomAttribute (B.Text n) (B.Text v)
360 partitionAttributesChildren ::
362 (Attributes, Trees Key Tokens)
363 partitionAttributesChildren ts = (attrs,children)
370 TreeN (KeyEqual n _wh) a -> Map.insert n v acc
373 Write.text Write.config_text{Write.config_text_escape = False} $
374 mapTreeKey cell1 (\_path -> cell1) <$> a
375 -- Write.treeRackUpLeft <$> a
378 children = Seq.filter (\t ->
381 TreeN KeyEqual{} _cs -> False