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
55 xmlify :: Inh -> a -> XMLs
56 instance Xmlify TCTs where
57 xmlify inh_orig = go inh_orig
59 go :: Inh -> TCTs -> XMLs
61 case Seq.viewl trees of
62 TreeN (Cell bp ep (KeyBar n _)) _ :< _
63 | (body,ts) <- spanlBar n trees
66 TreeN (Cell bp ep "artwork") $
67 maybe id (\v -> (Tree0 (Cell bp ep (XmlAttr "type" v)) <|)) (mimetype n) $
68 body >>= xmlify inh{inh_tree0=[]}
70 TreeN key@(unCell -> KeyColon n _) cs :< ts
71 | (cs',ts') <- spanlKeyColon n ts
73 go inh $ TreeN key (cs<>cs') <| ts'
75 TreeN (Cell bp ep KeyBrackets{}) _ :< _
76 | (rl,ts) <- spanlBrackets trees
79 TreeN (Cell bp ep "references") $
80 rl >>= xmlify inh_orig
82 _ | (ul,ts) <- spanlItems (==KeyDash) trees
83 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ul ->
85 TreeN (Cell bp ep "ul") $
86 ul >>= xmlify inh{inh_tree0=List.repeat xmlPara}
88 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trees
89 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ol ->
91 TreeN (Cell bp ep "ol") $
92 ol >>= xmlify inh{inh_tree0=List.repeat xmlPara}
94 t@(Tree0 toks) :< ts ->
96 [] -> xmlify inh_orig t <> go inh ts
97 _ | isTokenElem toks -> xmlify inh_orig t <> go inh ts
99 (case Seq.viewl toks of
101 Cell bp _ep _ :< _ -> (tree0 bp (xmlify inh_orig t) <|)) $
109 instance Xmlify TCT where
112 TreeN (Cell bp ep KeySection{}) ts ->
113 let (attrs,body) = partitionAttributesChildren ts in
115 { inh_tree0 = xmlTitle : List.repeat xmlPara
119 TreeN (Cell bp ep "section") $
120 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
123 TreeN key@(Cell bp ep (KeyColon kn _)) ts ->
124 let (attrs,body) = partitionAttributesChildren ts in
125 let inh' = inh { inh_tree0 =
127 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
128 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
129 "serie" -> List.repeat xmlName
130 "author" -> List.repeat xmlName
131 "editor" -> List.repeat xmlName
132 "org" -> List.repeat xmlName
136 _ | kn == "about" -> xmlAbout inh' key attrs body
138 _ | inh_figure inh && not (kn`List.elem`elems) ->
140 TreeN (Cell bp ep "figure") $
141 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
143 [Tree0{}] -> xmlify inh'{inh_tree0 = List.repeat xmlPara} body
144 _ -> xmlify inh'{inh_tree0 = xmlTitle : List.repeat xmlPara} body
146 _ -> Seq.singleton $ xmlKey inh' key attrs body
148 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
150 Tree0 ts -> xmlify inh ts
151 instance Xmlify Tokens where
153 case Seq.viewl toks of
154 Cell bp _ep (TokenPair PairParen paren)
155 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
159 (toList -> [Cell bl el (TokenLink lnk)]) ->
160 TreeN (Cell bp eb "eref") $
161 xmlAttrs [Cell bl el ("to",lnk)] <>
164 TreeN (Cell bp eb "rref") $
165 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.textify bracket)] <>
167 t :< ts -> xmlify inh t `unionXml` xmlify inh ts
169 instance Xmlify (Cell Token) where
170 xmlify inh (Cell bp ep tk) =
172 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
173 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
174 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
175 TokenLink lnk -> Seq.singleton $
176 TreeN (cell "eref") $
177 xmlAttrs [cell ("to",lnk)]
178 TokenPair PairBracket ts | to <- Plain.textify ts
179 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
181 TreeN (cell "rref") $
182 xmlAttrs [cell ("to",TL.toStrict to)]
183 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ xmlify inh ts
184 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ xmlify inh ts
185 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ xmlify inh ts
186 TokenPair PairFrenchquote toks@ts ->
190 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
192 m :> Cell br er (TokenPlain r) ->
194 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
195 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
198 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
199 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
201 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
203 TokenPair PairHash to ->
206 xmlAttrs [cell ("to",TL.toStrict $ Plain.textify to)]
207 TokenPair (PairElem name attrs) ts ->
209 TreeN (cell $ xmlLocalName name) $
210 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) ->
211 cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
214 let (o,c) = pairBorders p ts in
215 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
216 xmlify inh ts `unionXml`
217 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
222 mimetype :: Text -> Maybe Text
223 mimetype "hs" = Just "text/x-haskell"
224 mimetype "sh" = Just "text/x-shellscript"
225 mimetype "shell" = Just "text/x-shellscript"
226 mimetype "shellscript" = Just "text/x-shellscript"
229 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
230 xmlPhantom n bp = TreeN (Cell bp bp n)
231 xmlPara :: Pos -> XMLs -> XML
232 xmlPara = xmlPhantom "para"
233 xmlTitle :: Pos -> XMLs -> XML
234 xmlTitle = xmlPhantom "title"
235 xmlName :: Pos -> XMLs -> XML
236 xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
237 xmlName bp ts = xmlPhantom "name" bp ts
239 xmlDocument :: TCTs -> XMLs
241 case Seq.viewl trees of
242 TreeN (unCell -> KeySection{}) vs :< ts ->
243 case spanlTokens vs of
244 (titles@(Seq.viewl -> (Seq.viewl -> Cell bp _ep _ :< _) :< _), vs') ->
248 TreeN (unCell -> KeyColon "about" _) _ -> True
250 Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
253 { inh_titles = titles
255 , inh_tree0 = List.repeat xmlPara
258 _ -> xmlify def trees
259 _ -> xmlify def trees
263 Cell Key -> Seq (Cell (XmlName, Text)) ->
265 xmlAbout inh key attrs body =
267 xmlKey inh key attrs $
268 case Seq.viewl (inh_titles inh) of
269 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
270 ((<$> inh_titles inh) $ \title ->
271 TreeN (Cell bt bt $ KeyColon "title" "") $
272 Seq.singleton $ Tree0 title)
276 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
277 xmlKey inh (Cell bp ep key) attrs ts =
279 KeyColon n _wh -> d_key n
280 KeyGreat n _wh -> d_key n
281 KeyEqual n _wh -> d_key n
282 KeyBar n _wh -> d_key n
283 KeyDot _n -> TreeN (cell "li") $ xmlify inh ts
284 KeyDash -> TreeN (cell "li") $ xmlify inh ts
285 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
292 (\_path -> fmap $ cell1 . unCell) <$> ts
293 KeyLower n as -> TreeN (cell "artwork") $ xmlify inh ts
295 let inh' = inh{inh_figure = False} in
296 let (attrs',body) = partitionAttributesChildren ts in
297 TreeN (cell "reference") $
298 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
299 xmlify inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
301 TreeN (cell "include") $
302 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
309 TreeN (cell $ xmlLocalName n) $
313 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
314 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
316 -- | Unify two 'XMLs', merging border 'XmlText's if any.
317 unionXml :: XMLs -> XMLs -> XMLs
319 case (Seq.viewr x, Seq.viewl y) of
320 (xs :> x0, y0 :< ys) ->
322 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
324 Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
330 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
331 spanlBar name = first unKeyBar . spanBar
333 unKeyBar :: TCTs -> TCTs
334 unKeyBar = (=<<) $ \case
335 TreeN (unCell -> KeyBar{}) ts -> ts
339 TreeN (unCell -> KeyBar n _) _ | n == name -> True
342 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
343 spanlItems liKey ts =
344 let (lis, ts') = spanLIs ts in
345 foldl' accumLIs (mempty,ts') lis
347 spanLIs = Seq.spanl $ \case
348 TreeN (unCell -> liKey -> True) _ -> True
351 (unCell -> TokenPair (PairElem "li" _) _) -> True
354 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
355 [unCell -> TokenPair (PairElem "li" _) _] -> True
359 accumLIs acc@(oks,kos) t =
361 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
364 (`Seq.spanl` toks) $ \tok ->
366 TokenPair (PairElem "li" _) _ -> True
367 TokenPlain txt -> Char.isSpace`Text.all`txt
369 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
370 , if null ko then kos else Tree0 ko<|kos )
374 (unCell -> TokenPlain{}) -> False
377 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
380 TreeN (unCell -> KeyBar n _) _ -> n == name
381 TreeN (unCell -> KeyGreat n _) _ -> n == name
384 spanlBrackets :: TCTs -> (TCTs, TCTs)
387 TreeN (unCell -> KeyBrackets{}) _ -> True
390 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
394 _ -> undefined) <$>) .
399 getAttrId :: TCTs -> Text
401 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
402 Just (Tree0 toks) -> TL.toStrict $ Plain.textify toks
405 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
406 setXmlAttr a@(unCell -> (k, _v)) as =
407 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
408 Just idx -> Seq.update idx a as
411 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
412 defXmlAttr a@(unCell -> (k, _v)) as =
413 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
417 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
418 partitionAttributesChildren ts = (attrs,cs)
420 (as,cs) = (`Seq.partition` ts) $ \case
421 TreeN (unCell -> KeyEqual{}) _cs -> True
423 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
425 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
426 Cell bp ep (xmlLocalName n, v)
429 Plain.text def{Plain.state_escape = False} $
430 TreeSeq.mapAlsoNode (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a