1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE OverloadedLists #-}
4 {-# LANGUAGE OverloadedStrings #-}
5 {-# LANGUAGE RecordWildCards #-}
6 {-# LANGUAGE ViewPatterns #-}
7 {-# OPTIONS_GHC -fno-warn-orphans #-}
8 module Language.TCT.Write.XML where
10 import Control.Arrow (first)
11 import Control.Monad (Monad(..), (=<<))
13 import Data.Eq (Eq(..))
14 import Data.Foldable (null, foldl', any)
15 import Data.Function (($), (.), id)
16 import Data.Functor (Functor(..), (<$>))
17 import Data.Maybe (Maybe(..), maybe)
18 import Data.Monoid (Monoid(..))
19 import Data.Semigroup (Semigroup(..))
20 import Data.Sequence (Seq, ViewL(..), ViewR(..), (<|), (|>))
22 import Data.Text (Text)
23 import Data.TreeSeq.Strict (Tree(..))
24 import GHC.Exts (toList)
25 import Prelude (undefined)
26 import qualified Data.Char as Char
27 import qualified Data.List as List
28 import qualified Data.Sequence as Seq
29 import qualified Data.Text as Text
30 import qualified Data.Text.Lazy as TL
31 import qualified Language.TCT.Write.Text as Write
32 import qualified System.FilePath as FP
34 import Text.Blaze.XML ()
35 import Language.TCT hiding (Parser)
37 import qualified Data.TreeSeq.Strict as TreeSeq
42 { inhXml_figure :: Bool
43 , inhXml_tree0 :: [Pos -> XMLs -> XML]
44 , inhXml_titles :: Seq Tokens
48 { inhXml_figure = False
50 , inhXml_titles = mempty
53 mimetype :: Text -> Maybe Text
54 mimetype "hs" = Just "text/x-haskell"
55 mimetype "sh" = Just "text/x-shellscript"
56 mimetype "shell" = Just "text/x-shellscript"
57 mimetype "shellscript" = Just "text/x-shellscript"
60 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
61 xmlPhantom n bp = TreeN (Cell bp bp n)
62 xmlPara :: Pos -> XMLs -> XML
63 xmlPara = xmlPhantom "para"
64 xmlTitle :: Pos -> XMLs -> XML
65 xmlTitle = xmlPhantom "title"
66 xmlName :: Pos -> XMLs -> XML
67 xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
68 xmlName bp ts = xmlPhantom "name" bp ts
70 xmlDocument :: TCTs -> XMLs
72 case Seq.viewl trees of
73 TreeN (unCell -> KeySection{}) vs :< ts ->
74 case spanlTokens vs of
75 (titles@(Seq.viewl -> (Seq.viewl -> Cell bp _ep _ :< _) :< _), vs') ->
79 TreeN (unCell -> KeyColon "about" _) _ -> True
82 Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
85 { inhXml_titles = titles
86 , inhXml_figure = True
87 , inhXml_tree0 = List.repeat xmlPara
90 _ -> xmlTCTs inhXml trees
91 _ -> xmlTCTs inhXml trees
93 xmlTCTs :: InhXml -> TCTs -> XMLs
94 xmlTCTs inh_orig = go inh_orig
96 go :: InhXml -> TCTs -> XMLs
98 case Seq.viewl trees of
99 TreeN (Cell bp ep (KeyBar n _)) _ :< _
100 | (body,ts) <- spanlBar n trees
103 TreeN (Cell bp ep "artwork") $
104 maybe id (\v -> (Tree0 (Cell bp ep (XmlAttr "type" v)) <|)) (mimetype n) $
105 body >>= xmlTCT inh{inhXml_tree0=[]}
107 TreeN key@(unCell -> KeyColon n _) cs :< ts
108 | (cs',ts') <- spanlKeyColon n ts
110 go inh $ TreeN key (cs<>cs') <| ts'
112 TreeN (Cell bp ep KeyBrackets{}) _ :< _
113 | (rl,ts) <- spanlBrackets trees
116 TreeN (Cell bp ep "rl") $
117 rl >>= xmlTCT inh_orig
119 _ | (ul,ts) <- spanlItems (==KeyDash) trees
120 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ul ->
122 TreeN (Cell bp ep "ul") $
123 ul >>= xmlTCT inh{inhXml_tree0=List.repeat xmlPara}
125 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trees
126 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ol ->
128 TreeN (Cell bp ep "ol") $
129 ol >>= xmlTCT inh{inhXml_tree0=List.repeat xmlPara}
131 t@(Tree0 toks) :< ts | isTokenElem toks ->
135 t@(Tree0 toks) :< ts ->
136 case inhXml_tree0 inh of
139 go inh{inhXml_tree0=[]} ts
141 case Seq.viewl toks of
142 EmptyL -> go inh{inhXml_tree0=xs} ts
143 Cell bp _ep _ :< _ ->
144 (<| go inh{inhXml_tree0=xs} ts) $
154 xmlTCT :: InhXml -> TCT -> XMLs
157 TreeN (Cell bp ep KeySection{}) ts ->
158 let (attrs,body) = partitionAttributesChildren ts in
160 { inhXml_tree0 = xmlTitle : List.repeat xmlPara
161 , inhXml_figure = True
164 TreeN (Cell bp ep "section") $
165 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
168 TreeN key@(Cell bp ep (KeyColon kn _)) ts ->
169 let (attrs,body) = partitionAttributesChildren ts in
170 let inh' = inh { inhXml_tree0 =
172 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
173 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
174 "author" -> List.repeat xmlName
178 _ | kn == "about" -> xmlAbout inh' key attrs body
180 _ | inhXml_figure inh && not (kn`List.elem`elems) ->
182 TreeN (Cell bp ep "figure") $
183 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
185 [Tree0{}] -> xmlTCTs inh'{inhXml_tree0 = List.repeat xmlPara} body
186 _ -> xmlTCTs inh'{inhXml_tree0 = xmlTitle : List.repeat xmlPara} body
188 _ -> Seq.singleton $ xmlKey inh' key attrs body
190 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
192 Tree0 ts -> xmlTokens ts
196 Cell Key -> Seq (Cell (XmlName, Text)) ->
198 xmlAbout inh key attrs body =
200 xmlKey inh key attrs $
201 case Seq.viewl (inhXml_titles inh) of
202 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
203 ((<$> inhXml_titles inh) $ \title ->
204 TreeN (Cell bt bt $ KeyColon "title" "") $
205 Seq.singleton $ Tree0 title)
209 xmlKey :: InhXml -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
210 xmlKey inh (Cell bp ep key) attrs ts =
212 KeyColon n _wh -> d_key n
213 KeyGreat n _wh -> d_key n
214 KeyEqual n _wh -> d_key n
215 KeyBar n _wh -> d_key n
216 KeyDot _n -> TreeN (cell "li") $ xmlTCTs inh ts
217 KeyDash -> TreeN (cell "li") $ xmlTCTs inh ts
218 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
222 Write.text Write.config_text $
225 (\_path -> fmap $ cell1 . unCell) <$> ts
226 KeyLower n as -> TreeN (cell "artwork") $ xmlTCTs inh ts
228 let inh' = inh{inhXml_figure = False} in
229 TreeN (cell "reference") $
230 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) attrs) <>
233 TreeN (cell "include") $
234 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
241 TreeN (cell $ xmlLocalName n) $
245 xmlTokens :: Tokens -> XMLs
246 xmlTokens tok = goTokens tok
248 go :: Cell Token -> XMLs
251 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
252 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
253 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
254 TokenLink lnk -> Seq.singleton $
255 TreeN (cell "eref") $
256 xmlAttrs [cell ("to",lnk)] |>
257 Tree0 (cell $ XmlText lnk)
258 TokenPair PairBracket ts | to <- Write.textTokens ts
259 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
261 TreeN (cell "rref") $
262 xmlAttrs [cell ("to",TL.toStrict to)]
263 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ goTokens ts
264 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ goTokens ts
265 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ goTokens ts
266 TokenPair PairFrenchquote toks@ts ->
270 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
272 m :> Cell br er (TokenPlain r) ->
274 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
275 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
278 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
279 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
281 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
283 TokenPair PairHash to ->
286 xmlAttrs [cell ("to",TL.toStrict $ Write.textTokens to)]
287 TokenPair (PairElem name attrs) ts ->
289 TreeN (cell $ xmlLocalName name) $
290 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) -> cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
293 let (o,c) = pairBorders p ts in
294 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
295 goTokens ts `unionXml`
296 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
301 goTokens :: Tokens -> XMLs
303 case Seq.viewl toks of
304 Cell bp _ep (TokenPair PairParen paren)
305 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
309 (toList -> [Cell bl el (TokenLink lnk)]) ->
310 TreeN (Cell bp eb "eref") $
311 xmlAttrs [Cell bl el ("to",lnk)] <>
314 TreeN (Cell bp eb "rref") $
315 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Write.textTokens bracket)] <>
317 t :< ts -> go t `unionXml` goTokens ts
320 -- | Unify two 'XMLs', merging border 'XmlText's if any.
321 unionXml :: XMLs -> XMLs -> XMLs
323 case (Seq.viewr x, Seq.viewl y) of
324 (xs :> x0, y0 :< ys) ->
326 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
328 Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
335 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
336 spanlBar name = first unKeyBar . spanBar
338 unKeyBar :: TCTs -> TCTs
339 unKeyBar = (=<<) $ \case
340 TreeN (unCell -> KeyBar{}) ts -> ts
344 TreeN (unCell -> KeyBar n _) _ | n == name -> True
347 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
348 spanlItems liKey ts =
349 let (lis, ts') = spanLIs ts in
350 foldl' accumLIs (mempty,ts') lis
352 spanLIs = Seq.spanl $ \case
353 TreeN (unCell -> liKey -> True) _ -> True
356 (unCell -> TokenPair (PairElem "li" _) _) -> True
359 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
360 [unCell -> TokenPair (PairElem "li" _) _] -> True
364 accumLIs acc@(oks,kos) t =
366 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
369 (`Seq.spanl` toks) $ \tok ->
371 TokenPair (PairElem "li" _) _ -> True
372 TokenPlain txt -> Char.isSpace`Text.all`txt
374 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
375 , if null ko then kos else Tree0 ko<|kos )
379 (unCell -> TokenPlain{}) -> False
382 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
385 TreeN (unCell -> KeyBar n _) _ -> n == name
386 TreeN (unCell -> KeyGreat n _) _ -> n == name
389 spanlBrackets :: TCTs -> (TCTs, TCTs)
392 TreeN (unCell -> KeyBrackets{}) _ -> True
395 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
399 _ -> undefined) <$>) .
404 getAttrId :: TCTs -> Text
406 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
407 Just (Tree0 toks) -> TL.toStrict $ Write.textTokens toks
410 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
411 setXmlAttr a@(unCell -> (k, _v)) as =
412 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
413 Just idx -> Seq.update idx a as
416 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
417 defXmlAttr a@(unCell -> (k, _v)) as =
418 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
422 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
423 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
426 xmlAttr :: XmlAttrs -> (Text,Attr) -> XmlAttrs
427 xmlAttr acc (_,Attr{..}) = Map.insert (xmlLocalName attr_name) attr_value acc
432 d_Attributes :: XmlAttrs -> DTC -> DTC
433 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
434 B.AddCustomAttribute (B.Text n) (B.Text v)
437 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
438 partitionAttributesChildren ts = (attrs,cs)
440 (as,cs) = (`Seq.partition` ts) $ \case
441 TreeN (unCell -> KeyEqual{}) _cs -> True
443 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
445 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
446 Cell bp ep (xmlLocalName n, v)
449 Write.text Write.config_text{Write.config_text_escape = False} $
450 TreeSeq.mapAlsoKey (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a