Fix parsing HeaderSection.
authorJulien Moutinho <julm+hdoc@autogeree.net>
Fri, 9 Feb 2018 02:28:55 +0000 (03:28 +0100)
committerJulien Moutinho <julm+hdoc@autogeree.net>
Fri, 9 Feb 2018 03:21:02 +0000 (04:21 +0100)
Language/TCT/Debug.hs
Language/TCT/Tree.hs
Language/TCT/Write/XML.hs

index b5195faede2b4c17bb916c5fe97dbbb1bab635c2..b4d81c1548458f96b57cc847cc235e551bc43e33 100644 (file)
@@ -114,6 +114,10 @@ debug1 :: (Pretty r, Pretty a) => String -> String -> (a -> r) -> (a -> r)
 debug1 _nf _na = id
 {-# INLINE debug1 #-}
 
+debug1_ :: (Pretty r, Pretty a) => String -> (String,a) -> r -> r
+debug1_ _nf _na = id
+{-# INLINE debug1_ #-}
+
 debug2 :: (Pretty r, Pretty a, Pretty b) => String -> String -> String -> (a -> b -> r) -> (a -> b -> r)
 debug2 _nf _na _nb = id
 {-# INLINE debug2 #-}
index 0aaa969d7bbcbe47bfe090c18184b1f0a8d7507b..9a16a89bf5c2332e7d4c04d2c87b955fe913ae79 100644 (file)
@@ -145,7 +145,7 @@ initRows = [Tree0 (Cell p p NodeGroup)]
 -- This is the main entry point to build 'Rows' by accumulating 'Row' into them.
 mergeRow :: Rows -> Row -> Rows
 mergeRow rows row =
-       debug2_ "mergeRow" ("news",row) ("olds",rows) $
+       debug2_ "mergeRow" ("news",List.reverse row) ("olds",rows) $
        mergeRowPrefix 0 rows $ List.reverse row
 
 -- | Merge by considering matching prefixes.
@@ -164,20 +164,21 @@ mergeRowPrefix col rows row =
          , _old@(Tree (Cell _bo eo _o) _os):_olds ) ->
                case collapseRowsWhile isCollapsable rows of
                 [] -> mergeRowIndent rows row
-                head@(unTree -> Cell bh _eh h) : olds' ->
+                head@(unTree -> ch@(Cell bh _eh h)) : olds' ->
                        case (n,h) of
                        -- NOTE: zipping: when new is HeaderGreat, collapse last line downto col
                        -- then check if there is a matching HeaderGreat,
                        -- if so, discard new and restart with a col advanced to new's beginning
-                        (NodeHeader hn@HeaderGreat{}, NodeHeader hh@HeaderGreat{})
+                        (NodeHeader HeaderGreat{}, NodeHeader HeaderGreat{})
+                         | isAdjacent && isMatching ch -> discard
+                         {-
                          | pos_column bn == pos_column bh
                          , isAdjacent
-                         , hn == hh -> discard
+                         , hn == hh
+                         -}
                        -- NOTE: same for HeaderBar
-                        (NodeHeader hn@HeaderBar{}, NodeHeader hh@HeaderBar{})
-                         | pos_column bn == pos_column bh
-                         , isAdjacent
-                         , hn == hh -> discard
+                        (NodeHeader HeaderBar{}, NodeHeader HeaderBar{})
+                         | isAdjacent && isMatching ch -> discard
                        -- NOTE: collapsing: any other new aligned or on the right of an adjacent head
                        -- makes it collapse entirely
                         (_, NodeHeader HeaderGreat{})
@@ -190,11 +191,15 @@ mergeRowPrefix col rows row =
                        isAdjacent = pos_line bn - pos_line eo <= 1
                        discard  = debug "mergeRowPrefix/discard"  $ mergeRowPrefix (pos_column bh) rows news
                        collapse = debug "mergeRowPrefix/collapse" $ mergeRowPrefix col (collapseRoot head olds') row
-       where
-       isCollapsable = -- debug2 "mergeRowPrefix/isCollapsable" "new" "old" $
-        \_new@(unTree -> Cell bn _en _n) _old@(unTree -> Cell bo eo _o) ->
-               (pos_line bn - pos_line eo <= 1) && -- adjacent
-               col < pos_column bo                 -- righter than col
+               where
+               isMatching (Cell bh _eh h) =
+                       pos_column bn == pos_column bh &&
+                       n == h
+               isCollapsable = debug2 "mergeRowPrefix/isCollapsable" "new" "old" $
+                \_t0@(unTree -> c0@(Cell b0 _e0 _n0)) _t1@(unTree -> Cell b1 e1 _n1) ->
+                       not (isMatching c0) &&
+                       (pos_line b0 - pos_line e1 <= 1) && -- adjacent
+                       col < pos_column b1                 -- righter than col
 
 -- | Merge by considering indentation.
 mergeRowIndent :: Rows -> Row -> Rows
@@ -241,23 +246,27 @@ mergeRowIndent rows row =
                          , not isVerbatim -> collapse
                          | isAdjacent -> merge $ Tree (NodeText <$> Cell bo eo to <> Cell bn en tn) (os<>ns)
                        -- NOTE: HeaderSection can parent Nodes at the same level
-                        (NodeHeader (HeaderSection lvlNew), _)
-                         | rows'@(sec:olds') <- collapseRowsWhile isCollapsable rows
-                               , (unTree -> unCell -> NodeHeader (HeaderSection lvlOld)) <- sec ->
+                        (NodeHeader (HeaderSection lvlNew), NodeHeader (HeaderSection lvlOld)) ->
                                if debug0 "mergeRowIndent/lvlNew" lvlNew
                                 > debug0 "mergeRowIndent/lvlOld" lvlOld
-                               then -- # sec
-                                    -- ## new
-                                       {-concat using sec-} List.reverse row <> rows'
-                               else -- ## sec  or  # sec
-                                    -- # new        # new
-                                       {-collapse using sec-} mergeRowIndent (collapseRoot sec olds') row
+                               -- # old
+                               -- ## new
+                               then concat
+                               -- ## old  or  # old
+                               -- # new       # new
+                               else collapse
+                       -- NOTE: old is no HeaderSection, then collapse to any older and loop
+                        (NodeHeader HeaderSection{}, _)
+                         -- | rows'@(sec:olds') <- collapseSection (pos_column bn) rows
+                         | rows'@(sec:_) <- collapseRowsWhile isCollapsable rows
+                         , (unTree -> unCell -> NodeHeader HeaderSection{}) <- sec ->
+                                mergeRowIndent rows' row
                                where
-                               isCollapsable = -- debug2 "mergeRowIndent/isCollapsable" "new" "old" $
-                                \_new _old@(unTree -> Cell bt _et t) ->
-                                       case t of
+                               isCollapsable = debug2 "mergeRowIndent/isCollapsable" "new" "old" $
+                                \_t0@(unTree -> Cell b0 _e0 n0) _t1 ->
+                                       case n0 of
                                         NodeHeader HeaderSection{} -> False
-                                        _ -> pos_column bt == pos_column bn
+                                        _ -> pos_column bn == pos_column b0
                        -- NOTE: in case of alignment, HeaderSection is parent
                         (_, NodeHeader HeaderSection{}) -> concat
                        --
@@ -306,11 +315,23 @@ mergeRowIndent rows row =
 -- before calling 'mergeRowIndent' on it to get the given 'Rows'.
 collapseRows :: Rows -> Roots
 collapseRows rows =
+       debug1_ "collapseRows" ("rows",rows) $
        case collapseRowsWhile (\_new _old -> True) rows of
         [t] -> subTrees t
         _ -> undefined
        -- NOTE: subTrees returns the children of the updated initRows
 
+-- | Collapse downto any last HeaderSection, returning it and its level.
+collapseSection :: ColNum -> Rows -> Rows
+collapseSection col = debug1 "collapseSection" "rows" go
+       where
+       go rows@(new@(unTree -> Cell bn _en n):olds)
+        | col <= pos_column bn =
+               case n of
+                NodeHeader HeaderSection{} -> rows
+                _ -> collapseSection col $ collapseRoot new $ go olds
+       go _ = mempty
+
 collapseRowsWhile :: (Root -> Root -> Bool) -> Rows -> Rows
 collapseRowsWhile test = debug1 "collapseRowsWhile" "rows" $ \case
  [] -> mempty
@@ -320,41 +341,46 @@ collapseRowsWhile test = debug1 "collapseRowsWhile" "rows" $ \case
         old@(Tree (Cell bo eo o) _os):olds
          | not $ test new old -> rows
          | otherwise ->
-               case debug0 "colNew" (pos_column bn) `compare`
-                    debug0 "colOld" (pos_column bo) of
+               case debug0 "collapseRowsWhile/colNew" (pos_column bn) `compare`
+                    debug0 "collapseRowsWhile/colOld" (pos_column bo) of
                -- NOTE: new is vertically aligned
                 EQ ->
                        case (n,o) of
                        -- NOTE: HeaderSection can parent Nodes at the same level
-                        (NodeHeader (HeaderSection lvlNew), _)
-                         | sec:olds' <- collapseRowsWhile isCollapsable news
-                         , (unTree -> unCell -> NodeHeader (HeaderSection lvlOld)) <- sec ->
+                        (NodeHeader (HeaderSection lvlNew), NodeHeader (HeaderSection lvlOld)) ->
                                if debug0 "collapseRowsWhile/lvlNew" lvlNew
                                 > debug0 "collapseRowsWhile/lvlOld" lvlOld
-                               then -- # sec
-                                    -- ## new
-                                       collapseRowsWhile test $ collapseRoot new $ sec:olds'
-                               else -- ## sec  or  # sec
-                                    -- # new        # new
-                                       collapseRowsWhile test $ new:collapseRoot sec olds'
+                               -- # old
+                               -- ## new
+                               then collapse
+                               -- ## old  or  # old
+                               -- # new       # new
+                               else
+                                       debug "collapseRowsWhile/replace" $
+                                       collapseRowsWhile test $ (new:) $ collapseRoot old olds
+                       -- NOTE: old is no HeaderSection, then collapse to any older and loop
+                        (NodeHeader HeaderSection{}, _)
+                         | news'@(sec:_) <- debug0 "collapseRowsWhile/section" $ collapseRowsWhile isCollapsable news
+                         , (unTree -> unCell -> NodeHeader HeaderSection{}) <- sec ->
+                               collapseRowsWhile test news'
                                where
-                               isCollapsable =
-                                \_new _old@(unTree -> Cell bt _et t) ->
-                                       case t of
+                               isCollapsable = debug2 "collapseRowsWhile/isCollapsable" "new" "old" $
+                                \_t0@(unTree -> Cell b0 _e0 n0) _t1 ->
+                                       case n0 of
                                         NodeHeader HeaderSection{} -> False
-                                        _ -> pos_column bt == pos_column bn
+                                        _ -> pos_column bn == pos_column b0
                        -- NOTE: in case of alignment, HeaderSection is parent
-                        (_, NodeHeader HeaderSection{}) -> collapse
+                        (_, NodeHeader HeaderSection{}) -> debug "collapseRowsWhile/section/parent" collapse
                        -- NOTE: merge within old NodePara.
-                        (_, NodePara{}) | isAdjacent -> collapse
+                        (_, NodePara) | isAdjacent -> collapse
                        --
                         _ -> collapse2
                -- NOTE: new is either on the left or on the right
                 _ -> collapse
                where
                isAdjacent = pos_line bn - pos_line eo <= 1
-               collapse   = debug "collapseRowsWhile/collapse"  $ collapseRowsWhile test $ collapseRoot new news
-               collapse2  = debug "collapseRowsWhile/collapse2" $ collapseRowsWhile test $ collapseRoot new $ collapseRoot old olds
+               collapse   = debug "collapseRowsWhile/collapse"  $ collapseRowsWhile test $ collapseRoot new news
+               collapse2  = debug "collapseRowsWhile/collapse2" $ collapseRowsWhile test $ collapseRoot new $ collapseRoot old olds
 
 -- | Put a 'Root' as a child of the head 'Root'.
 --
@@ -367,7 +393,7 @@ collapseRoot new@(Tree (Cell bn en n) _ns) rows =
         [] -> return new
         old@(Tree (Cell bo eo o) os) : olds ->
                case (n,o) of
-               -- NOTE: never put a child into NodeText
+               -- NOTE: no child into NodeText
                 (_, NodeText{}) -> collapse2
                -- NOTE: NodeText can begin a NodePara
                 (NodeText tn, _) | not $ TL.null tn ->
@@ -383,10 +409,14 @@ collapseRoot new@(Tree (Cell bn en n) _ns) rows =
                         _ -> collapse
                -- NOTE: amongst remaining nodes, only adjacent ones may enter an old NodePara.
                --       Note that since a NodePara is never adjacent to another,
-               --       it is not nested within into another.
-               --       Note that an adjacent HeaderSection can enter a NodePara.
-                (_, NodePara) | isAdjacent -> collapse
-                              | otherwise  -> collapse2
+               --       it is not nested within another.
+                (_, NodePara)
+                 | isAdjacent ->
+                       case n of
+                       -- NOTE: no HeaderSection (even adjacent) within a NodePara
+                        NodeHeader HeaderSection{} -> collapse2
+                        _ -> collapse
+                 | otherwise -> collapse2
                 _ -> collapse
                where
                isAdjacent = pos_line bn - pos_line eo <= 1
index c3f02cd0020c58d1f3610f540757ecea47440825..5d0ece5fe12033e9b4aa115929eb65129a36902e 100644 (file)
@@ -12,15 +12,16 @@ import Data.Default.Class (Default(..))
 import Data.Eq (Eq(..))
 import Data.Foldable (Foldable(..))
 import Data.Function (($), (.))
-import Data.Functor ((<$>), (<$))
+import Data.Functor ((<$>), (<$), ($>))
 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.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
@@ -30,7 +31,7 @@ import qualified System.FilePath as FP
 
 import Text.Blaze.XML ()
 import Language.TCT hiding (Parser)
--- import Language.TCT.Debug
+import Language.TCT.Debug
 import Language.XML
 
 -- | Main entry point
@@ -45,11 +46,12 @@ xmlDocument :: Roots -> XMLs
 xmlDocument doc =
        -- (`S.evalState` def) $
        case Seq.viewl doc of
-        Tree (unCell -> NodeHeader HeaderSection{}) body :< foot ->
-               case Seq.viewl body of
-                title@(unTree -> Cell bt et NodePara{}) :< content ->
+        sec@(Tree (unCell -> NodeHeader HeaderSection{}) _body) :< foot ->
+               let (titles, content) = partitionSection sec in
+               case Seq.viewl titles of
+                (unTree -> Cell bt et _) :< _ ->
                        xmlify def
-                        { inh_titles = return title
+                        { inh_titles = titles
                         , inh_figure = True
                         } contentWithAbout <>
                        xmlify def foot
@@ -64,6 +66,23 @@ xmlDocument doc =
                 _ -> xmlify def doc
         _ -> xmlify def doc
 
+partitionSection :: Root -> (Roots, Roots)
+partitionSection (Tree (unCell -> NodeHeader (HeaderSection lvlPar)) body) =
+       case Seq.viewl body of
+        EmptyL -> mempty
+        title@(unTree -> Cell _bt 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 bs es (NodeHeader (HeaderSection lvlSub))) :< rs
+                               | lvlSub <= lvlPar
+                               , pos_line bs - pos_line ep <= 1 ->
+                               let (subs, ts') = spanlSubtitles es rs in
+                               (sub <| subs, ts')
+                        _ -> (mempty, ts)
+
 {-
 -- * Type 'Xmls'
 type Xmls = S.State State XMLs
@@ -208,7 +227,7 @@ instance Xmlify Roots where
                                go inh{inh_para} ts
                -}
 instance Xmlify Root where
-       xmlify inh (Tree cel@(Cell bp ep nod) ts) =
+       xmlify inh tr@(Tree cel@(Cell bp ep nod) ts) =
                case nod of
                 NodeGroup -> xmlify inh ts
                ----------------------
@@ -224,12 +243,23 @@ instance Xmlify Root where
                        case hdr of
                        --
                         HeaderSection{} ->
-                               let (attrs,body) = partitionAttrs ts in
                                Seq.singleton $
-                               element "section" $
-                                       xmlAttrs (attrs `defaultAttr` Cell ep ep ("id",getAttrId body)) <>
-                                       xmlify inh' body
+                               element "section" $ head <> xmlify inh' body
                                where
+                               (titles, content) = partitionSection tr
+                               (attrs, body)     = partitionAttrs content
+                               head =
+                                       case Seq.viewl titles of
+                                        EmptyL -> mempty
+                                        title@(unTree -> ct) :< subtitles ->
+                                               xmlAttrs (attrs `defaultAttr` (ct $> ("id",getAttrId title))) <>
+                                               aliases
+                                               where
+                                               aliases =
+                                                       subtitles >>= \subtitle@(unTree -> cs) ->
+                                                               return $
+                                                               Tree (cs $> XmlElem "alias") $
+                                                                       xmlAttrs (return $ cs $> ("id",getAttrId subtitle))
                                inh' = inh
                                 { inh_para   = xmlTitle : List.repeat xmlPara
                                 , inh_figure = True
@@ -249,7 +279,8 @@ instance Xmlify Root where
                                 _ | inh_figure inh && not (n`List.elem`elems) ->
                                        Seq.singleton $
                                        element "figure" $
-                                               xmlAttrs (setAttr (Cell ep ep ("type",n)) attrs) <>
+                                               -- xmlAttrs (setAttr (Cell ep ep ("type",n)) attrs) <>
+                                               xmlAttrs (attrs `defaultAttr` Cell bp bp ("type", n)) <>
                                                case toList body of
                                                 [Tree0{}] -> xmlify inh'{inh_para = List.repeat xmlPara} body
                                                 _         -> xmlify inh'{inh_para = xmlTitle : List.repeat xmlPara} body
@@ -504,11 +535,8 @@ partitionAttrs ts = (attrs,cs)
                v = Plain.text (Plain.setStart a def{Plain.state_escape = False}) a
         _ -> undefined
 
-getAttrId :: Roots -> TL.Text
-getAttrId ts =
-       case Seq.viewl ts of
-        EmptyL -> ""
-        t :< _ -> Plain.plainDocument $ Seq.singleton t
+getAttrId :: Root -> TL.Text
+getAttrId = Plain.plainDocument . Seq.singleton
 
 setAttr ::
  Cell (XmlName, TL.Text) ->