1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE OverloadedLists #-}
4 {-# LANGUAGE OverloadedStrings #-}
5 {-# LANGUAGE ViewPatterns #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Language.TCT.Write.XML where
9 import Control.Arrow (first)
10 import Control.Monad (Monad(..), (=<<))
12 import Data.Eq (Eq(..))
13 import Data.Foldable (null, foldl', any)
14 import Data.Function (($), (.), id)
15 import Data.Functor (Functor(..), (<$>))
16 import Data.Maybe (Maybe(..), maybe)
17 import Data.Monoid (Monoid(..))
18 import Data.Semigroup (Semigroup(..))
19 import Data.Sequence (Seq, ViewL(..), ViewR(..), (<|), (|>))
21 import Data.Text (Text)
22 import Data.TreeSeq.Strict (Tree(..))
23 import GHC.Exts (toList)
24 import Prelude (undefined)
25 import qualified Data.Char as Char
26 import qualified Data.List as List
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 Language.TCT.Write.Text as Write
31 import qualified System.FilePath as FP
33 import Text.Blaze.XML ()
34 import Language.TCT hiding (Parser)
36 import qualified Data.TreeSeq.Strict as TreeSeq
41 { inhXml_figure :: Bool
42 , inhXml_tree0 :: [Pos -> XMLs -> XML]
43 , inhXml_titles :: Seq Tokens
47 { inhXml_figure = False
49 , inhXml_titles = mempty
52 mimetype :: Text -> Maybe Text
53 mimetype "hs" = Just "text/x-haskell"
54 mimetype "sh" = Just "text/x-shellscript"
55 mimetype "shell" = Just "text/x-shellscript"
56 mimetype "shellscript" = Just "text/x-shellscript"
59 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
60 xmlPhantom n bp = TreeN (Cell bp bp n)
61 xmlPara :: Pos -> XMLs -> XML
62 xmlPara = xmlPhantom "para"
63 xmlTitle :: Pos -> XMLs -> XML
64 xmlTitle = xmlPhantom "title"
65 xmlName :: Pos -> XMLs -> XML
66 xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
67 xmlName bp ts = xmlPhantom "name" bp ts
69 xmlDocument :: TCTs -> XMLs
71 case Seq.viewl trees of
72 TreeN (unCell -> KeySection{}) vs :< ts ->
73 case spanlTokens vs of
74 (titles@(Seq.viewl -> (Seq.viewl -> Cell bp _ep _ :< _) :< _), vs') ->
78 TreeN (unCell -> KeyColon "about" _) _ -> True
81 Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
84 { inhXml_titles = titles
85 , inhXml_figure = True
86 , inhXml_tree0 = List.repeat xmlPara
89 _ -> xmlTCTs inhXml trees
90 _ -> xmlTCTs inhXml trees
92 xmlTCTs :: InhXml -> TCTs -> XMLs
93 xmlTCTs inh_orig = go inh_orig
95 go :: InhXml -> TCTs -> XMLs
97 case Seq.viewl trees of
98 TreeN (Cell bp ep (KeyBar n _)) _ :< _
99 | (body,ts) <- spanlBar n trees
102 TreeN (Cell bp ep "artwork") $
103 maybe id (\v -> (Tree0 (Cell bp ep (XmlAttr "type" v)) <|)) (mimetype n) $
104 body >>= xmlTCT inh{inhXml_tree0=[]}
106 TreeN key@(unCell -> KeyColon n _) cs :< ts
107 | (cs',ts') <- spanlKeyColon n ts
109 go inh $ TreeN key (cs<>cs') <| ts'
111 TreeN (Cell bp ep KeyBrackets{}) _ :< _
112 | (rl,ts) <- spanlBrackets trees
115 TreeN (Cell bp ep "rl") $
116 rl >>= xmlTCT inh_orig
118 _ | (ul,ts) <- spanlItems (==KeyDash) trees
119 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ul ->
121 TreeN (Cell bp ep "ul") $
122 ul >>= xmlTCT inh{inhXml_tree0=List.repeat xmlPara}
124 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trees
125 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ol ->
127 TreeN (Cell bp ep "ol") $
128 ol >>= xmlTCT inh{inhXml_tree0=List.repeat xmlPara}
130 t@(Tree0 toks) :< ts | isTokenElem toks ->
134 t@(Tree0 toks) :< ts ->
135 case inhXml_tree0 inh of
138 go inh{inhXml_tree0=[]} ts
140 case Seq.viewl toks of
141 EmptyL -> go inh{inhXml_tree0=xs} ts
142 Cell bp _ep _ :< _ ->
143 (<| go inh{inhXml_tree0=xs} ts) $
153 xmlTCT :: InhXml -> TCT -> XMLs
156 TreeN (Cell bp ep KeySection{}) ts ->
157 let (attrs,body) = partitionAttributesChildren ts in
159 { inhXml_tree0 = xmlTitle : List.repeat xmlPara
160 , inhXml_figure = True
163 TreeN (Cell bp ep "section") $
164 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
167 TreeN key@(Cell bp ep (KeyColon kn _)) ts ->
168 let (attrs,body) = partitionAttributesChildren ts in
169 let inh' = inh { inhXml_tree0 =
171 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
172 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
173 "author" -> List.repeat xmlName
177 _ | kn == "about" -> xmlAbout inh' key attrs body
179 _ | inhXml_figure inh && not (kn`List.elem`elems) ->
181 TreeN (Cell bp ep "figure") $
182 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
184 [Tree0{}] -> xmlTCTs inh'{inhXml_tree0 = List.repeat xmlPara} body
185 _ -> xmlTCTs inh'{inhXml_tree0 = xmlTitle : List.repeat xmlPara} body
187 _ -> Seq.singleton $ xmlKey inh' key attrs body
189 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
191 Tree0 ts -> xmlTokens ts
195 Cell Key -> Seq (Cell (XmlName, Text)) ->
197 xmlAbout inh key attrs body =
199 xmlKey inh key attrs $
200 case Seq.viewl (inhXml_titles inh) of
201 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
202 ((<$> inhXml_titles inh) $ \title ->
203 TreeN (Cell bt bt $ KeyColon "title" "") $
204 Seq.singleton $ Tree0 title)
208 xmlKey :: InhXml -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
209 xmlKey inh (Cell bp ep key) attrs ts =
211 KeyColon n _wh -> d_key n
212 KeyGreat n _wh -> d_key n
213 KeyEqual n _wh -> d_key n
214 KeyBar n _wh -> d_key n
215 KeyDot _n -> TreeN (cell "li") $ xmlTCTs inh ts
216 KeyDash -> TreeN (cell "li") $ xmlTCTs inh ts
217 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
221 Write.text Write.config_text $
224 (\_path -> fmap $ cell1 . unCell) <$> ts
225 KeyLower n as -> TreeN (cell "artwork") $ xmlTCTs inh ts
227 let inh' = inh{inhXml_figure = False} in
228 TreeN (cell "reference") $
229 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) attrs) <>
232 TreeN (cell "include") $
233 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
240 TreeN (cell $ xmlLocalName n) $
244 xmlTokens :: Tokens -> XMLs
245 xmlTokens tok = goTokens tok
247 go :: Cell Token -> XMLs
250 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
251 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
252 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
253 TokenLink lnk -> Seq.singleton $
254 TreeN (cell "eref") $
255 xmlAttrs [cell ("to",lnk)] |>
256 Tree0 (cell $ XmlText lnk)
257 TokenPair PairBracket ts | to <- Write.textTokens ts
258 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
260 TreeN (cell "rref") $
261 xmlAttrs [cell ("to",TL.toStrict to)]
262 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ goTokens ts
263 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ goTokens ts
264 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ goTokens ts
265 TokenPair PairFrenchquote toks@ts ->
269 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
271 m :> Cell br er (TokenPlain r) ->
273 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
274 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
277 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
278 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
280 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
282 TokenPair PairHash to ->
285 xmlAttrs [cell ("to",TL.toStrict $ Write.textTokens to)]
286 TokenPair (PairElem name attrs) ts ->
288 TreeN (cell $ xmlLocalName name) $
289 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) -> cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
292 let (o,c) = pairBorders p ts in
293 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
294 goTokens ts `unionXml`
295 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
300 goTokens :: Tokens -> XMLs
302 case Seq.viewl toks of
303 Cell bp _ep (TokenPair PairParen paren)
304 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
308 (toList -> [Cell bl el (TokenLink lnk)]) ->
309 TreeN (Cell bp eb "eref") $
310 xmlAttrs [Cell bl el ("to",lnk)] <>
313 TreeN (Cell bp eb "rref") $
314 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Write.textTokens bracket)] <>
316 t :< ts -> go t `unionXml` goTokens ts
319 -- | Unify two 'XMLs', merging border 'XmlText's if any.
320 unionXml :: XMLs -> XMLs -> XMLs
322 case (Seq.viewr x, Seq.viewl y) of
323 (xs :> x0, y0 :< ys) ->
325 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
327 Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
334 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
335 spanlBar name = first unKeyBar . spanBar
337 unKeyBar :: TCTs -> TCTs
338 unKeyBar = (=<<) $ \case
339 TreeN (unCell -> KeyBar{}) ts -> ts
343 TreeN (unCell -> KeyBar n _) _ | n == name -> True
346 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
347 spanlItems liKey ts =
348 let (lis, ts') = spanLIs ts in
349 foldl' accumLIs (mempty,ts') lis
351 spanLIs = Seq.spanl $ \case
352 TreeN (unCell -> liKey -> True) _ -> True
355 (unCell -> TokenPair (PairElem "li" _) _) -> True
358 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
359 [unCell -> TokenPair (PairElem "li" _) _] -> True
363 accumLIs acc@(oks,kos) t =
365 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
368 (`Seq.spanl` toks) $ \tok ->
370 TokenPair (PairElem "li" _) _ -> True
371 TokenPlain txt -> Char.isSpace`Text.all`txt
373 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
374 , if null ko then kos else Tree0 ko<|kos )
378 (unCell -> TokenPlain{}) -> False
381 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
384 TreeN (unCell -> KeyBar n _) _ -> n == name
385 TreeN (unCell -> KeyGreat n _) _ -> n == name
388 spanlBrackets :: TCTs -> (TCTs, TCTs)
391 TreeN (unCell -> KeyBrackets{}) _ -> True
394 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
398 _ -> undefined) <$>) .
403 getAttrId :: TCTs -> Text
405 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
406 Just (Tree0 toks) -> TL.toStrict $ Write.textTokens toks
409 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
410 setXmlAttr a@(unCell -> (k, _v)) as =
411 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
412 Just idx -> Seq.update idx a as
415 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
416 defXmlAttr a@(unCell -> (k, _v)) as =
417 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
421 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
422 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
425 xmlAttr :: XmlAttrs -> (Text,Attr) -> XmlAttrs
426 xmlAttr acc (_,Attr{..}) = Map.insert (xmlLocalName attr_name) attr_value acc
431 d_Attributes :: XmlAttrs -> DTC -> DTC
432 d_Attributes = flip $ Map.foldrWithKey $ \n v ->
433 B.AddCustomAttribute (B.Text n) (B.Text v)
436 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
437 partitionAttributesChildren ts = (attrs,cs)
439 (as,cs) = (`Seq.partition` ts) $ \case
440 TreeN (unCell -> KeyEqual{}) _cs -> True
442 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
444 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
445 Cell bp ep (xmlLocalName n, v)
448 Write.text Write.config_text{Write.config_text_escape = False} $
449 TreeSeq.mapAlsoKey (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a