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 Control.Monad.Trans.State as S
32 import qualified Language.TCT.Write.Plain as Plain
33 import qualified System.FilePath as FP
35 import Text.Blaze.XML ()
36 import Language.TCT hiding (Parser)
38 import qualified Data.TreeSeq.Strict as TreeSeq
40 import Debug.Trace (trace)
41 import Text.Show (show)
43 xmlDocument :: Roots -> XMLs
45 -- (`S.evalState` def) $
46 case Seq.viewl trees of
47 Tree (unCell -> NodeHeader HeaderSection{}) vs :< ts ->
48 case spanlTokens vs of
49 (titles@(Seq.viewl -> (Seq.viewl -> (posTree -> bp) :< _) :< _), vs') ->
53 Tree (unCell -> NodeHeader (HeaderColon "about" _)) _ -> True
55 Nothing -> Tree (Cell bp bp $ NodeHeader $ HeaderColon "about" "") mempty <| vs'
60 , inh_tree0 = List.repeat xmlPara
68 type Xmls = S.State State XMLs
69 type Xml = S.State State XML
70 instance Semigroup Xmls where
72 instance Monoid Xmls where
73 mempty = return mempty
81 instance Default State where
91 , inh_tree0 :: [Pos -> XMLs -> XML]
92 , inh_titles :: Seq Tokens
94 instance Default Inh where
103 xmlify :: Inh -> a -> XMLs
104 instance Xmlify Roots where
105 xmlify inh_orig = go inh_orig
107 go :: Inh -> Roots -> XMLs
109 case Seq.viewl trees of
110 Tree (Cell bp ep (NodeHeader (HeaderBar n _))) _ :< _
111 | (body,ts) <- spanlBar n trees
114 Tree (Cell bp ep "artwork") $
115 maybe id (\v -> (Tree0 (XmlAttr (Cell bp ep ("type", v))) <|)) (mimetype n) $
116 body >>= xmlify inh{inh_tree0=[]}
118 Tree nod@(unCell -> NodeHeader (HeaderColon n _)) cs :< ts
119 | (cs',ts') <- spanlHeaderColon n ts
121 go inh $ Tree nod (cs<>cs') <| ts'
123 Tree (Cell bp ep (NodeHeader HeaderBrackets{})) _ :< _
124 | (rl,ts) <- spanlBrackets trees
127 Tree (Cell bp ep "references") $
128 rl >>= xmlify inh_orig
130 _ | (ul,ts) <- spanlItems (==HeaderDash) trees
131 , Tree (Cell bp ep _) _ :< _ <- Seq.viewl ul ->
133 Tree (Cell bp ep "ul") $
134 ul >>= xmlify inh{inh_tree0=List.repeat xmlPara}
136 _ | (ol,ts) <- spanlItems (\case HeaderDot{} -> True; _ -> False) trees
137 , Tree (Cell bp ep _) _ :< _ <- Seq.viewl ol ->
139 Tree (Cell bp ep "ol") $
140 ol >>= xmlify inh{inh_tree0=List.repeat xmlPara}
142 t@(Tree0 toks) :< ts ->
143 case inh_tree0 inh of
144 [] -> xmlify inh_orig t <> go inh ts
145 _ | isTokenElem toks -> xmlify inh_orig t <> go inh ts
147 (case Seq.viewl toks of
149 (posTree -> bp) :< _ -> (tree0 bp (xmlify inh_orig t) <|)) $
157 instance Xmlify Root where
158 xmlify inh (Tree (Cell bp ep nod) ts) =
163 let (attrs,body) = partitionAttributesChildren ts in
165 { inh_tree0 = xmlTitle : List.repeat xmlPara
169 Tree (Cell bp ep "section") $
170 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
172 HeaderColon kn _wh ->
173 let (attrs,body) = partitionAttributesChildren ts in
174 let inh' = inh { inh_tree0 =
176 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
177 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
178 "serie" -> List.repeat xmlName
179 "author" -> List.repeat xmlName
180 "editor" -> List.repeat xmlName
181 "org" -> List.repeat xmlName
185 _ | kn == "about" -> xmlAbout inh' nod attrs body
186 _ | inh_figure inh && not (kn`List.elem`elems) ->
188 Tree (Cell bp ep "figure") $
189 xmlAttrs (setXmlAttr (Cell ep ep ("type", kn)) attrs) <>
191 [Tree0{}] -> xmlify inh'{inh_tree0 = List.repeat xmlPara} body
192 _ -> xmlify inh'{inh_tree0 = xmlTitle : List.repeat xmlPara} body
193 _ -> Seq.singleton $ x_Header inh' n
194 HeaderGreat n _wh -> x_Header inh' n
195 HeaderEqual n _wh -> x_Header inh' n
196 HeaderBar n _wh -> x_Header inh' n
197 HeaderDot _n -> Tree (cell "li") $ xmlify inh ts
198 HeaderDash -> Tree (cell "li") $ xmlify inh ts
199 HeaderDashDash -> Tree0 $ XmlComment $ cell $
200 -- debug1_ ("TS", ts) $
201 -- debug1_ ("RS", (S.evalState (Plain.rackUpLeft ts) Nothing)) $
202 Plain.text def $ S.evalState (Plain.rackUpLeft ts) Nothing
209 (\_k' -> cell1 . unCell)) <$> ts
211 HeaderLower n as -> Tree (cell "artwork") $ xmlify inh ts
212 HeaderBrackets ident ->
213 let inh' = inh{inh_figure = False} in
214 let (attrs',body) = partitionAttributesChildren ts in
215 Tree (cell "reference") $
216 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
217 xmlify inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
219 Tree (cell "include") $
220 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
224 PairBracket | to <- Plain.text def ts
225 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
228 xmlAttrs [cell ("to",TL.toStrict to)]
229 PairStar -> Seq.singleton . Tree (cell "b") $ xmlify inh ts
230 PairSlash -> Seq.singleton . Tree (cell "i") $ xmlify inh ts
231 PairBackquote -> Seq.singleton . Tree (cell "code") $ xmlify inh ts
238 (Seq.viewl -> Tree0 (Cell bl el (TokenPlain l)) :< ls) ->
240 m :> Tree0 (Cell br er (TokenPlain r)) ->
242 Tree0 (Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l)))
243 <|(m|>Tree0 (Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r))))
246 Tree0 (Cell bl el (TokenPlain (Text.dropAround Char.isSpace l))) <| ls
247 (Seq.viewr -> rs :> Tree0 (Cell br er (TokenPlain r))) ->
249 rs |> Tree0 (Cell br er (TokenPlain (Text.dropAround Char.isSpace r)))
255 xmlAttrs [cell ("to",TL.toStrict $ Plain.text def ts)]
256 PairElem name attrs ->
258 Tree (cell $ xmlLocalName name) $
259 xmlAttrs (Seq.fromList $ (\(_wh,ElemAttr{..}) ->
260 cell (xmlLocalName elemAttr_name,elemAttr_value)) <$> attrs) <>
263 let (o,c) = pairBorders p ts in
264 Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell bp bp o) `unionXml`
265 xmlify inh ts `unionXml`
266 Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell ep ep c)
269 TokenEscape c -> Seq.singleton $ Tree0 $ XmlPhrases $ phrasify c
270 TokenText t -> Seq.singleton $ Tree0 $ XmlText t
271 TokenTag t -> Seq.singleton $ Tree (cell "ref") $ xmlAttrs [cell ("to",t)]
272 TokenLink lnk -> Seq.singleton $ Tree (cell "eref") $ xmlAttrs [cell ("to",lnk)]
276 x_Header :: Inh -> Text -> XML
278 Tree (cell $ xmlLocalName n) $
284 instance Xmlify Tokens where
286 case Seq.viewl toks of
287 Tree (Cell bp _ep (NodePair PairParen)) paren
288 :< (Seq.viewl -> Tree (Cell bb eb (NodePair PairBracket)) bracket
292 (toList -> [Tree0 (Cell bl el (TokenLink lnk))]) ->
293 Tree (Cell bp eb "eref") $
294 xmlAttrs [Cell bl el ("to",lnk)] <>
297 Tree (Cell bp eb "rref") $
298 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.text def bracket)] <>
300 t :< ts -> xmlify inh t `unionXml` xmlify inh ts
303 instance Xmlify Token where
304 xmlify inh (Tree (Cell bp ep (NodePair p)) ts) =
305 xmlify inh (Tree0 tok) = do
310 whites :: Pos -> Pos -> Seq XmlText
311 whites (Pos bLine bCol) (Pos eLine eCol) =
312 case bLine`compate`eLine of
314 EQ -> horiz bCol eCol
317 instance Xmlify (Cell Phrase) where
318 xmlify _inh t = Seq.singleton $ Tree0 $ XmlPhrases $ Seq.singleton t
321 mimetype :: Text -> Maybe Text
322 mimetype "hs" = Just "text/x-haskell"
323 mimetype "sh" = Just "text/x-shellscript"
324 mimetype "shell" = Just "text/x-shellscript"
325 mimetype "shellscript" = Just "text/x-shellscript"
328 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
329 xmlPhantom n bp = Tree (Cell bp bp n)
330 xmlPara :: Pos -> XMLs -> XML
331 xmlPara = xmlPhantom "para"
332 xmlTitle :: Pos -> XMLs -> XML
333 xmlTitle = xmlPhantom "title"
334 xmlName :: Pos -> XMLs -> XML
335 xmlName bp (toList -> [Tree0 (XmlText (unCell -> t))]) = Tree0 (XmlAttr $ Cell bp bp ("name", t))
336 xmlName bp ts = xmlPhantom "name" bp ts
340 Cell Header -> Seq (Cell (XmlName, Text)) ->
342 xmlAbout inh hdr attrs body =
344 xmlHeader inh hdr attrs $
345 case Seq.viewl (inh_titles inh) of
346 (Seq.viewl -> (posTree -> bt) :< _) :< _ ->
347 ((<$> inh_titles inh) $ \title ->
348 Tree (Cell bt bt $ NodeHeader $ HeaderColon "title" "") $
349 Seq.singleton $ Tree0 title)
353 xmlHeader :: Inh -> Cell Header -> Seq (Cell (XmlName, Text)) -> Roots -> XML
354 xmlHeader inh (Cell bp ep hdr) attrs ts =
356 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
357 xmlAttrs = (Tree0 . XmlAttr <$>)
359 -- | Unify two 'XMLs', merging border 'XmlText's if any.
360 unionXml :: XMLs -> XMLs -> XMLs
362 case (Seq.viewr x, Seq.viewl y) of
363 (xs :> x0, y0 :< ys) ->
365 ( Tree0 (XmlPhrases tx)
366 , Tree0 (XmlPhrases ty) ) ->
368 Seq.singleton (Tree0 $ XmlPhrases $ tx <> ty) `unionXml`
371 , Tree0 (XmlText ty) ) ->
373 Seq.singleton (Tree0 $ XmlText $ tx <> ty) `unionXml`
379 spanlBar :: Name -> Roots -> (Roots, Roots)
380 spanlBar name = first unHeaderBar . spanBar
382 unHeaderBar :: Roots -> Roots
383 unHeaderBar = (=<<) $ \case
384 Tree (unCell -> NodeHeader HeaderBar{}) ts -> ts
388 Tree (unCell -> NodeHeader (HeaderBar n _)) _ | n == name -> True
391 spanlItems :: (Header -> Bool) -> Roots -> (Roots, Roots)
392 spanlItems liHeader ts =
393 let (lis, ts') = spanLIs ts in
394 foldl' accumLIs (mempty,ts') lis
396 spanLIs :: Roots -> (Roots, Roots)
397 spanLIs = Seq.spanl $ \case
398 Tree (unCell -> NodeHeader (liHeader -> True)) _ -> True
399 Tree (NodeToken toks) _ ->
401 TreeN (unCell -> NodePair (PairElem "li" _)) _ -> True
404 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
405 [unCell -> TokenPair (PairElem "li" _) _] -> True
409 accumLIs :: (Roots,Roots) -> Root -> (Roots,Roots)
410 accumLIs acc@(oks,kos) t =
412 Tree (unCell -> NodeHeader (liHeader -> True)) _ -> (oks|>t,kos)
415 (`Seq.spanl` toks) $ \case
416 Tree (unCell -> NodePair (PairElem "li" _)) _ -> True
417 -- (isTokenWhite -> True) -> True -- TODO: see if this is still useful
419 ( if null ok then oks else oks|>Tree0 (rmTokenWhite ok)
420 , if null ko then kos else Tree0 ko<|kos )
423 rmTokenWhite :: Tokens -> Tokens
426 (isTokenWhite -> False) -> True
430 spanlHeaderColon :: Name -> Roots -> (Roots, Roots)
431 spanlHeaderColon name =
433 Tree (unCell -> NodeHeader (HeaderBar n _)) _ -> n == name
434 Tree (unCell -> NodeHeader (HeaderGreat n _)) _ -> n == name
437 spanlBrackets :: Roots -> (Roots, Roots)
440 Tree (unCell -> NodeHeader HeaderBrackets{}) _ -> True
443 spanlTokens :: Roots -> (Seq Tokens, Roots)
447 _ -> undefined) <$>) .
452 getAttrId :: Roots -> Text
454 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
455 Just (Tree0 toks) -> TL.toStrict $ Plain.text def toks
458 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
459 setXmlAttr a@(unCell -> (k, _v)) as =
460 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
461 Just idx -> Seq.update idx a as
464 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
465 defXmlAttr a@(unCell -> (k, _v)) as =
466 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
470 partitionAttributesChildren :: Roots -> (Seq (Cell (XmlName, Text)), Roots)
471 partitionAttributesChildren ts = (attrs,cs)
473 (as,cs) = (`Seq.partition` ts) $ \case
474 Tree (unCell -> NodeHeader HeaderEqual{}) _cs -> True
478 Tree (Cell bp ep (NodeHeader (HeaderEqual n _wh))) a ->
479 Cell bp ep (xmlLocalName n, v)
482 Plain.text def{Plain.state_escape = False} $
488 (\_k' -> cell1 . unCell)) <$> a