Add <URL> when print-only.
[doclang.git] / Language / TCT / Write / XML.hs
index 2abdc8933c3bff3d1b44d4318fef9327d1f87109..2f6ab61d1366a2bbeb5176c547031b9f1b727f68 100644 (file)
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Language.TCT.Write.XML where
 
-import Control.Arrow (first)
-import Control.Monad (Monad(..), (=<<))
+import Control.Monad (Monad(..))
 import Data.Bool
 import Data.Default.Class (Default(..))
 import Data.Eq (Eq(..))
 import Data.Foldable (Foldable(..))
-import Data.Function (($), (.), id)
-import Data.Functor ((<$>), (<$))
-import Data.Maybe (Maybe(..), maybe, fromMaybe)
+import Data.Function (($), (.))
+import Data.Functor ((<$>), (<$), ($>))
+import Data.List.NonEmpty (NonEmpty(..))
+import Data.Maybe (Maybe(..))
 import Data.Monoid (Monoid(..))
+import Data.Ord (Ord(..))
 import Data.Semigroup (Semigroup(..))
 import Data.Sequence (Seq, ViewL(..), ViewR(..), (<|))
 import Data.Set (Set)
-import Data.TreeSeq.Strict (Tree(..))
+import Data.TreeSeq.Strict (Tree(..), tree0)
 import Data.Tuple (uncurry)
-import Prelude (undefined)
+import Prelude (Num(..), undefined)
 import qualified Data.Char as Char
 import qualified Data.List as List
 import qualified Data.Sequence as Seq
 import qualified Data.Text.Lazy as TL
 import qualified Language.TCT.Write.Plain as Plain
-import qualified System.FilePath as FP
 
-import Text.Blaze.XML ()
+-- import Language.TCT.Debug
+import Language.TCT.Utils
 import Language.TCT hiding (Parser)
-import Language.TCT.Debug
 import Language.XML
+import Text.Blaze.XML ()
 
-xmlDocument :: Roots -> XMLs
-xmlDocument trees =
+-- | Main entry point
+--
+-- NOTE: 'XmlNode' are still annotated with 'Cell',
+--       but nothing is done to preserve any ordering amongst them,
+--       because 'Node's sometimes need to be reordered
+--       (eg. about/title may have a title from the section before,
+--       hence outside of about).
+--       Still holding: @'cell_begin' < 'cell_end'@ and 'Cell' nesting.
+writeXML :: Roots -> XMLs
+writeXML doc =
        -- (`S.evalState` def) $
