From 33d4cd24013c8660c100a0070802a0e9d1211421 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Tue, 28 Apr 2020 22:47:10 -0400 Subject: metaverse, doc structure & blocks, change tracking --- org/default_misc.org | 32 ++++++++++++++ org/default_regex.org | 6 +-- org/metaverse.org | 78 +++++++++++++++++----------------- src/doc_reform/meta/defaults.d | 32 ++++++++++++++ src/doc_reform/meta/metadoc_from_src.d | 78 +++++++++++++++++----------------- src/doc_reform/meta/rgx.d | 6 +-- 6 files changed, 148 insertions(+), 84 deletions(-) diff --git a/org/default_misc.org b/org/default_misc.org index ab7033f..2ba2b8d 100644 --- a/org/default_misc.org +++ b/org/default_misc.org @@ -37,6 +37,38 @@ module doc_reform.meta.defaults; #+NAME: meta_defaults_template_init_flags #+BEGIN_SRC d +template spineDocStatus() { + @safe static auto status() { + struct _e { + enum sect { + unset, + head, + toc, + substantive, + bibliography, + glossary, + book_index, + blurb, + } + enum block { + off, + closing, + code, + poem, + block, + group, + table, + quote, + } + enum ocn { + on, // 0 object_number; + off, // 1 no object_number; + dummy, // 2 no object_number & dummy headings + } + } + return _e(); + } +} template spineRgxDocStructFlags() { /+ regex flags +/ @safe static int[string] flags_type_init() { diff --git a/org/default_regex.org b/org/default_regex.org index e432a32..6e6ee00 100644 --- a/org/default_regex.org +++ b/org/default_regex.org @@ -253,9 +253,9 @@ static smid_image_delimit = ctRegex!(`(?P
^|[ ]
 #+NAME: meta_rgx
 #+BEGIN_SRC d
 /+ inline markup book index +/
-static book_index                                     = ctRegex!(`^=\{\s*(?P.+?)\}$`, "m");
-static book_index_open                                = ctRegex!(`^=\{\s*([^}]*?)$`);
-static book_index_close                               = ctRegex!(`^(.*?)\}$`, "m");
+static book_index_item                                = ctRegex!(`^=\{\s*(?P.+?)\}$`, "m");
+static book_index_item_open                           = ctRegex!(`^=\{\s*([^}]*?)$`);
+static book_index_item_close                          = ctRegex!(`^(.*?)\}$`, "m");
 #+END_SRC
 
 ** switch
