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 | isTokenElem toks ->
98 t@(Tree0 toks) :< ts ->
102 go inh{inh_tree0=[]} ts
104 case Seq.viewl toks of
105 EmptyL -> go inh{inh_tree0=xs} ts
106 Cell bp _ep _ :< _ ->
107 (<| go inh{inh_tree0=xs} ts) $
116 instance Xmlify TCT where
119 TreeN (Cell bp ep KeySection{}) ts ->
120 let (attrs,body) = partitionAttributesChildren ts in
122 { inh_tree0 = xmlTitle : List.repeat xmlPara
126 TreeN (Cell bp ep "section") $
127 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
130 TreeN key@(Cell bp ep (KeyColon kn _)) ts ->
131 let (attrs,body) = partitionAttributesChildren ts in
132 let inh' = inh { inh_tree0 =
134 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
135 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
136 "serie" -> List.repeat xmlName
137 "author" -> List.repeat xmlName
138 "editor" -> List.repeat xmlName
139 "org" -> List.repeat xmlName
143 _ | kn == "about" -> xmlAbout inh' key attrs body
145 _ | inh_figure inh && not (kn`List.elem`elems) ->
147 TreeN (Cell bp ep "figure") $
148 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
150 [Tree0{}] -> xmlify inh'{inh_tree0 = List.repeat xmlPara} body
151 _ -> xmlify inh'{inh_tree0 = xmlTitle : List.repeat xmlPara} body
153 _ -> Seq.singleton $ xmlKey inh' key attrs body
155 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
157 Tree0 ts -> xmlify inh ts
158 instance Xmlify Tokens where
160 case Seq.viewl toks of
161 Cell bp _ep (TokenPair PairParen paren)
162 :< (Seq.viewl -> Cell bb eb (TokenPair PairBracket bracket)
166 (toList -> [Cell bl el (TokenLink lnk)]) ->
167 TreeN (Cell bp eb "eref") $
168 xmlAttrs [Cell bl el ("to",lnk)] <>
171 TreeN (Cell bp eb "rref") $
172 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.textify bracket)] <>
174 t :< ts -> xmlify inh t `unionXml` xmlify inh ts
176 instance Xmlify (Cell Token) where
177 xmlify inh (Cell bp ep tk) =
179 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
180 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
181 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
182 TokenLink lnk -> Seq.singleton $
183 TreeN (cell "eref") $
184 xmlAttrs [cell ("to",lnk)]
185 TokenPair PairBracket ts | to <- Plain.textify ts
186 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
188 TreeN (cell "rref") $
189 xmlAttrs [cell ("to",TL.toStrict to)]
190 TokenPair PairStar ts -> Seq.singleton $ TreeN (cell "b") $ xmlify inh ts
191 TokenPair PairSlash ts -> Seq.singleton $ TreeN (cell "i") $ xmlify inh ts
192 TokenPair PairBackquote ts -> Seq.singleton $ TreeN (cell "code") $ xmlify inh ts
193 TokenPair PairFrenchquote toks@ts ->
197 (Seq.viewl -> Cell bl el (TokenPlain l) :< ls) ->
199 m :> Cell br er (TokenPlain r) ->
201 Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l))
202 <|(m|>Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r)))
205 Cell bl el (TokenPlain (Text.dropAround Char.isSpace l)) <| ls
206 (Seq.viewr -> rs :> Cell br er (TokenPlain r)) ->
208 rs |> Cell br er (TokenPlain (Text.dropAround Char.isSpace r))
210 TokenPair PairHash to ->
213 xmlAttrs [cell ("to",TL.toStrict $ Plain.textify to)]
214 TokenPair (PairElem name attrs) ts ->
216 TreeN (cell $ xmlLocalName name) $
217 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) -> cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
220 let (o,c) = pairBorders p ts in
221 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
222 xmlify inh ts `unionXml`
223 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
228 mimetype :: Text -> Maybe Text
229 mimetype "hs" = Just "text/x-haskell"
230 mimetype "sh" = Just "text/x-shellscript"
231 mimetype "shell" = Just "text/x-shellscript"
232 mimetype "shellscript" = Just "text/x-shellscript"
235 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
236 xmlPhantom n bp = TreeN (Cell bp bp n)
237 xmlPara :: Pos -> XMLs -> XML
238 xmlPara = xmlPhantom "para"
239 xmlTitle :: Pos -> XMLs -> XML
240 xmlTitle = xmlPhantom "title"
241 xmlName :: Pos -> XMLs -> XML
242 xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
243 xmlName bp ts = xmlPhantom "name" bp ts
245 xmlDocument :: TCTs -> XMLs
247 case Seq.viewl trees of
248 TreeN (unCell -> KeySection{}) vs :< ts ->
249 case spanlTokens vs of
250 (titles@(Seq.viewl -> (Seq.viewl -> Cell bp _ep _ :< _) :< _), vs') ->
254 TreeN (unCell -> KeyColon "about" _) _ -> True
256 Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
259 { inh_titles = titles
261 , inh_tree0 = List.repeat xmlPara
264 _ -> xmlify def trees
265 _ -> xmlify def trees
269 Cell Key -> Seq (Cell (XmlName, Text)) ->
271 xmlAbout inh key attrs body =
273 xmlKey inh key attrs $
274 case Seq.viewl (inh_titles inh) of
275 (Seq.viewl -> Cell bt _et _ :< _) :< _ ->
276 ((<$> inh_titles inh) $ \title ->
277 TreeN (Cell bt bt $ KeyColon "title" "") $
278 Seq.singleton $ Tree0 title)
282 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
283 xmlKey inh (Cell bp ep key) attrs ts =
285 KeyColon n _wh -> d_key n
286 KeyGreat n _wh -> d_key n
287 KeyEqual n _wh -> d_key n
288 KeyBar n _wh -> d_key n
289 KeyDot _n -> TreeN (cell "li") $ xmlify inh ts
290 KeyDash -> TreeN (cell "li") $ xmlify inh ts
291 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
298 (\_path -> fmap $ cell1 . unCell) <$> ts
299 KeyLower n as -> TreeN (cell "artwork") $ xmlify inh ts
301 let inh' = inh{inh_figure = False} in
302 let (attrs',body) = partitionAttributesChildren ts in
303 TreeN (cell "reference") $
304 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
305 xmlify inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
307 TreeN (cell "include") $
308 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
315 TreeN (cell $ xmlLocalName n) $
319 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
320 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
322 -- | Unify two 'XMLs', merging border 'XmlText's if any.
323 unionXml :: XMLs -> XMLs -> XMLs
325 case (Seq.viewr x, Seq.viewl y) of
326 (xs :> x0, y0 :< ys) ->
328 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
330 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.textify 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 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
424 partitionAttributesChildren ts = (attrs,cs)
426 (as,cs) = (`Seq.partition` ts) $ \case
427 TreeN (unCell -> KeyEqual{}) _cs -> True
429 attrs = foldl' (\acc a -> acc |> attr a) Seq.empty as
431 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
432 Cell bp ep (xmlLocalName n, v)
435 Plain.text def{Plain.state_escape = False} $
436 TreeSeq.mapAlsoNode (cell1 . unCell) (\_path -> fmap $ cell1 . unCell) <$> a