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 "author" -> List.repeat xmlName
175 "editor" -> List.repeat xmlName
179 _ | kn == "about" -> xmlAbout inh' key attrs body
181 _ | inh_figure inh && not (kn`List.elem`elems) ->
183 TreeN (Cell bp ep "figure") $
184 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
186 [Tree0{}] -> xmlTCTs inh'{inh_tree0 = List.repeat xmlPara} body
187 _ -> xmlTCTs inh'{inh_tree0 = xmlTitle : List.repeat xmlPara} body
189 _ -> Seq.singleton $ xmlKey inh' key attrs body
191 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
193 Tree0 ts -> xmlTokens ts
197 Cell Key -> Seq (Cell (XmlName, Text)) ->
199 xmlAbout inh key attrs body =
201 xmlKey inh key attrs $
202 case Seq.viewl (inh_titles inh) of
203 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
204 ((<$> inh_titles inh) $ \title ->
205 TreeN (Cell bt bt $ KeyColon "title" "") $
206 Seq.singleton $ Tree0 title)
210 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
211 xmlKey inh (Cell bp ep key) attrs ts =
213 KeyColon n _wh -> d_key n
214 KeyGreat n _wh -> d_key n
215 KeyEqual n _wh -> d_key n
216 KeyBar n _wh -> d_key n
217 KeyDot _n -> TreeN (cell "li") $ xmlTCTs inh ts
218 KeyDash -> TreeN (cell "li") $ xmlTCTs inh ts
219 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
226 (\_path -> fmap $ cell1 . unCell) <$> ts
227 KeyLower n as -> TreeN (cell "artwork") $ xmlTCTs inh ts
229 let inh' = inh{inh_figure = False} in
230 let (attrs',body) = partitionAttributesChildren ts in
231 TreeN (cell "reference") $
232 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
235 TreeN (cell "include") $
236 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
243 TreeN (cell $ xmlLocalName n) $
247 xmlTokens :: Tokens -> XMLs
248 xmlTokens tok = goTokens tok
250 go :: Cell Token -> XMLs
253 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
254 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
255 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
256 TokenLink lnk -> Seq.singleton $
257 TreeN (cell "eref") $
258 xmlAttrs [cell ("to",lnk)]
259 TokenPair PairBracket ts | to <- Plain.plainifyTokens ts
260 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
262 TreeN (cell "rref") $
263 xmlAttrs [cell ("to",TL.toStrict to)]
264 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ goTokens ts
265 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ goTokens ts
266 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ goTokens ts
267 TokenPair PairFrenchquote toks@ts ->
271 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
273 m :> Cell br er (TokenPlain r) ->
275 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
276 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
279 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
280 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
282 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
284 TokenPair PairHash to ->
287 xmlAttrs [cell ("to",TL.toStrict $ Plain.plainifyTokens to)]
288 TokenPair (PairElem name attrs) ts ->
290 TreeN (cell $ xmlLocalName name) $
291 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) -> cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
294 let (o,c) = pairBorders p ts in
295 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
296 goTokens ts `unionXml`
297 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
302 goTokens :: Tokens -> XMLs
304 case Seq.viewl toks of
305 Cell bp _ep (TokenPair PairParen paren)
306 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
310 (toList -> [Cell bl el (TokenLink lnk)]) ->
311 TreeN (Cell bp eb "eref") $
312 xmlAttrs [Cell bl el ("to",lnk)] <>
315 TreeN (Cell bp eb "rref") $
316 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.plainifyTokens bracket)] <>
318 t :< ts -> go t `unionXml` goTokens ts
321 -- | Unify two 'XMLs', merging border 'XmlText's if any.
322 unionXml :: XMLs -> XMLs -> XMLs
324 case (Seq.viewr x, Seq.viewl y) of
325 (xs :> x0, y0 :< ys) ->
327 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
329 Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
336 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
337 spanlBar name = first unKeyBar . spanBar
339 unKeyBar :: TCTs -> TCTs
340 unKeyBar = (=<<) $ \case
341 TreeN (unCell -> KeyBar{}) ts -> ts
345 TreeN (unCell -> KeyBar n _) _ | n == name -> True
348 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
349 spanlItems liKey ts =
350 let (lis, ts') = spanLIs ts in
351 foldl' accumLIs (mempty,ts') lis
353 spanLIs = Seq.spanl $ \case
354 TreeN (unCell -> liKey -> True) _ -> True
357 (unCell -> TokenPair (PairElem "li" _) _) -> True
360 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
361 [unCell -> TokenPair (PairElem "li" _) _] -> True
365 accumLIs acc@(oks,kos) t =
367 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
370 (`Seq.spanl` toks) $ \tok ->
372 TokenPair (PairElem "li" _) _ -> True
373 TokenPlain txt -> Char.isSpace`Text.all`txt
375 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
376 , if null ko then kos else Tree0 ko<|kos )
380 (unCell -> TokenPlain{}) -> False
383 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
386 TreeN (unCell -> KeyBar n _) _ -> n == name
387 TreeN (unCell -> KeyGreat n _) _ -> n == name
390 spanlBrackets :: TCTs -> (TCTs, TCTs)
393 TreeN (unCell -> KeyBrackets{}) _ -> True
396 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
400 _ -> undefined) <$>) .
405 getAttrId :: TCTs -> Text
407 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
408 Just (Tree0 toks) -> TL.toStrict $ Plain.plainifyTokens toks
411 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
412 setXmlAttr a@(unCell -> (k, _v)) as =
413 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
414 Just idx -> Seq.update idx a as
417 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
418 defXmlAttr a@(unCell -> (k, _v)) as =
419 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
423 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
424 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
426 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
427 partitionAttributesChildren ts = (attrs,cs)
429 (as,cs) = (`Seq.partition` ts) $ \case
430 TreeN (unCell -> KeyEqual{}) _cs -> True
432 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
434 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
435 Cell bp ep (xmlLocalName n, v)
438 Plain.plainify def{Plain.inh_escape = False} $
439 TreeSeq.mapAlsoNode (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a