diff --git a/org/metaverse.org b/org/metaverse.org
index b51f4da..88c5e59 100644
--- a/org/metaverse.org
+++ b/org/metaverse.org
@@ -536,6 +536,7 @@ scope(exit) {
 #+NAME: abs_init_rest
 #+BEGIN_SRC d
 mixin spineRgxDocStructFlags;
+mixin spineDocStatus;
 mixin spineNode;
 auto node_para_int_    = node_metadata_para_int;
 auto node_para_str_    = node_metadata_para_str;
@@ -559,6 +560,12 @@ uint[string] dochas = [
   "images"            : 0,
 ];
 auto obj_type_status = flags_type_init;
+int[string] track = [
+  "section" : 0,
+  "block"   : 0,
+  "obj"     : 0,
+  "ocn"     : 0,
+];
 string[string] object_number_poem = [
   "start" : "",
   "end"   : ""
@@ -739,18 +746,15 @@ 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["biblio_section"] == State.on
+|| (track["section"] == status.sect.bibliography
   && ((!(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;
-  obj_type_status["blurb_section"]    = State.off;
+  track["section"] = status.sect.bibliography;
   if (opt_action.backmatter && opt_action.section_biblio) {
-    line.flow_txt_block_biblio(obj_type_status, bib_entry, biblio_entry_str_json, biblio_arr_json);
+    line.flow_txt_block_biblio(obj_type_status, bib_entry, biblio_entry_str_json, biblio_arr_json, track);
     debug(bibliobuild) {
       writeln("-  ", biblio_entry_str_json);
       writeln("-> ", biblio_arr_json.length);
@@ -771,7 +775,7 @@ 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["glossary_section"] == State.on
+|| (track["section"] == status.sect.glossary
   && ((!(line.matchFirst(rgx.heading_biblio)))
   && (!(line.matchFirst(rgx.heading_blurb)))
   && (!(line.matchFirst(rgx.heading)))
@@ -782,9 +786,7 @@ if there is a glossary section you need to:
     writeln(__LINE__);
     writeln(line);
   }
-  obj_type_status["glossary_section"] = State.on;
-  obj_type_status["biblio_section"]   = State.off;
-  obj_type_status["blurb_section"]    = State.off;
+  track["section"] = status.sect.glossary;
   if (opt_action.backmatter && opt_action.section_glossary) {
     indent=[
       "hang_position" : 0,
@@ -881,20 +883,17 @@ 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["blurb_section"] == State.on
+|| (track["section"] == status.sect.blurb
   && ((!(line.matchFirst(rgx.heading_glossary)))
   && (!(line.matchFirst(rgx.heading_biblio)))
   && (!(line.matchFirst(rgx.heading)))
   && (!(line.matchFirst(rgx.comment)))))
 ) {
-  /+ within section (block object): blurb +/
+  track["section"] = status.sect.blurb;
   debug(blurb) {
     writeln(__LINE__);
     writeln(line);
   }
-  obj_type_status["glossary_section"] = State.off;
-  obj_type_status["biblio_section"]   = State.off;
-  obj_type_status["blurb_section"]    = State.on;
   if (opt_action.backmatter && opt_action.section_blurb) {
     indent=[
       "hang_position" : 0,
@@ -1139,9 +1138,9 @@ if (obj_type_status["blocks"] == TriState.closing) {
     writeln(line);
   }
   assert(
-    line.matchFirst(rgx.book_index)
-    || line.matchFirst(rgx.book_index_open)
-    || obj_type_status["book_index"] == State.on,
+    line.matchFirst(rgx.book_index_item)
+    || line.matchFirst(rgx.book_index_item_open)
+    || track["section"] == status.sect.book_index,
     "\nblocks closed, unless followed by book index, non-matching line:\n  \""
     ~ line ~ "\""
   );
@@ -1152,10 +1151,10 @@ if (obj_type_status["blocks"] == TriState.closing) {
 
 #+NAME: abs_in_loop_body_not_block_obj
 #+BEGIN_SRC d
-if (line.matchFirst(rgx.book_index)
-|| line.matchFirst(rgx.book_index_open)
-|| obj_type_status["book_index"] == State.on )  {                              /+ book_index +/
-  an_object = line.flow_book_index_(an_object, book_idx_tmp, obj_type_status, opt_action);
+if (line.matchFirst(rgx.book_index_item)
+|| line.matchFirst(rgx.book_index_item_open)
+|| track["section"] == status.sect.book_index)  {                              /+ book_index +/
+  an_object = line.flow_book_index_(an_object, book_idx_tmp, obj_type_status, track, opt_action);
 #+END_SRC
 
 ******* not book index [+1]
@@ -1221,7 +1220,8 @@ if (line.matchFirst(rgx.book_index)
         lv,
         collapsed_lev,
         obj_type_status,
-        conf_make_meta
+        conf_make_meta,
+        track,
       );
     } else if (line_occur["para"] == State.off) {                              /+ para match +/
       an_object_key="body_nugget";
@@ -1512,9 +1512,7 @@ if (the_document_body_section.length > 0) {
   && (the_document_body_section.length > previous_length)) {
     if ((the_document_body_section[$-1].metainfo.is_a == "heading")
     && (the_document_body_section[$-1].metainfo.heading_lev_markup < 5)) {
-      obj_type_status["glossary_section"] = State.off;
-      obj_type_status["biblio_section"]   = State.off;
-      obj_type_status["blurb_section"]    = State.off;
+      track["section"] = status.sect.unset;
     }
     if (the_document_body_section[$-1].metainfo.is_a == "verse") {             /+ scan for endnotes for whole poem (each verse in poem) +/
       foreach (i; previous_length .. the_document_body_section.length) {
@@ -3658,15 +3656,15 @@ final string biblio_tag_map_()(string abr) {
   return ref int[string] obj_type_status,
   return ref int         bib_entry,
   return ref string      biblio_entry_str_json,
-  return ref string[]    biblio_arr_json
+  return ref string[]    biblio_arr_json,
+  return ref int[string] track,
 ) {
   mixin spineBiblio;
+  mixin spineDocStatus;
   auto jsn = BibJsnStr();
   static auto rgx = RgxI();
   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;
+    track["section"] = status.sect.bibliography;
   }
   if (line.empty) {
     debug {
@@ -4671,10 +4669,12 @@ process and use an_object["table_head"] (then empty it)
              string[string]  an_object,
   return ref string          book_idx_tmp,
   return ref int[string]     obj_type_status,
+  return ref int[string]     track,
              B               opt_action,
 ) {
+  mixin spineDocStatus;
   static auto rgx = RgxI();
-  if (auto m = line.match(rgx.book_index)) {                                   /+ match book_index +/
+  if (auto m = line.match(rgx.book_index_item)) {                                   /+ match book_index +/
     debug(bookindexmatch) {
       writefln(
         "* [bookindex] %s\n",
@@ -4682,8 +4682,8 @@ process and use an_object["table_head"] (then empty it)
       );
     }
     an_object["bookindex_nugget"] = m.captures[1].to!string;
-  } else if (auto m = line.match(rgx.book_index_open))  {                      /+ match open book_index +/
-    obj_type_status["book_index"] = State.on;
+  } else if (auto m = line.match(rgx.book_index_item_open))  {                      /+ match open book_index +/
+    track["section"] = status.sect.book_index;
     if (opt_action.backmatter && opt_action.section_bookindex) {
       book_idx_tmp = m.captures[1].to!string;
       debug(bookindexmatch) {
@@ -4693,9 +4693,9 @@ process and use an_object["table_head"] (then empty it)
         );
       }
     }
-  } else if (obj_type_status["book_index"] == State.on )  {                    /+ book_index flag set +/
-    if (auto m = line.match(rgx.book_index_close))  {
-      obj_type_status["book_index"] = State.off;
+  } else if (track["section"] == status.sect.book_index)  {                    /+ book_index flag set +/
+    if (auto m = line.match(rgx.book_index_item_close))  {
+      track["section"] = status.sect.unset;
       if (opt_action.backmatter
       && opt_action.section_bookindex) {
         an_object["bookindex_nugget"] = book_idx_tmp ~ m.captures[1].to!string;
@@ -4881,16 +4881,16 @@ process and use an_object["table_head"] (then empty it)
   return ref int[string]     collapsed_lev,
   return ref int[string]     obj_type_status,
   return ref CMM             conf_make_meta,
+  return ref int[string]     track,
 ) {
+  mixin spineDocStatus;
   static auto rgx = RgxI();
   if (auto m = line.match(rgx.headings)) {                                      /+ heading match +/
     ++line_occur["heading"];
     obj_type_status["heading"]            = State.on;
     obj_type_status["para"]               = State.off;
     if (line.match(rgx.heading_seg_and_above)) {
-      obj_type_status["glossary_section"] = State.off;
-      obj_type_status["biblio_section"]   = State.off;
-      obj_type_status["blurb_section"]    = State.off;
+      track["section"]                    = status.sect.unset;
     }
     an_object[an_object_key] ~= line ~= "\n";
     an_object["lev"] ~= m.captures[1];
diff --git a/src/doc_reform/meta/defaults.d b/src/doc_reform/meta/defaults.d
index e592be7..8b6edad 100644
--- a/src/doc_reform/meta/defaults.d
+++ b/src/doc_reform/meta/defaults.d
@@ -2,6 +2,38 @@
   default settings
 +/
 module doc_reform.meta.defaults;
+template spineDocStatus() {
+  @safe static auto status() {
+    struct _e {
+      enum sect {
+        unset,
+        head,
+        toc,
+        substantive,
+        bibliography,
+        glossary,
+        book_index,
+        blurb,
+      }
+      enum block {
+        off,
+        closing,
+        code,
+        poem,
+        block,
+        group,
+        table,
+        quote,
+      }
+      enum ocn {
+        on,    // 0 object_number;
+        off,   // 1 no object_number;
+        dummy, // 2 no object_number & dummy headings
+      }
+    }
+    return _e();
+  }
+}
 template spineRgxDocStructFlags() {
   /+ regex flags +/
   @safe static int[string] flags_type_init() {
diff --git a/src/doc_reform/meta/metadoc_from_src.d b/src/doc_reform/meta/metadoc_from_src.d
index f5ff735..6aa1eb6 100644
--- a/src/doc_reform/meta/metadoc_from_src.d
+++ b/src/doc_reform/meta/metadoc_from_src.d
@@ -356,6 +356,7 @@ template docAbstraction() {
       reset_note_numbers=true;
     }
     mixin spineRgxDocStructFlags;
+    mixin spineDocStatus;
     mixin spineNode;
     auto node_para_int_    = node_metadata_para_int;
     auto node_para_str_    = node_metadata_para_str;
@@ -379,6 +380,12 @@ template docAbstraction() {
       "images"            : 0,
     ];
     auto obj_type_status = flags_type_init;
+    int[string] track = [
+      "section" : 0,
+      "block"   : 0,
+      "obj"     : 0,
+      "ocn"     : 0,
+    ];
     string[string] object_number_poem = [
       "start" : "",
       "end"   : ""
@@ -528,18 +535,15 @@ template docAbstraction() {
                                                                                 /+ 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["biblio_section"] == State.on
+        || (track["section"] == status.sect.bibliography
           && ((!(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;
-          obj_type_status["blurb_section"]    = State.off;
+          track["section"] = status.sect.bibliography;
           if (opt_action.backmatter && opt_action.section_biblio) {
-            line.flow_txt_block_biblio(obj_type_status, bib_entry, biblio_entry_str_json, biblio_arr_json);
+            line.flow_txt_block_biblio(obj_type_status, bib_entry, biblio_entry_str_json, biblio_arr_json, track);
             debug(bibliobuild) {
               writeln("-  ", biblio_entry_str_json);
               writeln("-> ", biblio_arr_json.length);
@@ -547,7 +551,7 @@ template docAbstraction() {
           }
           continue;
         } else if (line.matchFirst(rgx.heading_glossary)
-        || (obj_type_status["glossary_section"] == State.on
+        || (track["section"] == status.sect.glossary
           && ((!(line.matchFirst(rgx.heading_biblio)))
           && (!(line.matchFirst(rgx.heading_blurb)))
           && (!(line.matchFirst(rgx.heading)))
@@ -558,9 +562,7 @@ template docAbstraction() {
             writeln(__LINE__);
             writeln(line);
           }
-          obj_type_status["glossary_section"] = State.on;
-          obj_type_status["biblio_section"]   = State.off;
-          obj_type_status["blurb_section"]    = State.off;
+          track["section"] = status.sect.glossary;
           if (opt_action.backmatter && opt_action.section_glossary) {
             indent=[
               "hang_position" : 0,
@@ -644,20 +646,17 @@ template docAbstraction() {
           }
           continue;
         } else if (line.matchFirst(rgx.heading_blurb)
-        || (obj_type_status["blurb_section"] == State.on
+        || (track["section"] == status.sect.blurb
           && ((!(line.matchFirst(rgx.heading_glossary)))
           && (!(line.matchFirst(rgx.heading_biblio)))
           && (!(line.matchFirst(rgx.heading)))
           && (!(line.matchFirst(rgx.comment)))))
         ) {
-          /+ within section (block object): blurb +/
+          track["section"] = status.sect.blurb;
           debug(blurb) {
             writeln(__LINE__);
             writeln(line);
           }
-          obj_type_status["glossary_section"] = State.off;
-          obj_type_status["biblio_section"]   = State.off;
-          obj_type_status["blurb_section"]    = State.on;
           if (opt_action.backmatter && opt_action.section_blurb) {
             indent=[
               "hang_position" : 0,
@@ -855,17 +854,17 @@ template docAbstraction() {
                 writeln(line);
               }
               assert(
-                line.matchFirst(rgx.book_index)
-                || line.matchFirst(rgx.book_index_open)
-                || obj_type_status["book_index"] == State.on,
+                line.matchFirst(rgx.book_index_item)
+                || line.matchFirst(rgx.book_index_item_open)
+                || track["section"] == status.sect.book_index,
                 "\nblocks closed, unless followed by book index, non-matching line:\n  \""
                 ~ line ~ "\""
               );
             }
-            if (line.matchFirst(rgx.book_index)
-            || line.matchFirst(rgx.book_index_open)
-            || obj_type_status["book_index"] == State.on )  {                              /+ book_index +/
-              an_object = line.flow_book_index_(an_object, book_idx_tmp, obj_type_status, opt_action);
+            if (line.matchFirst(rgx.book_index_item)
+            || line.matchFirst(rgx.book_index_item_open)
+            || track["section"] == status.sect.book_index)  {                              /+ book_index +/
+              an_object = line.flow_book_index_(an_object, book_idx_tmp, obj_type_status, track, opt_action);
             } else {                                                                       /+ not book_index +/
               an_object_key="body_nugget";
               if (auto m = line.matchFirst(rgx.comment)) {                                 /+ matched comment +/
@@ -913,7 +912,8 @@ template docAbstraction() {
                     lv,
                     collapsed_lev,
                     obj_type_status,
-                    conf_make_meta
+                    conf_make_meta,
+                    track,
                   );
                 } else if (line_occur["para"] == State.off) {                              /+ para match +/
                   an_object_key="body_nugget";
@@ -1166,9 +1166,7 @@ template docAbstraction() {
         && (the_document_body_section.length > previous_length)) {
           if ((the_document_body_section[$-1].metainfo.is_a == "heading")
           && (the_document_body_section[$-1].metainfo.heading_lev_markup < 5)) {
-            obj_type_status["glossary_section"] = State.off;
-            obj_type_status["biblio_section"]   = State.off;
-            obj_type_status["blurb_section"]    = State.off;
+            track["section"] = status.sect.unset;
           }
           if (the_document_body_section[$-1].metainfo.is_a == "verse") {             /+ scan for endnotes for whole poem (each verse in poem) +/
             foreach (i; previous_length .. the_document_body_section.length) {
@@ -3215,15 +3213,15 @@ template docAbstraction() {
     return ref int[string] obj_type_status,
     return ref int         bib_entry,
     return ref string      biblio_entry_str_json,
-    return ref string[]    biblio_arr_json
+    return ref string[]    biblio_arr_json,
+    return ref int[string] track,
   ) {
     mixin spineBiblio;
+    mixin spineDocStatus;
     auto jsn = BibJsnStr();
     static auto rgx = RgxI();
     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;
+      track["section"] = status.sect.bibliography;
     }
     if (line.empty) {
       debug {
@@ -3688,10 +3686,12 @@ template docAbstraction() {
                string[string]  an_object,
     return ref string          book_idx_tmp,
     return ref int[string]     obj_type_status,
+    return ref int[string]     track,
                B               opt_action,
   ) {
+    mixin spineDocStatus;
     static auto rgx = RgxI();
-    if (auto m = line.match(rgx.book_index)) {                                   /+ match book_index +/
+    if (auto m = line.match(rgx.book_index_item)) {                                   /+ match book_index +/
       debug(bookindexmatch) {
         writefln(
           "* [bookindex] %s\n",
@@ -3699,8 +3699,8 @@ template docAbstraction() {
         );
       }
       an_object["bookindex_nugget"] = m.captures[1].to!string;
-    } else if (auto m = line.match(rgx.book_index_open))  {                      /+ match open book_index +/
-      obj_type_status["book_index"] = State.on;
+    } else if (auto m = line.match(rgx.book_index_item_open))  {                      /+ match open book_index +/
+      track["section"] = status.sect.book_index;
       if (opt_action.backmatter && opt_action.section_bookindex) {
         book_idx_tmp = m.captures[1].to!string;
         debug(bookindexmatch) {
@@ -3710,9 +3710,9 @@ template docAbstraction() {
           );
         }
       }
-    } else if (obj_type_status["book_index"] == State.on )  {                    /+ book_index flag set +/
-      if (auto m = line.match(rgx.book_index_close))  {
-        obj_type_status["book_index"] = State.off;
+    } else if (track["section"] == status.sect.book_index)  {                    /+ book_index flag set +/
+      if (auto m = line.match(rgx.book_index_item_close))  {
+        track["section"] = status.sect.unset;
         if (opt_action.backmatter
         && opt_action.section_bookindex) {
           an_object["bookindex_nugget"] = book_idx_tmp ~ m.captures[1].to!string;
@@ -3879,16 +3879,16 @@ template docAbstraction() {
     return ref int[string]     collapsed_lev,
     return ref int[string]     obj_type_status,
     return ref CMM             conf_make_meta,
+    return ref int[string]     track,
   ) {
+    mixin spineDocStatus;
     static auto rgx = RgxI();
     if (auto m = line.match(rgx.headings)) {                                      /+ heading match +/
       ++line_occur["heading"];
       obj_type_status["heading"]            = State.on;
       obj_type_status["para"]               = State.off;
       if (line.match(rgx.heading_seg_and_above)) {
-        obj_type_status["glossary_section"] = State.off;
-        obj_type_status["biblio_section"]   = State.off;
-        obj_type_status["blurb_section"]    = State.off;
+        track["section"]                    = status.sect.unset;
       }
       an_object[an_object_key] ~= line ~= "\n";
       an_object["lev"] ~= m.captures[1];
diff --git a/src/doc_reform/meta/rgx.d b/src/doc_reform/meta/rgx.d
index 5a0fbdc..07ec2d4 100644
--- a/src/doc_reform/meta/rgx.d
+++ b/src/doc_reform/meta/rgx.d
@@ -128,9 +128,9 @@ static template spineRgxIn() {
     static smid_a_image                                    = ctRegex!(`(?P
(?:^|[ ]|[^\S]?)[{](?:~\^\s+|\s*))(?P[a-zA-Z0-9._-]+?\.(?:png|gif|jpg))(?P(?:.*?)\s*[}](?:image|(?:(?:https?|git):\/\/|¤?\.\.\/|¤?\.\/|¤|#)\S+?)(?=[;:!,?.]?([ )\]]|$)))`, "mg");
     static smid_image_delimit                              = ctRegex!(`(?P
^|[ ]|[^\S]?)\{\s*(?P.+?)\s*\}(?:image)(?=[;:!,?.]?([ )\]]|$))`, "mg");
     /+ inline markup book index +/
-    static book_index                                     = ctRegex!(`^=\{\s*(?P.+?)\}$`, "m");
-    static book_index_open                                = ctRegex!(`^=\{\s*([^}]*?)$`);
-    static book_index_close                               = ctRegex!(`^(.*?)\}$`, "m");
+    static book_index_item                                = ctRegex!(`^=\{\s*(?P.+?)\}$`, "m");
+    static book_index_item_open                           = ctRegex!(`^=\{\s*([^}]*?)$`);
+    static book_index_item_close                          = ctRegex!(`^(.*?)\}$`, "m");
     static auto_heading_numbering_lv1                    = ctRegex!(`^1~`, "m");
     static auto_heading_numbering_lv2                    = ctRegex!(`^2~`, "m");
     static auto_heading_numbering_lv3                    = ctRegex!(`^3~`, "m");
-- 
cgit v1.2.3