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 :: TCTs -> XMLs
45 -- (`S.evalState` def) $
46 case Seq.viewl trees of
47 TreeN (unCell -> KeySection{}) vs :< ts ->
48 case spanlTokens vs of
49 (titles@(Seq.viewl -> (Seq.viewl -> (posTree -> bp) :< _) :< _), vs') ->
53 TreeN (unCell -> KeyColon "about" _) _ -> True
55 Nothing -> TreeN (Cell bp bp $ KeyColon "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 TCTs where
105 xmlify inh_orig = go inh_orig
107 go :: Inh -> TCTs -> XMLs
109 case Seq.viewl trees of
110 TreeN (Cell bp ep (KeyBar n _)) _ :< _
111 | (body,ts) <- spanlBar n trees
114 TreeN (Cell bp ep "artwork") $
115 maybe id (\v -> (Tree0 (XmlAttr (Cell bp ep ("type", v))) <|)) (mimetype n) $
116 body >>= xmlify inh{inh_tree0=[]}
118 TreeN key@(unCell -> KeyColon n _) cs :< ts
119 | (cs',ts') <- spanlKeyColon n ts
121 go inh $ TreeN key (cs<>cs') <| ts'
123 TreeN (Cell bp ep KeyBrackets{}) _ :< _
124 | (rl,ts) <- spanlBrackets trees
127 TreeN (Cell bp ep "references") $
128 rl >>= xmlify inh_orig
130 _ | (ul,ts) <- spanlItems (==KeyDash) trees
131 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ul ->
133 TreeN (Cell bp ep "ul") $
134 ul >>= xmlify inh{inh_tree0=List.repeat xmlPara}
136 _ | (ol,ts) <- spanlItems (\case KeyDot{} -> True; _ -> False) trees
137 , TreeN (Cell bp ep _) _ :< _ <- Seq.viewl ol ->
139 TreeN (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 TCT where
160 TreeN (Cell bp ep KeySection{}) ts ->
161 let (attrs,body) = partitionAttributesChildren ts in
163 { inh_tree0 = xmlTitle : List.repeat xmlPara
167 TreeN (Cell bp ep "section") $
168 xmlAttrs (defXmlAttr (Cell ep ep ("id", getAttrId body)) attrs) <>
171 TreeN key@(Cell bp ep (KeyColon kn _)) ts ->
172 let (attrs,body) = partitionAttributesChildren ts in
173 let inh' = inh { inh_tree0 =
175 "about" -> xmlTitle : xmlTitle : List.repeat xmlPara
176 "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
177 "serie" -> List.repeat xmlName
178 "author" -> List.repeat xmlName
179 "editor" -> List.repeat xmlName
180 "org" -> List.repeat xmlName
184 _ | kn == "about" -> xmlAbout inh' key attrs body
186 _ | inh_figure inh && not (kn`List.elem`elems) ->
188 TreeN (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
194 _ -> Seq.singleton $ xmlKey inh' key attrs body
196 TreeN key ts -> Seq.singleton $ xmlKey inh key mempty ts
198 Tree0 ts -> xmlify inh ts
199 instance Xmlify Tokens where
201 case Seq.viewl toks of
202 TreeN (Cell bp _ep PairParen) paren
203 :< (Seq.viewl -> TreeN (Cell bb eb PairBracket) bracket
207 (toList -> [Tree0 (Cell bl el (TokenLink lnk))]) ->
208 TreeN (Cell bp eb "eref") $
209 xmlAttrs [Cell bl el ("to",lnk)] <>
212 TreeN (Cell bp eb "rref") $
213 xmlAttrs [Cell bb eb ("to",TL.toStrict $ Plain.text def bracket)] <>
215 t :< ts -> xmlify inh t `unionXml` xmlify inh ts
217 instance Xmlify Token where
218 xmlify inh (TreeN (Cell bp ep p) ts) =
220 PairBracket | to <- Plain.text def ts
221 , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
223 TreeN (cell "rref") $
224 xmlAttrs [cell ("to",TL.toStrict to)]
225 PairStar -> Seq.singleton . TreeN (cell "b") $ xmlify inh ts
226 PairSlash -> Seq.singleton . TreeN (cell "i") $ xmlify inh ts
227 PairBackquote -> Seq.singleton . TreeN (cell "code") $ xmlify inh ts
234 (Seq.viewl -> Tree0 (Cell bl el (TokenPlain l)) :< ls) ->
236 m :> Tree0 (Cell br er (TokenPlain r)) ->
238 Tree0 (Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l)))
239 <|(m|>Tree0 (Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r))))
242 Tree0 (Cell bl el (TokenPlain (Text.dropAround Char.isSpace l))) <| ls
243 (Seq.viewr -> rs :> Tree0 (Cell br er (TokenPlain r))) ->
245 rs |> Tree0 (Cell br er (TokenPlain (Text.dropAround Char.isSpace r)))
251 xmlAttrs [cell ("to",TL.toStrict $ Plain.text def ts)]
252 PairElem name attrs ->
254 TreeN (cell $ xmlLocalName name) $
255 xmlAttrs (Seq.fromList $ (\(_wh,ElemAttr{..}) ->
256 cell (xmlLocalName elemAttr_name,elemAttr_value)) <$> attrs) <>
259 let (o,c) = pairBorders p ts in
260 Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell bp bp o) `unionXml`
261 xmlify inh ts `unionXml`
262 Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell ep ep c)
266 xmlify inh (Tree0 tok) = do
268 TokenPhrases ps -> xmlify inh $ ps
269 TokenEscape c -> Seq.singleton $ Tree0 $ XmlPhrases $ phrasify c
270 TokenRaw t -> Seq.singleton $ Tree0 $ XmlText t
271 TokenTag t -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
272 TokenLink (Cell bp ep lnk) ->
273 xmlify (Cell bp ep ()) <>
274 Seq.singleton (TreeN (cell "eref") $ xmlAttrs [cell ("to",lnk)])
279 whites :: Pos -> Pos -> Seq XmlText
280 whites (Pos bLine bCol) (Pos eLine eCol) =
281 case bLine`compate`eLine of
283 EQ -> horiz bCol eCol
286 instance Xmlify (Cell Phrase) where
287 xmlify _inh t = Seq.singleton $ Tree0 $ XmlPhrases $ Seq.singleton t
289 mimetype :: Text -> Maybe Text
290 mimetype "hs" = Just "text/x-haskell"
291 mimetype "sh" = Just "text/x-shellscript"
292 mimetype "shell" = Just "text/x-shellscript"
293 mimetype "shellscript" = Just "text/x-shellscript"
296 xmlPhantom :: XmlName -> Pos -> XMLs -> XML
297 xmlPhantom n bp = TreeN (Cell bp bp n)
298 xmlPara :: Pos -> XMLs -> XML
299 xmlPara = xmlPhantom "para"
300 xmlTitle :: Pos -> XMLs -> XML
301 xmlTitle = xmlPhantom "title"
302 xmlName :: Pos -> XMLs -> XML
303 xmlName bp (toList -> [Tree0 (XmlText (unCell -> t))]) = Tree0 (XmlAttr $ Cell bp bp ("name", t))
304 xmlName bp ts = xmlPhantom "name" bp ts
308 Cell Key -> Seq (Cell (XmlName, Text)) ->
310 xmlAbout inh key attrs body =
312 xmlKey inh key attrs $
313 case Seq.viewl (inh_titles inh) of
314 (Seq.viewl -> (posTree -> bt) :< _) :< _ ->
315 ((<$> inh_titles inh) $ \title ->
316 TreeN (Cell bt bt $ KeyColon "title" "") $
317 Seq.singleton $ Tree0 title)
321 xmlKey :: Inh -> Cell Key -> Seq (Cell (XmlName, Text)) -> TCTs -> XML
322 xmlKey inh (Cell bp ep key) attrs ts =
324 KeyColon n _wh -> d_key n
325 KeyGreat n _wh -> d_key n
326 KeyEqual n _wh -> d_key n
327 KeyBar n _wh -> d_key n
328 KeyDot _n -> TreeN (cell "li") $ xmlify inh ts
329 KeyDash -> TreeN (cell "li") $ xmlify inh ts
330 KeyDashDash -> Tree0 $ XmlComment $ cell $ TL.toStrict com
334 trace ("TS: "<>show ts) $
335 trace ("RS: "<>show (S.evalState (Plain.rackUpLeft ts) Nothing)) $
336 Plain.text def $ S.evalState (Plain.rackUpLeft ts) Nothing
343 (\_k' -> cell1 . unCell)) <$> ts
345 KeyLower n as -> TreeN (cell "artwork") $ xmlify inh ts
347 let inh' = inh{inh_figure = False} in
348 let (attrs',body) = partitionAttributesChildren ts in
349 TreeN (cell "reference") $
350 xmlAttrs (setXmlAttr (Cell ep ep ("id", ident)) (attrs<>attrs')) <>
351 xmlify inh'{inh_tree0 = xmlTitle : xmlTitle : List.repeat xmlPara} body
353 TreeN (cell "include") $
354 xmlAttrs [cell ("href", Text.pack $ FP.replaceExtension p "dtc")] <>
361 TreeN (cell $ xmlLocalName n) $
365 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
366 xmlAttrs = (Tree0 . XmlAttr <$>)
368 -- | Unify two 'XMLs', merging border 'XmlText's if any.
369 unionXml :: XMLs -> XMLs -> XMLs
371 case (Seq.viewr x, Seq.viewl y) of
372 (xs :> x0, y0 :< ys) ->
374 ( Tree0 (XmlPhrases tx)
375 , Tree0 (XmlPhrases ty) ) ->
377 Seq.singleton (Tree0 $ XmlPhrases $ tx <> ty) `unionXml`
380 , Tree0 (XmlText ty) ) ->
382 Seq.singleton (Tree0 $ XmlText $ tx <> ty) `unionXml`
388 spanlBar :: Name -> TCTs -> (TCTs, TCTs)
389 spanlBar name = first unKeyBar . spanBar
391 unKeyBar :: TCTs -> TCTs
392 unKeyBar = (=<<) $ \case
393 TreeN (unCell -> KeyBar{}) ts -> ts
397 TreeN (unCell -> KeyBar n _) _ | n == name -> True
400 spanlItems :: (Key -> Bool) -> TCTs -> (TCTs, TCTs)
401 spanlItems liKey ts =
402 let (lis, ts') = spanLIs ts in
403 foldl' accumLIs (mempty,ts') lis
405 spanLIs :: TCTs -> (TCTs, TCTs)
406 spanLIs = Seq.spanl $ \case
407 TreeN (unCell -> liKey -> True) _ -> True
410 TreeN (unCell -> PairElem "li" _) _ -> True
413 case toList $ Seq.dropWhileR (isTokenWhite . unCell) toks of
414 [unCell -> TokenPair (PairElem "li" _) _] -> True
418 accumLIs :: (TCTs,TCTs) -> TCT -> (TCTs,TCTs)
419 accumLIs acc@(oks,kos) t =
421 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
424 (`Seq.spanl` toks) $ \case
425 TreeN (unCell -> PairElem "li" _) _ -> True
426 -- (isTokenWhite -> True) -> True -- TODO: see if this is still useful
428 ( if null ok then oks else oks|>Tree0 (rmTokenWhite ok)
429 , if null ko then kos else Tree0 ko<|kos )
432 rmTokenWhite :: Tokens -> Tokens
435 (isTokenWhite -> False) -> True
439 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
442 TreeN (unCell -> KeyBar n _) _ -> n == name
443 TreeN (unCell -> KeyGreat n _) _ -> n == name
446 spanlBrackets :: TCTs -> (TCTs, TCTs)
449 TreeN (unCell -> KeyBrackets{}) _ -> True
452 spanlTokens :: TCTs -> (Seq Tokens, TCTs)
456 _ -> undefined) <$>) .
461 getAttrId :: TCTs -> Text
463 case Seq.index ts <$> Seq.findIndexL TreeSeq.isTree0 ts of
464 Just (Tree0 toks) -> TL.toStrict $ Plain.text def toks
467 setXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
468 setXmlAttr a@(unCell -> (k, _v)) as =
469 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
470 Just idx -> Seq.update idx a as
473 defXmlAttr :: Cell (XmlName, Text) -> Seq (Cell (XmlName, Text)) -> Seq (Cell (XmlName, Text))
474 defXmlAttr a@(unCell -> (k, _v)) as =
475 case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
479 partitionAttributesChildren :: TCTs -> (Seq (Cell (XmlName, Text)), TCTs)
480 partitionAttributesChildren ts = (attrs,cs)
482 (as,cs) = (`Seq.partition` ts) $ \case
483 TreeN (unCell -> KeyEqual{}) _cs -> True
487 TreeN (Cell bp ep (KeyEqual n _wh)) a ->
488 Cell bp ep (xmlLocalName n, v)
491 Plain.text def{Plain.state_escape = False} $
497 (\_k' -> cell1 . unCell)) <$> a