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.Default.Class (Default(..))
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.Plain as Plain
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
43 , inh_tree0 :: [Pos -> XMLs -> XML]
44 , inh_titles :: Seq Tokens
46 instance Default Inh where
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'
87 , inh_tree0 = List.repeat xmlPara
90 _ -> xmlTCTs def trees
91 _ -> xmlTCTs def trees
93 xmlTCTs :: Inh -> TCTs -> XMLs
94 xmlTCTs inh_orig = go inh_orig
96 go :: Inh -> 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{inh_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 "references") $
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{inh_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{inh_tree0=List.repeat xmlPara}
131 t@(Tree0 toks) :< ts | isTokenElem toks ->
135 t@(Tree0 toks) :< ts ->
136 case inh_tree0 inh of
139 go inh{inh_tree0=[]} ts
141 case Seq.viewl toks of
142 EmptyL -> go inh{inh_tree0=xs} ts
143 Cell bp _ep _ :< _ ->
144 (<| go inh{inh_tree0=xs} ts) $
154 xmlTCT :: Inh -> TCT -> XMLs
157 TreeN (Cell bp ep KeySection{}) ts ->
158 let (attrs,body) = partitionAttributesChildren ts in
160 { inh_tree0 = xmlTitle : List.repeat xmlPara
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 { inh_tree0 =
172 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
173 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
174 "serie" -> List.repeat xmlName
175 "author" -> List.repeat xmlName
176 "editor" -> List.repeat xmlName
177 "org" -> List.repeat xmlName
181 _ | kn == "about" -> xmlAbout inh' key attrs body
183 _ | inh_figure inh && not (kn`List.elem`elems) ->
185 TreeN (Cell bp ep "figure") $
186 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
188 [Tree0{}] -> xmlTCTs inh'{inh_tree0 = List.repeat xmlPara} body
189 _ -> xmlTCTs inh'{inh_tree0 = xmlTitle : List.repeat xmlPara} body
191 _ -> Seq.singleton $ xmlKey inh' key attrs body
193 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
195 Tree0 ts -> xmlTokens ts
199 Cell Key -> Seq (Cell (XmlName, Text)) ->
201 xmlAbout inh key attrs body =
203 xmlKey inh key attrs $
204 case Seq.viewl (inh_titles inh) of
205 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
206 ((<$> inh_titles inh) $ \title ->
207 TreeN (Cell bt bt $ KeyColon "title" "") $
208 Seq.singleton $ Tree0 title)
212 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
213 xmlKey inh (Cell bp ep key) attrs ts =
215 KeyColon n _wh -> d_key n
216 KeyGreat n _wh -> d_key n
217 KeyEqual n _wh -> d_key n
218 KeyBar n _wh -> d_key n
219 KeyDot _n -> TreeN (cell "li") $ xmlTCTs inh ts
220 KeyDash -> TreeN (cell "li") $ xmlTCTs inh ts
221 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
228 (\_path -> fmap $ cell1 . unCell) <$> ts
229 KeyLower n as -> TreeN (cell "artwork") $ xmlTCTs inh ts
231 let inh' = inh{inh_figure = False} in
232 let (attrs',body) = partitionAttributesChildren ts in
233 TreeN (cell "reference") $
234 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
235 xmlTCTs inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
237 TreeN (cell "include") $
238 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
245 TreeN (cell $ xmlLocalName n) $
249 xmlTokens :: Tokens -> XMLs
250 xmlTokens tok = goTokens tok
252 go :: Cell Token -> XMLs
255 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
256 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
257 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
258 TokenLink lnk -> Seq.singleton $
259 TreeN (cell "eref") $
260 xmlAttrs [cell ("to",lnk)]
261 TokenPair PairBracket ts | to <- Plain.textify ts
262 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
264 TreeN (cell "rref") $
265 xmlAttrs [cell ("to",TL.toStrict to)]
266 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ goTokens ts
267 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ goTokens ts
268 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ goTokens ts
269 TokenPair PairFrenchquote toks@ts ->
273 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
275 m :> Cell br er (TokenPlain r) ->
277 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
278 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
281 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
282 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
284 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
286 TokenPair PairHash to ->
289 xmlAttrs [cell ("to",TL.toStrict $ Plain.textify to)]
290 TokenPair (PairElem name attrs) ts ->
292 TreeN (cell $ xmlLocalName name) $
293 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) -> cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
296 let (o,c) = pairBorders p ts in
297 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
298 goTokens ts `unionXml`
299 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
304 goTokens :: Tokens -> XMLs
306 case Seq.viewl toks of
307 Cell bp _ep (TokenPair PairParen paren)
308 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
312 (toList -> [Cell bl el (TokenLink lnk)]) ->
313 TreeN (Cell bp eb "eref") $
314 xmlAttrs [Cell bl el ("to",lnk)] <>
317 TreeN (Cell bp eb "rref") $
318 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.textify bracket)] <>
320 t :< ts -> go t `unionXml` goTokens ts
323 -- | Unify two 'XMLs', merging border 'XmlText's if any.
324 unionXml :: XMLs -> XMLs -> XMLs
326 case (Seq.viewr x, Seq.viewl y) of
327 (xs :> x0, y0 :< ys) ->
329 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
331 Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
338 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
339 spanlBar name = first unKeyBar . spanBar
341 unKeyBar :: TCTs -> TCTs
342 unKeyBar = (=<<) $ \case
343 TreeN (unCell -> KeyBar{}) ts -> ts
347 TreeN (unCell -> KeyBar n _) _ | n == name -> True
350 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
351 spanlItems liKey ts =
352 let (lis, ts') = spanLIs ts in
353 foldl' accumLIs (mempty,ts') lis
355 spanLIs = Seq.spanl $ \case
356 TreeN (unCell -> liKey -> True) _ -> True
359 (unCell -> TokenPair (PairElem "li" _) _) -> True
362 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
363 [unCell -> TokenPair (PairElem "li" _) _] -> True
367 accumLIs acc@(oks,kos) t =
369 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
372 (`Seq.spanl` toks) $ \tok ->
374 TokenPair (PairElem "li" _) _ -> True
375 TokenPlain txt -> Char.isSpace`Text.all`txt
377 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
378 , if null ko then kos else Tree0 ko<|kos )
382 (unCell -> TokenPlain{}) -> False
385 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
388 TreeN (unCell -> KeyBar n _) _ -> n == name
389 TreeN (unCell -> KeyGreat n _) _ -> n == name
392 spanlBrackets :: TCTs -> (TCTs, TCTs)
395 TreeN (unCell -> KeyBrackets{}) _ -> True
398 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
402 _ -> undefined) <$>) .
407 getAttrId :: TCTs -> Text
409 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
410 Just (Tree0 toks) -> TL.toStrict $ Plain.textify toks
413 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
414 setXmlAttr a@(unCell -> (k, _v)) as =
415 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
416 Just idx -> Seq.update idx a as
419 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
420 defXmlAttr a@(unCell -> (k, _v)) as =
421 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
425 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
426 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
428 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
429 partitionAttributesChildren ts = (attrs,cs)
431 (as,cs) = (`Seq.partition` ts) $ \case
432 TreeN (unCell -> KeyEqual{}) _cs -> True
434 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
436 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
437 Cell bp ep (xmlLocalName n, v)
440 Plain.text def{Plain.state_escape = False} $
441 TreeSeq.mapAlsoNode (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a