From 383deb217e3ec7d226ae6afdf587c6533a2a43fa Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph.amissah@gmail.com>
Date: Thu, 23 Apr 2020 16:12:53 -0400
Subject: backmatter, special sections, multiple fixes

- fix special sections eat other special sections,
  e.g. glossary eats bibliography & other headings
- glossary stop object numbering on empty lines
- glossary remove indent markup instruction
- bibliography provide missing heading
---
 org/default_regex.org                  |  10 +--
 org/metaverse.org                      | 159 +++++++++++++++------------------
 src/doc_reform/meta/metadoc_from_src.d | 153 +++++++++++++++----------------
 src/doc_reform/meta/rgx.d              |  10 +--
 4 files changed, 154 insertions(+), 178 deletions(-)

diff --git a/org/default_regex.org b/org/default_regex.org
index 9ad5539..e432a32 100644
--- a/org/default_regex.org
+++ b/org/default_regex.org
@@ -117,6 +117,7 @@ static yaml_config                                    = ctRegex!(`^[a-z]+\s*:\s*
 /+ heading & paragraph operators +/
 static heading_a                                      = ctRegex!(`^:?[A][~] `, "m");
 static heading                                        = ctRegex!(`^:?([A-D1-4])[~]([a-z0-9_.-]*[?]?)\s+`,"i");
+static headings                                       = ctRegex!(`^:?(?P<level>[A-D1-4])[~](?:[a-z0-9_.-]*[?]?|[!](?:glossary|bibliogrphy|biblio|references?|blurb))(?:\s|$)`,"i");
 static heading_seg_and_above                          = ctRegex!(`^:?([A-D1])[~]([a-z0-9_.-]*[?]?)\s+`,"i");
 static heading_marker                                 = ctRegex!(`^:?([A-D1-4])[~]`);
 static heading_anchor_tag                             = ctRegex!(`^:?[A-D1-4][~](?P<anchor>[a-z0-9_.-]+) `,"i");
@@ -126,12 +127,9 @@ static heading_extract_unnamed_anchor_tag             = ctRegex!(`^:?[A-D1-4][~]
 static heading_marker_missing_tag                     = ctRegex!(`^:?([A-D1-4])[~] `);
 static heading_anchor_tag_plus_colon                  = ctRegex!(`^:?([A-D1-4][~])([a-z0-9_.:-]+) `,"i");
 static heading_marker_tag_has_colon                   = ctRegex!(`([:])`);
-static heading_biblio                                 = ctRegex!(`^:?(1)[~][!](biblio(?:graphy)?|references?)`);
-static heading_glossary                               = ctRegex!(`^:?(1)[~][!](glossary)`);
-static heading_blurb                                  = ctRegex!(`^:?(1)[~][!](blurb)`);
-static heading_biblio_glossary                        = ctRegex!(`^:?(?:(1)[~][!](?:(?:biblio(?:graphy)?|references?)|glossary)|[A-D1][~])`);
-static heading_biblio_blurb                           = ctRegex!(`^:?(?:(1)[~][!](?:(?:biblio(?:graphy)?|references?)|blurb)|[A-D1][~])`);
-static heading_blurb_glossary                         = ctRegex!(`^:?(?:(1)[~][!](?:blurb|glossary)|[A-D1][~])`);
+static heading_biblio                                 = ctRegex!(`^1[~][!](biblio(?:graphy)?|references?)`);
+static heading_glossary                               = ctRegex!(`^1[~][!](glossary)`);
+static heading_blurb                                  = ctRegex!(`^1[~][!](blurb)`);
 static para_bullet                                    = ctRegex!(`^_[*] `);
 static para_bullet_indent                             = ctRegex!(`^_(?P<indent>[1-9])[*] `);
 static para_indent                                    = ctRegex!(`^_(?P<indent>[1-9])[ ]`);
diff --git a/org/metaverse.org b/org/metaverse.org
index 63b3450..290ba97 100644
--- a/org/metaverse.org
+++ b/org/metaverse.org
@@ -738,17 +738,13 @@ line = line.inline_markup_faces; // by text line (rather than by text object), l
 
 #+NAME: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
-if ((line.matchFirst(rgx.heading_biblio)
-  && obj_type_status["para"]  != State.on
-  && obj_type_status["group"] != State.on
-  && obj_type_status["block"] != State.on
-  && obj_type_status["poem"]  != State.on
-  && obj_type_status["table"] != State.on
-  && obj_type_status["quote"] != State.on)
+if (line.matchFirst(rgx.heading_biblio)
 || (obj_type_status["biblio_section"] == State.on
-&& (!(line.matchFirst(rgx.heading_blurb_glossary)))
-&& (!(line.matchFirst(rgx.heading)))
-&& (!(line.matchFirst(rgx.comment))))) {
+  && ((!(line.matchFirst(rgx.heading_glossary)))
+  && (!(line.matchFirst(rgx.heading_blurb)))
+  && (!(line.matchFirst(rgx.heading)))
+  && (!(line.matchFirst(rgx.comment)))))
+) {
   /+ within section (block object): biblio +/
   obj_type_status["glossary_section"] = State.off;
   obj_type_status["biblio_section"]   = State.on;
@@ -774,17 +770,13 @@ if there is a glossary section you need to:
 
 #+NAME: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
-} else if ((line.matchFirst(rgx.heading_glossary)
-  && obj_type_status["para"]  != State.on
-  && obj_type_status["group"] != State.on
-  && obj_type_status["block"] != State.on
-  && obj_type_status["poem"]  != State.on
-  && obj_type_status["table"] != State.on
-  && obj_type_status["quote"] != State.on)
+} else if (line.matchFirst(rgx.heading_glossary)
 || (obj_type_status["glossary_section"] == State.on
-&& (!(line.matchFirst(rgx.heading_biblio_blurb)))
-&& (!(line.matchFirst(rgx.heading)))
-&& (!(line.matchFirst(rgx.comment))))) {
+  && ((!(line.matchFirst(rgx.heading_biblio)))
+  && (!(line.matchFirst(rgx.heading_blurb)))
+  && (!(line.matchFirst(rgx.heading)))
+  && (!(line.matchFirst(rgx.comment)))))
+) {
   /+ within section (block object): glossary +/
   debug(glossary) {
     writeln(__LINE__);
@@ -862,7 +854,7 @@ if there is a glossary section you need to:
       comp_obj_para.metainfo.is_of_section        = "glossary";
       comp_obj_para.metainfo.is_of_type           = "para";
       comp_obj_para.metainfo.is_a                 = "glossary";
-      comp_obj_para.text                          = line.to!string.strip;
+      comp_obj_para.text                          = links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, "");
       comp_obj_para.metainfo.ocn                  = 0;
       comp_obj_para.metainfo.identifier           = "";
       comp_obj_para.metainfo.object_number_off    = true;
@@ -888,17 +880,13 @@ if there is a blurb section you need to:
 
 #+NAME: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
-} else if ((line.matchFirst(rgx.heading_blurb)
-  && obj_type_status["para"]  != State.on
-  && obj_type_status["group"] != State.on
-  && obj_type_status["block"] != State.on
-  && obj_type_status["poem"]  != State.on
-  && obj_type_status["table"] != State.on
-  && obj_type_status["quote"] != State.on)
+} else if (line.matchFirst(rgx.heading_blurb)
 || (obj_type_status["blurb_section"] == State.on
-&& (!(line.matchFirst(rgx.heading_biblio_glossary)))
-&& (!(line.matchFirst(rgx.heading)))
-&& (!(line.matchFirst(rgx.comment))))) {
+  && ((!(line.matchFirst(rgx.heading_glossary)))
+  && (!(line.matchFirst(rgx.heading_biblio)))
+  && (!(line.matchFirst(rgx.heading)))
+  && (!(line.matchFirst(rgx.comment)))))
+) {
   /+ within section (block object): blurb +/
   debug(blurb) {
     writeln(__LINE__);
@@ -998,7 +986,7 @@ if there is a blurb section you need to:
         tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
         tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
       }
-    } else if (line.matchFirst(rgx.heading)
+    } else if (line.matchFirst(rgx.headings)
     && (opt_action.backmatter && opt_action.section_blurb)) {
       comp_obj_heading_                                              = comp_obj_heading_.init;
       comp_obj_heading_.metainfo.is_of_part                          = "backmatter";
@@ -1224,9 +1212,17 @@ if (line.matchFirst(rgx.book_index)
        - should be incorporated in composite objects
        - should happen before endnote links set (they need to be moved down?)
     +/
-    if (line.matchFirst(rgx.heading)) {                                        /+ heading match +/
+    if (line.matchFirst(rgx.headings)) {                                        /+ heading match +/
       line = line._doc_header_and_make_substitutions_(conf_make_meta);
-      an_object = line.flow_heading_matched_(an_object, line_occur, an_object_key, lv, collapsed_lev, obj_type_status, conf_make_meta);
+      an_object = line.flow_heading_matched_(
+        an_object,
+        line_occur,
+        an_object_key,
+        lv,
+        collapsed_lev,
+        obj_type_status,
+        conf_make_meta
+      );
     } else if (line_occur["para"] == State.off) {                              /+ para match +/
       an_object_key="body_nugget";
       line = line
@@ -1636,7 +1632,7 @@ if (biblio_ordered.length > 0) {
     comp_obj_heading_.text                            = "Bibliography";
     comp_obj_heading_.metainfo.ocn                    = 0;
     comp_obj_heading_.metainfo.identifier             = "";
-    comp_obj_heading_.metainfo.dummy_heading          = true;
+    comp_obj_heading_.metainfo.dummy_heading          = false;
     comp_obj_heading_.metainfo.object_number_off      = true;
     comp_obj_heading_.metainfo.object_number_type     = 0;
     comp_obj_heading_.tags.segment_anchor_tag_epub    = "_part_bibliography";
@@ -1647,6 +1643,8 @@ if (biblio_ordered.length > 0) {
     comp_obj_heading_.metainfo.heading_lev_collapsed  = 1;
     comp_obj_heading_.metainfo.parent_ocn             = 1;
     comp_obj_heading_.metainfo.parent_lev_markup      = 0;
+    comp_obj_heading_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 0, 0, 0, 0];
+    comp_obj_heading_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0];
     the_bibliography_section                          ~= comp_obj_heading_;
     tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
     tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
@@ -1670,11 +1668,46 @@ if (biblio_ordered.length > 0) {
     comp_obj_heading_.metainfo.heading_lev_collapsed  = 2;
     comp_obj_heading_.metainfo.parent_ocn             = 1;
     comp_obj_heading_.metainfo.parent_lev_markup      = 0;
+    comp_obj_heading_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 1, 0, 0, 0];
+    comp_obj_heading_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 1, 0, 0, 0, 0, 0];
     comp_obj_heading_.tags.anchor_tags                = ["bibliography"];
     the_bibliography_section                          ~= comp_obj_heading_;
     tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
     tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
   }
+  {
+    string out_;
+    foreach (entry; biblio_ordered) {
+      out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.",
+        ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str),
+        entry["fulltitle"].str,
+        ((entry["journal"].str.empty) ? "" : ", " ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic),
+        ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str),
+        ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str),
+        ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""),
+        ", " ~ entry["year"].str,
+        ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str),
+        ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str),
+        ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str),
+        ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
+      );
+      comp_obj_para                               = comp_obj_para.init;
+      comp_obj_para.metainfo.is_of_part           = "backmatter";
+      comp_obj_para.metainfo.is_of_section        = "bibliography";
+      comp_obj_para.metainfo.is_of_type           = "para";
+      comp_obj_para.metainfo.is_a                 = "bibliography";
+      comp_obj_para.text                          = out_.to!string.strip;
+      comp_obj_para.metainfo.ocn                  = 0;
+      comp_obj_para.metainfo.identifier           = "";
+      comp_obj_para.metainfo.object_number_off    = true;
+      comp_obj_para.metainfo.object_number_type   = 0;
+      comp_obj_para.attrib.indent_hang            = 0;
+      comp_obj_para.attrib.indent_base            = 1;
+      comp_obj_para.attrib.bullet                 = bullet;
+      comp_obj_para.tags.anchor_tags              = [anchor_tag];
+      the_bibliography_section                    ~= comp_obj_para;
+    }
+  }
 } else {
   comp_obj_heading_                                 = comp_obj_heading_.init;
   comp_obj_heading_.metainfo.is_of_part             = "empty";
@@ -1695,43 +1728,6 @@ if (biblio_ordered.length > 0) {
 }
 #+END_SRC
 
-***** format biblio string
-
-#+NAME: abs_post
-#+BEGIN_SRC d
-string out_;
-foreach (entry; biblio_ordered) {
-  out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.",
-    ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str),
-    entry["fulltitle"].str,
-    ((entry["journal"].str.empty) ? "" : ", " ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic),
-    ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str),
-    ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str),
-    ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""),
-    ", " ~ entry["year"].str,
-    ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str),
-    ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str),
-    ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str),
-    ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
-  );
-  comp_obj_para                               = comp_obj_para.init;
-  comp_obj_para.metainfo.is_of_part           = "backmatter";
-  comp_obj_para.metainfo.is_of_section        = "bibliography";
-  comp_obj_para.metainfo.is_of_type           = "para";
-  comp_obj_para.metainfo.is_a                 = "bibliography";
-  comp_obj_para.text                          = out_.to!string.strip;
-  comp_obj_para.metainfo.ocn                  = 0;
-  comp_obj_para.metainfo.identifier           = "";
-  comp_obj_para.metainfo.object_number_off    = true;
-  comp_obj_para.metainfo.object_number_type   = 0;
-  comp_obj_para.attrib.indent_hang            = 0;
-  comp_obj_para.attrib.indent_base            = 1;
-  comp_obj_para.attrib.bullet                 = bullet;
-  comp_obj_para.tags.anchor_tags              = [anchor_tag];
-  the_bibliography_section                    ~= comp_obj_para;
-}
-#+END_SRC
-
 #+NAME: abs_post
 #+BEGIN_SRC d
 debug(bibliosection) {
@@ -2643,7 +2639,7 @@ if (the_glossary_section.length > 1) {
         obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
       }
       obj = obj.obj_heading_ancestors(lv_ancestors_txt);
-    } else if (obj.metainfo.is_a == "glossary") {
+    } else if (obj.metainfo.is_a == "glossary" && !(obj.text.empty)) {
       obj_cite_digits         = ocn_emit(OCNstatus.on);
       obj.metainfo.ocn        = obj_cite_digits.object_number;
       obj.metainfo.identifier = obj_cite_digits.identifier;
@@ -3657,14 +3653,7 @@ final string biblio_tag_map_()(string abr) {
   mixin spineBiblio;
   auto jsn = BibJsnStr();
   static auto rgx = RgxI();
-  if (line.matchFirst(rgx.heading_biblio)
-    && obj_type_status["para"]  != State.on
-    && obj_type_status["group"] != State.on
-    && obj_type_status["block"] != State.on
-    && obj_type_status["poem"]  != State.on
-    && obj_type_status["table"] != State.on
-    && obj_type_status["quote"] != State.on
-  ) {
+  if (line.matchFirst(rgx.heading_biblio)) {
     obj_type_status["glossary_section"] = State.off;
     obj_type_status["biblio_section"]   = TriState.on;
     obj_type_status["blurb_section"]    = State.off;
@@ -4884,7 +4873,7 @@ process and use an_object["table_head"] (then empty it)
   return ref CMM             conf_make_meta,
 ) {
   static auto rgx = RgxI();
-  if (auto m = line.match(rgx.heading)) {                                      /+ heading match +/
+  if (auto m = line.match(rgx.headings)) {                                      /+ heading match +/
     ++line_occur["heading"];
     obj_type_status["heading"]            = State.on;
     obj_type_status["para"]               = State.off;
@@ -5596,7 +5585,7 @@ process and use an_object["table_head"] (then empty it)
     bool reset_note_numbers=false
   ) {
     obj_txt["munge"] = obj_txt_in
-     .replaceFirst(rgx.heading, "")
+     .replaceFirst(rgx.headings, "")
      .replaceFirst(rgx.object_number_off_all, "")
      .strip;
     TxtPlusHasFootnotesUrlsImages t = object_notes_and_links_(obj_txt["munge"], reset_note_numbers);
@@ -5880,9 +5869,7 @@ static struct ObjInlineMarkup {
     char[] heading_toc_,
   ) {
    auto m = (cast(char[]) heading_toc_).matchFirst(rgx.heading);
-   heading_toc_ = (m.post).replaceAll(
-     rgx.inline_notes_curly_gen,
-     "");
+   heading_toc_ = (m.post).replaceAll(rgx.inline_notes_curly_gen, "");
    return heading_toc_;
   };
   @safe ObjGenericComposite[] flow_table_of_contents_gather_headings(CMM)(
diff --git a/src/doc_reform/meta/metadoc_from_src.d b/src/doc_reform/meta/metadoc_from_src.d
index 532d097..a714941 100644
--- a/src/doc_reform/meta/metadoc_from_src.d
+++ b/src/doc_reform/meta/metadoc_from_src.d
@@ -527,17 +527,13 @@ template docAbstraction() {
                                                                                 /+ (includes regular text paragraph, headings & blocks other than code) +/
                                                                                 /+ heading, glossary, blurb, poem, group, block, quote, table +/
         line = line.inline_markup_faces; // by text line (rather than by text object), linebreaks in para problematic
-        if ((line.matchFirst(rgx.heading_biblio)
-          && obj_type_status["para"]  != State.on
-          && obj_type_status["group"] != State.on
-          && obj_type_status["block"] != State.on
-          && obj_type_status["poem"]  != State.on
-          && obj_type_status["table"] != State.on
-          && obj_type_status["quote"] != State.on)
+        if (line.matchFirst(rgx.heading_biblio)
         || (obj_type_status["biblio_section"] == State.on
-        && (!(line.matchFirst(rgx.heading_blurb_glossary)))
-        && (!(line.matchFirst(rgx.heading)))
-        && (!(line.matchFirst(rgx.comment))))) {
+          && ((!(line.matchFirst(rgx.heading_glossary)))
+          && (!(line.matchFirst(rgx.heading_blurb)))
+          && (!(line.matchFirst(rgx.heading)))
+          && (!(line.matchFirst(rgx.comment)))))
+        ) {
           /+ within section (block object): biblio +/
           obj_type_status["glossary_section"] = State.off;
           obj_type_status["biblio_section"]   = State.on;
@@ -550,17 +546,13 @@ template docAbstraction() {
             }
           }
           continue;
-        } else if ((line.matchFirst(rgx.heading_glossary)
-          && obj_type_status["para"]  != State.on
-          && obj_type_status["group"] != State.on
-          && obj_type_status["block"] != State.on
-          && obj_type_status["poem"]  != State.on
-          && obj_type_status["table"] != State.on
-          && obj_type_status["quote"] != State.on)
+        } else if (line.matchFirst(rgx.heading_glossary)
         || (obj_type_status["glossary_section"] == State.on
-        && (!(line.matchFirst(rgx.heading_biblio_blurb)))
-        && (!(line.matchFirst(rgx.heading)))
-        && (!(line.matchFirst(rgx.comment))))) {
+          && ((!(line.matchFirst(rgx.heading_biblio)))
+          && (!(line.matchFirst(rgx.heading_blurb)))
+          && (!(line.matchFirst(rgx.heading)))
+          && (!(line.matchFirst(rgx.comment)))))
+        ) {
           /+ within section (block object): glossary +/
           debug(glossary) {
             writeln(__LINE__);
@@ -638,7 +630,7 @@ template docAbstraction() {
               comp_obj_para.metainfo.is_of_section        = "glossary";
               comp_obj_para.metainfo.is_of_type           = "para";
               comp_obj_para.metainfo.is_a                 = "glossary";
-              comp_obj_para.text                          = line.to!string.strip;
+              comp_obj_para.text                          = links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, "");
               comp_obj_para.metainfo.ocn                  = 0;
               comp_obj_para.metainfo.identifier           = "";
               comp_obj_para.metainfo.object_number_off    = true;
@@ -651,17 +643,13 @@ template docAbstraction() {
             obj_type_status["ocn_status"] = OCNstatus.on;
           }
           continue;
-        } else if ((line.matchFirst(rgx.heading_blurb)
-          && obj_type_status["para"]  != State.on
-          && obj_type_status["group"] != State.on
-          && obj_type_status["block"] != State.on
-          && obj_type_status["poem"]  != State.on
-          && obj_type_status["table"] != State.on
-          && obj_type_status["quote"] != State.on)
+        } else if (line.matchFirst(rgx.heading_blurb)
         || (obj_type_status["blurb_section"] == State.on
-        && (!(line.matchFirst(rgx.heading_biblio_glossary)))
-        && (!(line.matchFirst(rgx.heading)))
-        && (!(line.matchFirst(rgx.comment))))) {
+          && ((!(line.matchFirst(rgx.heading_glossary)))
+          && (!(line.matchFirst(rgx.heading_biblio)))
+          && (!(line.matchFirst(rgx.heading)))
+          && (!(line.matchFirst(rgx.comment)))))
+        ) {
           /+ within section (block object): blurb +/
           debug(blurb) {
             writeln(__LINE__);
@@ -761,7 +749,7 @@ template docAbstraction() {
                 tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
                 tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
               }
-            } else if (line.matchFirst(rgx.heading)
+            } else if (line.matchFirst(rgx.headings)
             && (opt_action.backmatter && opt_action.section_blurb)) {
               comp_obj_heading_                                              = comp_obj_heading_.init;
               comp_obj_heading_.metainfo.is_of_part                          = "backmatter";
@@ -916,9 +904,17 @@ template docAbstraction() {
                    - should be incorporated in composite objects
                    - should happen before endnote links set (they need to be moved down?)
                 +/
-                if (line.matchFirst(rgx.heading)) {                                        /+ heading match +/
+                if (line.matchFirst(rgx.headings)) {                                        /+ heading match +/
                   line = line._doc_header_and_make_substitutions_(conf_make_meta);
-                  an_object = line.flow_heading_matched_(an_object, line_occur, an_object_key, lv, collapsed_lev, obj_type_status, conf_make_meta);
+                  an_object = line.flow_heading_matched_(
+                    an_object,
+                    line_occur,
+                    an_object_key,
+                    lv,
+                    collapsed_lev,
+                    obj_type_status,
+                    conf_make_meta
+                  );
                 } else if (line_occur["para"] == State.off) {                              /+ para match +/
                   an_object_key="body_nugget";
                   line = line
@@ -1257,7 +1253,7 @@ template docAbstraction() {
         comp_obj_heading_.text                            = "Bibliography";
         comp_obj_heading_.metainfo.ocn                    = 0;
         comp_obj_heading_.metainfo.identifier             = "";
-        comp_obj_heading_.metainfo.dummy_heading          = true;
+        comp_obj_heading_.metainfo.dummy_heading          = false;
         comp_obj_heading_.metainfo.object_number_off      = true;
         comp_obj_heading_.metainfo.object_number_type     = 0;
         comp_obj_heading_.tags.segment_anchor_tag_epub    = "_part_bibliography";
@@ -1268,6 +1264,8 @@ template docAbstraction() {
         comp_obj_heading_.metainfo.heading_lev_collapsed  = 1;
         comp_obj_heading_.metainfo.parent_ocn             = 1;
         comp_obj_heading_.metainfo.parent_lev_markup      = 0;
+        comp_obj_heading_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 0, 0, 0, 0];
+        comp_obj_heading_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0];
         the_bibliography_section                          ~= comp_obj_heading_;
         tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
         tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
@@ -1291,11 +1289,46 @@ template docAbstraction() {
         comp_obj_heading_.metainfo.heading_lev_collapsed  = 2;
         comp_obj_heading_.metainfo.parent_ocn             = 1;
         comp_obj_heading_.metainfo.parent_lev_markup      = 0;
+        comp_obj_heading_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 1, 0, 0, 0];
+        comp_obj_heading_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 1, 0, 0, 0, 0, 0];
         comp_obj_heading_.tags.anchor_tags                = ["bibliography"];
         the_bibliography_section                          ~= comp_obj_heading_;
         tag_assoc[comp_obj_heading_.tags.anchor_tag_html]["seg_lv4"]              = comp_obj_heading_.tags.in_segment_html;
         tag_assoc[comp_obj_heading_.tags.segment_anchor_tag_epub]["seg_lv1_to_4"] = comp_obj_heading_.tags.segment_anchor_tag_epub;
       }
+      {
+        string out_;
+        foreach (entry; biblio_ordered) {
+          out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.",
+            ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str),
+            entry["fulltitle"].str,
+            ((entry["journal"].str.empty) ? "" : ", " ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic),
+            ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str),
+            ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str),
+            ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""),
+            ", " ~ entry["year"].str,
+            ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str),
+            ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str),
+            ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str),
+            ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
+          );
+          comp_obj_para                               = comp_obj_para.init;
+          comp_obj_para.metainfo.is_of_part           = "backmatter";
+          comp_obj_para.metainfo.is_of_section        = "bibliography";
+          comp_obj_para.metainfo.is_of_type           = "para";
+          comp_obj_para.metainfo.is_a                 = "bibliography";
+          comp_obj_para.text                          = out_.to!string.strip;
+          comp_obj_para.metainfo.ocn                  = 0;
+          comp_obj_para.metainfo.identifier           = "";
+          comp_obj_para.metainfo.object_number_off    = true;
+          comp_obj_para.metainfo.object_number_type   = 0;
+          comp_obj_para.attrib.indent_hang            = 0;
+          comp_obj_para.attrib.indent_base            = 1;
+          comp_obj_para.attrib.bullet                 = bullet;
+          comp_obj_para.tags.anchor_tags              = [anchor_tag];
+          the_bibliography_section                    ~= comp_obj_para;
+        }
+      }
     } else {
       comp_obj_heading_                                 = comp_obj_heading_.init;
       comp_obj_heading_.metainfo.is_of_part             = "empty";
@@ -1314,37 +1347,6 @@ template docAbstraction() {
       comp_obj_heading_.metainfo.parent_lev_markup      = 0;
       the_bibliography_section                          ~= comp_obj_heading_;
     }
-    string out_;
-    foreach (entry; biblio_ordered) {
-      out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.",
-        ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str),
-        entry["fulltitle"].str,
-        ((entry["journal"].str.empty) ? "" : ", " ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic),
-        ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str),
-        ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str),
-        ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""),
-        ", " ~ entry["year"].str,
-        ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str),
-        ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str),
-        ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str),
-        ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
-      );
-      comp_obj_para                               = comp_obj_para.init;
-      comp_obj_para.metainfo.is_of_part           = "backmatter";
-      comp_obj_para.metainfo.is_of_section        = "bibliography";
-      comp_obj_para.metainfo.is_of_type           = "para";
-      comp_obj_para.metainfo.is_a                 = "bibliography";
-      comp_obj_para.text                          = out_.to!string.strip;
-      comp_obj_para.metainfo.ocn                  = 0;
-      comp_obj_para.metainfo.identifier           = "";
-      comp_obj_para.metainfo.object_number_off    = true;
-      comp_obj_para.metainfo.object_number_type   = 0;
-      comp_obj_para.attrib.indent_hang            = 0;
-      comp_obj_para.attrib.indent_base            = 1;
-      comp_obj_para.attrib.bullet                 = bullet;
-      comp_obj_para.tags.anchor_tags              = [anchor_tag];
-      the_bibliography_section                    ~= comp_obj_para;
-    }
     debug(bibliosection) {
       foreach (o; the_bibliography_section) {
         writeln(o.text);
@@ -2026,7 +2028,7 @@ template docAbstraction() {
             obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
           }
           obj = obj.obj_heading_ancestors(lv_ancestors_txt);
-        } else if (obj.metainfo.is_a == "glossary") {
+        } else if (obj.metainfo.is_a == "glossary" && !(obj.text.empty)) {
           obj_cite_digits         = ocn_emit(OCNstatus.on);
           obj.metainfo.ocn        = obj_cite_digits.object_number;
           obj.metainfo.identifier = obj_cite_digits.identifier;
@@ -3208,14 +3210,7 @@ template docAbstraction() {
     mixin spineBiblio;
     auto jsn = BibJsnStr();
     static auto rgx = RgxI();
-    if (line.matchFirst(rgx.heading_biblio)
-      && obj_type_status["para"]  != State.on
-      && obj_type_status["group"] != State.on
-      && obj_type_status["block"] != State.on
-      && obj_type_status["poem"]  != State.on
-      && obj_type_status["table"] != State.on
-      && obj_type_status["quote"] != State.on
-    ) {
+    if (line.matchFirst(rgx.heading_biblio)) {
       obj_type_status["glossary_section"] = State.off;
       obj_type_status["biblio_section"]   = TriState.on;
       obj_type_status["blurb_section"]    = State.off;
@@ -3876,7 +3871,7 @@ template docAbstraction() {
     return ref CMM             conf_make_meta,
   ) {
     static auto rgx = RgxI();
-    if (auto m = line.match(rgx.heading)) {                                      /+ heading match +/
+    if (auto m = line.match(rgx.headings)) {                                      /+ heading match +/
       ++line_occur["heading"];
       obj_type_status["heading"]            = State.on;
       obj_type_status["para"]               = State.off;
@@ -4506,7 +4501,7 @@ template docAbstraction() {
       bool reset_note_numbers=false
     ) {
       obj_txt["munge"] = obj_txt_in
-       .replaceFirst(rgx.heading, "")
+       .replaceFirst(rgx.headings, "")
        .replaceFirst(rgx.object_number_off_all, "")
        .strip;
       TxtPlusHasFootnotesUrlsImages t = object_notes_and_links_(obj_txt["munge"], reset_note_numbers);
@@ -4679,9 +4674,7 @@ template docAbstraction() {
       char[] heading_toc_,
     ) {
      auto m = (cast(char[]) heading_toc_).matchFirst(rgx.heading);
-     heading_toc_ = (m.post).replaceAll(
-       rgx.inline_notes_curly_gen,
-       "");
+     heading_toc_ = (m.post).replaceAll(rgx.inline_notes_curly_gen, "");
      return heading_toc_;
     };
     @safe ObjGenericComposite[] flow_table_of_contents_gather_headings(CMM)(
diff --git a/src/doc_reform/meta/rgx.d b/src/doc_reform/meta/rgx.d
index b777f2e..5a0fbdc 100644
--- a/src/doc_reform/meta/rgx.d
+++ b/src/doc_reform/meta/rgx.d
@@ -49,6 +49,7 @@ static template spineRgxIn() {
     /+ heading & paragraph operators +/
     static heading_a                                      = ctRegex!(`^:?[A][~] `, "m");
     static heading                                        = ctRegex!(`^:?([A-D1-4])[~]([a-z0-9_.-]*[?]?)\s+`,"i");
+    static headings                                       = ctRegex!(`^:?(?P<level>[A-D1-4])[~](?:[a-z0-9_.-]*[?]?|[!](?:glossary|bibliogrphy|biblio|references?|blurb))(?:\s|$)`,"i");
     static heading_seg_and_above                          = ctRegex!(`^:?([A-D1])[~]([a-z0-9_.-]*[?]?)\s+`,"i");
     static heading_marker                                 = ctRegex!(`^:?([A-D1-4])[~]`);
     static heading_anchor_tag                             = ctRegex!(`^:?[A-D1-4][~](?P<anchor>[a-z0-9_.-]+) `,"i");
@@ -58,12 +59,9 @@ static template spineRgxIn() {
     static heading_marker_missing_tag                     = ctRegex!(`^:?([A-D1-4])[~] `);
     static heading_anchor_tag_plus_colon                  = ctRegex!(`^:?([A-D1-4][~])([a-z0-9_.:-]+) `,"i");
     static heading_marker_tag_has_colon                   = ctRegex!(`([:])`);
-    static heading_biblio                                 = ctRegex!(`^:?(1)[~][!](biblio(?:graphy)?|references?)`);
-    static heading_glossary                               = ctRegex!(`^:?(1)[~][!](glossary)`);
-    static heading_blurb                                  = ctRegex!(`^:?(1)[~][!](blurb)`);
-    static heading_biblio_glossary                        = ctRegex!(`^:?(?:(1)[~][!](?:(?:biblio(?:graphy)?|references?)|glossary)|[A-D1][~])`);
-    static heading_biblio_blurb                           = ctRegex!(`^:?(?:(1)[~][!](?:(?:biblio(?:graphy)?|references?)|blurb)|[A-D1][~])`);
-    static heading_blurb_glossary                         = ctRegex!(`^:?(?:(1)[~][!](?:blurb|glossary)|[A-D1][~])`);
+    static heading_biblio                                 = ctRegex!(`^1[~][!](biblio(?:graphy)?|references?)`);
+    static heading_glossary                               = ctRegex!(`^1[~][!](glossary)`);
+    static heading_blurb                                  = ctRegex!(`^1[~][!](blurb)`);
     static para_bullet                                    = ctRegex!(`^_[*] `);
     static para_bullet_indent                             = ctRegex!(`^_(?P<indent>[1-9])[*] `);
     static para_indent                                    = ctRegex!(`^_(?P<indent>[1-9])[ ]`);
-- 
cgit v1.2.3