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 (posTree -> bp) :< _ -> (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 TreeN (Cell bp _ep PairParen) paren
155 :< (Seq.viewl -> TreeN (Cell bb eb PairBracket) bracket
159 (toList -> [Tree0 (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 Token where
170 xmlify inh (TreeN (Cell bp ep p) ts) =
172 PairBracket | to <- Plain.textify ts
173 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
175 TreeN (cell "rref") $
176 xmlAttrs [cell ("to",TL.toStrict to)]
177 PairStar -> Seq.singleton $ TreeN (cell "b") $ xmlify inh ts
178 PairSlash -> Seq.singleton $ TreeN (cell "i") $ xmlify inh ts
179 PairBackquote -> Seq.singleton $ TreeN (cell "code") $ xmlify inh ts
184 (Seq.viewl -> Tree0 (Cell bl el (TokenPlain l)) :< ls) ->
186 m :> Tree0 (Cell br er (TokenPlain r)) ->
188 Tree0 (Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l)))
189 <|(m|>Tree0 (Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r))))
192 Tree0 (Cell bl el (TokenPlain (Text.dropAround Char.isSpace l))) <| ls
193 (Seq.viewr -> rs :> Tree0 (Cell br er (TokenPlain r))) ->
195 rs |> Tree0 (Cell br er (TokenPlain (Text.dropAround Char.isSpace r)))
200 xmlAttrs [cell ("to",TL.toStrict $ Plain.textify ts)]
201 PairElem name attrs ->
203 TreeN (cell $ xmlLocalName name) $
204 xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) ->
205 cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
208 let (o,c) = pairBorders p ts in
209 Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
210 xmlify inh ts `unionXml`
211 Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
215 xmlify _inh (Tree0 (Cell bp ep tok)) =
217 TokenPlain t -> Seq.singleton $ Tree0 $ cell $ XmlText t
218 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
219 TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
220 TokenLink lnk -> Seq.singleton $
221 TreeN (cell "eref") $
222 xmlAttrs [cell ("to",lnk)]
227 mimetype :: Text -> Maybe Text
228 mimetype "hs" = Just "text/x-haskell"
229 mimetype "sh" = Just "text/x-shellscript"
230 mimetype "shell" = Just "text/x-shellscript"
231 mimetype "shellscript" = Just "text/x-shellscript"
234 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
235 xmlPhantom n bp = TreeN (Cell bp bp n)
236 xmlPara :: Pos -> XMLs -> XML
237 xmlPara = xmlPhantom "para"
238 xmlTitle :: Pos -> XMLs -> XML
239 xmlTitle = xmlPhantom "title"
240 xmlName :: Pos -> XMLs -> XML
241 xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
242 xmlName bp ts = xmlPhantom "name" bp ts
244 xmlDocument :: TCTs -> XMLs
246 case Seq.viewl trees of
247 TreeN (unCell -> KeySection{}) vs :< ts ->
248 case spanlTokens vs of
249 (titles@(Seq.viewl -> (Seq.viewl -> (posTree -> bp) :< _) :< _), vs') ->
253 TreeN (unCell -> KeyColon "about" _) _ -> True
255 Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
258 { inh_titles = titles
260 , inh_tree0 = List.repeat xmlPara
263 _ -> xmlify def trees
264 _ -> xmlify def trees
268 Cell Key -> Seq (Cell (XmlName, Text)) ->
270 xmlAbout inh key attrs body =
272 xmlKey inh key attrs $
273 case Seq.viewl (inh_titles inh) of
274 (Seq.viewl -> (posTree -> bt) :< _) :< _ ->
275 ((<$> inh_titles inh) $ \title ->
276 TreeN (Cell bt bt $ KeyColon "title" "") $
277 Seq.singleton $ Tree0 title)
281 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
282 xmlKey inh (Cell bp ep key) attrs ts =
284 KeyColon n _wh -> d_key n
285 KeyGreat n _wh -> d_key n
286 KeyEqual n _wh -> d_key n
287 KeyBar n _wh -> d_key n
288 KeyDot _n -> TreeN (cell "li") $ xmlify inh ts
289 KeyDash -> TreeN (cell "li") $ xmlify inh ts
290 KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
300 (\_k' -> cell1 . unCell)) <$> ts
301 KeyLower n as -> TreeN (cell "artwork") $ xmlify inh ts
303 let inh' = inh{inh_figure = False} in
304 let (attrs',body) = partitionAttributesChildren ts in
305 TreeN (cell "reference") $
306 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
307 xmlify inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
309 TreeN (cell "include") $
310 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
317 TreeN (cell $ xmlLocalName n) $
321 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
322 xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
324 -- | Unify two 'XMLs', merging border 'XmlText's if any.
325 unionXml :: XMLs -> XMLs -> XMLs
327 case (Seq.viewr x, Seq.viewl y) of
328 (xs :> x0, y0 :< ys) ->
330 (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
332 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 TreeN (unCell -> 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) $ \case
373 TreeN (unCell -> PairElem "li" _) _ -> True
374 Tree0 (unCell -> TokenPlain txt) -> Char.isSpace`Text.all`txt
376 ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
377 , if null ko then kos else Tree0 ko<|kos )
381 (Tree0 (unCell -> TokenPlain{})) -> False
384 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
387 TreeN (unCell -> KeyBar n _) _ -> n == name
388 TreeN (unCell -> KeyGreat n _) _ -> n == name
391 spanlBrackets :: TCTs -> (TCTs, TCTs)
394 TreeN (unCell -> KeyBrackets{}) _ -> True
397 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
401 _ -> undefined) <$>) .
406 getAttrId :: TCTs -> Text
408 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
409 Just (Tree0 toks) -> TL.toStrict $ Plain.textify toks
412 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
413 setXmlAttr a@(unCell -> (k, _v)) as =
414 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
415 Just idx -> Seq.update idx a as
418 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
419 defXmlAttr a@(unCell -> (k, _v)) as =
420 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
424 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
425 partitionAttributesChildren ts = (attrs,cs)
427 (as,cs) = (`Seq.partition` ts) $ \case
428 TreeN (unCell -> KeyEqual{}) _cs -> True
432 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
433 Cell bp ep (xmlLocalName n, v)
436 Plain.text def{Plain.state_escape = False} $
442 (\_k' -> cell1 . unCell)) <$> a