-       case Seq.viewl trees of
-        Tree (unCell -> NodeHeader HeaderSection{}) vs :< ts ->
-               case spanlNodeToken vs of
-                (titles@(Seq.viewl -> (unTree -> cell_begin -> bp) :< _), vs') ->
-                       let vs'' =
-                               case Seq.findIndexL
-                                (\case
-                                Tree (unCell -> NodeHeader (HeaderColon "about" _)) _ -> True
-                                _ -> False) vs' of
-                                Nothing -> Tree (Cell bp bp $ NodeHeader $ HeaderColon "about" "") mempty <| vs'
-                                Just{} -> vs' in
+       case Seq.viewl doc of
+        sec@(Tree (unCell -> NodeHeader HeaderSection{}) _body) :< foot ->
+               let (titles, content) = partitionSection sec in
+               case Seq.viewl titles of
+                (unTree -> Cell st _) :< _ ->
                        xmlify def
                         { inh_titles = titles
                         , inh_figure = True
-                        , inh_para   = List.repeat xmlPara
-                        } vs'' <>
-                       xmlify def ts
-                _ -> xmlify def trees
-        _ -> xmlify def trees
-
-{-
--- * Type 'Xmls'
-type Xmls = S.State State XMLs
-type Xml  = S.State State XML
-instance Semigroup Xmls where
-       (<>) = liftA2 (<>)
-instance Monoid Xmls where
-       mempty  = return mempty
-       mappend = (<>)
+                        } contentWithAbout <>
+                       xmlify def foot
+                       where
+                       contentWithAbout =
+                               case Seq.findIndexL isAbout content of
+                                Nothing -> Tree (Cell st $ NodeHeader $ HeaderColon "about" "") mempty <| content
+                                Just{} -> content
+                       isAbout = \case
+                        (unTree -> (unCell -> NodeHeader (HeaderColon "about" _wh))) -> True
+                        _ -> False
+                _ -> xmlify def doc
+        _ -> xmlify def doc
 
--- * Type 'State'
-data State
- =   State
- {   state_pos :: Pos
- }
-instance Default State where
-       def = State
-        { state_pos = pos1
-        }
--}
+partitionSection :: Root -> (Roots, Roots)
+partitionSection (Tree (unCell -> NodeHeader (HeaderSection lvlPar)) body) =
+       case Seq.viewl body of
+        EmptyL -> mempty
+        title@(unTree -> Cell (Span{span_end=et}:|_) NodePara) :< rest ->
+               let (subtitles, content) = spanlSubtitles et rest in
+               (title <| (subtitles >>= subTrees), content)
+               where
+               spanlSubtitles ep ts =
+                       case Seq.viewl ts of
+                        sub@(unTree -> Cell (Span{..}:|_) (NodeHeader (HeaderSection lvlSub))) :< rs
+                               | lvlSub <= lvlPar
+                               , pos_line span_begin - pos_line ep <= 1 ->
+                               let (subs, ts') = spanlSubtitles span_end rs in
+                               (sub <| subs, ts')
+                        _ -> (mempty, ts)
+        _ -> (mempty, body)
+partitionSection _ = mempty
 
 -- * Type 'Inh'
 data Inh
  =   Inh
  {   inh_figure :: Bool
- ,   inh_para   :: [Cell () -> XMLs -> XML]
+ ,   inh_para   :: [Inh -> Root -> XML]
  ,   inh_titles :: Roots
  }
 instance Default Inh where
        def = Inh
         { inh_figure = False
-        , inh_para   = []
+        , inh_para   = List.repeat elementPara
         , inh_titles = mempty
         }
 
-{-
-newtype Merge a = Merge a
- deriving (Functor)
-instance Semigroup (Merge Roots) where
-       (<>) = unionTokens
-instance Monad (Merge Roots) where
-       return = Merge
-       Merge m >>= f =
-               foldMap nn
--}
+-- ** 'inh_para'
+elementPara :: Inh -> Root -> XML
+elementPara inh (Tree c ts) = Tree (XmlElem "para" <$ c) $ xmlify inh ts
+
+elementTitle :: Inh -> Root -> XML
+elementTitle inh (Tree c ts) = Tree (XmlElem "title" <$ c) $ xmlify inh ts
+
+elementName :: Inh -> Root -> XML
+elementName inh (Tree c ts) = Tree (XmlElem "name" <$ c) $ xmlify inh ts
+
+attributeName :: Inh -> Root -> XML
+attributeName _inh (Tree c ts) = tree0 (XmlAttr "name" (Plain.writePlain ts) <$ c)
 
 -- * Class 'Xmlify'
 class Xmlify a where
@@ -110,167 +120,216 @@ instance Xmlify Roots where
        xmlify inh roots =
                case Seq.viewl roots of
                 EmptyL -> mempty
-                l@(Tree cel@(Cell bp _ep nod) ts) :< rs ->
-                       case nod of
-                        NodeHeader (HeaderBar n _wh)
-                         | (span, rest) <- spanlHeaderBar n roots ->
-                               let (attrs,body) = partitionAttrs span in
-                               (<| xmlify inh rest) $
-                               element "artwork" $
-                                       xmlAttrs (attrs `defaultAttr` Cell bp bp ("type", fromMaybe "text/plain" $ mimetype n)) <>
-                                       xmlify inh{inh_para=[]} body
-                       ----------------------
-                        NodeHeader (HeaderGreat n _wh)
-                         | (span, rest) <- spanlHeaderGreat n roots ->
-                               let (attrs,body) = partitionAttrs span in
-                               (<| xmlify inh rest) $
-                               element "artwork" $
-                                       xmlAttrs (attrs `defaultAttr` Cell bp bp ("type", fromMaybe "text/plain" $ mimetype n)) <>
-                                       xmlify inh{inh_para=[]} (debug0 "body" body)
+                r@(Tree cr@(Cell _sr nr) ts) :< rs ->
+                       case nr of
                        ----------------------
+                        -- NOTE: HeaderColon becomes parent
+                        -- of any continuous following-sibling HeaderBar or HeaderGreat
                         NodeHeader (HeaderColon n _wh)
-                         | (span, rest) <- spanlHeaderColon rs
+                         | (span, rest) <- spanlHeaderColon rs
                          , not $ null span ->
-                               xmlify inh $ Tree cel (ts<>span) <| rest
+                               xmlify inh (Tree cr (ts<>span)) <>
+                               xmlify inh rest
+                               where
+                               spanlHeaderColon :: Roots -> (Roots, Roots)
+                               spanlHeaderColon =
+                                       Seq.spanl $ \case
+                                        Tree (unCell -> NodeHeader (HeaderBar   m _)) _ -> m == n
+                                        Tree (unCell -> NodeHeader (HeaderGreat m _)) _ -> m == n
+                                        _ -> False
                        ----------------------
+                        -- NOTE: gather HeaderBrackets
                         NodeHeader HeaderBrackets{}
                          | (span,rest) <- spanlBrackets roots
                          , not (null span) ->
                                (<| xmlify inh rest) $
                                element "references" $
-                                       xmlify inh span
+                                       span >>= xmlify inh
+                               where
+                               spanlBrackets :: Roots -> (Roots, Roots)
+                               spanlBrackets =
+                                       Seq.spanl $ \case
+                                        Tree (unCell -> NodeHeader HeaderBrackets{}) _ -> True
+                                        _ -> False
                        ----------------------
+                        -- NOTE: merge adjacent NodeText-s, shouldn't be needed, but just in case.
                         NodeText x
                          | Tree (cy@(unCell -> NodeText y)) ys :< rs' <- Seq.viewl rs ->
-                               xmlify inh $ Tree (NodeText <$> (x <$ cel) <> (y <$ cy)) (ts <> ys) <| rs'
+                               xmlify inh $ Tree (NodeText <$> (x <$ cr) <> (y <$ cy)) (ts <> ys) <| rs'
                        ----------------------
+                        -- NOTE: detect [some text](http://some.url) or [SomeRef]
                         NodePair PairParen
-                         | Tree (Cell bb eb (NodePair PairBracket)) bracket :< rs' <- Seq.viewl rs ->
+                         | Tree (Cell sb (NodePair PairBracket)) bracket :< rs' <- Seq.viewl rs ->
                                (<| xmlify inh rs') $
                                case bracket of
-                                (toList -> [unTree -> Cell bl el (NodeToken (TokenLink lnk))]) ->
+                                (toList -> [unTree -> Cell sl (NodeToken (TokenLink lnk))]) ->
                                        element "eref" $
-                                               xmlAttrs [Cell bl el ("to",lnk)] <>
+                                               xmlAttrs [Cell sl ("to",lnk)] <>
                                                xmlify inh ts
                                 _ ->
                                        element "rref" $
-                                               xmlAttrs [Cell bb eb ("to",Plain.plainDocument bracket)] <>
+                                               xmlAttrs [Cell sb ("to",Plain.writePlain bracket)] <>
                                                xmlify inh ts
                        ----------------------
+                        -- NOTE: gather HeaderDash
                         _ | (span, rest) <- spanlItems (==HeaderDash) roots
                           , not $ null span ->
                                (<| xmlify inh rest) $
                                element "ul" $
-                                       span >>= xmlify inh{inh_para=List.repeat xmlPara}
+                                       span >>= xmlify inh{inh_para=List.repeat elementPara}
                        ----------------------
-                        _ | (span,rest) <- spanlItems (\case HeaderDot{} -> True; _ -> False) roots
+                        -- NOTE: gather HeaderDot
+                          | (span,rest) <- spanlItems (\case HeaderDot{} -> True; _ -> False) roots
                           , not $ null span ->
                                (<| xmlify inh rest) $
                                element "ol" $
-                                       span >>= xmlify inh{inh_para=List.repeat xmlPara}
+                                       span >>= xmlify inh{inh_para=List.repeat elementPara}
+                               where
+                               spanlItems :: (Header -> Bool) -> Roots -> (Roots, Roots)
+                               spanlItems liHeader =
+                                       Seq.spanl $ \(unTree -> (unCell -> nod)) ->
+                                               case nod of
+                                                NodeHeader (HeaderColon "li" _wh) -> True
+                                                NodeHeader hdr -> liHeader hdr
+                                                NodePair (PairElem "li" _as) -> True
+                                                _ -> False
                        ----------------------
+                        NodePara | para:inh_para <- inh_para inh ->
+                               para inh r <|
+                               xmlify inh{inh_para} rs
+                       ----------------------
+                        -- NOTE: context-free Root
                         _ ->
-                               xmlify inh l <>
+                               xmlify inh r `unionXml`
                                xmlify inh rs
                        where
                        element :: XmlName -> XMLs -> XML
-                       element n = tree (XmlElem n <$ cel)
-               {-
-                t@(Tree (NodePair (PairElem))) :< ts ->
-                       case inh_para inh of
-                        []                   -> xmlify inh t <> go inh ts
-                        _ | isTokenElem toks -> xmlify inh t <> go inh ts
-                        tree0:inh_para ->
-                               (case Seq.viewl toks of
-                                EmptyL -> id
-                                (unTree -> cell_begin -> bp) :< _ -> (tree0 bp (xmlify inh t) <|)) $
-                               go inh{inh_para} ts
-               -}
+                       element n = Tree (XmlElem n <$ cr)
 instance Xmlify Root where
-       xmlify inh (Tree cel@(Cell bp ep nod) ts) =
+       xmlify inh tn@(Tree (Cell ss@(sn:|ssn) nod) ts) =
                case nod of
-                NodeGroup -> xmlify inh ts
                ----------------------
                 NodePara ->
                        case inh_para inh of
                         [] -> xmlify inh ts
-                        para:inh_para ->
-                               Seq.singleton $
-                               para (() <$ cel) $
-                               xmlify inh{inh_para} ts
+                        para:_ -> Seq.singleton $ para inh tn
                ----------------------
                 NodeHeader hdr ->
                        case hdr of
+                       --
                         HeaderSection{} ->
-                               let (attrs,body) = partitionAttrs ts in
-                               let inh' = inh
-                                        { inh_para  = xmlTitle : List.repeat xmlPara
-                                        , inh_figure = True
-                                        } in
                                Seq.singleton $
-                               element "section" $
-                                       xmlAttrs (attrs `defaultAttr` Cell ep ep ("id",getAttrId body)) <>
-                                       xmlify inh' body
-                        HeaderColon kn _wh ->
+                               element "section" $ head <> xmlify inh' body
+                               where
+                               (titles, content) = partitionSection tn
+                               (attrs, body)     = partitionAttrs content
+                               head =
+                                       case Seq.viewl titles of
+                                        EmptyL -> mempty
+                                        title@(unTree -> ct) :< subtitles ->
+                                               xmlAttrs (attrs `defaultAttr` (ct $> ("id",getAttrId title))) <>
+                                               xmlify inh{inh_para=List.repeat elementTitle} title <>
+                                               aliases
+                                               where
+                                               aliases =
+                                                       subtitles >>= \subtitle@(unTree -> cs) ->
+                                                               return $
+                                                               Tree (cs $> XmlElem "alias") $
+                                                                       xmlAttrs [cs $> ("id",getAttrId subtitle)]
+                               inh' = inh
+                                { inh_para   = List.repeat elementPara
+                                , inh_figure = True
+                                }
+                       --
+                        HeaderColon n _wh ->
                                let (attrs,body) = partitionAttrs ts in
-                               let inh' = inh { inh_para =
-                                       case kn of
-                                        "about"     -> xmlTitle : xmlTitle : List.repeat xmlPara
-                                        "reference" -> xmlTitle : xmlTitle : List.repeat xmlPara
-                                        "serie"     -> List.repeat xmlName
-                                        "author"    -> List.repeat xmlName
-                                        "editor"    -> List.repeat xmlName
-                                        "org"       -> List.repeat xmlName
-                                        _           -> []
-                                } in
-                               case () of
-                                _ | kn == "about" -> xmlAbout inh' cel {-attrs-} body
-                                _ | inh_figure inh && not (kn`List.elem`elems) ->
+                               case n of
+                               -- NOTE: insert titles into <about>.
+                                "about" ->
+                                       Seq.singleton $
+                                       element "about" $
+                                               xmlify inh' (inh_titles inh) <>
+                                               xmlAttrs attrs <>
+                                               xmlify inh'{inh_figure=False} body
+                               -- NOTE: in <figure> mode, unreserved elements become <figure>
+                                _ | inh_figure inh && n`List.notElem`elems || TL.null n ->
                                        Seq.singleton $
                                        element "figure" $
-                                               xmlAttrs (setAttr (Cell ep ep ("type",kn)) attrs) <>
+                                               -- xmlAttrs (setAttr (Cell en en ("type",n)) attrs) <>
+                                               xmlAttrs (attrs `defaultAttr` Cell (sn{span_end=span_begin sn}:|ssn) ("type", n)) <>
                                                case toList body of
-                                                [Tree0{}] -> xmlify inh'{inh_para = List.repeat xmlPara} body
-                                                _         -> xmlify inh'{inh_para = xmlTitle : List.repeat xmlPara} body
+                                                [Tree0{}] -> xmlify inh'{inh_para = List.repeat elementPara} body
+                                                _         -> xmlify inh'{inh_para = elementTitle : List.repeat elementPara} body
+                               -- NOTE: reserved elements
                                 _ ->
                                        Seq.singleton $
-                                       element (xmlLocalName kn) $
+                                       element (xmlLocalName n) $
                                                xmlAttrs attrs <>
-                                               xmlify inh' ts
-                        HeaderGreat n _wh -> Seq.singleton $ element (xmlLocalName n) $ xmlify inh ts
-                        HeaderEqual n _wh -> Seq.singleton $ element (xmlLocalName n) $ xmlify inh ts
-                        HeaderBar   n _wh -> Seq.singleton $ element (xmlLocalName n) $ xmlify inh ts
-                        HeaderDot _n   -> Seq.singleton $ element "li" $ xmlify inh ts
-                        HeaderDash     -> Seq.singleton $ element "li" $ xmlify inh ts
-                        HeaderDashDash -> Seq.singleton $ Tree0 $ cell $ XmlComment $
-                                       -- debug1_ ("TS", ts) $
-                                       -- debug1_ ("RS", (S.evalState (Plain.rackUpLeft ts) Nothing)) $
-                                       Plain.plainDocument ts
-                                       -- Plain.text def $ S.evalState (Plain.rackUpLeft ts) Nothing
-                                       {-
-                                       TreeSeq.mapAlsoNode
-                                        (cell1 . unCell)
-                                        (\_k -> fmap $
-                                               TreeSeq.mapAlsoNode
-                                                (cell1 . unCell)
-                                                (\_k' -> cell1 . unCell)) <$> ts
-                                       -}
-                        HeaderBrackets ident ->
-                               let inh' = inh{inh_figure = False} in
+                                               xmlify inh' body
+                               where
+                               inh' = inh
+                                { inh_para =
+                                       case n of
+                                        "about"     -> List.repeat elementTitle
+                                        "reference" -> elementTitle : List.repeat elementPara
+                                        "serie"     -> List.repeat attributeName
+                                        "author"    -> List.repeat attributeName
+                                        "editor"    -> List.repeat attributeName
+                                        "org"       -> List.repeat attributeName
+                                        "note"      -> List.repeat elementPara
+                                        _           -> []
+                                }
+                       --
+                        HeaderBar n wh ->
+                               if inh_figure inh && n`List.notElem`elems || TL.null n
+                               then
+                                       Seq.singleton $
+                                       element "artwork" $
+                                               xmlAttrs (Seq.singleton $ Cell (sn{span_end=span_end sn}:|ssn) ("type", n)) <>
+                                               xmlify inh{inh_para=[]} ts
+                               else
+                                       xmlify inh $
+                                               Tree (cell $ NodeHeader $ HeaderColon n wh) ts
+                       --
+                        HeaderGreat n _wh ->
+                               Seq.singleton $
                                let (attrs,body) = partitionAttrs ts in
+                               element "quote" $
+                                       xmlAttrs (attrs `defaultAttr` Cell (sn{span_end=span_end sn}:|ssn) ("type", n)) <>
+                                       xmlify inh{inh_para=List.repeat elementPara} body
+                       --
+                        HeaderEqual n _wh ->
                                Seq.singleton $
-                               element "reference" $
-                                       xmlAttrs (setAttr (Cell ep ep ("id",ident)) attrs) <>
-                                       xmlify inh'{inh_para = xmlTitle : xmlTitle : List.repeat xmlPara} body
-                        HeaderDotSlash p ->
+                               Tree0 $ cell $ XmlAttr (xmlLocalName n) $
+                                       Plain.text (Plain.setStart ts def{Plain.state_escape = False}) ts
+                       --
+                        HeaderDot n ->
                                Seq.singleton $
-                               element "include" $
-                                       xmlAttrs [cell ("href",TL.pack $ FP.replaceExtension p "dtc")] <>
+                               element "li" $
+                                       let span_end = (span_begin sn){pos_column=pos_column (span_begin sn) + int (TL.length n)} in
+                                       xmlAttrs (Seq.singleton $ Cell (sn{span_end}:|ssn) ("name", n)) <>
                                        xmlify inh ts
+                       --
+                        HeaderDash -> Seq.singleton $ element "li" $ xmlify inh ts
+                       --
+                        HeaderDashDash ->
+                               Seq.singleton $ Tree0 $ cell $
+                                       XmlComment $ Plain.writePlain ts
+                       --
+                        HeaderBrackets ident ->
+                               let (attrs,body) = partitionAttrs ts in
+                               Seq.singleton $
+                               element "reference" $
+                                       xmlAttrs (setAttr (Cell (sn{span_end=span_end sn}:|ssn) ("id",ident)) attrs) <>
+                                       xmlify inh'{inh_para = elementTitle : elementTitle : List.repeat elementPara} body
+                               where
+                               inh' = inh{inh_figure = False}
+                       --
+                        HeaderDotSlash _file -> xmlify inh ts
                ----------------------
                 NodePair pair ->
                        case pair of
-                        PairBracket | to <- Plain.plainDocument ts
+                        PairBracket | to <- Plain.writePlain ts
                                     , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
                                Seq.singleton $
                                element "rref" $
@@ -281,27 +340,24 @@ instance Xmlify Root where
                         PairFrenchquote ->
                                Seq.singleton $
                                element "q" $
-                                       xmlify inh ts
-                               {-
-                               case ts of
-                                (Seq.viewl -> Tree0 (Cell bl el (TokenPlain l)) :< ls) ->
-                                       case Seq.viewr ls of
-                                        m :> Tree0 (Cell br er (TokenPlain r)) ->
+                                       case ts of
+                                        (Seq.viewl -> Tree0 (Cell sl (NodeToken (TokenText l))) :< ls) ->
+                                               case Seq.viewr ls of
+                                                m :> Tree0 (Cell sr (NodeToken (TokenText r))) ->
+                                                       xmlify inh $
+                                                               Tree0 (Cell sl (NodeToken (TokenText (TL.dropWhile Char.isSpace l))))
+                                                                Seq.<|(m Seq.|>Tree0 (Cell sr (NodeToken (TokenText (TL.dropWhileEnd Char.isSpace r)))))
+                                                _ ->
+                                                       xmlify inh $
+                                                               Tree0 (Cell sl (NodeToken (TokenText (TL.dropAround Char.isSpace l)))) Seq.<| ls
+                                        (Seq.viewr -> rs :> Tree0 (Cell sr (NodeToken (TokenText r)))) ->
                                                xmlify inh $
-                                                       Tree0 (Cell bl el (TokenPlain (Text.dropWhile Char.isSpace l)))
-                                                        <|(m|>Tree0 (Cell br er (TokenPlain (Text.dropWhileEnd Char.isSpace r))))
-                                        _ ->
-                                               xmlify inh $
-                                                       Tree0 (Cell bl el (TokenPlain (Text.dropAround Char.isSpace l))) <| ls
-                                (Seq.viewr -> rs :> Tree0 (Cell br er (TokenPlain r))) ->
-                                       xmlify inh $
-                                               rs |> Tree0 (Cell br er (TokenPlain (Text.dropAround Char.isSpace r)))
-                                _ -> xmlify inh ts
-                                -}
+                                                       rs Seq.|> Tree0 (Cell sr (NodeToken (TokenText (TL.dropAround Char.isSpace r))))
+                                        _ -> xmlify inh ts
                         PairHash ->
                                Seq.singleton $
                                element "ref" $
-                                       xmlAttrs [cell ("to",Plain.plainDocument ts)]
+                                       xmlAttrs [cell ("to",Plain.writePlain ts)]
                         PairElem name attrs ->
                                Seq.singleton $
                                element (xmlLocalName name) $
@@ -309,10 +365,13 @@ instance Xmlify Root where
                                                cell (xmlLocalName elemAttr_name,elemAttr_value)) <$> attrs) <>
                                        xmlify inh ts
                         _ ->
-                               let (open, close) = pairBorders pair ts in
-                               Seq.singleton (Tree0 $ Cell bp bp $ XmlText open) `unionXml`
+                               Seq.singleton (Tree0 $ Cell (sn{span_end=bn'}:|ssn) $ XmlText open) `unionXml`
                                xmlify inh ts `unionXml`
-                               Seq.singleton (Tree0 $ Cell ep ep $ XmlText close)
+                               Seq.singleton (Tree0 $ Cell (sn{span_begin=en'}:|ssn) $ XmlText close)
+                               where
+                               (open, close) = pairBorders pair ts
+                               bn' = (span_begin sn){pos_column=pos_column (span_begin sn) + int (TL.length open)}
+                               en' = (span_end   sn){pos_column=pos_column (span_end   sn) - int (TL.length close)}
                ----------------------
                 NodeText t -> Seq.singleton $ Tree0 $ cell $ XmlText t
                ----------------------
@@ -329,159 +388,15 @@ instance Xmlify Root where
                                xmlify inh ts
                where
                cell :: a -> Cell a
-               cell = Cell bp ep
+               cell = Cell ss
                element :: XmlName -> XMLs -> XML
-               element n = tree (cell $ XmlElem n)
-
--- | TODO: add more mimetypes
-mimetype :: TL.Text -> Maybe TL.Text
-mimetype "txt"         = Just "text/plain"
-mimetype "plain"       = Just "text/plain"
-mimetype "hs"          = Just "text/x-haskell"
-mimetype "sh"          = Just "text/x-shellscript"
-mimetype "shell"       = Just "text/x-shellscript"
-mimetype "shellscript" = Just "text/x-shellscript"
-mimetype _             = Nothing
-
-xmlPara :: Cell a -> XMLs -> XML
-xmlPara c = tree (XmlElem "para" <$ c)
-
-xmlTitle :: Cell a -> XMLs -> XML
-xmlTitle c = tree (XmlElem "title" <$ c)
-
-xmlName :: Cell a -> XMLs -> XML
--- xmlName bp (toList -> [unTree -> unCell -> XmlText t]) = Tree0 $ Cell bp bp $ XmlAttr "name" t
-xmlName c = tree (XmlElem "name" <$ c)
+               element n = Tree (cell $ XmlElem n)
+instance Xmlify (Seq (Cell (XmlName,TL.Text))) where
+       xmlify _inh = xmlAttrs
 
-xmlAbout ::
- Inh ->
- Cell Node ->
- -- Seq (Cell (XmlName, Text)) ->
- Roots -> XMLs
-xmlAbout inh nod body =
-       xmlify inh $ Tree nod $
-       case Seq.viewl (inh_titles inh) of
-        (unTree -> cell_begin -> bt) :< _ ->
-               ((<$> inh_titles inh) $ \title ->
-                       Tree (Cell bt bt $ NodeHeader $ HeaderColon "title" "") $
-                               Seq.singleton $ title)
-                <> body
-        _ -> body
-
-xmlAttrs :: Seq (Cell (XmlName,TL.Text)) -> XMLs
-xmlAttrs = (Tree0 . (uncurry XmlAttr <$>) <$>)
-
--- | Unify two 'XMLs', merging border 'XmlText's if any.
-unionXml :: XMLs -> XMLs -> XMLs
-unionXml x y =
-       case (Seq.viewr x, Seq.viewl y) of
-        (xs :> x0, y0 :< ys) ->
-               case (x0,y0) of
-                (  Tree0 (Cell bx ex (XmlText tx))
-                 , Tree0 (Cell by ey (XmlText ty)) ) ->
-                       xs `unionXml`
-                       Seq.singleton (Tree0 $ (XmlText <$>) $ Cell bx ex tx <> Cell by ey ty) `unionXml`
-                       ys
-                _ -> x <> y
-        (Seq.EmptyR, _) -> y
-        (_, Seq.EmptyL) -> x
-
-unionsXml :: Foldable f => f XMLs -> XMLs
-unionsXml = foldl' unionXml mempty
-
-partitionAttrs :: Roots -> (Seq (Cell (XmlName, TL.Text)), Roots)
-partitionAttrs ts = (attrs,cs)
-       where
-       (as,cs) = (`Seq.partition` ts) $ \case
-                Tree (unCell -> NodeHeader (HeaderEqual (TL.null -> False) _wh)) _cs -> True
-                _ -> False
-       attrs = attr <$> as
-       attr = \case
-        Tree (Cell bp ep (NodeHeader (HeaderEqual n _wh))) a ->
-               Cell bp ep (xmlLocalName n, v)
-               where
-               v = Plain.text (Plain.setStart a def{Plain.state_escape = False}) a
-        _ -> undefined
-
-spanlHeaderBar :: Name -> Roots -> (Roots, Roots)
-spanlHeaderBar name = first unHeaderBar . debug0 "spanBar" . spanBar
- -- FIXME: use unTree
-       where
-       unHeaderBar :: Roots -> Roots
-       unHeaderBar = (=<<) $ \case
-                Tree (unCell -> NodeHeader HeaderBar{}) ts -> ts
-                ts -> return ts
-       spanBar =
-               Seq.spanl $ \case
-                Tree (unCell -> NodeHeader (HeaderBar n _)) _ | n == name -> True
-                Tree (unCell -> NodeHeader (HeaderGreat n _)) _ | n == name -> True
-                _ -> False
-
-spanlHeaderGreat :: Name -> Roots -> (Roots, Roots)
-spanlHeaderGreat name = first unHeaderGreat . debug0 "spanGreat" . spanGreat
- -- FIXME: use unTree
-       where
-       unHeaderGreat :: Roots -> Roots
-       unHeaderGreat = (=<<) $ \case
-                Tree (unCell -> NodeHeader HeaderGreat{}) ts -> ts
-                ts -> return ts
-       spanGreat =
-               Seq.spanl $ \case
-                Tree (unCell -> NodeHeader (HeaderGreat n _)) _ | n == name -> True
-                _ -> False
-
-spanlItems :: (Header -> Bool) -> Roots -> (Roots, Roots)
-spanlItems liHeader =
-       Seq.spanl $ \(unTree -> unCell -> nod) ->
-               case nod of
-                NodeHeader (HeaderColon "li" _wh) -> True
-                NodeHeader hdr -> liHeader hdr
-                NodePair (PairElem "li" _as) -> True
-                _ -> False
-
-spanlHeaderColon :: Name -> Roots -> (Roots, Roots)
-spanlHeaderColon name =
-       Seq.spanl $ \case
-        Tree (unCell -> NodeHeader (HeaderBar   n _)) _ -> n == name
-        Tree (unCell -> NodeHeader (HeaderGreat n _)) _ -> n == name
-        _ -> False
-
-spanlBrackets :: Roots -> (Roots, Roots)
-spanlBrackets =
-       Seq.spanl $ \case
-        Tree (unCell -> NodeHeader HeaderBrackets{}) _ -> True
-        _ -> False
-
-spanlNodeToken :: Roots -> (Roots, Roots)
-spanlNodeToken =
-       Seq.spanl (\case
-        Tree (unCell -> NodeToken{}) _ -> True
-        _ -> False)
-
-getAttrId :: Roots -> TL.Text
-getAttrId ts =
-       case Seq.viewl ts of
-        EmptyL -> ""
-        t :< _ -> Plain.plainDocument $ Seq.singleton t
-
-setAttr ::
- Cell (XmlName, TL.Text) ->
- Seq (Cell (XmlName, TL.Text)) ->
- Seq (Cell (XmlName, TL.Text))
-setAttr a@(unCell -> (k, _v)) as =
-       case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
-        Just idx -> Seq.update idx a as
-        Nothing -> a <| as
-
-defaultAttr ::
- Seq (Cell (XmlName, TL.Text)) ->
- Cell (XmlName, TL.Text) ->
- Seq (Cell (XmlName, TL.Text))
-defaultAttr as a@(unCell -> (k, _v)) =
-       case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
-        Just _idx -> as
-        Nothing -> a <| as
+-- * Elements
 
+-- | Reserved elements' name
 elems :: Set TL.Text
 elems =
  [ "about"
@@ -497,6 +412,7 @@ elems =
  , "authors"
  , "bcp14"
  , "br"
+ , "break"
  , "call"
  , "city"
  , "code"
@@ -574,3 +490,65 @@ elems =
  , "xml"
  , "zipcode"
  ]
+
+-- * Attributes
+
+-- | Convenient alias, forcing the types
+xmlAttrs :: Seq (Cell (XmlName,TL.Text)) -> XMLs
+xmlAttrs = (Tree0 . (uncurry XmlAttr <$>) <$>)
+
+-- | Extract attributes
+partitionAttrs :: Roots -> (Seq (Cell (XmlName, TL.Text)), Roots)
+partitionAttrs ts = (attrs,cs)
+       where
+       (as,cs) = (`Seq.partition` ts) $ \case
+        Tree (unCell -> NodeHeader (HeaderEqual n _wh)) _cs -> not $ TL.null n
+        _ -> False
+       attrs = attr <$> as
+       attr = \case
+        Tree (Cell ssn (NodeHeader (HeaderEqual n _wh))) a ->
+               Cell ssn (xmlLocalName n, v)
+               where
+               v = Plain.text (Plain.setStart a def{Plain.state_escape = False}) a
+        _ -> undefined
+
+getAttrId :: Root -> TL.Text
+getAttrId = Plain.writePlain . Seq.singleton
+
+setAttr ::
+ Cell (XmlName, TL.Text) ->
+ Seq (Cell (XmlName, TL.Text)) ->
+ Seq (Cell (XmlName, TL.Text))
+setAttr a@(unCell -> (k, _v)) as =
+       case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
+        Just idx -> Seq.update idx a as
+        Nothing -> a <| as
+
+defaultAttr ::
+ Seq (Cell (XmlName, TL.Text)) ->
+ Cell (XmlName, TL.Text) ->
+ Seq (Cell (XmlName, TL.Text))
+defaultAttr as a@(unCell -> (k, _v)) =
+       case Seq.findIndexL (\(unCell -> (n,_v)) -> n == k) as of
+        Just _idx -> as
+        Nothing -> a <| as
+
+-- * Text
+
+-- | Unify two 'XMLs', merging border 'XmlText's if any.
+unionXml :: XMLs -> XMLs -> XMLs
+unionXml x y =
+       case (Seq.viewr x, Seq.viewl y) of
+        (xs :> x0, y0 :< ys) ->
+               case (x0,y0) of
+                (  Tree0 (Cell ssx@(Span {span_file=fx}:|_sx) (XmlText tx))
+                 , Tree0 (Cell ssy@(Span {span_file=fy}:|_sy) (XmlText ty)) ) | fx == fy ->
+                       xs `unionXml`
+                       Seq.singleton (Tree0 $ (XmlText <$>) $ Cell ssx tx <> Cell ssy ty) `unionXml`
+                       ys
+                _ -> x <> y
+        (Seq.EmptyR, _) -> y
+        (_, Seq.EmptyL) -> x
+
+unionsXml :: Foldable f => f XMLs -> XMLs
+unionsXml = foldl' unionXml mempty