diff options
Diffstat (limited to 'org/ao_doc_abstraction.org')
| -rw-r--r-- | org/ao_doc_abstraction.org | 5998 | 
1 files changed, 5998 insertions, 0 deletions
diff --git a/org/ao_doc_abstraction.org b/org/ao_doc_abstraction.org new file mode 100644 index 0000000..6911b63 --- /dev/null +++ b/org/ao_doc_abstraction.org @@ -0,0 +1,5998 @@ +#+TITLE: sdp document abstraction +#+AUTHOR: Ralph Amissah +#+EMAIL: ralph.amissah@gmail.com +#+STARTUP: indent +#+LANGUAGE: en +#+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t +#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc +#+OPTIONS: author:nil email:nil creator:nil timestamp:nil +#+PROPERTY: header-args :padline no :exports code :noweb yes +#+EXPORT_SELECT_TAGS: export +#+EXPORT_EXCLUDE_TAGS: noexport +#+FILETAGS: :sdp:rel:ao: +#+TAGS: assert(a) class(c) debug(d) mixin(m) sdp(s) tangle(T) template(t) WEB(W) noexport(n) + +[[./sdp.org][sdp]]  [[./][org/]] +* 1. Document Abstraction                                  :abstract:process: +Process markup document, create document abstraction. + +** 0. ao abstract doc source:                       :ao_abstract_doc_source: + +#+BEGIN_SRC d :tangle ../src/sdp/ao_abstract_doc_source.d +/++ +  document abstraction: +  abstraction of sisu markup for downstream processing +  ao_abstract_doc_source.d ++/ +template SiSUdocAbstraction() { +  /+ ↓ abstraction imports +/ +  <<abs_imports>> +  /+ ↓ abstraction mixins +/ +  <<abs_mixins>> +  /+ ↓ abstraction struct init +/ +  <<abs_init_struct>> +  /+ ↓ abstract marked up document +/ +  auto SiSUdocAbstraction(Src,Make,Meta,Opt)( +    Src                  markup_sourcefile_content, +    Make                 dochead_make_aa, +    Meta                 dochead_meta_aa, +    Opt                  opt_action_bool, +  ) { +    auto rgx = Rgx(); +    debug(asserts){ +      static assert(is(typeof(markup_sourcefile_content) == char[][])); +      static assert(is(typeof(dochead_make_aa)           == string[string][string])); +      static assert(is(typeof(dochead_meta_aa)           == string[string][string])); +      static assert(is(typeof(opt_action_bool)           == bool[string])); +    } +    /+ ↓ abstraction init +/ +    <<abs_init_rest>> +    /+ abstraction init ↑ +/ +    /+ ↓ loop markup document/text line by line +/ +    srcDocLoop: +    foreach (line; markup_sourcefile_content) { +      /+ ↓ markup document/text line by line +/ +      <<abs_in_loop_body_00>> +      if (type["code"] == TriState.on) { +        <<abs_in_loop_body_00_code_block>> +      } else if (!matchFirst(line, rgx.skip_from_regular_parse)) { +        /+ object other than "code block" object +           (includes regular text paragraph, headings & blocks other than code) +/ +        <<abs_in_loop_body_non_code_obj>> +        } else { +          /+ not within a block group +/ +          <<abs_in_loop_body_open_block_obj_assert>> +          if (matchFirst(line, rgx.block_open)) { +            <<abs_in_loop_body_open_block_obj>> +          } else if (!line.empty) { +            /+ line not empty +/ +            /+ non blocks (headings, paragraphs) & closed blocks +/ +            <<abs_in_loop_body_not_block_obj>> +          } else if (type["blocks"] == TriState.closing) { +            /+ line empty, with blocks flag +/ +            <<abs_in_loop_body_not_block_obj_line_empty_blocks_flags>> +          } else { +            /+ line.empty, post contents, empty variables: +/ +            <<abs_in_loop_body_not_block_obj_line_empty>> +          } // close else for line empty +        } // close else for not the above +      } // close after non code, other blocks or regular text +      <<abs_in_loop_body_01>> +    } /+ ← closed: loop markup document/text line by line +/ +    /+ ↓ post loop markup document/text +/ +    <<abs_post>> +    /+ post loop markup document/text ↑ +/ +  } /+ ← closed: abstract doc source +/ +  /+ ↓ abstraction functions +/ +  <<abs_functions_object_reset>> +  <<abs_functions_header_set_common>> +  <<abs_functions_ocn_status>> +  <<abs_functions_block>> +  <<abs_functions_block_code>> +  <<abs_functions_block_biblio>> +  // <<abs_functions_block_glossary>> +  <<abs_functions_block_poem>> +  <<abs_functions_block_group>> +  <<abs_functions_block_block>> +  <<abs_functions_block_quote>> +  <<abs_functions_block_table>> +  <<abs_functions_block_line_status_empty>> +  <<abs_functions_book_index>> +  <<abs_functions_heading>> +  <<abs_functions_para>> +  /+ abstraction functions ↑ +/ +  /+ ↓ abstraction function emitters +/ +  <<ao_emitters_ocn>> +  /+ +/ +  <<ao_emitters_obj_inline_markup_munge>> +  <<ao_emitters_obj_inline_markup>> +  <<ao_emitters_obj_inline_markup_and_anchor_tags>> +  <<ao_emitters_obj_inline_markup_table_of_contents>> +  <<ao_emitters_obj_inline_markup_private>> +  <<ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags>> +  <<ao_emitters_obj_inline_markup_close>> +  /+ +/ +  <<ao_emitters_obj_attributes>> +  <<ao_emitters_obj_attributes_public>> +  <<ao_emitters_obj_attributes_private>> +  <<ao_emitters_obj_attributes_private_an_attribute>> +  <<ao_emitters_obj_attributes_private_json>> +  <<ao_emitters_obj_attributes_private_close>> +  /+ +/ +  <<ao_emitters_book_index_nugget>> +  <<ao_emitters_book_index_report_indented>> +  <<ao_emitters_book_index_report_section>> +  /+ +/ +  <<ao_emitters_endnotes>> +  /+ +/ +  <<ao_emitters_bibliography>> +  /+ +/ +  <<ao_emitters_metadata>> +  /+ abstraction functions emitters ↑ +/ +  /+ ↓ abstraction functions assertions +/ +  <<abs_functions_assertions>> +  /+ abstraction functions assertions ↑ +/ +} /+ ← closed: template SiSUdocAbstraction +/ +#+END_SRC + +** 1. _pre loop processing_                                            :pre: +*** imports                                                       :imports: + +[[./ao_defaults.org][ao_defaults]] + +#+name: abs_imports +#+BEGIN_SRC d +import +  ao_object_setter, +  ao_defaults, +  ao_rgx, +  output_hub; +private import +  std.algorithm, +  std.array, +  std.container, +  std.exception, +  std.file, +  std.getopt, +  std.json, +  std.path, +  std.process, +  std.range, +  std.regex, +  std.stdio, +  std.string, +  std.traits, +  std.typecons, +  std.uni, +  std.utf, +  std.conv : to; +#+END_SRC + +*** mixins                                                         :mixins: + +#+name: abs_mixins +#+BEGIN_SRC d +mixin ObjectSetter; +mixin InternalMarkup; +mixin SiSUrgxInit; +#+END_SRC + +*** initialize                                                 :initialize: +**** initialize general + +#+name: abs_init_struct +#+BEGIN_SRC d +/+ initialize +/ +ObjGenericComposite[][string] the_table_of_contents_section; +ObjGenericComposite[] the_document_head_section, the_document_body_section, the_bibliography_section, the_glossary_section, the_blurb_section; +ObjGenericComposite[] the_dom_tail_section; +string[string] an_object, processing; +string an_object_key; +string[] anchor_tags; +string anchor_tag_; +string segment_anchor_tag_that_object_belongs_to; +string segment_anchor_tag_that_object_belongs_to_uri; +auto note_section = NotesSection(); +/+ enum +/ +enum State { off, on } +enum TriState { off, on, closing } +enum DocStructMarkupHeading { +  h_sect_A, +  h_sect_B, +  h_sect_C, +  h_sect_D, +  h_text_1, +  h_text_2, +  h_text_3, +  h_text_4, +  h_text_5, // extra level, drop +  content_non_header +} // header section A-D; header text 1-4 +enum DocStructCollapsedHeading { lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7 } +/+ biblio variables +/ +string biblio_tag_name, biblio_tag_entry, st; +string[] biblio_arr_json; +string biblio_entry_str_json; +JSONValue[] bib_arr_json; +int bib_entry; +/+ counters +/ +int cntr, previous_count, previous_length; +int[string] line_occur; +string[] html_segnames=["toc"]; +int html_segnames_ptr=0; +int html_segnames_ptr_cntr=0; +int verse_line, heading_ptr; +/+ paragraph attributes +/ +int[string] indent; +bool bullet = true; +string content_non_header = "8"; +auto obj_im = ObjInlineMarkup(); +auto obj_att = ObjAttributes(); +/+ ocn +/ +int obj_cite_number, obj_cite_number_; +auto object_citation_number = OCNemitter(); +int[] dom_markedup = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,]; +int[] dom_markedup_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,]; +int[] dom_collapsed = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,]; +int[] dom_collapsed_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,]; +enum DomTags { none, open, close, close_and_open, open_still, } +#+END_SRC + +**** initialize heading ancestors + +#+name: abs_init_struct +#+BEGIN_SRC d +void heading_ancestors(O)( +  auto ref O         obj, +  ref string[]       lv_ancestors, +) { +  switch (obj.heading_lev_markup) { +  case 0: +    lv_ancestors[0] = to!string(obj.text); +    foreach(k; 1..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 1: +    lv_ancestors[1] = to!string(obj.text); +    foreach(k; 2..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 2: +    lv_ancestors[2] = to!string(obj.text); +    foreach(k; 3..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 3: +    lv_ancestors[3] = to!string(obj.text); +    foreach(k; 4..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 4: +    lv_ancestors[4] = to!string(obj.text); +    foreach(k; 5..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 5: +    lv_ancestors[5] = to!string(obj.text); +    foreach(k; 6..8) { +      lv_ancestors[k] = ""; +    } +    goto default; +  case 6: +    lv_ancestors[6] = to!string(obj.text); +    lv_ancestors[7] = ""; +    goto default; +  case 7: +    lv_ancestors[7] = to!string(obj.text); +    goto default; +  default: +    obj.heading_ancestors_text = lv_ancestors.dup; +  } +} +#+END_SRC + +**** initialize dom markup tags + +#+name: abs_init_struct +#+BEGIN_SRC d +auto dom_set_markup_tags(int[] dom, int lev) { +  foreach (i; 0 .. 8) { +    if (i < lev) { +      if (dom[i] == DomTags.open +         || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.open_still; +      } else if (dom[i] == DomTags.close) { +        dom[i] = DomTags.none; +      } +    } else if (i == lev) { +      if (lev  == 0 +        && dom[i] == DomTags.open_still +      ) { +        dom[i] = DomTags.close; +      } else if (dom[i] == DomTags.open +        || dom[i] == DomTags.open_still +        || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.close_and_open; +      } else { +        dom[i] = DomTags.open; +      } +    } else if (i > lev) { +      if (dom[i] == DomTags.close) { +        dom[i] = DomTags.none; +      } else if (dom[i] == DomTags.open +        || dom[i] == DomTags.open_still +        || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.close; +      } +    } +  } +  debug(dom) { +    writeln(lev, ": ", dom); +  } +  return dom; +} +#+END_SRC + +**** initialize dom collapsed tags + +#+name: abs_init_struct +#+BEGIN_SRC d +auto dom_set_collapsed_tags(int[] dom, int lev) { +  foreach (i; 0 .. 8) { +    if (i < lev) { +      if (dom[i] == DomTags.open +         || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.open_still; +      } else if (dom[i] == DomTags.close) { +        dom[i] = DomTags.none; +      } +    } else if (i == lev) { +      if (lev  == 0 +        && dom[i] == DomTags.open_still +      ) { +        dom[i] = DomTags.close; +      } else if (dom[i] == DomTags.open +        || dom[i] == DomTags.open_still +        || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.close_and_open; +      } else { +        dom[i] = DomTags.open; +      } +    } else if (i > lev) { +      if (dom[i] == DomTags.close) { +        dom[i] = DomTags.none; +      } else if (dom[i] == DomTags.open +        || dom[i] == DomTags.open_still +        || dom[i] == DomTags.close_and_open +      ) { +        dom[i] = DomTags.close; +      } +    } +  } +  debug(dom) { +    writeln(lev, ": ", dom); +  } +  return dom; +} +#+END_SRC + +**** initialize ocn emit + +#+name: abs_init_struct +#+BEGIN_SRC d +int ocn_emit(int ocn_status_flag) { +  return object_citation_number.ocn_emitter(ocn_status_flag); +} +/+ book index variables +/ +string book_idx_tmp; +string[][string][string] bookindex_unordered_hashes; +auto bookindex_extract_hash = BookIndexNuggetHash(); +string[][string][string] bkidx_hash( +  string bookindex_section, +  int    obj_cite_number +) { +  return bookindex_extract_hash.bookindex_nugget_hash(bookindex_section, obj_cite_number); +} +/+ node +/ +ObjGenericComposite comp_obj_heading, comp_obj_location, comp_obj_block, comp_obj_code, comp_obj_poem_ocn, comp_obj_comment; +auto node_construct = NodeStructureMetadata(); +#+END_SRC + +*** scope + +#+name: abs_init_rest +#+BEGIN_SRC d +scope(success) { +} +scope(failure) { +} +scope(exit) { +  destroy(the_document_head_section); +  destroy(the_table_of_contents_section); +  destroy(the_document_body_section); +  destroy(the_bibliography_section); +  destroy(an_object); +  destroy(processing); +  destroy(biblio_arr_json); +} +#+END_SRC + +*** init rest + +#+name: abs_init_rest +#+BEGIN_SRC d +mixin SiSUrgxInitFlags; +mixin SiSUnode; +auto node_para_int_    = node_metadata_para_int; +auto node_para_str_    = node_metadata_para_str; +ObjGenericComposite comp_obj_heading_, comp_obj_para, comp_obj_toc; +line_occur = [ +  "heading"  : 0, +  "para"     : 0, +  "glossary" : 0, +  "blurb"    : 0, +]; +auto type = flags_type_init; +string[string] obj_cite_number_poem = [ +  "start" : "", +  "end"   : "" +]; +string[] lv_ancestors = [ "", "", "", "", "", "", "", "", ]; +int[string] lv = [ +  "lv" : State.off, +  "h0" : State.off, +  "h1" : State.off, +  "h2" : State.off, +  "h3" : State.off, +  "h4" : State.off, +  "h5" : State.off, +  "h6" : State.off, +  "h7" : State.off, +  "lev_int_collapsed" : 0, +]; +int[string] collapsed_lev = [ +  "h0" : State.off, +  "h1" : State.off, +  "h2" : State.off, +  "h3" : State.off, +  "h4" : State.off, +  "h5" : State.off, +  "h6" : State.off, +  "h7" : State.off +]; +string[string] heading_match_str = [ +  "h_A": "^(none)", +  "h_B": "^(none)", +  "h_C": "^(none)", +  "h_D": "^(none)", +  "h_1": "^(none)", +  "h_2": "^(none)", +  "h_3": "^(none)", +  "h_4": "^(none)" +]; +auto heading_match_rgx = [ +  "h_A": regex(r"^(none)"), +  "h_B": regex(r"^(none)"), +  "h_C": regex(r"^(none)"), +  "h_D": regex(r"^(none)"), +  "h_1": regex(r"^(none)"), +  "h_2": regex(r"^(none)"), +  "h_3": regex(r"^(none)"), +  "h_4": regex(r"^(none)") +]; +string _anchor_tag; +string toc_txt_; +an_object["glossary_nugget"] = ""; +an_object["blurb_nugget"] = ""; +comp_obj_heading_                       = comp_obj_heading_.init; +comp_obj_heading_.use                   = "frontmatter"; +comp_obj_heading_.is_of                 = "para"; +comp_obj_heading_.is_a                  = "heading"; +comp_obj_heading_.text                  = "Table of Contents"; +comp_obj_heading_.ocn                   = 0; +comp_obj_heading_.obj_cite_number       = ""; +comp_obj_heading_.segment_anchor_tag    = "toc"; +comp_obj_heading_.marked_up_level       = "1"; +comp_obj_heading_.heading_lev_markup    = 4; +comp_obj_heading_.heading_lev_collapsed = 1; +comp_obj_heading_.parent_ocn            = 1; +comp_obj_heading_.parent_lev_markup     = 0; +comp_obj_heading_.ptr_html_segnames     = html_segnames_ptr; +comp_obj_heading_.anchor_tags           = ["toc"]; +auto toc_head                           = comp_obj_heading_; +html_segnames_ptr_cntr++; +the_table_of_contents_section = [ +  "seg": [toc_head], +  "scroll": [toc_head], +]; +auto mkup = InlineMarkup(); +auto munge = ObjInlineMarkupMunge(); +string[][string] lev4_subtoc; +#+END_SRC + +** 2. _loop: process document body_ [+6]                              :loop: +*** loop scope                                                      :scope: + +#+name: abs_in_loop_body_00 +#+BEGIN_SRC d +/+ scope +/ +scope(exit) { +} +scope(failure) { +  stderr.writefln( +    "%s\n%s\n%s:%s failed here:\n  line: %s", +    __MODULE__, __FUNCTION__, +    __FILE__, __LINE__, +    line, +  ); +} +line = replaceAll(line, rgx.true_dollar, "$$$$"); +  // dollar represented as $$ needed to stop submatching on $ +  // (substitutions using ${identifiers} must take into account (i.e. happen earlier)) +debug(source) {                                  // source lines +  writeln(line); +} +debug(srclines) { +  if (!line.empty) {                             // source lines, not empty +    writefln( +      "* %s", +      line +    ); +  } +} +#+END_SRC + +*** check whether obj_cite_number is on or turned off                 :ocn: + +#+name: abs_in_loop_body_00 +#+BEGIN_SRC d +if (!line.empty) { +  _check_ocn_status_(line, type); +} +#+END_SRC + +*** [#A] separate regular markup text from code blocks [+5] +**** code blocks                                              :block:code: + +#+name: abs_in_loop_body_00_code_block +#+BEGIN_SRC d +/+ block object: code +/ +_code_block_(line, an_object, type); +continue; +#+END_SRC + +**** non code objects (other blocks or regular text) [+4]       :non_code: +***** in section (biblio, glossary, blurb) (block group) [+1] :block:active: +****** within section: biblio                                   :biblio: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +if ((matchFirst(line, rgx.heading_biblio) +|| (type["biblio_section"] == State.on +&& (!matchFirst(line, rgx.heading_blurb_glossary)))) +&& (!matchFirst(line, rgx.heading)) +&& (!matchFirst(line, rgx.comment))) { +  /+ within section (block object): biblio +/ +  type["glossary_section"] = State.off; +  type["biblio_section"] = State.on; +  type["blurb_section"] = State.off; +  if (opt_action_bool["backmatter"] && opt_action_bool["section_biblio"]) { +    _biblio_block_(line, type, bib_entry, biblio_entry_str_json, biblio_arr_json); // +    debug(bibliobuild) { +      writeln("-  ", biblio_entry_str_json); +      writeln("-> ", biblio_arr_json.length); +    } +  } +  continue; +#+END_SRC + +****** within section: glossary                               :glossary: + +if there is a glossary section you need to: +- extract it +- create standard headings +- markup contents in standard way like regular paragraphs +  - need indentation and regular paragraph inline markup +- reconstitute the document with the glossary section following the endnotes + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if ((matchFirst(line, rgx.heading_glossary) +|| (type["glossary_section"] == State.on +&& (!matchFirst(line, rgx.heading_biblio_blurb)))) +&& (!matchFirst(line, rgx.heading)) +&& (!matchFirst(line, rgx.comment))) { +  /+ within section (block object): glossary +/ +  debug(glossary) { +    writeln(__LINE__); +    writeln(line); +  } +  // _glossary_block_(line, type); +  type["glossary_section"] = State.on; +  type["biblio_section"] = State.off; +  type["blurb_section"] = State.off; +  if (opt_action_bool["backmatter"] && opt_action_bool["section_glossary"]) { +    indent=[ +      "hang_position" : 0, +      "base_position" : 0, +    ]; +    bullet = false; +    type["para"] = State.on; +    line_occur["para"] = State.off; +    an_object_key="glossary_nugget"; // +    if (matchFirst(line, rgx.heading_glossary)) { +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Glossary"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      the_glossary_section                    ~= comp_obj_heading_; +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Glossary"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.segment_anchor_tag    = "glossary"; +      comp_obj_heading_.marked_up_level       = "1"; +      comp_obj_heading_.heading_lev_markup    = 4; +      comp_obj_heading_.heading_lev_collapsed = 2; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      comp_obj_heading_.anchor_tags           = ["glossary"]; +      the_glossary_section                    ~= comp_obj_heading_; +    } else { +      _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); +      comp_obj_para                       = comp_obj_para.init; +      comp_obj_para.use                   = "backmatter"; +      comp_obj_para.is_of                 = "para"; +      comp_obj_para.is_a                  = "glossary"; +      comp_obj_para.text                  = to!string(line).strip; +      comp_obj_para.ocn                   = 0; +      comp_obj_para.obj_cite_number       = ""; +      comp_obj_para.indent_hang           = indent["hang_position"]; +      comp_obj_para.indent_base           = indent["base_position"]; +      comp_obj_para.bullet                = bullet; +      the_glossary_section                ~= comp_obj_para; +    } +    type["ocn_status"] = TriState.off; +  } +  continue; +#+END_SRC + +****** within section: blurb                                     :blurb: + +if there is a blurb section you need to: +- extract it +- create standard headings (or use line provided in 1~ heading) +- markup contents in standard way like regular paragraphs +  - need regular paragraph inline markup +- reconstitute the document with the blurb section at the very end of the doucment + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if ((matchFirst(line, rgx.heading_blurb) +|| (type["blurb_section"] == State.on +&& (!matchFirst(line, rgx.heading_biblio_glossary)))) +&& (!matchFirst(line, rgx.heading)) +&& (!matchFirst(line, rgx.comment))) { +  /+ within section (block object): blurb +/ +  debug(blurb) { +    writeln(__LINE__); +    writeln(line); +  } +  type["glossary_section"] = State.off; +  type["biblio_section"] = State.off; +  type["blurb_section"] = State.on; +  if (opt_action_bool["backmatter"] && opt_action_bool["section_blurb"]) { +    indent=[ +      "hang_position" : 0, +      "base_position" : 0, +    ]; +    bullet = false; +    type["para"] = State.on; +    line_occur["para"] = State.off; +    an_object_key="blurb_nugget"; +    if (matchFirst(line, rgx.heading_blurb)) { +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Blurb"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      the_blurb_section                       ~= comp_obj_heading_; +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Blurb"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.segment_anchor_tag    = "blurb"; +      comp_obj_heading_.marked_up_level       = "1"; +      comp_obj_heading_.heading_lev_markup    = 4; +      comp_obj_heading_.heading_lev_collapsed = 2; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      comp_obj_heading_.anchor_tags           = ["blurb"]; +      the_blurb_section                       ~= comp_obj_heading_; +    } else if ((matchFirst(line, rgx.heading)) +    && (opt_action_bool["backmatter"] && opt_action_bool["section_blurb"])) { +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = to!string(line); +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.segment_anchor_tag    = "blurb"; +      comp_obj_heading_.marked_up_level       = to!string(an_object["lev"]); +      comp_obj_heading_.heading_lev_markup    = to!int(an_object["lev_markup_number"]);    // make int, remove need to conv +      comp_obj_heading_.heading_lev_collapsed = to!int(an_object["lev_collapsed_number"]); // make int, remove need to conv +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      the_blurb_section                   ~= comp_obj_heading_; +    } else { +      _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); +      comp_obj_para                       = comp_obj_para.init; +      comp_obj_para.use                   = "backmatter"; +      comp_obj_para.is_of                 = "para"; +      comp_obj_para.is_a                  = "blurb"; +      comp_obj_para.text                  = to!string(line).strip; +      comp_obj_para.ocn                   = 0; +      comp_obj_para.obj_cite_number       = ""; +      comp_obj_para.indent_hang           = indent["hang_position"]; +      comp_obj_para.indent_base           = indent["base_position"]; +      comp_obj_para.bullet                = bullet; +      the_blurb_section                   ~= comp_obj_para; +    } +    type["ocn_status"] = TriState.off; +  } +  continue; +#+END_SRC + +***** in blocks [+1]                                       :block:active: +****** within block: poem                                         :poem: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if (type["poem"] == TriState.on) { +  /+ within block object: poem +/ +  _poem_block_(line, an_object, type, cntr, obj_cite_number_poem, dochead_make_aa); +  continue; +#+END_SRC + +****** within block: group                                       :group: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +/+ within block object: group +/ +} else if (type["group"] == TriState.on) { +  /+ within block object: group +/ +  _group_block_(line, an_object, type); +  continue; +#+END_SRC + +****** within block: block                                       :block: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if (type["block"] == TriState.on) { +  /+ within block object: block +/ +  _block_block_(line, an_object, type); +  continue; +#+END_SRC + +****** within block: quote                                       :quote: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if (type["quote"] == TriState.on) { +  /+ within block object: quote +/ +  _quote_block_(line, an_object, type); +  continue; +#+END_SRC + +****** within block: table                                       :table: + +#+name: abs_in_loop_body_non_code_obj +#+BEGIN_SRC d +} else if (type["table"] == TriState.on) { +  /+ within block object: table +/ +  _table_block_(line, an_object, type); +  continue; +#+END_SRC + +***** not identified as being within block group (could still be, or not) [+3] +****** assert + +#+name: abs_in_loop_body_open_block_obj_assert +#+BEGIN_SRC d +assert( +  (type["blocks"] == TriState.off) +  || (type["blocks"] == TriState.closing), +  "block status: none or closed" +); +assertions_flag_types_block_status_none_or_closed(type); +#+END_SRC + +****** block open + +#+name: abs_in_loop_body_open_block_obj +#+BEGIN_SRC d +if (matchFirst(line, (rgx.block_poem_open))) { +  /+ poem to verse exceptions! +/ +  object_reset(an_object); +  processing.remove("verse"); +  obj_cite_number_poem["start"] = to!string(obj_cite_number); +} +_start_block_(line, type, obj_cite_number_poem); +continue; +#+END_SRC + +****** line not empty [+2] +******* asserts                                                :assert: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +assert( +  !line.empty, +  "line tested, line not empty surely" +); +assert( +  (type["blocks"] == TriState.off) +  || (type["blocks"] == TriState.closing), +  "code block status: none or closed" +); +if (type["blocks"] == TriState.closing) { +  // blocks closed, unless followed by book index +  debug(check) {                           // block +    writeln(__LINE__); +    writeln(line); +  } +  assert( +    matchFirst(line, rgx.book_index) +    || matchFirst(line, rgx.book_index_open) +    || type["book_index"] == State.on +  ); +} +#+END_SRC + +******* book index                                          :bookindex: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +if ((matchFirst(line, rgx.book_index)) +|| (matchFirst(line, rgx.book_index_open)) +|| (type["book_index"] == State.on ))  { +  /+ book_index +/ +  _book_index_(line, book_idx_tmp, an_object, type, opt_action_bool); +#+END_SRC + +******* not book index [+1] + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +} else { +  /+ not book_index +/ +#+END_SRC + +******** matched: comment                              :comment:match: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +  an_object_key="body_nugget"; +  if (auto m = matchFirst(line, rgx.comment)) { +    /+ matched comment +/ +    debug(comment) { +      writeln(line); +    } +    an_object[an_object_key] ~= line ~= "\n"; +    comp_obj_comment                   = comp_obj_comment.init; +    comp_obj_comment.use               = "comment"; +    comp_obj_comment.is_of             = "comment"; +    comp_obj_comment.is_a              = "comment"; +    comp_obj_comment.text              = an_object[an_object_key].strip; +    the_document_body_section          ~= comp_obj_comment; +    _common_reset_(line_occur, an_object, type); +    processing.remove("verse"); +    ++cntr; +#+END_SRC + +******** flag not set & line not exist: heading or para :heading:paragraph: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +  } else if (((line_occur["para"] == State.off) +  && (line_occur["heading"] == State.off)) +  && ((type["para"] == State.off) +  && (type["heading"] == State.off))) { +    /+ heading or para but neither flag nor line exists +/ +    if ((dochead_make_aa["make"]["headings"].length > 2) +    && (type["make_headings"] == State.off)) { +      /+ heading found +/ +      _heading_found_(line, dochead_make_aa["make"]["headings"], heading_match_str, heading_match_rgx, type); +    } +    if ((type["make_headings"] == State.on) +    && ((line_occur["para"] == State.off) +    && (line_occur["heading"] == State.off)) +    && ((type["para"] == State.off) +    && (type["heading"] == State.off))) { +      /+ heading make set +/ +      _heading_make_set_(line, line_occur, heading_match_rgx, type); +    } +    /+ TODO node info: all headings identified at this point, +       - extract node info here?? +       - how long can it wait? +       - should be incorporated in composite objects +       - should happen before endnote links set (they need to be moved down?) +      // node_construct.node_emitter_heading segment anchor tag +    +/ +    if (matchFirst(line, rgx.heading)) { +      /+ heading match +/ +      _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); +    } else if (line_occur["para"] == State.off) { +      /+ para match +/ +      an_object_key="body_nugget"; +      _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); +    } +#+END_SRC + +******** line exist: heading                                 :heading: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +  } else if (line_occur["heading"] > State.off) { +    /+ heading +/ +    debug(heading) { +      writeln(line); +    } +    an_object[an_object_key] ~= line ~= "\n"; +    ++line_occur["heading"]; +#+END_SRC + +******** line exist: para                                       :para: + +#+name: abs_in_loop_body_not_block_obj +#+BEGIN_SRC d +  } else if (line_occur["para"] > State.off) { +    /+ paragraph +/ +    debug(para) { +      writeln(line); +    } +    an_object[an_object_key] ~= " " ~ line; +    ++line_occur["para"]; +  } +} +#+END_SRC + +****** line empty, with block flag + +#+name: abs_in_loop_body_not_block_obj_line_empty_blocks_flags +#+BEGIN_SRC d +_block_flag_line_empty_( +  line, +  an_object, +  the_document_body_section, +  bookindex_unordered_hashes, +  obj_cite_number, +  comp_obj_heading, +  cntr, +  type, +  obj_cite_number_poem, +  dochead_make_aa +); +#+END_SRC + +****** line empty [+1] +******* assert line empty                                      :assert: + +#+name: abs_in_loop_body_not_block_obj_line_empty +#+BEGIN_SRC d +assert( +  line.empty, +  "line should be empty" +); +assert( +  (type["blocks"] == State.off), +  "code block status: none" +); +#+END_SRC + +******* heading object                                 :heading:object: + +#+name: abs_in_loop_body_not_block_obj_line_empty +#+BEGIN_SRC d +if ((type["heading"] == State.on) +&& (line_occur["heading"] > State.off)) { +  /+ heading object (current line empty) +/ +  obj_cite_number = (to!int(an_object["lev_markup_number"]) == 0) +  ? (ocn_emit(3)) +  : (obj_cite_number = ocn_emit(type["ocn_status"])); +  an_object["bookindex_nugget"] = +    ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +  bookindex_unordered_hashes = +    bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +  an_object["is"] = "heading"; +  an_object_key="body_nugget"; +  auto substantive_object_and_anchor_tags_tuple = +    obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +  an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +  anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +  if (to!int(an_object["lev_markup_number"]) == 4) { +    segment_anchor_tag_that_object_belongs_to = anchor_tags[0]; +    segment_anchor_tag_that_object_belongs_to_uri = anchor_tags[0] ~ ".fnSuffix"; +    anchor_tag_ = anchor_tags[0]; +  } else if (to!int(an_object["lev_markup_number"]) > 4) { +    segment_anchor_tag_that_object_belongs_to = anchor_tag_; +    segment_anchor_tag_that_object_belongs_to_uri = anchor_tag_ ~ ".fnSuffix#" ~ to!string(obj_cite_number); +  } else if (to!int(an_object["lev_markup_number"]) < 4) { +    segment_anchor_tag_that_object_belongs_to = ""; +    segment_anchor_tag_that_object_belongs_to_uri = ""; +  } +  /+ (incrementally build toc) table of contents here! +/ +  _anchor_tag=to!string(obj_cite_number); +  the_table_of_contents_section = obj_im.table_of_contents_gather_headings( +    an_object, +    dochead_make_aa, +    segment_anchor_tag_that_object_belongs_to, +    _anchor_tag, +    lev4_subtoc, +    the_table_of_contents_section, +  ); +  if (an_object["lev_markup_number"] == "4") { +    html_segnames ~= segment_anchor_tag_that_object_belongs_to; +    html_segnames_ptr = html_segnames_ptr_cntr; +    html_segnames_ptr_cntr++; +  } +  auto comp_obj_heading = +    node_construct.node_emitter_heading( +      an_object["substantive"],                     // string +      an_object["lev"],                             // string +      an_object["lev_markup_number"],               // string +      an_object["lev_collapsed_number"],            // string +      segment_anchor_tag_that_object_belongs_to,    // string +      obj_cite_number,                              // int +      cntr,                                         // int +      heading_ptr,                                  // int +      lv_ancestors,                                 // string[] +      an_object["is"],                              // string +      html_segnames_ptr,                            // int +    ); +  ++heading_ptr; +  debug(segments) { +    writeln(an_object["lev_markup_number"]); +    writeln(segment_anchor_tag_that_object_belongs_to); +  } +  the_document_body_section ~= comp_obj_heading; +  // track previous heading and make assertions +  debug(objectrelated1) { // check +    writeln(line); +  } +  _common_reset_(line_occur, an_object, type); +  an_object.remove("lev"); +  an_object.remove("lev_markup_number"); +  processing.remove("verse"); +  ++cntr; +#+END_SRC + +******* paragraph object                             :paragraph:object: + +#+name: abs_in_loop_body_not_block_obj_line_empty +#+BEGIN_SRC d +} else if ((type["para"] == State.on) && (line_occur["para"] > State.off)) { +  /+ paragraph object (current line empty) +/ +  obj_cite_number = ocn_emit(type["ocn_status"]); +  an_object["bookindex_nugget"] = +    ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +  bookindex_unordered_hashes = +    bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +  an_object["is"] = "para"; +  auto comp_obj_heading = +    node_construct.node_location_emitter( +      content_non_header, +      segment_anchor_tag_that_object_belongs_to, +      obj_cite_number, +      cntr, +      heading_ptr-1, +      an_object["is"], +    ); +  auto substantive_object_and_anchor_tags_tuple = +    obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +  an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +  anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +  comp_obj_para                       = comp_obj_para.init; +  comp_obj_para.use                   = "body"; +  comp_obj_para.is_of                 = "para"; +  comp_obj_para.is_a                  = "para"; +  comp_obj_para.text                  = to!string(an_object["substantive"]).strip; +  comp_obj_para.ocn                   = obj_cite_number; +  comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +  comp_obj_para.indent_hang           = indent["hang_position"]; +  comp_obj_para.indent_base           = indent["base_position"]; +  comp_obj_para.bullet                = bullet; +  comp_obj_para.anchor_tags           = anchor_tags; +  the_document_body_section           ~= comp_obj_para; +  _common_reset_(line_occur, an_object, type); +  indent=[ +    "hang_position" : 0, +    "base_position" : 0, +  ]; +  bullet = false; +  processing.remove("verse"); +  ++cntr; +} else { +  assert( +    line == null, +    "line variable should be empty, should not occur" +  ); +  // check what happens when paragraph separated by 2 newlines +} +#+END_SRC + +*** regular text objects                                   :text:paragraph: + +#+name: abs_in_loop_body_01 +#+BEGIN_SRC d +/+ unless (the_document_body_section.length == 0) ? +/ +if (the_document_body_section.length > 0) { +  if (((the_document_body_section[$-1].is_a == "para") +  || (the_document_body_section[$-1].is_a == "heading") +  || (the_document_body_section[$-1].is_a == "group")) +  && (the_document_body_section.length > previous_length) +) { +    if ((the_document_body_section[$-1].is_a == "heading") +    && (the_document_body_section[$-1].heading_lev_markup < 5)) { +      type["biblio_section"] = State.off; +      type["glossary_section"] = State.off; +      type["blurb_section"] = State.off; +    } +    previous_length = to!int(the_document_body_section.length); +    if ( +      match(the_document_body_section[$-1].text, +      rgx.inline_notes_delimiter_al_regular_number_note) +    ) { +      previous_count=to!int(the_document_body_section.length -1); +      note_section.gather_notes_for_endnote_section( +        the_document_body_section, +        segment_anchor_tag_that_object_belongs_to, +        to!int(the_document_body_section.length-1), +      ); +    } +  } +} +#+END_SRC + +** 3. _post main-loop processing_                                       :post: +/+ +  Backmatter: +  - endnotes +  - glossary +  - bibliography / references +  - book index +  - blurb ++/ + +*** tie up preparation of document sections +**** endnotes section (scroll & seg)                            :endnotes: + +#+name: abs_post +#+BEGIN_SRC d +auto en_tuple = +  note_section.endnote_objects(obj_cite_number, opt_action_bool); +static assert(!isTypeTuple!(en_tuple)); +auto the_endnotes_section = en_tuple[0]; +obj_cite_number = en_tuple[1]; +debug(endnotes) { +  writefln( +    "%s %s", +    __LINE__, +    the_endnotes_section.length +  ); +  foreach (o; the_endnotes_section) { +    writeln(o); +  } +} +#+END_SRC + +**** no glossary section?                                       :glossary: + +#+name: abs_post +#+BEGIN_SRC d +if (an_object["glossary_nugget"].length == 0) { +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "empty"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  comp_obj_heading_.text                  = "(skip) there is no Glossary section"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_heading_.obj_cite_number       = ""; +  comp_obj_heading_.marked_up_level       = "B"; +  comp_obj_heading_.heading_lev_markup    = 1; +  comp_obj_heading_.heading_lev_collapsed = 1; +  comp_obj_heading_.parent_ocn            = 1; +  comp_obj_heading_.parent_lev_markup     = 0; +  the_glossary_section                    ~= comp_obj_heading_; +} else { +  writeln("gloss"); +} +debug(glossary) { +  foreach (gloss; the_glossary_section) { +    writeln(gloss.text); +  } +} +#+END_SRC + +**** bibliography section (objects)                         :bibliography: + +#+name: abs_post +#+BEGIN_SRC d +auto biblio_unsorted_incomplete = biblio_arr_json.dup; +auto biblio = Bibliography(); +auto biblio_ordered = +  biblio._bibliography_(biblio_unsorted_incomplete, bib_arr_json); +#+END_SRC + +#+name: abs_post +#+BEGIN_SRC d +if (biblio_ordered.length > 0) { +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "backmatter"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  comp_obj_heading_.text                  = "Bibliography"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_heading_.obj_cite_number       = ""; +  comp_obj_heading_.marked_up_level       = "B"; +  comp_obj_heading_.heading_lev_markup    = 1; +  comp_obj_heading_.heading_lev_collapsed = 1; +  comp_obj_heading_.parent_ocn            = 1; +  comp_obj_heading_.parent_lev_markup     = 0; +  the_bibliography_section                ~= comp_obj_heading_; +  // --- +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "backmatter"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  comp_obj_heading_.text                  = "Bibliography"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_heading_.obj_cite_number       = ""; +  comp_obj_heading_.segment_anchor_tag    = "bibliography"; +  comp_obj_heading_.marked_up_level       = "1"; +  comp_obj_heading_.heading_lev_markup    = 4; +  comp_obj_heading_.heading_lev_collapsed = 2; +  comp_obj_heading_.parent_ocn            = 1; +  comp_obj_heading_.parent_lev_markup     = 0; +  comp_obj_heading_.anchor_tags           = ["bibliography"]; +  the_bibliography_section                ~= comp_obj_heading_; +} else { +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "empty"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  comp_obj_heading_.text                  = "(skip) there is no Bibliography"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_heading_.obj_cite_number       = ""; +  comp_obj_heading_.marked_up_level       = "B"; +  comp_obj_heading_.heading_lev_markup    = 1; +  comp_obj_heading_.heading_lev_collapsed = 1; +  comp_obj_heading_.parent_ocn            = 1; +  comp_obj_heading_.parent_lev_markup     = 0; +  the_bibliography_section                ~= comp_obj_heading_; +} +#+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) ? "" : ", /{" ~ entry["journal"].str ~ "}/"), +    ((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.use                   = "backmatter"; +  comp_obj_para.is_of                 = "para"; +  comp_obj_para.is_a                  = "bibliography"; +  comp_obj_para.text                  = to!string(out_).strip; +  comp_obj_para.ocn                   = 0; +  comp_obj_para.obj_cite_number       = ""; +  comp_obj_para.indent_hang           = 0; +  comp_obj_para.indent_base           = 1; +  comp_obj_para.bullet                = bullet; +  comp_obj_para.anchor_tags           = anchor_tags; +  the_bibliography_section            ~= comp_obj_para; +} +#+END_SRC + +#+name: abs_post +#+BEGIN_SRC d +debug(bibliosection) { +  foreach (o; the_bibliography_section) { +    writeln(o.text); +  } +} +#+END_SRC + +***** bibliography components + +auto biblio_entry_tags_jsonstr =  `{ +  "is"                   : "", +  "sortby_deemed_author_year_title"  : "", +  "deemed_author"                    : "", +  "author_raw"                       : "", +  "author"                           : "", +  "author_arr"                       : [ "" ], +  "editor_raw"                       : "", +  "editor"                           : "", +  "editor_arr"                       : [ "" ], +  "title"                            : "", +  "subtitle"                         : "", +  "fulltitle"                        : "", +  "language"                         : "", +  "trans"                            : "", +  "src"                              : "", +  "journal"                          : "", +  "in"                               : "", +  "volume"                           : "", +  "edition"                          : "", +  "year"                             : "", +  "place"                            : "", +  "publisher"                        : "", +  "url"                              : "", +  "pages"                            : "", +  "note"                             : "", +  "short_name"                       : "", +  "id"                               : "" +}`; // is: book, article, magazine, newspaper, blog, other + +**** bookindex section (scroll & seg)                         :book:index: + +#+name: abs_post +#+BEGIN_SRC d +auto bi = BookIndexReportSection(); +auto bi_tuple = +  bi.bookindex_build_abstraction_section( +    bookindex_unordered_hashes, +    obj_cite_number, +    segment_anchor_tag_that_object_belongs_to, +    opt_action_bool, +  ); +static assert(!isTypeTuple!(bi_tuple)); +auto the_bookindex_section = bi_tuple[0]; +obj_cite_number = bi_tuple[1]; +debug(bookindex) { +  foreach (bi_entry; the_bookindex_section["seg"]) { +    writeln(bi_entry); +  } +} +#+END_SRC + +**** no blurb section?                                             :blurb: + +#+name: abs_post +#+BEGIN_SRC d +if (an_object["blurb_nugget"].length == 0) { +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "empty"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  comp_obj_heading_.text                  = "(skip) there is no Blurb section"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_para.obj_cite_number           = ""; +  comp_obj_heading_.segment_anchor_tag    = ""; +  comp_obj_heading_.marked_up_level       = "B"; +  comp_obj_heading_.heading_lev_markup    = 1; +  comp_obj_heading_.heading_lev_collapsed = 1; +  comp_obj_heading_.parent_ocn            = 1; +  comp_obj_heading_.parent_lev_markup     = 0; +  the_blurb_section                       ~= comp_obj_heading_; +} +debug(blurb) { +  foreach (blurb; the_blurb_section) { +    writeln(blurb.text); +  } +} +#+END_SRC + +**** toc backmatter, table of contents backmatter (scroll & seg) :contents: + +#+name: abs_post +#+BEGIN_SRC d +indent=[ +  "hang_position" : 1, +  "base_position" : 1, +]; +comp_obj_toc                       = comp_obj_toc.init; +comp_obj_toc.use                   = "frontmatter"; +comp_obj_toc.is_of                 = "para"; +comp_obj_toc.is_a                  = "toc"; +comp_obj_toc.ocn                   = 0; +comp_obj_toc.obj_cite_number       = ""; +comp_obj_toc.indent_hang           = indent["hang_position"]; +comp_obj_toc.indent_base           = indent["base_position"]; +comp_obj_toc.bullet                = false; +if (the_endnotes_section.length > 1) { +  toc_txt_ = format( +    "{ %s }%s../%s.fnSuffix", +    "Endnotes", +    mkup.mark_internal_site_lnk, +    "endnotes",               // segment_anchor_tag_that_object_belongs_to +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["seg"]    ~= comp_obj_toc; +} +if (the_glossary_section.length > 1) { +  toc_txt_ = format( +    "{ %s }%s../%s.fnSuffixs", +    "Glossary", +    mkup.mark_internal_site_lnk, +    "glossary",               // segment_anchor_tag_that_object_belongs_to +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["seg"]    ~= comp_obj_toc; +  toc_txt_ = format( +    "{ %s }#%s", +    "Glossary", +    "glossary",               // _anchor_tag +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["scroll"] ~= comp_obj_toc; +} +if (the_bibliography_section.length > 1){ +  toc_txt_ = format( +    "{ %s }%s../%s.fnSuffix", +    "Bibliography", +    mkup.mark_internal_site_lnk, +    "bibliography",           // segment_anchor_tag_that_object_belongs_to +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["seg"]    ~= comp_obj_toc; + +  toc_txt_ = format( +    "{ %s }#%s", +    "Bibliography", +    "bibliography",           // _anchor_tag +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["scroll"] ~= comp_obj_toc; +} +if (the_bookindex_section["seg"].length > 1) { +  toc_txt_ = format( +    "{ %s }%s../%s.fnSuffix", +    "Book Index", +    mkup.mark_internal_site_lnk, +    "bookindex",              // segment_anchor_tag_that_object_belongs_to +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["seg"]    ~= comp_obj_toc; +} +if (the_bookindex_section["scroll"].length > 1) { +  toc_txt_ = format( +    "{ %s }#%s", +    "Book Index", +    "bookindex",              // _anchor_tag +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["scroll"] ~= comp_obj_toc; +} +if (the_blurb_section.length > 1) { +  toc_txt_ = format( +    "{ %s }%s../%s.fnSuffix", +    "Blurb", +    mkup.mark_internal_site_lnk, +    "blurb",                  // segment_anchor_tag_that_object_belongs_to +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["seg"]    ~= comp_obj_toc; +  toc_txt_ = format( +    "{ %s }#%s", +    "Blurb", +    "blurb",                  // _anchor_tag +  ); +  toc_txt_= munge.url_links(toc_txt_); +  comp_obj_toc.text                       = to!string(toc_txt_).strip; +  the_table_of_contents_section["scroll"] ~= comp_obj_toc; +} +debug(toc) { +  writefln( +    "%s %s", +    __LINE__, +    the_table_of_contents_section["seg"].length +  ); +  foreach (toc_linked_heading; the_table_of_contents_section["seg"]) { +    writeln(mkup.indent_by_spaces_provided(toc_linked_heading.indent_hang), toc_linked_heading.text); +  } +} +debug(tocscroll) { +  writefln( +    "%s %s", +    __LINE__, +    the_table_of_contents_section["seg"].length +  ); +  foreach (toc_linked_heading; the_table_of_contents_section["scroll"]) { +    writeln(mkup.indent_by_spaces_provided(toc_linked_heading.indent_hang), toc_linked_heading.text); +  } +} +#+END_SRC + +**** doc head (separate document head from body, make space for toc) + +#+name: abs_post +#+BEGIN_SRC d +the_document_head_section ~= the_document_body_section[0]; +the_document_body_section=the_document_body_section[1..$]; +#+END_SRC + +*** TODO minor loops                                                 :post: +**** 1. loop: backmatter loop up to lev4: html_segnames, set backmatter pointers + +could optimise by +- skipping second and third pass unless the output html seg or epub is being made! +NOTE there are issues attempting to do this on first pass +- as +  - backmatter is created out of sequence and +  - it is not certain which are present +it is quite neat to have all in one place as we have here: + +#+name: abs_post +#+BEGIN_SRC d +if (the_endnotes_section.length > 1) { +  html_segnames ~= "endnotes"; +  html_segnames_ptr = html_segnames_ptr_cntr; +  foreach (ref section; the_endnotes_section) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  html_segnames_ptr_cntr++; +} +if (the_glossary_section.length > 1) { +  html_segnames ~= "glossary"; +  html_segnames_ptr = html_segnames_ptr_cntr; +  foreach (ref section; the_glossary_section) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  html_segnames_ptr_cntr++; +} +if (the_bibliography_section.length > 1) { +  html_segnames ~= "bibliography"; +  html_segnames_ptr = html_segnames_ptr_cntr; +  foreach (ref section; the_bibliography_section) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  html_segnames_ptr_cntr++; +} +if (the_bookindex_section["scroll"].length > 1) { +  html_segnames ~= "bookindex"; +  html_segnames_ptr = html_segnames_ptr_cntr; +  foreach (ref section; the_bookindex_section["scroll"]) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  foreach (ref section; the_bookindex_section["seg"]) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  html_segnames_ptr_cntr++; +} +if (the_blurb_section.length > 1) { +  html_segnames ~= "blurb"; +  html_segnames_ptr = html_segnames_ptr_cntr; +  foreach (ref section; the_blurb_section) { +    if (section.heading_lev_markup == 4) { +      section.ptr_html_segnames = html_segnames_ptr; +      break; +    } +  } +  html_segnames_ptr_cntr++; +} +#+END_SRC + +**** 2. loop: all objects structural relationships (sections, segments, objects) + +needed for DOM structure, segnames & subtoc, backmatter pointers & unique image +list + +if used minimally only for DOM structure, segnames, subtoc, could optimise by +- skipping second and third pass unless the output html seg or epub is being +  made! + +or could conveniently be used more extensively for ancestors as well (though +this can be extracted earlier) + +Build here: +- DOM structure +- ancestors and decendants + +(as needed) up to document heading 1~, lev4 html: + +during the third pass all previous and next segment names are known +next are not yet known for backmatter during the second pass + +#+name: abs_post +#+BEGIN_SRC d +foreach (ref obj; the_document_head_section) { +  if (obj.is_a == "heading") { +    debug(dom) { +      writeln(obj.text); +    } +    if ((opt_action_bool["html"]) +    || (opt_action_bool["html_scroll"]) +    || (opt_action_bool["html_seg"]) +    || (opt_action_bool["epub"])) { +      obj.dom_markedup = +        dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +      obj.dom_collapsed = +        dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +    } +    heading_ancestors(obj, lv_ancestors); +  } +} +if (the_table_of_contents_section["scroll"].length > 1) { +  dom_markedup_buffer = dom_markedup.dup; +  dom_collapsed_buffer = dom_collapsed.dup; +  foreach (ref obj; the_table_of_contents_section["scroll"]) { +    if (obj.is_a == "heading") { +      if (obj.heading_lev_markup == 4) { +        obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +  dom_markedup = dom_markedup_buffer.dup; +  dom_collapsed = dom_collapsed_buffer.dup; +  foreach (ref obj; the_table_of_contents_section["seg"]) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ multiple 1~ levels, loop through document body +/ +if (the_document_body_section.length > 1) { +  foreach (ref obj; the_document_body_section) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.lev4_subtoc = lev4_subtoc[obj.segment_anchor_tag]; +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ optional only one 1~ level +/ +if (the_endnotes_section.length > 1) { +  dom_markedup_buffer = dom_markedup.dup; +  dom_collapsed_buffer = dom_collapsed.dup; +  dom_markedup = dom_markedup_buffer.dup; +  dom_collapsed = dom_collapsed_buffer.dup; +  foreach (ref obj; the_endnotes_section) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ optional only one 1~ level +/ +if (the_glossary_section.length > 1) { +  foreach (ref obj; the_glossary_section) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ optional only one 1~ level +/ +if (the_bibliography_section.length > 1) { +  foreach (ref obj; the_bibliography_section) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ optional only one 1~ level +/ +if (the_bookindex_section["scroll"].length > 1) { +  dom_markedup_buffer = dom_markedup.dup; +  dom_collapsed_buffer = dom_collapsed.dup; +  foreach (ref obj; the_bookindex_section["scroll"]) { +    if (obj.is_a == "heading") { +      debug(dom) { +      // writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +  dom_markedup = dom_markedup_buffer.dup; +  dom_collapsed = dom_collapsed_buffer.dup; +  foreach (ref obj; the_bookindex_section["seg"]) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +} +/+ optional only one 1~ level +/ +if (the_blurb_section.length > 1) { +  foreach (ref obj; the_blurb_section) { +    if (obj.is_a == "heading") { +      debug(dom) { +        writeln(obj.text); +      } +      if (obj.heading_lev_markup == 4) { +        obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1]; +        if (html_segnames.length > obj.ptr_html_segnames + 1) { +          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1]; +        } +        assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]); +      } +      if ((opt_action_bool["html"]) +      || (opt_action_bool["html_scroll"]) +      || (opt_action_bool["html_seg"]) +      || (opt_action_bool["epub"])) { +        obj.dom_markedup = +          dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup; +        obj.dom_collapsed = +          dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup; +      } +      heading_ancestors(obj, lv_ancestors); +    } +  } +  /+ TODO +    - note create/insert heading object sole purpose eof close all open tags +      sort out: +      - obj.dom_markedup = dom_markedup; +      - obj.dom_collapsed = dom_collapsed; +  +/ +  dom_markedup = dom_set_markup_tags(dom_markedup, 0); +  dom_collapsed = dom_set_collapsed_tags(dom_collapsed, 0); +  comp_obj_heading_                       = comp_obj_heading_.init; +  comp_obj_heading_.use                   = "empty"; +  comp_obj_heading_.is_of                 = "para"; +  comp_obj_heading_.is_a                  = "heading"; +  // comp_obj_heading_.text                  = "(skip) this is the DOM tail"; +  comp_obj_heading_.ocn                   = 0; +  comp_obj_para.obj_cite_number           = ""; +  comp_obj_heading_.segment_anchor_tag    = ""; +  comp_obj_heading_.marked_up_level       = ""; +  comp_obj_heading_.heading_lev_markup    = 9; +  comp_obj_heading_.heading_lev_collapsed = 9; +  comp_obj_heading_.parent_ocn            = 0; +  comp_obj_heading_.parent_lev_markup     = 0; +  comp_obj_heading_.dom_markedup          = dom_markedup.dup; +  comp_obj_heading_.dom_collapsed         = dom_collapsed.dup; +  the_dom_tail_section                    ~= comp_obj_heading_; +} +#+END_SRC + +** 4. _return document tuple_                                         :post: +*** the document                                                 :document: + +#+name: abs_post +#+BEGIN_SRC d +auto document_the = [ +  "head":             the_document_head_section, +  "toc_seg":          the_table_of_contents_section["seg"], +  "toc_scroll":       the_table_of_contents_section["scroll"], +  /+ substantive/body: +/ +  "body":             the_document_body_section, +  /+ backmatter: +/ +  "endnotes":         the_endnotes_section, +  "glossary":         the_glossary_section, +  "bibliography":     the_bibliography_section, +  "bookindex_scroll": the_bookindex_section["scroll"], +  "bookindex_seg":    the_bookindex_section["seg"], +  "blurb":            the_blurb_section, +  /+ dom tail only +/ +  "tail":             the_dom_tail_section, +]; +#+END_SRC + +*** document _section keys_ sequence + +#+name: abs_post +#+BEGIN_SRC d +string[][string] document_section_keys_sequenced = [ +  "seg":    ["head", "toc_seg", "body",], +  "scroll": ["head", "toc_scroll", "body",] +]; +if (document_the["endnotes"].length > 1) { +  document_section_keys_sequenced["seg"]    ~= "endnotes"; +  document_section_keys_sequenced["scroll"] ~= "endnotes"; +} +if (document_the["glossary"].length > 1) { +  document_section_keys_sequenced["seg"]    ~= "glossary"; +  document_section_keys_sequenced["scroll"] ~= "glossary"; +} +if (document_the["bibliography"].length > 1) { +  document_section_keys_sequenced["seg"]    ~= "bibliography"; +  document_section_keys_sequenced["scroll"] ~= "bibliography"; +} +if (document_the["bookindex_seg"].length > 1) { +  document_section_keys_sequenced["seg"]    ~= "bookindex_seg"; +} +if (document_the["bookindex_scroll"].length > 1) { +  document_section_keys_sequenced["scroll"] ~= "bookindex_scroll"; +} +if (document_the["blurb"].length > 1) { +  document_section_keys_sequenced["seg"]    ~= "blurb"; +  document_section_keys_sequenced["scroll"] ~= "blurb"; +} +if ((opt_action_bool["html"]) +|| (opt_action_bool["html_scroll"]) +|| (opt_action_bool["html_seg"]) +|| (opt_action_bool["epub"])) { +  document_section_keys_sequenced["seg"]    ~= "tail"; +  document_section_keys_sequenced["scroll"] ~= "tail"; +} +#+END_SRC + +*** clean out structure + +#+name: abs_post +destroy(the_document_head_section); +destroy(the_document_table_of_contents_section); +destroy(the_document_body_section); +destroy(the_endnotes_section); +destroy(the_glossary_section); +destroy(the_bibliography_section); +destroy(the_bookindex_section); +destroy(the_blurb_section); +#+END_SRC + +*** [#A] _return document tuple_                               :return:tuple: + +#+name: abs_post +#+BEGIN_SRC d +auto t = tuple( +  document_the, +  document_section_keys_sequenced, +  html_segnames, +); +return t; +#+END_SRC + +** 5. Functions                                          :abstract:function: + +functions used in document abstraction + +*** set & resets                                                    :reset: +**** object reset: remove (clean)                          :object:remove: + +#+name: abs_functions_object_reset +#+BEGIN_SRC d +auto object_reset(O)(ref O an_object) { +  debug(asserts){ +    static assert(is(typeof(an_object) == string[string])); +  } +  an_object.remove("body_nugget"); +  an_object.remove("substantive"); +  an_object.remove("is"); +  an_object.remove("attrib"); +  an_object.remove("bookindex_nugget"); +} +#+END_SRC + +**** set, initialize or re-initialize                                :set: + +#+name: abs_functions_header_set_common +#+BEGIN_SRC d +auto _common_reset_(L,O,T)( +  ref L line_occur, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line_occur) == int[string])); +    static assert(is(typeof(an_object)  == string[string])); +    static assert(is(typeof(type)       == int[string])); +  } +  line_occur["heading"] = State.off; +  line_occur["para"]    = State.off; +  type["heading"]       = State.off; +  type["para"]          = State.off; +  object_reset(an_object); +} +#+END_SRC + +*** check obj_cite_number status in document                          :ocn: + +#+name: abs_functions_ocn_status +#+BEGIN_SRC d +void _check_ocn_status_(L,T)( +  L     line, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line) == char[])); +    static assert(is(typeof(type) == int[string])); +  } +  auto rgx = Rgx(); +  if ((!line.empty) && (type["ocn_status_multi_obj"] == TriState.off)) { +    /+ not multi-line object, check whether obj_cite_number is on or turned off +/ +    if (matchFirst(line, rgx.obj_cite_number_block_marks)) { +      /+ switch off obj_cite_number +/ +      if (matchFirst(line, rgx.obj_cite_number_off_block)) { +        type["ocn_status_multi_obj"] = TriState.on; +        debug(ocnoff) { +          writeln(line); +        } +      } +      if (matchFirst(line, rgx.obj_cite_number_off_block_dh)) { +        type["ocn_status_multi_obj"] = TriState.closing; +        debug(ocnoff) { +          writeln(line); +        } +      } +    } else { +      if (type["ocn_status_multi_obj"] == TriState.off) { +        if (matchFirst(line, rgx.obj_cite_number_off)) { +          type["ocn_status"] = TriState.on; +        } else if (matchFirst(line, rgx.obj_cite_number_off_dh)) { +          type["ocn_status"] = TriState.closing; +        } else { +          type["ocn_status"] = TriState.off; +        } +      } else { +        type["ocn_status"] = +          type["ocn_status_multi_obj"]; +      } +    } +  } else if ((!line.empty) && (type["ocn_status_multi_obj"] > TriState.off)) { +    if (matchFirst(line, rgx.obj_cite_number_off_block_close)) { +      type["ocn_status_multi_obj"] = TriState.off; +      type["ocn_status"] = TriState.off; +      debug(ocnoff) { +        writeln(line); +      } +    } +  } +} +#+END_SRC + +*** block                                                           :block: +**** block start (open) block                                      :start: +***** function open for block starts + +#+name: abs_functions_block +#+BEGIN_SRC d +void _start_block_(L,T,N)( +  L     line, +  ref T type, +  N     obj_cite_number_poem +) { +  debug(asserts){ +    static assert(is(typeof(line)                 == char[])); +    static assert(is(typeof(type)                 == int[string])); +    static assert(is(typeof(obj_cite_number_poem) == string[string])); +  } +#+END_SRC + +***** block (various) curly open                                  :curly: + +#+name: abs_functions_block +#+BEGIN_SRC d +  auto rgx = Rgx(); +  if (matchFirst(line, rgx.block_curly_code_open)) { +    /+ curly code open +/ +    debug(code) {                              // code (curly) open +      writefln( +        "* [code curly] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["code"] = TriState.on; +    type["curly_code"] = TriState.on; +  } else if (matchFirst(line, rgx.block_curly_poem_open)) { +    /+ curly poem open +/ +    debug(poem) {                              // poem (curly) open +      writefln( +        "* [poem curly] %s", +        line +      ); +    } +    obj_cite_number_poem["start"] = +      to!string(obj_cite_number); +    type["blocks"] = TriState.on; +    type["verse_new"] = State.on; +    type["poem"] = TriState.on; +    type["curly_poem"] = TriState.on; +  } else if (matchFirst(line, rgx.block_curly_group_open)) { +    /+ curly group open +/ +    debug(group) {                             // group (curly) open +      writefln( +        "* [group curly] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["group"] = TriState.on; +    type["curly_group"] = TriState.on; +  } else if (matchFirst(line, rgx.block_curly_block_open)) { +    /+ curly block open +/ +    debug(block) {                             // block (curly) open +      writefln( +        "* [block curly] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["block"] = TriState.on; +    type["curly_block"] = TriState.on; +  } else if (matchFirst(line, rgx.block_curly_quote_open)) { +    /+ curly quote open +/ +    debug(quote) {                             // quote (curly) open +      writefln( +        "* [quote curly] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["quote"] = TriState.on; +    type["curly_quote"] = TriState.on; +  } else if (matchFirst(line, rgx.block_curly_table_open)) { +    /+ curly table open +/ +    debug(table) {                             // table (curly) open +      writefln( +        "* [table curly] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["table"] = TriState.on; +    type["curly_table"] = TriState.on; +#+END_SRC + +***** block (various) tic open                                      :tic: + +#+name: abs_functions_block +#+BEGIN_SRC d +  } else if (matchFirst(line, rgx.block_tic_code_open)) { +    /+ tic code open +/ +    debug(code) {                              // code (tic) open +      writefln( +        "* [code tic] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["code"] = TriState.on; +    type["tic_code"] = TriState.on; +  } else if (matchFirst(line, rgx.block_tic_poem_open)) { +    /+ tic poem open +/ +    debug(poem) {                              // poem (tic) open +      writefln( +        "* [poem tic] %s", +        line +      ); +    } +    obj_cite_number_poem["start"] = to!string(obj_cite_number); +    type["blocks"] = TriState.on; +    type["verse_new"] = State.on; +    type["poem"] = TriState.on; +    type["tic_poem"] = TriState.on; +  } else if (matchFirst(line, rgx.block_tic_group_open)) { +    /+ tic group open +/ +    debug(group) {                             // group (tic) open +      writefln( +        "* [group tic] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["group"] = TriState.on; +    type["tic_group"] = TriState.on; +  } else if (matchFirst(line, rgx.block_tic_block_open)) { +    /+ tic block open +/ +    debug(block) {                             // block (tic) open +      writefln( +        "* [block tic] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["block"] = TriState.on; +    type["tic_block"] = TriState.on; +  } else if (matchFirst(line, rgx.block_tic_quote_open)) { +    /+ tic quote open +/ +    debug(quote) {                             // quote (tic) open +      writefln( +        "* [quote tic] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["quote"] = TriState.on; +    type["tic_quote"] = TriState.on; +  } else if (matchFirst(line, rgx.block_tic_table_open)) { +    /+ tic table open +/ +    debug(table) {                             // table (tic) open +      writefln( +        "* [table tic] %s", +        line +      ); +    } +    type["blocks"] = TriState.on; +    type["table"] = TriState.on; +    type["tic_table"] = TriState.on; +  } +#+END_SRC + +***** function close for block starts + +#+name: abs_functions_block +#+BEGIN_SRC d +} +#+END_SRC + +**** block continue (an open block)                             :continue: +***** code block (special status, deal with first)                 :code: + +#+name: abs_functions_block_code +#+BEGIN_SRC d +void _code_block_(L,O,T)( +  ref L line, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)      == char[])); +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(type)      == int[string])); +  } +  auto rgx = Rgx(); +  if (type["curly_code"] == TriState.on) { +    if (matchFirst(line, rgx.block_curly_code_close)) { +      debug(code) {                                    // code (curly) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["code"] = TriState.closing; +      type["curly_code"] = TriState.off; +    } else { +      debug(code) {                                    // code (curly) line +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";        // code (curly) line +    } +  } else if (type["tic_code"] == TriState.on) { +    if (matchFirst(line, rgx.block_tic_close)) { +      debug(code) {                                    // code (tic) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["code"] = TriState.closing; +      type["tic_code"] = TriState.off; +    } else { +      debug(code) {                                    // code (tic) line +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";        // code (tic) line +    } +  } +} +#+END_SRC + +***** biblio block                                               :biblio: +****** biblio tag map + +#+name: abs_functions_block_biblio +#+BEGIN_SRC d +final string biblio_tag_map(A)(A abr) { +  debug(asserts){ +    static assert(is(typeof(abr) == string)); +  } +  auto btm = [ +    "au"                               : "author_raw", +    "ed"                               : "editor_raw", +    "ti"                               : "fulltitle", +    "lng"                              : "language", +    "jo"                               : "journal", +    "vol"                              : "volume", +    "edn"                              : "edition", +    "yr"                               : "year", +    "pl"                               : "place", +    "pb"                               : "publisher", +    "pub"                              : "publisher", +    "pg"                               : "pages", +    "pgs"                              : "pages", +    "sn"                               : "short_name" +  ]; +  return btm[abr]; +} +#+END_SRC + +******* +consider+ + +#+name: none +#+BEGIN_SRC d +final string biblio_tag_map_(A)(A abr) { +  debug(asserts){ +    static assert(is(typeof(abr) == string)); +  } +  string name; +  switch (abr) { +  case "au": +    name="author_raw"; +    break; +  case "ed": +    name="editor_raw"; +    break; +  case "ti": +    name="fulltitle"; +    break; +  case "lng": +    name="language"; +    break; +  case "jo": +    name="journal"; +    break; +  case "vol": +    name="volume"; +    break; +  case "edn": +    name="edition"; +    break; +  case "yr": +    name="year"; +    break; +  case "pl": +    name="place"; +    break; +  case "pb": +    name="publisher"; +    break; +  case "pub": +    name="publisher"; +    break; +  case "pg": +    name="pages"; +    break; +  case "pgs": +    name="pages"; +    break; +  case "sn": +    name="short_name"; +    break; +  default: +    name=abr; +    break; +  } +  return name; +} +#+END_SRC + +****** biblio block + +#+name: abs_functions_block_biblio +#+BEGIN_SRC d +void _biblio_block_( +  char[] line, +  ref int[string] type, +  ref int bib_entry, +  ref string biblio_entry_str_json, +  ref string[] biblio_arr_json +) { +  mixin SiSUbiblio; +  auto jsn = BibJsnStr(); +  auto rgx = Rgx(); +  if (matchFirst(line, rgx.heading_biblio)) { +    type["biblio_section"] = TriState.on; +    type["blurb_section"] = State.off; +    type["glossary_section"] = State.off; +  } +  if (line.empty) { +    debug { +      debug(biblioblock) { +        writeln("---"); +      } +      debug(biblioblockinclude) { +        writeln(biblio_entry_str_json.length); +      } +    } +    if ((bib_entry == State.off) +    && (biblio_entry_str_json.empty)) { +      bib_entry = State.on; +      biblio_entry_str_json = jsn.biblio_entry_tags_jsonstr; +    } else if (!(biblio_entry_str_json.empty)) { +      bib_entry = State.off; +      if (!(biblio_entry_str_json == jsn.biblio_entry_tags_jsonstr)) { +        auto biblio_entry = parseJSON(biblio_entry_str_json); +        if (biblio_entry["fulltitle"].str.empty) { +          writeln("check problem entry (Title missing): ", biblio_entry_str_json); +        } else if ((biblio_entry["author_raw"].str.empty) && (biblio_entry["editor_raw"].str.empty)) { +          writeln("check problem entry (No author and no editor): ", biblio_entry_str_json); +        } else { +          biblio_arr_json ~= biblio_entry_str_json; +        } +        biblio_entry_str_json = jsn.biblio_entry_tags_jsonstr; +      } +    } else { // CHECK ERROR +      writeln("?? 2. ERROR ", biblio_entry_str_json, "??"); +      biblio_entry_str_json = ""; +    } +  } else if (matchFirst(line, rgx.biblio_tags)) { +    debug(biblioblock) { +      writeln(line); +    } +    auto bt = match(line, rgx.biblio_tags); +    bib_entry = State.off; +    st=to!string(bt.captures[1]); +    auto header_tag_value=to!string(bt.captures[2]); +    JSONValue j = parseJSON(biblio_entry_str_json); +    biblio_tag_name = (match(st, rgx.biblio_abbreviations)) +      ? (biblio_tag_map(st)) +      : st; +    j.object[biblio_tag_name] = header_tag_value; +    debug(bibliounsortedcheckduplicates) { +      writeln(biblio_tag_name, ": ", header_tag_value); +      writeln("--"); +    } +    switch (biblio_tag_name) { +    case "author_raw": // author_arr author (fn sn) +      j["author_arr"] = +        split(header_tag_value, rgx.arr_delimiter); +      string tmp; +      biblioAuthorLoop: +      foreach (au; j["author_arr"].array) { +        if (auto x = match(au.str, rgx.name_delimiter)) { +          tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; +        } else { +          tmp ~= au.str; +        } +      } +      tmp = replace(tmp, rgx.trailing_comma, ""); +      j["author"].str = tmp; +      goto default; +    case "editor_raw": // editor_arr editor (fn sn) +      j["editor_arr"] = +        split(header_tag_value, rgx.arr_delimiter); +      string tmp; +      biblioEditorLoop: +      foreach (ed; j["editor_arr"].array) { +        if (auto x = match(ed.str, rgx.name_delimiter)) { +          tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; +        } else { +          tmp ~= ed.str; +        } +      } +      tmp = replace(tmp, rgx.trailing_comma, ""); +      j["editor"].str = tmp; +      goto default; +    case "fulltitle": // title & subtitle +      goto default; +    default: +      break; +    } +    auto s = j.toString(); +    debug(biblio1) { +      writefln( +        "* %s: %s\n%s", +        biblio_tag_name, +        biblio_tag_entry, +        j[biblio_tag_name] +      ); +    } +    if ((match(line, rgx.comment))) { +      writeln("ERROR", line, "COMMENT"); +      writeln("ERROR", s, "%%"); +    } +    if (!(match(line, rgx.comment))) { +      debug(biblioblockinclude) { +        writeln(line); +      } +      biblio_entry_str_json = s; +    } else { +      biblio_entry_str_json = ""; +    } +    header_tag_value=""; +  } +} +#+END_SRC + +***** TODO poem block, verse objects                         :poem:verse: + +why extra object stuff only in poem/verse? + +#+name: abs_functions_block_poem +#+BEGIN_SRC d +void _poem_block_(L,O,T,C,N,Ma)( +  L     line, +  ref O an_object, +  ref T type, +  ref C cntr, +  N     obj_cite_number_poem, +  Ma    dochead_make_aa, +) { +  debug(asserts){ +    static assert(is(typeof(line)                 == char[])); +    static assert(is(typeof(an_object)            == string[string])); +    static assert(is(typeof(type)                 == int[string])); +    static assert(is(typeof(cntr)                 == int)); +    static assert(is(typeof(obj_cite_number_poem) == string[string])); +    static assert(is(typeof(dochead_make_aa)      == string[string][string])); +  } +  auto rgx = Rgx(); +  if (type["curly_poem"] == TriState.on) { +    if (matchFirst(line, rgx.block_curly_poem_close)) { +      an_object[an_object_key]="verse"; +      debug(poem) {                               // poem (curly) close +        writefln( +          "* [poem curly] %s", +          line +        ); +      } +      if (processing.length > 0) { +        an_object[an_object_key] = processing["verse"]; +      } +      debug(poem) {                               // poem (curly) close +        writeln(__LINE__); +        writefln( +          "* %s %s", +          obj_cite_number, +          line +        ); +      } +      if (an_object.length > 0) { +        debug(poem) {                             // poem (curly) close +          writeln( +            obj_cite_number, +            an_object[an_object_key] +          ); +        } +        an_object["is"] = "verse"; +        auto substantive_object_and_anchor_tags_tuple = +          obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +        an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +        anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +        comp_obj_block                            = comp_obj_block.init; +        comp_obj_block.use                        = "body"; +        comp_obj_block.is_of                      = "block"; +        comp_obj_block.is_a                       = "verse"; +        comp_obj_block.ocn                        = obj_cite_number; +        comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +        comp_obj_block.text                       = an_object["substantive"]; +        the_document_body_section                 ~= comp_obj_block; +        object_reset(an_object); +        processing.remove("verse"); +        ++cntr; +      } +      obj_cite_number_poem["end"] = +        to!string(obj_cite_number); +      type["blocks"] = TriState.closing; +      type["poem"] = TriState.closing; +      type["curly_poem"] = TriState.off; +    } else { +      processing["verse"] ~= line ~= "\n"; +      if (type["verse_new"] == State.on) { +        obj_cite_number = +          ocn_emit(type["ocn_status"]); +        type["verse_new"] = State.off; +      } else if (matchFirst(line, rgx.newline_eol_delimiter_only)) { +        verse_line = TriState.off; +        type["verse_new"] = State.on; +      } +      if (type["verse_new"] == State.on) { +        verse_line=1; +        an_object[an_object_key] = processing["verse"]; +        debug(poem) {                          // poem verse +          writefln( +            "* %s curly\n%s", +            obj_cite_number, +            an_object[an_object_key] +          ); +        } +        processing.remove("verse"); +        an_object["is"] = "verse"; +        auto comp_obj_location = node_construct.node_location_emitter( +          content_non_header, +          segment_anchor_tag_that_object_belongs_to, +          obj_cite_number, +          cntr, +          heading_ptr-1, +          an_object["is"] +        ); +        auto substantive_object_and_anchor_tags_tuple = +          obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +        an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +        anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +        comp_obj_block                            = comp_obj_block.init; +        comp_obj_block.use                        = "body"; +        comp_obj_block.is_of                      = "block"; +        comp_obj_block.is_a                       = "verse"; +        comp_obj_block.ocn                        = obj_cite_number; +        comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +        comp_obj_block.text                       = an_object["substantive"]; +        the_document_body_section                 ~= comp_obj_block; +        object_reset(an_object); +        processing.remove("verse"); +        ++cntr; +      } +    } +  } else if (type["tic_poem"] == TriState.on) { +    if (auto m = matchFirst(line, rgx.block_tic_close)) { // tic_poem_close +      an_object[an_object_key]="verse"; +      debug(poem) {                                       // poem (curly) close +        writefln( +          "* [poem tic] %s", +          line +        ); +      } +      if (processing.length > 0) { +        an_object[an_object_key] = processing["verse"]; +      } +      if (an_object.length > 0) { +        debug(poem) {                                     // poem (tic) close +          writeln(__LINE__); +          writeln(obj_cite_number, line); +        } +        processing.remove("verse"); +        an_object["is"] = "verse"; +        auto substantive_object_and_anchor_tags_tuple = +          obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +        an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +        anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +        comp_obj_block                            = comp_obj_block.init; +        comp_obj_block.use                        = "body"; +        comp_obj_block.is_of                      = "block"; +        comp_obj_block.is_a                       = "verse"; +        comp_obj_block.ocn                        = obj_cite_number; +        comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +        comp_obj_block.text                       = an_object["substantive"]; +        the_document_body_section                 ~= comp_obj_block; +        obj_cite_number_poem["end"]               = to!string(obj_cite_number); +        object_reset(an_object); +        processing.remove("verse"); +        ++cntr; +      } +      type["blocks"] = TriState.closing; +      type["poem"] = TriState.closing; +      type["tic_poem"] = TriState.off; +    } else { +      processing["verse"] ~= line ~= "\n"; +      if (type["verse_new"] == State.on) { +        obj_cite_number = +          ocn_emit(type["ocn_status"]); +        type["verse_new"] = State.off; +      } else if (matchFirst(line, rgx.newline_eol_delimiter_only)) { +        type["verse_new"] = State.on; +        verse_line = TriState.off; +      } +      if (type["verse_new"] == State.on) { +        verse_line=1; +        an_object[an_object_key] = processing["verse"]; +        debug(poem) {                            // poem (tic) close +          writefln( +            "* %s tic\n%s", +            obj_cite_number, +            an_object[an_object_key] +          ); +        } +        processing.remove("verse"); +        an_object["is"] = "verse"; +        auto comp_obj_location = +          node_construct.node_location_emitter( +            content_non_header, +            segment_anchor_tag_that_object_belongs_to, +            obj_cite_number, +            cntr, +            heading_ptr-1, +            an_object["is"] +          ); +        auto substantive_object_and_anchor_tags_tuple = +          obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +        an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +        anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +        comp_obj_block                            = comp_obj_block.init; +        comp_obj_block.use                        = "body"; +        comp_obj_block.is_of                      = "block"; +        comp_obj_block.is_a                       = "verse"; +        comp_obj_block.ocn                        = obj_cite_number; +        comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +        comp_obj_block.text                       = an_object["substantive"]; +        the_document_body_section                 ~= comp_obj_block; +        object_reset(an_object); +        processing.remove("verse"); +        ++cntr; +      } +    } +  } +} +#+END_SRC + +***** group block                                                 :group: + +#+name: abs_functions_block_group +#+BEGIN_SRC d +void _group_block_(L,O,T)( +  ref L line, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)      == char[])); +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(type)      == int[string])); +  } +  auto rgx = Rgx(); +  if (type["curly_group"] == State.on) { +    if (matchFirst(line, rgx.block_curly_group_close)) { +      debug(group) {                              // group (curly) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["group"] = TriState.closing; +      type["curly_group"] = TriState.off; +    } else { +      debug(group) {                              // group +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build group array (or string) +    } +  } else if (type["tic_group"] == TriState.on) { +    if (matchFirst(line, rgx.block_tic_close)) { +      debug(group) {                              // group (tic) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["group"] = TriState.closing; +      type["tic_group"] = TriState.off; +    } else { +      debug(group) {                              // group +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build group array (or string) +    } +  } +} +#+END_SRC + +***** block block                                                 :block: + +#+name: abs_functions_block_block +#+BEGIN_SRC d +void _block_block_(L,O,T)( +  ref L line, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)      == char[])); +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(type)      == int[string])); +  } +  auto rgx = Rgx(); +  if (type["curly_block"] == TriState.on) { +    if (matchFirst(line, rgx.block_curly_block_close)) { +      debug(block) {                             // block (curly) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["block"] = TriState.closing; +      type["curly_block"] = TriState.off; +    } else { +      debug(block) {                             // block +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build block array (or string) +    } +  } else if (type["tic_block"] == TriState.on) { +    if (matchFirst(line, rgx.block_tic_close)) { +      debug(block) {                              // block (tic) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["block"] = TriState.closing; +      type["tic_block"] = TriState.off; +    } else { +      debug(block) {                             // block +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build block array (or string) +    } +  } +} +#+END_SRC + +***** quote block                                                 :quote: + +#+name: abs_functions_block_quote +#+BEGIN_SRC d +void _quote_block_(L,O,T)( +  ref L line, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)      == char[])); +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(type)      == int[string])); +  } +  auto rgx = Rgx(); +  if (type["curly_quote"] == TriState.on) { +    if (matchFirst(line, rgx.block_curly_quote_close)) { +      debug(quote) {                              // quote (curly) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["quote"] = TriState.closing; +      type["curly_quote"] = TriState.off; +    } else { +      debug(quote) { +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build quote array (or string) +    } +  } else if (type["tic_quote"] == TriState.on) { +    if (matchFirst(line, rgx.block_tic_close)) { +      debug(quote) {                              // quote (tic) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["quote"] = TriState.closing; +      type["tic_quote"] = TriState.off; +    } else { +      debug(quote) { +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";   // build quote array (or string) +    } +  } +} +#+END_SRC + +***** table block                                                 :table: + +#+name: abs_functions_block_table +#+BEGIN_SRC d +void _table_block_(L,O,T)( +  ref L line, +  ref O an_object, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)      == char[])); +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(type)      == int[string])); +  } +  auto rgx = Rgx(); +  if (type["curly_table"] == TriState.on) { +    if (matchFirst(line, rgx.block_curly_table_close)) { +      debug(table) {                           // table (curly) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["table"] = TriState.closing; +      type["curly_table"] = TriState.off; +    } else { +      debug(table) {                           // table +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";           // build table array (or string) +    } +  } else if (type["tic_table"] == TriState.on) { +    if (matchFirst(line, rgx.block_tic_close)) { +      debug(table) {                           // table (tic) close +        writeln(line); +      } +      type["blocks"] = TriState.closing; +      type["table"] = TriState.closing; +      type["tic_table"] = TriState.off; +    } else { +      debug(table) {                           // table +        writeln(line); +      } +      an_object[an_object_key] ~= line ~= "\n";           // build table array (or string) +    } +  } +} +#+END_SRC + +**** block end (close an open block): line empty, block flag       :close: + +#+name: abs_functions_block_line_status_empty +#+BEGIN_SRC d +void _block_flag_line_empty_( +  char[]                       line, +  ref string[string]           an_object, +  ref ObjGenericComposite[]    the_document_body_section, +  ref string[][string][string] bookindex_unordered_hashes, +  ref int                      obj_cite_number, +  ref ObjGenericComposite      _comp_obj_heading, +  ref int                      cntr, +  ref int[string]              type, +  string[string]               obj_cite_number_poem, +  string[string][string]       dochead_make_aa, +) { +  // line.empty, post contents, empty variables --------------- +  assert( +    line.empty, +    "line should be empty" +  ); +  assert( +    (type["blocks"] == TriState.closing), +    "code block status: closed" +  ); +  assertions_flag_types_block_status_none_or_closed(type); +  if (type["code"] == TriState.closing) { +    obj_cite_number = +      ocn_emit(type["ocn_status"]); +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "code"; +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +      ); +    auto substantive_object_and_anchor_tags_tuple = +      obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +    an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +    anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +    comp_obj_code                             = comp_obj_code.init; +    comp_obj_code.use                         = "body"; +    comp_obj_code.is_of                       = "block"; +    comp_obj_code.is_a                        = "code"; +    comp_obj_code.ocn                         = obj_cite_number; +    comp_obj_code.obj_cite_number             = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    comp_obj_code.text                        = an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_code; +    object_reset(an_object); +    processing.remove("verse"); +    ++cntr; +    type["blocks"] = TriState.off; +    type["code"] = TriState.off; +  } else if (type["poem"] == TriState.closing) { +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "verse"; // check also +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +      ); +    comp_obj_poem_ocn                         = comp_obj_poem_ocn.init; +    comp_obj_poem_ocn.use                     = "body"; +    comp_obj_poem_ocn.is_of                   = "block"; +    comp_obj_poem_ocn.is_a                    = "poem"; +    comp_obj_poem_ocn.ocn                     = obj_cite_number; +    comp_obj_poem_ocn.obj_cite_number         = (obj_cite_number_poem["start"], obj_cite_number_poem["end"]); +    comp_obj_poem_ocn.text                    = ""; // an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_poem_ocn; +    object_reset(an_object); +    processing.remove("verse"); +    type["blocks"] = TriState.off; +    type["poem"] = TriState.off; +  } else if (type["table"] == TriState.closing) { +    obj_cite_number = +      ocn_emit(type["ocn_status"]); +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "table"; +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +      ); +    auto substantive_object_and_anchor_tags_tuple = +      obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +    an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +    anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +    comp_obj_block                            = comp_obj_block.init; +    comp_obj_block.use                        = "body"; +    comp_obj_block.is_of                      = "block"; +    comp_obj_block.is_a                       = "table"; +    comp_obj_block.ocn                        = obj_cite_number; +    comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    comp_obj_block.text                       = an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_block; +    object_reset(an_object); +    processing.remove("verse"); +    ++cntr; +    type["blocks"] = TriState.off; +    type["table"] = TriState.off; +  } else if (type["group"] == TriState.closing) { +    obj_cite_number = +      ocn_emit(type["ocn_status"]); +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "group"; +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +      ); +    auto substantive_object_and_anchor_tags_tuple = +      obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +    an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +    anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +    comp_obj_block                            = comp_obj_block.init; +    comp_obj_block.use                        = "body"; +    comp_obj_block.is_of                      = "block"; +    comp_obj_block.is_a                       = "group"; +    comp_obj_block.ocn                        = obj_cite_number; +    comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    comp_obj_block.text                       = an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_block; +    object_reset(an_object); +    processing.remove("verse"); +    ++cntr; +    type["blocks"] = TriState.off; +    type["group"] = TriState.off; +  } else if (type["block"] == TriState.closing) { +    obj_cite_number = ocn_emit(type["ocn_status"]); +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "block"; +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +       ); +    auto substantive_object_and_anchor_tags_tuple = +      obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +    an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +    anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +    comp_obj_block                            = comp_obj_block.init; +    comp_obj_block.use                        = "body"; +    comp_obj_block.is_of                      = "block"; +    comp_obj_block.is_a                       = "block"; +    comp_obj_block.ocn                        = obj_cite_number; +    comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    comp_obj_block.text                       = an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_block; +    object_reset(an_object); +    processing.remove("verse"); +    ++cntr; +    type["blocks"] = TriState.off; +    type["block"] = TriState.off; +  } else if (type["quote"] == TriState.closing) { +    obj_cite_number = +      ocn_emit(type["ocn_status"]); +    an_object["bookindex_nugget"] = +      ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; +    bookindex_unordered_hashes = +      bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); +    an_object["is"] = "quote"; +    auto comp_obj_location = +      node_construct.node_location_emitter( +        content_non_header, +        segment_anchor_tag_that_object_belongs_to, +        obj_cite_number, +        cntr, +        heading_ptr-1, +        an_object["is"] +      ); +    auto substantive_object_and_anchor_tags_tuple = +      obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); +    an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; +    anchor_tags = substantive_object_and_anchor_tags_tuple[1]; +    comp_obj_block                            = comp_obj_block.init; +    comp_obj_block.use                        = "body"; +    comp_obj_block.is_of                      = "block"; +    comp_obj_block.is_a                       = "quote"; +    comp_obj_block.ocn                        = obj_cite_number; +    comp_obj_block.obj_cite_number            = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    comp_obj_block.text                       = an_object["substantive"]; +    the_document_body_section                 ~= comp_obj_block; +    object_reset(an_object); +    processing.remove("verse"); +    ++cntr; +    type["blocks"] = TriState.off; +    type["quote"] = TriState.off; +  } +} +#+END_SRC + +*** book index                                                  :bookindex: + +#+name: abs_functions_book_index +#+BEGIN_SRC d +auto _book_index_(L,I,O,T,B)( +  L      line, +  ref I  book_idx_tmp, +  ref O  an_object, +  ref T  type, +  B      opt_action_bool, +) { +  debug(asserts){ +    static assert(is(typeof(line)            == char[])); +    static assert(is(typeof(book_idx_tmp)    == string)); +    static assert(is(typeof(an_object)       == string[string])); +    static assert(is(typeof(type)            == int[string])); +    static assert(is(typeof(opt_action_bool) == bool[string])); +  } +  auto rgx = Rgx(); +  if (auto m = match(line, rgx.book_index)) { +    /+ match book_index +/ +    debug(bookindexmatch) {                       // book index +      writefln( +        "* [bookindex] %s\n", +        to!string(m.captures[1]), +      ); +    } +    an_object["bookindex_nugget"] = to!string(m.captures[1]); +  } else if (auto m = match(line, rgx.book_index_open))  { +    /+ match open book_index +/ +    type["book_index"] = State.on; +    if (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"]) { +      book_idx_tmp = to!string(m.captures[1]); +      debug(bookindexmatch) {                       // book index +        writefln( +          "* [bookindex] %s\n", +          book_idx_tmp, +        ); +      } +    } +  } else if (type["book_index"] == State.on )  { +    /+ book_index flag set +/ +    if (auto m = match(line, rgx.book_index_close))  { +      type["book_index"] = State.off; +      if (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"]) { +        an_object["bookindex_nugget"] = book_idx_tmp ~ to!string(m.captures[1]); +        debug(bookindexmatch) {                     // book index +          writefln( +            "* [bookindex] %s\n", +            book_idx_tmp, +          ); +        } +      } +      book_idx_tmp = ""; +    } else { +      if (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"]) { +        book_idx_tmp ~= line; +      } +    } +  } +} +#+END_SRC + +*** heading or paragraph                                :heading:paragraph: +**** heading found                                               :heading: + +#+name: abs_functions_heading +#+BEGIN_SRC d +auto _heading_found_(L,X,H,R,T)( +  L     line, +  X     dochead_make_identify_unmarked_headings, +  ref H heading_match_str, +  ref R heading_match_rgx, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)                                    == char[])); +    static assert(is(typeof(dochead_make_identify_unmarked_headings) == string)); +    static assert(is(typeof(heading_match_str)                       == string[string])); +    static assert(is(typeof(heading_match_rgx)                       == Regex!(char)[string])); +    static assert(is(typeof(type)                                    == int[string])); +  } +  auto rgx = Rgx(); +  if ((dochead_make_identify_unmarked_headings.length > 2) +  && (type["make_headings"] == State.off)) { +    /+ headings found +/ +    debug(headingsfound) { +      writeln(dochead_make_identify_unmarked_headings); +    } +    char[][] make_headings_spl = +      split( +        cast(char[]) dochead_make_identify_unmarked_headings, +        rgx.make_heading_delimiter); +    debug(headingsfound) { +      writeln(make_headings_spl.length); +      writeln(make_headings_spl); +    } +    switch (make_headings_spl.length) { +    case 7 : +      if (!empty(make_headings_spl[6])) { +        heading_match_str["h_4"] = +          "^(" ~ to!string(make_headings_spl[6]) ~ ")"; +        heading_match_rgx["h_4"] = +          regex(heading_match_str["h_4"]); +      } +      goto case; +    case 6 : +      if (!empty(make_headings_spl[5])) { +        heading_match_str["h_3"] = +          "^(" ~ to!string(make_headings_spl[5]) ~ ")"; +        heading_match_rgx["h_3"] = +          regex(heading_match_str["h_3"]); +      } +      goto case; +    case 5 : +      if (!empty(make_headings_spl[4])) { +        heading_match_str["h_2"] = +          "^(" ~ to!string(make_headings_spl[4]) ~ ")"; +        heading_match_rgx["h_2"] = +          regex(heading_match_str["h_2"]); +      } +      goto case; +    case 4 : +      if (!empty(make_headings_spl[3])) { +        heading_match_str["h_1"] = +          "^(" ~ to!string(make_headings_spl[3]) ~ ")"; +        heading_match_rgx["h_1"] = +          regex(heading_match_str["h_1"]); +      } +      goto case; +    case 3 : +      if (!empty(make_headings_spl[2])) { +        heading_match_str["h_D"] = +          "^(" ~ to!string(make_headings_spl[2]) ~ ")"; +        heading_match_rgx["h_D"] = +          regex(heading_match_str["h_D"]); +      } +      goto case; +    case 2 : +      if (!empty(make_headings_spl[1])) { +        heading_match_str["h_C"] = +          "^(" ~ to!string(make_headings_spl[1]) ~ ")"; +        heading_match_rgx["h_C"] = +          regex(heading_match_str["h_C"]); +      } +      goto case; +    case 1 : +      if (!empty(make_headings_spl[0])) { +        heading_match_str["h_B"] = +          "^(" ~ to!string(make_headings_spl[0]) ~ ")"; +        heading_match_rgx["h_B"] = +          regex(heading_match_str["h_B"]); +      } +      break; +    default: +      break; +    } +    type["make_headings"] = State.on; +  } +} +#+END_SRC + +**** heading make set                                       :heading: + +#+name: abs_functions_heading +#+BEGIN_SRC d +auto _heading_make_set_(L,C,R,T)( +  L     line, +  C     line_occur, +  ref R heading_match_rgx, +  ref T type +) { +  debug(asserts){ +    static assert(is(typeof(line)              == char[])); +    static assert(is(typeof(line_occur)        == int[string])); +    static assert(is(typeof(heading_match_rgx) == Regex!(char)[string])); +    static assert(is(typeof(type)              == int[string])); +  } +  if ((type["make_headings"] == State.on) +  && ((line_occur["para"] == State.off) +  && (line_occur["heading"] == State.off)) +  && ((type["para"] == State.off) +  && (type["heading"] == State.off))) { +    /+ heading make set +/ +    if (matchFirst(line, heading_match_rgx["h_B"])) { +      line = "B~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_C"])) { +      line = "C~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_D"])) { +      line = "D~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_1"])) { +      line = "1~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_2"])) { +      line = "2~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_3"])) { +      line = "3~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +    if (matchFirst(line, heading_match_rgx["h_4"])) { +      line = "4~ " ~ line; +      debug(headingsfound) { +        writeln(line); +      } +    } +  } +} +#+END_SRC + +**** heading match                                               :heading: + +#+name: abs_functions_heading +#+BEGIN_SRC d +auto _heading_matched_(L,C,O,K,Lv,Lc,T,Me)( +  ref L  line, +  ref C  line_occur, +  ref O  an_object, +  ref K  an_object_key, +  ref Lv lv, +  ref Lc collapsed_lev, +  ref T  type, +  ref Me dochead_meta_aa, +) { +  debug(asserts){ +    static assert(is(typeof(line)            == char[])); +    static assert(is(typeof(line_occur)      == int[string])); +    static assert(is(typeof(an_object)       == string[string])); +    static assert(is(typeof(an_object_key)   == string)); +    static assert(is(typeof(lv)              == int[string])); +    static assert(is(typeof(collapsed_lev)   == int[string])); +    static assert(is(typeof(type)            == int[string])); +    static assert(is(typeof(dochead_meta_aa) == string[string][string])); +  } +  auto rgx = Rgx(); +  if (auto m = match(line, rgx.heading)) { +    /+ heading match +/ +    type["heading"] = State.on; +    if (match(line, rgx.heading_seg_and_above)) { +      type["biblio_section"] = State.off; +      type["glossary_section"] = State.off; +      type["blurb_section"] = State.off; +    } +    type["para"] = State.off; +    ++line_occur["heading"]; +    an_object[an_object_key] ~= line ~= "\n"; +    an_object["lev"] ~= m.captures[1]; +    assertions_doc_structure(an_object, lv); // includes most of the logic for collapsed levels +    switch (an_object["lev"]) { +    case "A": +      an_object[an_object_key]=replaceFirst(an_object[an_object_key], +        rgx.variable_doc_title, (dochead_meta_aa["title"]["full"] ~ ",")); +      an_object[an_object_key]=replaceFirst(an_object[an_object_key], +        rgx.variable_doc_author, dochead_meta_aa["creator"]["author"]); +      collapsed_lev["h0"] = 0; +      an_object["lev_collapsed_number"] = +        to!string(collapsed_lev["h0"]); +      lv["lv"] = DocStructMarkupHeading.h_sect_A; +      ++lv["h0"]; +      lv["h1"] = State.off; +      lv["h2"] = State.off; +      lv["h3"] = State.off; +      lv["h4"] = State.off; +      lv["h5"] = State.off; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "B": +      collapsed_lev["h1"] = collapsed_lev["h0"] + 1; +      an_object["lev_collapsed_number"] = +        to!string(collapsed_lev["h1"]); +      lv["lv"] = DocStructMarkupHeading.h_sect_B; +      ++lv["h1"]; +      lv["h2"] = State.off; +      lv["h3"] = State.off; +      lv["h4"] = State.off; +      lv["h5"] = State.off; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "C": +      collapsed_lev["h2"] = collapsed_lev["h1"] + 1; +      an_object["lev_collapsed_number"] = +        to!string(collapsed_lev["h2"]); +      lv["lv"] = DocStructMarkupHeading.h_sect_C; +      ++lv["h2"]; +      lv["h3"] = State.off; +      lv["h4"] = State.off; +      lv["h5"] = State.off; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "D": +      collapsed_lev["h3"] = collapsed_lev["h2"] + 1; +      an_object["lev_collapsed_number"] = +        to!string(collapsed_lev["h3"]); +      lv["lv"] = DocStructMarkupHeading.h_sect_D; +      ++lv["h3"]; +      lv["h4"] = State.off; +      lv["h5"] = State.off; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "1": +      if (lv["h3"] > State.off) { +        collapsed_lev["h4"] = collapsed_lev["h3"] + 1; +      } else if (lv["h2"] > State.off) { +        collapsed_lev["h4"] = collapsed_lev["h2"] + 1; +      } else if (lv["h1"] > State.off) { +        collapsed_lev["h4"] = collapsed_lev["h1"] + 1; +      } else if (lv["h0"] > State.off) { +        collapsed_lev["h4"] = collapsed_lev["h0"] + 1; +      } +      an_object["lev_collapsed_number"] = +        to!string(collapsed_lev["h4"]); +      lv["lv"] = DocStructMarkupHeading.h_text_1; +      ++lv["h4"]; +      lv["h5"] = State.off; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "2": +      if (lv["h5"] > State.off) { +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h5"]); +      } else if (lv["h4"] > State.off) { +        collapsed_lev["h5"] = collapsed_lev["h4"] + 1; +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h5"]); +      } +      lv["lv"] = DocStructMarkupHeading.h_text_2; +      ++lv["h5"]; +      lv["h6"] = State.off; +      lv["h7"] = State.off; +      goto default; +    case "3": +      if (lv["h6"] > State.off) { +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h6"]); +      } else if (lv["h5"] > State.off) { +        collapsed_lev["h6"] = collapsed_lev["h5"] + 1; +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h6"]); +      } +      lv["lv"] = DocStructMarkupHeading.h_text_3; +      ++lv["h6"]; +      lv["h7"] = State.off; +      goto default; +    case "4": +      if (lv["h7"] > State.off) { +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h7"]); +      } else if (lv["h6"] > State.off) { +        collapsed_lev["h7"] = collapsed_lev["h6"] + 1; +        an_object["lev_collapsed_number"] = +          to!string(collapsed_lev["h7"]); +      } +      lv["lv"] = DocStructMarkupHeading.h_text_4; +      ++lv["h7"]; +      goto default; +    default: +      an_object["lev_markup_number"] = to!string(lv["lv"]); +    } +    debug(heading) {                         // heading +      writeln(strip(line)); +    } +  } +} +#+END_SRC + +**** para match                                                     :para: + +#+name: abs_functions_para +#+BEGIN_SRC d +auto _para_match_(L,O,K,I,B,T,C)( +  ref L  line, +  ref O  an_object, +  ref K  an_object_key, +  ref I  indent, +  ref B  bullet, +  ref T  type, +  ref C  line_occur, +) { +  debug(asserts){ +    static assert(is(typeof(line)          == char[])); +    static assert(is(typeof(an_object)     == string[string])); +    static assert(is(typeof(an_object_key) == string)); +    static assert(is(typeof(indent)        == int[string])); +    static assert(is(typeof(bullet)        == bool)); +    static assert(is(typeof(type)          == int[string])); +    static assert(is(typeof(line_occur)    == int[string])); +  } +  auto rgx = Rgx(); +  if (line_occur["para"] == State.off) { +    /+ para matches +/ +    type["para"] = State.on; +    an_object[an_object_key] ~= line;        // body_nugget +    indent=[ +      "hang_position" : 0, +      "base_position" : 0, +    ]; +    bullet = false; +    if (auto m = matchFirst(line, rgx.para_indent)) { +      debug(paraindent) {                    // para indent +        writeln(line); +      } +      indent["hang_position"] = to!int(m.captures[1]); +      indent["base_position"] = 0; +    } else if (matchFirst(line, rgx.para_bullet)) { +      debug(parabullet) {                    // para bullet +        writeln(line); +      } +      bullet = true; +    } else if (auto m = matchFirst(line, rgx.para_indent_hang)) { +      debug(paraindenthang) {                // para indent hang +        writeln(line); +      } +      indent=[ +        "hang_position" : to!int(m.captures[1]), +        "base_position" : to!int(m.captures[2]), +      ]; +    } else if (auto m = matchFirst(line, rgx.para_bullet_indent)) { +      debug(parabulletindent) {              // para bullet indent +        writeln(line); +      } +      indent=[ +        "hang_position" : to!int(m.captures[1]), +        "base_position" : 0, +      ]; +      bullet = true; +    } +    ++line_occur["para"]; +  } +} +#+END_SRC + +*** function emitters                                            :emitters: +**** object                                                       :object: +***** ocn                                                           :ocn: + +#+name: ao_emitters_ocn +#+BEGIN_SRC d +struct OCNemitter { +  int obj_cite_number, obj_cite_number_; +  int ocn_emitter(int ocn_status_flag) +  in { assert(ocn_status_flag <= 3); } +  body { +    if (ocn_status_flag == 3) { +      obj_cite_number = obj_cite_number_ = 1; +    } else { +      obj_cite_number=(ocn_status_flag == 0) +      ? ++obj_cite_number_ +      : 0; +    } +    assert(obj_cite_number >= 0); +    return obj_cite_number; +  } +  invariant() { +  } +} +#+END_SRC + +***** object inline markup munge                          :markup:inline: + +#+name: ao_emitters_obj_inline_markup_munge +#+BEGIN_SRC d +struct ObjInlineMarkupMunge { +  string[string] obj_txt; +  int n_foot, n_foot_reg, n_foot_sp_asterisk, n_foot_sp_plus; +  string asterisks_; +  string obj_txt_out, tail, note; +  auto rgx = Rgx(); +  auto mkup = InlineMarkup(); +  private auto initialize_note_numbers() { +    n_foot = 0; +    n_foot_reg = 0; +    n_foot_sp_asterisk = 0; +    n_foot_sp_plus = 0; +  } +  string url_links(Ot)(Ot obj_txt_in) { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +    /+ url matched +/ +    if (auto m = matchAll(obj_txt_in, rgx.inline_url)) { +      /+ link: naked url: http://url +/ +      if (match(obj_txt_in, rgx.inline_link_naked_url)) { +        obj_txt_in = +          replaceAll( +            obj_txt_in, +            rgx.inline_link_naked_url, +            ("$1" ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~  mkup.url_o ~ "$2" ~  mkup.url_c ~ "$3")            // ("$1{ $2 }$2$3") +          ); +      } +      /+ link with helper for endnote including the url: +           {~^ link which includes url as footnote }http://url +         maps to: +           { link which includes url as footnote }http://url~{ { http://url }http://url }~ +      +/ +      if (match(obj_txt_in, rgx.inline_link_endnote_url_helper)) { +        obj_txt_in = +          replaceAll( +            obj_txt_in, +            rgx.inline_link_endnote_url_helper_punctuated, +            (mkup.lnk_o ~ " $1 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ "~{ " ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~  " }~$3") // ("{ $1 }$2~{ { $2 }$2 }~$3") +          ); +        obj_txt_in = +          replaceAll( +            obj_txt_in, +            rgx.inline_link_endnote_url_helper, +            (mkup.lnk_o ~ " $1 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ "~{ " ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~  " }~")   // ("{ $1 }$2~{ { $2 }$2 }~") +          ); +      } +      /+ link with regular markup: +         { linked text or image }http://url +      +/ +      if (match(obj_txt_in, rgx.inline_link_markup_regular)) { +        obj_txt_in = +          replaceAll( +            obj_txt_in, +            rgx.inline_link_markup_regular, +            ("$1" ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~  mkup.url_o ~ "$3" ~  mkup.url_c ~ "$4")            // ("$1{ $2 }$3$4") +          ); +      } +    } +    return obj_txt_in; +  } +  string footnotes_endnotes_markup_and_number_or_stars(Ot)(Ot obj_txt_in) {                                // here endnotes are marked up +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +    /+ endnotes (regular) +/ +    obj_txt_in = +      replaceAll( +        obj_txt_in, +        rgx.inline_notes_curly, +        (mkup.en_a_o ~ " $1" ~ mkup.en_a_c) +      ); +    if (match(obj_txt_in, rgx.inline_notes_al_gen)) { +      if (auto m = matchAll(obj_txt_in, rgx.inline_text_and_note_al_)) { +        foreach(n; m) { +          if (match(to!string(n.hit), rgx.inline_al_delimiter_open_symbol_star)) { +            ++n_foot_sp_asterisk; +            asterisks_ = "*"; +            n_foot=n_foot_sp_asterisk; +            obj_txt_out ~= +              (replaceFirst( +                to!string(n.hit), +                rgx.inline_al_delimiter_open_symbol_star, +                (mkup.en_a_o ~ replicate(asterisks_, n_foot_sp_asterisk) ~ " ") +              ) ~ "\n"); +          } else if (match(to!string(n.hit), rgx.inline_al_delimiter_open_regular)) { +            ++n_foot_reg; +            n_foot=n_foot_reg; +            obj_txt_out ~= +              (replaceFirst( +                to!string(n.hit), +                rgx.inline_al_delimiter_open_regular, +                (mkup.en_a_o ~ to!string(n_foot) ~ " ") +              ) ~ "\n"); +          } else { +            obj_txt_out ~= to!string(n.hit) ~ "\n"; +          } +        } +      } +    } else { +      obj_txt_out = obj_txt_in; +    } +    return obj_txt_out; +  } +  private auto object_notes_(string obj_txt_in) +  in { } +  body { +    obj_txt_out = ""; +    tail = ""; +    /+ special endnotes +/ +    obj_txt_in = replaceAll( +      obj_txt_in, +      rgx.inline_notes_curly_sp_asterisk, +      (mkup.en_a_o ~ "*" ~ " $1" ~ mkup.en_a_c) +    ); +    obj_txt_in = +      replaceAll( +        obj_txt_in, +        rgx.inline_notes_curly_sp_plus, +        (mkup.en_a_o ~ "+" ~ " $1" ~ mkup.en_a_c) +      ); +    /+ url matched +/ +    if (auto m = matchAll(obj_txt_in, rgx.inline_url)) { +      obj_txt_in = url_links(obj_txt_in); +    } +    obj_txt_out = footnotes_endnotes_markup_and_number_or_stars(obj_txt_in); +    debug(footnotes) { +      writeln(obj_txt_out, tail); +    } +    obj_txt_out = obj_txt_out ~ tail; +    debug(footnotesdone) { +      foreach(m; matchAll(obj_txt_out, +      (mkup.en_a_o ~ `\s*(.+?)` ~ mkup.en_a_c))) { +        writeln(m.captures[1]); +        writeln(m.hit); +      } +    } +    return obj_txt_out; +  } +  string para(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.para_attribs, ""); +    obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, ""); +    obj_txt["munge"]=object_notes_(obj_txt["munge"]); +    debug(munge) { +      writeln(__LINE__); +      writeln(obj_txt_in); +      writeln(__LINE__); +      writeln(to!string(obj_txt["munge"])); +    } +    return obj_txt["munge"]; +  } +  string heading(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.heading, ""); +    obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, ""); +    obj_txt["munge"]=strip(obj_txt["munge"]); +    obj_txt["munge"]=object_notes_(obj_txt["munge"]); +    debug(munge) { +      writeln(__LINE__); +      writeln(obj_txt_in); +      writeln(__LINE__); +      writeln(to!string(obj_txt["munge"])); +    } +    return obj_txt["munge"]; +  } +  invariant() { +  } +  /+ revisit +/ +  string code(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string group(string obj_txt_in) +  in { } +  body { +    obj_txt["munge"]=obj_txt_in; +    obj_txt["munge"]=object_notes_(obj_txt["munge"]); +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string block(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    obj_txt["munge"]=object_notes_(obj_txt["munge"]); +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string verse(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    obj_txt["munge"]=object_notes_(obj_txt["munge"]); +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string quote(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string table(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    return obj_txt["munge"]; +  } +  invariant() { +  } +  string comment(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    obj_txt["munge"]=obj_txt_in; +    return obj_txt["munge"]; +  } +  invariant() { +  } +} +#+END_SRC + +***** toc, tags, object inline markup                     :markup:inline: +****** open + +#+name: ao_emitters_obj_inline_markup +#+BEGIN_SRC d +struct ObjInlineMarkup { +  auto rgx = Rgx(); +  auto munge = ObjInlineMarkupMunge(); +  string[string] obj_txt; +#+END_SRC + +****** object inline markup and anchor tags              :markup:inline: + +#+name: ao_emitters_obj_inline_markup_and_anchor_tags +#+BEGIN_SRC d +  auto obj_inline_markup_and_anchor_tags(O,K,Ma)( +    O  obj_, +    K  obj_key_, +    Ma dochead_make_aa +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_)            == string[string])); +      static assert(is(typeof(obj_key_)        == string)); +      static assert(is(typeof(dochead_make_aa) == string[string][string])); +    } +  } +  body { +    obj_txt["munge"]=obj_[obj_key_].dup; +    obj_txt["munge"]=(match(obj_["is"], ctRegex!(`verse|code`))) +    ? obj_txt["munge"] +    : strip(obj_txt["munge"]); +    static __gshared string[] anchor_tags_ = []; +    switch (obj_["is"]) { +    case "heading": +      static __gshared string anchor_tag = ""; +      // TODO WORK ON, you still need to ensure that level 1 anchor_tags are unique +      obj_txt["munge"]=_configured_auto_heading_numbering_and_segment_anchor_tags(obj_txt["munge"], obj_, dochead_make_aa); +      obj_txt["munge"]=_make_segment_anchor_tags_if_none_provided(obj_txt["munge"], obj_["lev"]); +      if (auto m = match(obj_txt["munge"], rgx.heading_anchor_tag)) { +        anchor_tag = m.captures[1]; +        anchor_tags_ ~=anchor_tag; +      } else if (obj_["lev"] == "1") { +        writeln("heading anchor tag missing: ", obj_txt["munge"]); +      } +      obj_txt["munge"]=munge.heading(obj_txt["munge"]); +      break; +    case "para": +      obj_txt["munge"]=munge.para(obj_txt["munge"]); +      break; +    case "code": +      obj_txt["munge"]=munge.code(obj_txt["munge"]); +      break; +    case "group": +      obj_txt["munge"]=munge.group(obj_txt["munge"]); +      break; +    case "block": +      obj_txt["munge"]=munge.block(obj_txt["munge"]); +      break; +    case "verse": +      obj_txt["munge"]=munge.verse(obj_txt["munge"]); +      break; +    case "quote": +      obj_txt["munge"]=munge.quote(obj_txt["munge"]); +      break; +    case "table": +      obj_txt["munge"]=munge.table(obj_txt["munge"]); +      break; +    case "comment": +      obj_txt["munge"]=munge.comment(obj_txt["munge"]); +      break; +    case "doc_end_reset": +      munge.initialize_note_numbers(); +      break; +    default: +      break; +    } +    auto t = tuple( +     obj_txt["munge"], +     anchor_tags_, +    ); +    anchor_tags_=[]; +    return t; +  } +  invariant() { +  } +#+END_SRC + +****** toc, table of contents build, gather headings     :markup:inline: + +#+name: ao_emitters_obj_inline_markup_table_of_contents +#+BEGIN_SRC d +  auto _clean_heading_toc_(Toc)( +    Toc heading_toc_, +  ) { +   debug(asserts){ +     static assert(is(typeof(heading_toc_) == char[])); +   } +   auto m = matchFirst(cast(char[]) heading_toc_, rgx.heading); +   heading_toc_ = +     replaceAll( +       m.post, +       rgx.inline_notes_curly_gen, +       ("") +     ); +   return heading_toc_; +  }; +  auto table_of_contents_gather_headings(O,Ma,Ts,Ta,X,Toc)( +    O     obj_, +    Ma    dochead_make_aa, +    Ts    segment_anchor_tag_that_object_belongs_to, +    Ta    _anchor_tag, +    ref X lev4_subtoc, +    Toc   the_table_of_contents_section, +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_)                                      == string[string])); +      static assert(is(typeof(dochead_make_aa)                           == string[string][string])); +      static assert(is(typeof(segment_anchor_tag_that_object_belongs_to) == string)); +      static assert(is(typeof(_anchor_tag)                               == string)); +      static assert(is(typeof(lev4_subtoc)                               == string[][string])); +      static assert(is(typeof(the_table_of_contents_section)             == ObjGenericComposite[][string])); +    } +  } +  body { +    ObjGenericComposite comp_obj_toc; +    mixin InternalMarkup; +    auto mkup = InlineMarkup(); +    char[] heading_toc_ = to!(char[])(obj_["body_nugget"].dup.strip); +    heading_toc_ = _clean_heading_toc_(heading_toc_); +    auto attrib=""; +    string toc_txt_, subtoc_txt_; +    int[string] indent; +    if (to!int(obj_["lev_markup_number"]) > 0) { +      indent=[ +        "hang_position" : to!int(obj_["lev_markup_number"]), +        "base_position" : to!int(obj_["lev_markup_number"]), +      ]; +      toc_txt_ = format( +        "{ %s }#%s", +        heading_toc_, +        _anchor_tag, +      ); +      toc_txt_= munge.url_links(toc_txt_); +      comp_obj_toc                       = comp_obj_toc.init; +      comp_obj_toc.use                   = "frontmatter"; +      comp_obj_toc.is_of                 = "para"; +      comp_obj_toc.is_a                  = "toc"; +      comp_obj_toc.ocn                   = 0; +      comp_obj_toc.obj_cite_number       = ""; +      comp_obj_toc.indent_hang           = indent["hang_position"]; +      comp_obj_toc.indent_base           = indent["base_position"]; +      comp_obj_toc.bullet                = false; +      comp_obj_toc.text                  = to!string(toc_txt_).strip; +      the_table_of_contents_section["scroll"] ~= comp_obj_toc; +    } else { +      indent=[ +        "hang_position" : 0, +        "base_position" : 0, +      ]; +      comp_obj_toc                       = comp_obj_toc.init; +      comp_obj_toc.use                   = "frontmatter"; +      comp_obj_toc.is_of                 = "para"; +      comp_obj_toc.is_a                  = "toc"; +      comp_obj_toc.ocn                   = 0; +      comp_obj_toc.obj_cite_number       = ""; +      comp_obj_toc.indent_hang           = indent["hang_position"]; +      comp_obj_toc.indent_base           = indent["base_position"]; +      comp_obj_toc.bullet                = false; +      comp_obj_toc.text                  = "Table of Contents"; +      the_table_of_contents_section["scroll"] ~= comp_obj_toc; +    } +    comp_obj_toc                       = comp_obj_toc.init; +    comp_obj_toc.use                   = "frontmatter"; +    comp_obj_toc.is_of                 = "para"; +    comp_obj_toc.is_a                  = "toc"; +    comp_obj_toc.ocn                   = 0; +    comp_obj_toc.obj_cite_number       = ""; +    comp_obj_toc.bullet                = false; +    switch (to!int(obj_["lev_markup_number"])) { +    case 0: +      indent=[ +        "hang_position" : 0, +        "base_position" : 0, +      ]; +      toc_txt_ = "{ Table of Contents }" ~ mkup.mark_internal_site_lnk ~ "../toc.fnSuffix"; +      toc_txt_= munge.url_links(toc_txt_); +      comp_obj_toc.indent_hang             = indent["hang_position"]; +      comp_obj_toc.indent_base             = indent["base_position"]; +      comp_obj_toc.text                    = to!string(toc_txt_).strip; +      the_table_of_contents_section["seg"] ~= comp_obj_toc; +      break; +    case 1: .. case 3: +      indent=[ +        "hang_position" : to!int(obj_["lev_markup_number"]), +        "base_position" : to!int(obj_["lev_markup_number"]), +      ]; +      toc_txt_ = format( +        "%s", +        heading_toc_, +      ); +      toc_txt_= munge.url_links(toc_txt_); +      comp_obj_toc.indent_hang             = indent["hang_position"]; +      comp_obj_toc.indent_base             = indent["base_position"]; +      comp_obj_toc.text                    = to!string(toc_txt_).strip; +      the_table_of_contents_section["seg"] ~= comp_obj_toc; +      break; +    case 4: +      toc_txt_ = format( +        "{ %s }%s../%s.fnSuffix", +        heading_toc_, +        mkup.mark_internal_site_lnk, +        segment_anchor_tag_that_object_belongs_to, +      ); +      lev4_subtoc[segment_anchor_tag_that_object_belongs_to] = []; +      toc_txt_= munge.url_links(toc_txt_); +      indent=[ +        "hang_position" : to!int(obj_["lev_markup_number"]), +        "base_position" : to!int(obj_["lev_markup_number"]), +      ]; +      comp_obj_toc.indent_hang             = indent["hang_position"]; +      comp_obj_toc.indent_base             = indent["base_position"]; +      comp_obj_toc.text                    = to!string(toc_txt_).strip; +      the_table_of_contents_section["seg"] ~= comp_obj_toc; +      break; +    case 5: .. case 7: +      toc_txt_ = format( +        "{ %s }%s../%s.fnSuffix#%s", +        heading_toc_, +        mkup.mark_internal_site_lnk, +        segment_anchor_tag_that_object_belongs_to, +        _anchor_tag, +      ); +      subtoc_txt_ = format( +        "{ %s }#%s", +        heading_toc_, +        _anchor_tag, +      ); +      lev4_subtoc[segment_anchor_tag_that_object_belongs_to] ~= obj_["lev_markup_number"] ~ "~ " ~ to!string(subtoc_txt_).strip; +      toc_txt_= munge.url_links(toc_txt_); +      indent=[ +        "hang_position" : to!int(obj_["lev_markup_number"]), +        "base_position" : to!int(obj_["lev_markup_number"]), +      ]; +      comp_obj_toc.indent_hang             = indent["hang_position"]; +      comp_obj_toc.indent_base             = indent["base_position"]; +      comp_obj_toc.text                    = to!string(toc_txt_).strip; +      the_table_of_contents_section["seg"] ~= comp_obj_toc; +      break; +    default: +      break; +    } +    return the_table_of_contents_section; +  } +  invariant() { +  } +#+END_SRC + +****** private: + +#+name: ao_emitters_obj_inline_markup_private +#+BEGIN_SRC d +private: +#+END_SRC + +******* make heading number and segment anchor tags if instructed :markup:inline:segment:anchor:tags: + +#+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags +#+BEGIN_SRC d +  static string _configured_auto_heading_numbering_and_segment_anchor_tags(M,O,Ma)( +    M  munge_, +    O  obj_, +    Ma dochead_make_aa +  ) { +    debug(asserts){ +      static assert(is(typeof(munge_)          == string)); +      static assert(is(typeof(obj_)            == string[string])); +      static assert(is(typeof(dochead_make_aa) == string[string][string])); +    } +    if (dochead_make_aa["make"]["num_top"].length > 0) { +      if (!(match(munge_, rgx.heading_anchor_tag))) { +        static __gshared int heading_num_top_level=9; +        static __gshared int heading_num_depth=2; +        static __gshared int heading_num_0 = 0; +        static __gshared int heading_num_1 = 0; +        static __gshared int heading_num_2 = 0; +        static __gshared int heading_num_3 = 0; +        static __gshared string heading_number_auto_composite = ""; +        if (heading_num_top_level==9) { +          if (dochead_make_aa["make"]["num_depth"].length > 0) { +            heading_num_depth = to!uint(dochead_make_aa["make"]["num_depth"]); +          } +          switch (dochead_make_aa["make"]["num_top"]) { +          case "A": +            break; +          case "B": +            heading_num_top_level=1; +            break; +          case "C": +            heading_num_top_level=2; +            break; +          case "D": +            heading_num_top_level=3; +            break; +          case "1": +            heading_num_top_level=4; +            break; +          case "2": +            heading_num_top_level=5; +            break; +          case "3": +            heading_num_top_level=6; +            break; +          case "4": +            heading_num_top_level=7; +            break; +          default: +            break; +          } +        } +        /+ num_depth minimum 0 (1.) default 2 (1.1.1) max 3 (1.1.1.1) implement +/ +        if (heading_num_top_level > to!uint(obj_["lev_markup_number"])) { +          heading_num_0 = 0; +          heading_num_1 = 0; +          heading_num_2 = 0; +          heading_num_3 = 0; +        } else if (heading_num_top_level == to!uint(obj_["lev_markup_number"])) { +          heading_num_0 ++; +          heading_num_1 = 0; +          heading_num_2 = 0; +          heading_num_3 = 0; +        } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 1)) { +          heading_num_1 ++; +          heading_num_2 = 0; +          heading_num_3 = 0; +        } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 2)) { +          heading_num_2 ++; +          heading_num_3 = 0; +        } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 3)) { +          heading_num_3 ++; +        } +        if (heading_num_3 > 0) { +          heading_number_auto_composite = +            (heading_num_depth == 3) +            ? ( to!string(heading_num_0) ~ "." ~ +                  to!string(heading_num_1) ~ "." ~ +                  to!string(heading_num_2) ~ "." ~ +                  to!string(heading_num_3) +                ) +            : ""; +        } else if (heading_num_2 > 0) { +          heading_number_auto_composite = +            ((heading_num_depth >= 2) +            && (heading_num_depth <= 3)) +            ?  ( to!string(heading_num_0) ~ "." ~ +                  to!string(heading_num_1) ~ "." ~ +                  to!string(heading_num_2) +                ) +            : ""; +        } else if (heading_num_1 > 0) { +          heading_number_auto_composite = +            ((heading_num_depth >= 1) +            && (heading_num_depth <= 3)) +            ? ( to!string(heading_num_0) ~ "." ~ +                  to!string(heading_num_1) +                ) +            : ""; +        } else if (heading_num_0 > 0) { +          heading_number_auto_composite = +            ((heading_num_depth >= 0) +            && (heading_num_depth <= 3)) +            ?  (to!string(heading_num_0)) +            : ""; +        } else { +          heading_number_auto_composite = ""; +        } +        debug(heading_number_auto) { +          writeln(heading_number_auto_composite); +        } +        if (!empty(heading_number_auto_composite)) { +          munge_=replaceFirst(munge_, rgx.heading, +            "$1~$2 " ~ heading_number_auto_composite ~ ". "); +          munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, +            "$1~" ~ heading_number_auto_composite ~ " "); +        } +      } +    } +    return munge_; +  } +#+END_SRC + +******** unittests + +#+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags +#+BEGIN_SRC d +#+END_SRC + +******* make segment anchor tags if not provided :markup:inline:segment:anchor:tags: + +#+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags +#+BEGIN_SRC d + +  static string _make_segment_anchor_tags_if_none_provided(M,Lv)(M munge_, Lv lev_) { +    debug(asserts){ +      static assert(is(typeof(munge_) == string)); +      static assert(is(typeof(lev_)   == string)); +    } +    if (!(match(munge_, rgx.heading_anchor_tag))) { // if (anchor_tags_.length == 0) { +      if (match(munge_, rgx.heading_identify_anchor_tag)) { +        if (auto m = match(munge_, rgx.heading_extract_named_anchor_tag)) { +          munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, +            "$1~" ~ toLower(m.captures[1]) ~ "_"  ~ m.captures[2] ~ " "); +        } else if (auto m = match(munge_, rgx.heading_extract_unnamed_anchor_tag)) { +          munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, +            "$1~" ~ "s" ~ m.captures[1] ~ " "); +        } +      } else if (lev_ == "1") { // (if not successful) manufacture a unique anchor tag for lev=="1" +        static __gshared int heading_num_lev1 = 0; +        heading_num_lev1 ++; +        munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, +          "$1~" ~ "x" ~ to!string(heading_num_lev1) ~ " "); +      } +    } +    return munge_; +  } +#+END_SRC + +******** unittests + +#+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags +#+BEGIN_SRC d +  unittest { +    string txt_lev="1"; +    string txt_in, txt_out; + +    txt_in = "1~copyright Copyright"; +    txt_out ="1~copyright Copyright"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in = "1~ 6. Writing Copyright Licenses"; +    txt_out ="1~s6 6. Writing Copyright Licenses"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ 1. Reinforcing trends"; +    txt_out= "1~s1 1. Reinforcing trends"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ 11 SCIENCE AS A COMMONS"; +    txt_out= "1~s11 11 SCIENCE AS A COMMONS"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ Chapter 1"; +    txt_out="1~chapter_1 Chapter 1"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ Chapter 1."; +    txt_out="1~chapter_1 Chapter 1."; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ Chapter 1: Done"; +    txt_out="1~chapter_1 Chapter 1: Done"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in=  "1~ Chapter 11 - The Battle Over the Institutional Ecology of the Digital Environment"; +    txt_out= "1~chapter_11 Chapter 11 - The Battle Over the Institutional Ecology of the Digital Environment"; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ CHAPTER I."; +    txt_out="1~x1 CHAPTER I."; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); + +    txt_in= "1~ CHAPTER II."; +    txt_out="1~x2 CHAPTER II."; +    assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); +  } +#+END_SRC + +****** close + +#+name: ao_emitters_obj_inline_markup_close +#+BEGIN_SRC d +} +#+END_SRC + +***** object attrib                                          :attributes: +****** attributes structure open, public + +#+name: ao_emitters_obj_attributes +#+BEGIN_SRC d +struct ObjAttributes { +  string[string] _obj_attrib; +#+END_SRC + +****** attributes structure open, public + +#+name: ao_emitters_obj_attributes_public +#+BEGIN_SRC d +  string obj_attributes(Oi,OR,OH)( +    Oi obj_is_, +    OR obj_raw, +    OH _comp_obj_heading, +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_is_)           == string)); +      static assert(is(typeof(obj_raw)           == string)); +      static assert(is(typeof(_comp_obj_heading) == ObjGenericComposite)); +    } +  } +  body { +    scope(exit) { +      destroy(obj_is_); +      destroy(obj_raw); +      destroy(_comp_obj_heading); +    } +    _obj_attrib["json"] ="{"; +    switch (obj_is_) { +    case "heading": +      _obj_attrib["json"] ~= _heading(obj_raw); +      break; +    case "para": +      _obj_attrib["json"] ~= _para_and_blocks(obj_raw) +      ~ _para(obj_raw); +      break; +    case "code": +      _obj_attrib["json"] ~= _code(obj_raw); +      break; +    case "group": +      _obj_attrib["json"] ~= _para_and_blocks(obj_raw) +      ~ _group(obj_raw); +      break; +    case "block": +      _obj_attrib["json"] ~= _para_and_blocks(obj_raw) +      ~ _block(obj_raw); +      break; +    case "verse": +      _obj_attrib["json"] ~= _verse(obj_raw); +      break; +    case "quote": +      _obj_attrib["json"] ~= _quote(obj_raw); +      break; +    case "table": +      _obj_attrib["json"] ~= _table(obj_raw); +      break; +    case "comment": +      _obj_attrib["json"] ~= _comment(obj_raw); +      break; +    default: +      _obj_attrib["json"] ~= _para(obj_raw); +      break; +    } +    _obj_attrib["json"] ~=" }"; +    _obj_attrib["json"]=_set_additional_values_parse_as_json(_obj_attrib["json"], obj_is_, _comp_obj_heading); +    debug(structattrib) { +      if (oa_j["is"].str() == "heading") { +        writeln(_obj_attrib["json"]); +        writeln( +          "is: ", oa_j["is"].str(), +          "; obj_cite_number: ", oa_j["obj_cite_number"].integer() +        ); +      } +    } +    return _obj_attrib["json"]; +  } +  invariant() { +  } +#+END_SRC + +****** private + +#+name: ao_emitters_obj_attributes_private +#+BEGIN_SRC d +  private: +  string _obj_attributes; +#+END_SRC + +******* attrubutes +******** para and block + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _para_and_blocks(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    if (matchFirst(obj_txt_in, rgx.para_bullet)) { +      _obj_attributes =" \"bullet\": \"true\"," +      ~ " \"indent_hang\": 0," +      ~ " \"indent_base\": 0,"; +    } else if (auto m = matchFirst(obj_txt_in, rgx.para_bullet_indent)) { +      _obj_attributes =" \"bullet\": \"true\"," +      ~ " \"indent_hang\": " ~ to!string(m.captures[1]) ~ "," +      ~ " \"indent_base\": " ~ to!string(m.captures[1]) ~ ","; +    } else if (auto m = matchFirst(obj_txt_in, rgx.para_indent_hang)) { +      _obj_attributes =" \"bullet\": \"false\"," +      ~ " \"indent_hang\": " ~ to!string(m.captures[1]) ~ "," +      ~ " \"indent_base\": " ~  to!string(m.captures[2]) ~ ","; +    } else if (auto m = matchFirst(obj_txt_in, rgx.para_indent)) { +      _obj_attributes =" \"bullet\": \"false\"," +      ~ " \"indent_hang\": " ~ to!string(m.captures[1]) ~ "," +      ~ " \"indent_base\": " ~ to!string(m.captures[1]) ~ ","; +    } else { +      _obj_attributes =" \"bullet\": \"false\"," +      ~ " \"indent_hang\": 0," +      ~ " \"indent_base\": 0,"; +    } +    return _obj_attributes; +  } +#+END_SRC + +******** para + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _para(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"para\"," +    ~ " \"is\": \"para\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** heading + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _heading(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"para\"," +    ~ " \"is\": \"heading\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** code + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _code(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"code\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** group + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _group(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"group\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** block + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _block(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"block\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** verse + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _verse(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"verse\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** quote + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _quote(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"quote\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** table + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _table(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"content\"," +    ~ " \"of\": \"block\"," +    ~ " \"is\": \"table\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******** comment + +#+name: ao_emitters_obj_attributes_private_an_attribute +#+BEGIN_SRC d +  string _comment(Ot)(Ot obj_txt_in) +  in { +    debug(asserts){ +      static assert(is(typeof(obj_txt_in) == string)); +    } +  } +  body { +    _obj_attributes = " \"use\": \"comment\"," +    ~ " \"of\": \"comment\"," +    ~ " \"is\": \"comment\""; +    return _obj_attributes; +  } +  invariant() { +  } +#+END_SRC + +******* set additional attribute values, parse as json + +#+name: ao_emitters_obj_attributes_private_json +#+BEGIN_SRC d +  string _set_additional_values_parse_as_json(OA,Oi,OH)( +    OA _obj_attrib, +    Oi obj_is_, +    OH _comp_obj_heading, +  ) { +    debug(asserts){ +      static assert(is(typeof(_obj_attrib)       == string)); +      static assert(is(typeof(obj_is_)           == string)); +      static assert(is(typeof(_comp_obj_heading) == ObjGenericComposite)); +    } +    JSONValue oa_j = parseJSON(_obj_attrib); +    assert( +      (oa_j.type == JSON_TYPE.OBJECT) +    ); +    if (obj_is_ == "heading") { +      oa_j.object["obj_cite_number"] = _comp_obj_heading.ocn; +      oa_j.object["lev_markup_number"] = _comp_obj_heading.heading_lev_markup; +      oa_j.object["lev_collapsed_number"] = _comp_obj_heading.heading_lev_collapsed; +      oa_j.object["heading_ptr"] = +        _comp_obj_heading.ptr_heading; +      oa_j.object["doc_object_ptr"] = +        _comp_obj_heading.ptr_doc_object; +    } +    oa_j.object["parent_obj_cite_number"] = _comp_obj_heading.parent_ocn; +    oa_j.object["parent_lev_markup_number"] = _comp_obj_heading.parent_lev_markup; +    _obj_attrib = oa_j.toString(); +    return _obj_attrib; +  } +#+END_SRC + +****** close + +#+name: ao_emitters_obj_attributes_private_close +#+BEGIN_SRC d +} +#+END_SRC + +**** book index                                               :book:index: +***** book index nugget hash                                :hash:nugget: + +#+name: ao_emitters_book_index_nugget +#+BEGIN_SRC d +struct BookIndexNuggetHash { +  string main_term, sub_term, sub_term_bits; +  int obj_cite_number_offset, obj_cite_number_endpoint; +  string[] obj_cite_numbers; +  string[][string][string] bi; +  string[][string][string] hash_nugget; +  string[] bi_main_terms_split_arr; +  string[][string][string] bookindex_nugget_hash(BI,N)( +    BI bookindex_section, +    N  obj_cite_number +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(bookindex_section) == string)); +      static assert(is(typeof(obj_cite_number)   == int)); +    } +    debug(bookindexraw) { +      if (!bookindex_section.empty) { +        writeln( +          "* [bookindex] ", +          "[", to!string(obj_cite_number), "] ", bookindex_section +        ); +      } +    } +  } +  body { +    auto rgx = Rgx(); +    if (!bookindex_section.empty) { +      auto bi_main_terms_split_arr = +        split(bookindex_section, rgx.bi_main_terms_split); +      foreach (bi_main_terms_content; bi_main_terms_split_arr) { +        auto bi_main_term_and_rest = +          split(bi_main_terms_content, rgx.bi_main_term_plus_rest_split); +        if (auto m = match( +          bi_main_term_and_rest[0], +          rgx.bi_term_and_obj_cite_numbers_match) +        ) { +          main_term = strip(m.captures[1]); +          obj_cite_number_offset = to!int(m.captures[2]); +          obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset); +          obj_cite_numbers ~= (to!string(obj_cite_number) ~ "-" ~ to!string(obj_cite_number_endpoint)); +        } else { +          main_term = strip(bi_main_term_and_rest[0]); +          obj_cite_numbers ~= to!string(obj_cite_number); +        } +        bi[main_term]["_a"] ~= obj_cite_numbers; +        obj_cite_numbers=null; +        if (bi_main_term_and_rest.length > 1) { +          auto bi_sub_terms_split_arr = +            split( +              bi_main_term_and_rest[1], +              rgx.bi_sub_terms_plus_obj_cite_number_offset_split +            ); +          foreach (sub_terms_bits; bi_sub_terms_split_arr) { +            if (auto m = match(sub_terms_bits, rgx.bi_term_and_obj_cite_numbers_match)) { +              sub_term = strip(m.captures[1]); +              obj_cite_number_offset = to!int(m.captures[2]); +              obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset); +              obj_cite_numbers ~= (to!string(obj_cite_number) ~ " - " ~ to!string(obj_cite_number_endpoint)); +            } else { +              sub_term = strip(sub_terms_bits); +              obj_cite_numbers ~= to!string(obj_cite_number); +            } +            if (!empty(sub_term)) { +              bi[main_term][sub_term] ~= obj_cite_numbers; +            } +            obj_cite_numbers=null; +          } +        } +      } +    } +    hash_nugget = bi; +    return hash_nugget; +  } +  invariant() { +  } +} +#+END_SRC + +***** book index (sort &) report indented               :report:indented: + +#+name: ao_emitters_book_index_report_indented +#+BEGIN_SRC d +struct BookIndexReportIndent { +  int mkn, skn; +  auto bookindex_report_indented(BI)( +    BI bookindex_unordered_hashes +  ) { +    debug(asserts){ +      static assert(is(typeof(bookindex_unordered_hashes) == string[][string][string])); +    } +    auto mainkeys= +      bookindex_unordered_hashes.byKey.array.sort().release; +    foreach (mainkey; mainkeys) { +      debug(bookindex) { +        writeln(mainkey); +      } +      auto subkeys= +        bookindex_unordered_hashes[mainkey].byKey.array.sort().release; +      foreach (subkey; subkeys) { +        debug(bookindex) { +          writeln("  ", subkey); +          writeln("    ", to!string( +            bookindex_unordered_hashes[mainkey][subkey] +          )); +        } +        ++skn; +      } +      ++mkn; +    } +  } +} +#+END_SRC + +***** book index (sort &) report section                 :report:section: +****** book index struct open + +#+name: ao_emitters_book_index_report_section +#+BEGIN_SRC d +struct BookIndexReportSection { +  int  mkn, skn; +  auto rgx = Rgx(); +  auto munge = ObjInlineMarkupMunge(); +#+END_SRC + +****** bookindex write section + +#+name: ao_emitters_book_index_report_section +#+BEGIN_SRC d +  auto bookindex_write_section(BI)( +    BI bookindex_unordered_hashes +  ) { +    debug(asserts){ +      static assert(is(typeof(bookindex_unordered_hashes) == string[][string][string])); +    } +    auto mainkeys=bookindex_unordered_hashes.byKey.array.sort().release; +    foreach (mainkey; mainkeys) { +      write("_0_1 !{", mainkey, "}! "); +      foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { +        auto go = replaceAll(ref_, rgx.book_index_go, "$1"); +        write(" {", ref_, "}#", go, ", "); +      } +      writeln(" \\\\"); +      bookindex_unordered_hashes[mainkey].remove("_a"); +      auto subkeys= +        bookindex_unordered_hashes[mainkey].byKey.array.sort().release; +      foreach (subkey; subkeys) { +        write("  ", subkey, ", "); +        foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { +          auto go = replaceAll(ref_, rgx.book_index_go, "$1"); +          write(" {", ref_, "}#", go, ", "); +        } +        writeln(" \\\\"); +        ++skn; +      } +      ++mkn; +    } +  } +#+END_SRC + +****** book index (sort &) build section                :report:section: + +#+name: ao_emitters_book_index_report_section +#+BEGIN_SRC d +  auto bookindex_build_abstraction_section(BI,N,Ta,B)( +    BI bookindex_unordered_hashes, +    N  obj_cite_number, +    Ta segment_anchor_tag_that_object_belongs_to, +    B  opt_action_bool, +  ) { +    debug(asserts){ +      static assert(is(typeof(bookindex_unordered_hashes)                == string[][string][string])); +      static assert(is(typeof(obj_cite_number)                           == int)); +      static assert(is(typeof(segment_anchor_tag_that_object_belongs_to) == string)); +      static assert(is(typeof(opt_action_bool)                           == bool[string])); +    } +    mixin SiSUnode; +    mixin InternalMarkup; +    auto mkup = InlineMarkup(); +    string type_is; +    string lev; +    int heading_lev_markup, heading_lev_collapsed; +    string attrib; +    int[string] indent; +    auto mainkeys = +      bookindex_unordered_hashes.byKey.array.sort().release; +    ObjGenericComposite[][string] bookindex_section; +    ObjGenericComposite comp_obj_heading_, comp_obj_para; +    auto node_para_int_ = node_metadata_para_int; +    auto node_para_str_ = node_metadata_para_str; +    if ((mainkeys.length > 0) +    && (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"])) { +      string bi_tmp_seg, bi_tmp_scroll; +      string[] bi_tmp_tags; +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Book Index"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      bookindex_section["scroll"]             ~= comp_obj_heading_; +      bookindex_section["seg"]                ~= comp_obj_heading_; +      ++obj_cite_number; +      ++mkn; +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Index"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.segment_anchor_tag    = "bookindex"; +      comp_obj_heading_.marked_up_level       = "1"; +      comp_obj_heading_.heading_lev_markup    = 4; +      comp_obj_heading_.heading_lev_collapsed = 2; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      comp_obj_heading_.anchor_tags           = ["bookindex"]; +      bookindex_section["scroll"]             ~= comp_obj_heading_; +      bookindex_section["seg"]                ~= comp_obj_heading_; +      ++obj_cite_number; +      ++mkn; +      import std.array : appender; +      auto buffer = appender!(char[])(); +      string[dchar] transTable = [' ' : "_"]; +      foreach (mainkey; mainkeys) { +        bi_tmp_tags = [""]; +        bi_tmp_scroll = "!{" ~ mainkey ~ "}! "; +        buffer.clear(); +        bi_tmp_tags ~= translate(mainkey, transTable); +        bi_tmp_seg = "!{" ~ mainkey ~ "}! "; +        foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { +          auto go = replaceAll(ref_, rgx.book_index_go, "$1"); +          bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", "); +          bi_tmp_seg ~= (segment_anchor_tag_that_object_belongs_to.empty) +          ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ") +          : munge.url_links(" {" ~ ref_ ~ "}" ~ mkup.mark_internal_site_lnk ~ "../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#" ~ go ~ ", "); +        } +        bi_tmp_scroll ~= " \\\\\n    "; +        bi_tmp_seg ~= " \\\\\n    "; +        bookindex_unordered_hashes[mainkey].remove("_a"); +        auto subkeys = +          bookindex_unordered_hashes[mainkey].byKey.array.sort().release; +        foreach (subkey; subkeys) { +          bi_tmp_scroll ~= subkey ~ ", "; +          buffer.clear(); +          bi_tmp_tags ~= translate(subkey, transTable); +          bi_tmp_seg ~= subkey ~ ", "; +          foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { +            auto go = replaceAll(ref_, rgx.book_index_go, "$1"); +            bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", "); +            bi_tmp_seg ~= (segment_anchor_tag_that_object_belongs_to.empty) +            ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ") +            : munge.url_links(" {" ~ ref_ ~ "}" ~ mkup.mark_internal_site_lnk ~ "../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#" ~ go ~ ", "); +          } +          bi_tmp_scroll ~= " \\\\\n    "; +          bi_tmp_seg ~= " \\\\\n    "; +          ++skn; +        } +        bi_tmp_scroll = replaceFirst(bi_tmp_scroll, rgx.trailing_linebreak, ""); +        bi_tmp_seg = replaceFirst(bi_tmp_seg, rgx.trailing_linebreak, ""); +        comp_obj_para                       = comp_obj_para.init; +        comp_obj_para.use                   = "backmatter"; +        comp_obj_para.is_of                 = "para"; +        comp_obj_para.is_a                  = "bookindex"; +        comp_obj_para.text                  = to!string(bi_tmp_scroll).strip; +        comp_obj_para.ocn                   = obj_cite_number; +        comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +        comp_obj_para.anchor_tags           = bi_tmp_tags; +        comp_obj_para.indent_hang           = 0; +        comp_obj_para.indent_base           = 1; +        comp_obj_para.bullet                = false; +        bookindex_section["scroll"]         ~= comp_obj_para; +        comp_obj_para.text                  = to!string(bi_tmp_seg).strip; +        bookindex_section["seg"]            ~= comp_obj_para; +        ++obj_cite_number; +        ++mkn; +      } +    } else {                              // no book index, (figure out what to do here) +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.text                  = "(skip) there is no Book Index"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      bookindex_section["scroll"]             ~= comp_obj_heading_; +      bookindex_section["seg"]                ~= comp_obj_heading_; +    } +    auto t = tuple(bookindex_section, obj_cite_number); +    return t; +  } +#+END_SRC + +****** book index struct close + +#+name: ao_emitters_book_index_report_section +#+BEGIN_SRC d +} +#+END_SRC + +**** (end)notes section                                 :endnotes:section: + +#+name: ao_emitters_endnotes +#+BEGIN_SRC d +struct NotesSection { +  string[string] object_notes; +  int previous_count; +  int mkn; +  auto rgx = Rgx(); +#+END_SRC + +***** gather notes for endnote section struct open + +#+name: ao_emitters_endnotes +#+BEGIN_SRC d +  private auto gather_notes_for_endnote_section( +    ObjGenericComposite[] contents_am, +    string                segment_anchor_tag_that_object_belongs_to, +    int                   cntr, +  ) +  in { +    // endnotes/ footnotes for +    // doc objects other than paragraphs & headings +    // various forms of grouped text +    assert((contents_am[cntr].is_a == "para") +    || (contents_am[cntr].is_a == "heading") +    || (contents_am[cntr].is_a == "group")); +    assert(cntr >= previous_count); +    previous_count=cntr; +    assert( +      match(contents_am[cntr].text, +      rgx.inline_notes_delimiter_al_regular_number_note) +    ); +  } +  body { +    mixin InternalMarkup; +    auto mkup = InlineMarkup(); +    auto munge = ObjInlineMarkupMunge(); +    foreach( +      m; +      matchAll( +        contents_am[cntr].text, +        rgx.inline_notes_delimiter_al_regular_number_note +      ) +    ) { +      debug(endnotes_build) { +        writeln( +          "{^{", m.captures[1], ".}^}" ~ mkup.mark_internal_site_lnk ~ "../", segment_anchor_tag_that_object_belongs_to, ".fnSuffix#noteref_\n  ", m.captures[1], " ", +          m.captures[2]); // sometimes need segment name (segmented html & epub) +      } +      // TODO NEXT you need anchor for segments at this point -> +      object_notes["anchor"] ~= "#note_" ~ m.captures[1] ~ "』"; +      object_notes["notes"] ~= (segment_anchor_tag_that_object_belongs_to.empty) +      ? (munge.url_links( +          "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~ +          m.captures[1]) ~ " " ~ m.captures[2] ~ "』" +        ) +      : (munge.url_links( +          "{^{" ~ m.captures[1] ~ ".}^}" ~ mkup.mark_internal_site_lnk ~ "../" ~ +          segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#noteref_" ~ +          m.captures[1]) ~ " " ~ m.captures[2] ~ "』" +        ); +    } +    return object_notes; +  } +#+END_SRC + +***** gathered notes + +#+name: ao_emitters_endnotes +#+BEGIN_SRC d +  private auto gathered_notes() +  in { +  } +  body { +    string[][string] endnotes_; +    if (object_notes.length > 1) { +      endnotes_["notes"] = (split(object_notes["notes"], rgx.break_string))[0..$-1]; +      endnotes_["anchor"] = (split(object_notes["anchor"], rgx.break_string))[0..$-1]; +    } else { +      endnotes_["notes"] = []; +      endnotes_["anchor"] = []; +    } +    return endnotes_; +  } +#+END_SRC + +***** endnote objects + +#+name: ao_emitters_endnotes +#+BEGIN_SRC d +  private auto endnote_objects( +    int            obj_cite_number, +    bool[string]   opt_action_bool, +  ) +  in { +  } +  body { +    mixin SiSUnode; +    ObjGenericComposite[] the_endnotes_section; +    auto endnotes_ = gathered_notes(); +    string type_is; +    string lev, lev_markup_number, lev_collapsed_number; +    string attrib; +    int[string] indent; +    ObjGenericComposite comp_obj_heading_; +    if ((endnotes_["notes"].length > 0) +    && (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"])) { +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Endnotes"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      the_endnotes_section                    ~= comp_obj_heading_; +      ++obj_cite_number; +      ++mkn; +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "backmatter"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "Endnotes"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.segment_anchor_tag    = "endnotes"; +      comp_obj_heading_.marked_up_level       = "1"; +      comp_obj_heading_.heading_lev_markup    = 4; +      comp_obj_heading_.heading_lev_collapsed = 2; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      comp_obj_heading_.anchor_tags           = ["endnotes"]; +      the_endnotes_section                    ~= comp_obj_heading_; +      ++obj_cite_number; +      ++mkn; +    } else { +      comp_obj_heading_                       = comp_obj_heading_.init; +      comp_obj_heading_.use                   = "empty"; +      comp_obj_heading_.is_of                 = "para"; +      comp_obj_heading_.is_a                  = "heading"; +      comp_obj_heading_.text                  = "(skip) there are no Endnotes"; +      comp_obj_heading_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_heading_.marked_up_level       = "B"; +      comp_obj_heading_.heading_lev_markup    = 1; +      comp_obj_heading_.heading_lev_collapsed = 1; +      comp_obj_heading_.parent_ocn            = 1; +      comp_obj_heading_.parent_lev_markup     = 0; +      the_endnotes_section                    ~= comp_obj_heading_; +    } +    if (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"]) { +      ObjGenericComposite comp_obj_endnote_; +      comp_obj_endnote_                       = comp_obj_endnote_.init; +      comp_obj_endnote_.use                   = "backmatter"; +      comp_obj_endnote_.is_of                 = "para"; +      comp_obj_endnote_.is_a                  = "endnote"; +      comp_obj_endnote_.ocn                   = 0; +      comp_obj_heading_.obj_cite_number       = ""; +      comp_obj_endnote_.indent_hang           = 0; +      comp_obj_endnote_.indent_base           = 0; +      comp_obj_endnote_.bullet                = false; +      foreach (i, endnote; endnotes_["notes"]) { +        auto     m                            = (matchFirst(endnote, rgx.note_ref)); +        string   notenumber                   = to!string(m.captures[1]); +        string   anchor_tag                   = "note_" ~ notenumber; +        comp_obj_endnote_.anchor_tags         ~= [ endnotes_["anchor"][i] ]; +        comp_obj_endnote_.text                = endnote.strip; +        the_endnotes_section                  ~= comp_obj_endnote_; +      } +    } +    auto t = tuple(the_endnotes_section, obj_cite_number); +    return t; +  } +#+END_SRC + +***** gather notes for endnote section struct close + +#+name: ao_emitters_endnotes +#+BEGIN_SRC d +} +#+END_SRC + +**** bibliography                                           :bibliography: +***** biblio struct open + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +struct Bibliography { +#+END_SRC + +***** biblio + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +  public JSONValue[] _bibliography_(Bi,BJ)( +    ref Bi biblio_unsorted_incomplete, +    ref BJ bib_arr_json +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(biblio_unsorted_incomplete) == string[])); +      static assert(is(typeof(bib_arr_json)               == JSONValue[])); +    } + } +  body { +    JSONValue[] biblio_unsorted = +      _biblio_unsorted_complete_(biblio_unsorted_incomplete, bib_arr_json); +    JSONValue[] biblio_sorted__ = biblio_sort(biblio_unsorted); +    biblio_debug(biblio_sorted__); +    debug(biblio0) { +      writeln("---"); +      writeln("unsorted incomplete: ", biblio_unsorted_incomplete.length); +      writeln("json:                ", bib_arr_json.length); +      writeln("unsorted:            ", biblio_unsorted.length); +      writeln("sorted:              ", biblio_sorted__.length); +      int cntr; +      int[7] x; +      while (cntr < x.length) { +        writeln(cntr, ": ", biblio_sorted__[cntr]["fulltitle"]); +        cntr++; +      } +    } +    return biblio_sorted__; +  } +#+END_SRC + +***** biblio unsorted complete + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +  final private JSONValue[] _biblio_unsorted_complete_(Bi,BJ)( +    Bi     biblio_unordered, +    ref BJ bib_arr_json +  ) { +    debug(asserts){ +      static assert(is(typeof(biblio_unordered) == string[])); +      static assert(is(typeof(bib_arr_json)     == JSONValue[])); +    } +    foreach (bibent; biblio_unordered) { +      // update bib to include deemed_author, needed for: +      // sort_bibliography_array_by_deemed_author_year_title +      // either: sort on multiple fields, or; create such sort field +      JSONValue j = parseJSON(bibent); +      if (!empty(j["fulltitle"].str)) { +        if (!empty(j["author_raw"].str)) { +          j["deemed_author"]=j["author_arr"][0]; +        } else if (!empty(j["editor_raw"].str)) { +          j["deemed_author"]=j["editor_arr"][0]; +        } +        j["sortby_deemed_author_year_title"] = ( +          j["deemed_author"].str ~ +           "; " ~ +           j["year"].str ~ +           "; "  ~ +           j["fulltitle"].str +        ); +      } +      bib_arr_json ~= j; +    } +    JSONValue[] biblio_unsorted_array_of_json_objects = +      bib_arr_json.dup; +    return biblio_unsorted_array_of_json_objects; +  } +#+END_SRC + +***** biblio sort + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +  final private JSONValue[] biblio_sort(BJ)(BJ biblio_unordered) { +    debug(asserts){ +      static assert(is(typeof(biblio_unordered) == JSONValue[])); +    } +    JSONValue[] biblio_sorted_; +    biblio_sorted_ = +      sort!((a, b){ +        return ((a["sortby_deemed_author_year_title"].str) < (b["sortby_deemed_author_year_title"].str)); +      })(biblio_unordered).array; +    debug(bibliosorted) { +      foreach (j; biblio_sorted_) { +        if (!empty(j["fulltitle"].str)) { +          writeln(j["sortby_deemed_author_year_title"]); +        } +      } +    } +    return biblio_sorted_; +  } +#+END_SRC + +***** biblio debug + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +  void biblio_debug(BJ)(BJ biblio_sorted) { +    debug(asserts){ +      static assert(is(typeof(biblio_sorted) == JSONValue[])); +    } +    debug(biblio0) { +      foreach (j; biblio_sorted) { +        if (!empty(j["fulltitle"].str)) { +          writeln(j["sortby_deemed_author_year_title"]); +        } +      } +    } +  } +#+END_SRC + +***** biblio struct close + +#+name: ao_emitters_bibliography +#+BEGIN_SRC d +} +#+END_SRC + +**** node structure metadata                     :structure:metadata:node: +***** metadata node struct open + +#+name: ao_emitters_metadata +#+BEGIN_SRC d +struct NodeStructureMetadata { +  int lv, lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7; +  int obj_cite_number; +  int[string] p_; // p_ parent_ +  auto rgx = Rgx(); +#+END_SRC + +***** TODO node metadata emitter + +#+name: ao_emitters_metadata +#+BEGIN_SRC d +  ObjGenericComposite node_location_emitter(Lv,Ta,N,C,P,I)( +    Lv lev_markup_number, +    Ta segment_anchor_tag, +    N  obj_cite_number_, +    C  cntr_, +    P  ptr_, +    I  is_ +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(lev_markup_number)  == string)); +      static assert(is(typeof(segment_anchor_tag) == string)); +      static assert(is(typeof(obj_cite_number_)   == int)); +      static assert(is(typeof(cntr_)              == int)); +      static assert(is(typeof(ptr_)               == int)); +      static assert(is(typeof(is_)                == string)); +    } +    assert(is_ != "heading"); +    assert(to!int(obj_cite_number_) >= 0); +  } +  body { +    assert(is_ != "heading"); // should not be necessary +    assert(to!int(obj_cite_number_) >= 0); // should not be necessary +    int obj_cite_number=to!int(obj_cite_number_); +    if (lv7 > State.off) { +      p_["lev_markup_number"] = DocStructMarkupHeading.h_text_4; +      p_["obj_cite_number"] = lv7; +    } else if (lv6 > State.off) { +      p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3; +      p_["obj_cite_number"] = lv6; +    } else if (lv5 > State.off) { +      p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2; +      p_["obj_cite_number"] = lv5; +    } else { +      p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1; +      p_["obj_cite_number"] = lv4; +    } +    ObjGenericComposite comp_obj_location; +    comp_obj_location                       = comp_obj_location.init; +    comp_obj_location.is_a                  = is_; +    comp_obj_location.ocn                   = obj_cite_number_; +    comp_obj_location.segment_anchor_tag    = to!string(segment_anchor_tag); +    comp_obj_location.parent_ocn            = p_["obj_cite_number"]; +    comp_obj_location.parent_lev_markup     = p_["lev_markup_number"]; +    debug(node) { +      if (match(lev_markup_number, rgx.levels_numbered_headings)) { +        writeln("x ", to!string(_node)); +      } else { +        writeln("- ", to!string(_node)); +      } +    } +    assert(comp_obj_location.parent_lev_markup >= 4); +    assert(comp_obj_location.parent_lev_markup <= 7); +    assert(comp_obj_location.parent_ocn >= 0); +    return comp_obj_location; +  } +  invariant() { +  } +#+END_SRC + +***** TODO node metadata emitter heading, (including most segnames & their pointers) + +#+name: ao_emitters_metadata +#+BEGIN_SRC d +  ObjGenericComposite node_emitter_heading(T,L,Lm,Lc,Ta,N,C,P,LA,I,PSn)( +    T   _text, +    L   lev, +    Lm  lev_markup_number, +    Lc  lev_collapsed_number, +    Ta  segment_anchor_tag, +    N   obj_cite_number_, +    C   cntr_, +    P   ptr_, +    LA  lv_ancestors, +    I   is_, +    PSn html_segnames_ptr, +  ) +  in { +    debug(asserts){ +      static assert(is(typeof(_text)                == string)); +      static assert(is(typeof(lev)                  == string)); +      static assert(is(typeof(lev_markup_number)    == string)); +      static assert(is(typeof(lev_collapsed_number) == string)); +      static assert(is(typeof(segment_anchor_tag)   == string)); +      static assert(is(typeof(obj_cite_number_)     == int)); +      static assert(is(typeof(cntr_)                == int)); +      static assert(is(typeof(ptr_)                 == int)); +      static assert(is(typeof(lv_ancestors)         == string[])); +      static assert(is(typeof(is_)                  == string)); +      static assert(is(typeof(html_segnames_ptr)    == int)); +    } +    assert(is_ == "heading"); +    assert(to!int(obj_cite_number_) >= 0); +    assert( +      match(lev_markup_number, rgx.levels_numbered), +      ("not a valid heading level: " ~ lev_markup_number ~ " at " ~ to!string(obj_cite_number_)) +    ); +    if (match(lev_markup_number, rgx.levels_numbered)) { +      if (to!int(lev_markup_number) == 0) { +        assert(to!int(obj_cite_number_) == 1); +      } +    } +  } +  body { +    int obj_cite_number = to!int(obj_cite_number_); +    switch (to!int(lev_markup_number)) { +    case 0: +      lv = DocStructMarkupHeading.h_sect_A; +      lv0 = obj_cite_number; +      lv1=0; lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; +      p_["lev_markup_number"] = 0; +      p_["obj_cite_number"] = 0; +      break; +    case 1: +      lv = DocStructMarkupHeading.h_sect_B; +      lv1 = obj_cite_number; +      lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_sect_A; +      p_["obj_cite_number"] = lv0; +      break; +    case 2: +      lv = DocStructMarkupHeading.h_sect_C; +      lv2 = obj_cite_number; +      lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_sect_B; +      p_["obj_cite_number"] = lv1; +      break; +    case 3: +      lv = DocStructMarkupHeading.h_sect_D; +      lv3=obj_cite_number; +      lv4=0; lv5=0; lv6=0; lv7=0; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_sect_C; +      p_["obj_cite_number"] = lv2; +      break; +    case 4: +      lv = DocStructMarkupHeading.h_text_1; +      lv4 = obj_cite_number; +      lv5=0; lv6=0; lv7=0; +      if (lv3 > State.off) { +        p_["lev_markup_number"] = +          DocStructMarkupHeading.h_sect_D; +        p_["obj_cite_number"] = lv3; +      } else if (lv2 > State.off) { +        p_["lev_markup_number"] = +          DocStructMarkupHeading.h_sect_C; +        p_["obj_cite_number"] = lv2; +      } else if (lv1 > State.off) { +        p_["lev_markup_number"] = +          DocStructMarkupHeading.h_sect_B; +        p_["obj_cite_number"] = lv1; +      } else { +        p_["lev_markup_number"] = +          DocStructMarkupHeading.h_sect_A; +        p_["obj_cite_number"] = lv0; +      } +      break; +    case 5: +      lv = DocStructMarkupHeading.h_text_2; +      lv5 = obj_cite_number; +      lv6=0; lv7=0; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_text_1; +      p_["obj_cite_number"] = lv4; +      break; +    case 6: +      lv = DocStructMarkupHeading.h_text_3; +      lv6 = obj_cite_number; +      lv7=0; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_text_2; +      p_["obj_cite_number"] = lv5; +      break; +    case 7: +      lv = DocStructMarkupHeading.h_text_4; +      lv7 = obj_cite_number; +      p_["lev_markup_number"] = +        DocStructMarkupHeading.h_text_3; +      p_["obj_cite_number"] = lv6; +      break; +    default: +      break; +    } +    ObjGenericComposite _comp_obj_heading_; +    _comp_obj_heading_                           = _comp_obj_heading_.init; +    _comp_obj_heading_.use                       = "body"; +    _comp_obj_heading_.is_of                     = "para"; +    _comp_obj_heading_.is_a                      = "heading";   //                   = is_; // check whether needed, constant??? +    _comp_obj_heading_.text                      = to!string(_text).strip; +    _comp_obj_heading_.ocn                       = obj_cite_number_; +    _comp_obj_heading_.obj_cite_number           = (obj_cite_number==0) ? "" : to!string(obj_cite_number); +    _comp_obj_heading_.segment_anchor_tag        = to!string(segment_anchor_tag); +    _comp_obj_heading_.marked_up_level           = lev; +    _comp_obj_heading_.heading_lev_markup        = (!(lev_markup_number.empty) ? to!int(lev_markup_number) : 0); +    _comp_obj_heading_.heading_lev_collapsed     = (!(lev_collapsed_number.empty) ? to!int(lev_collapsed_number) : 0); +    _comp_obj_heading_.parent_ocn                = p_["obj_cite_number"]; +    _comp_obj_heading_.parent_lev_markup         = p_["lev_markup_number"]; +    _comp_obj_heading_.heading_ancestors_text    = lv_ancestors; +    _comp_obj_heading_.ptr_doc_object            = cntr_; +    _comp_obj_heading_.ptr_html_segnames         = ((lev_markup_number == "4") ? html_segnames_ptr : 0); +    _comp_obj_heading_.ptr_heading               = ptr_; +    debug(node) { +      if (match(lev_markup_number, rgx.levels_numbered_headings)) { +        writeln("* ", to!string(_node)); +      } +    } +    debug(nodeheading) { +      if (match(lev_markup_number, rgx.levels_numbered_headings)) { +        writeln("* ", to!string(_node)); +      } +    } +    assert(_comp_obj_heading_.parent_lev_markup <= 7); +    assert(_comp_obj_heading_.parent_ocn >= 0); +    if (match(lev_markup_number, rgx.levels_numbered_headings)) { +      assert(_comp_obj_heading_.heading_lev_markup <= 7); +      assert(_comp_obj_heading_.ocn >= 0); +      if (_comp_obj_heading_.parent_lev_markup > 0) { +        assert(_comp_obj_heading_.parent_lev_markup < _comp_obj_heading_.heading_lev_markup); +        if (_comp_obj_heading_.ocn != 0) { +          assert(_comp_obj_heading_.parent_ocn < _comp_obj_heading_.ocn); +        } +      } +      if (_comp_obj_heading_.heading_lev_markup == 0) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_sect_A); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_sect_B) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_sect_A); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_sect_C) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_sect_B); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_sect_D) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_sect_C); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_text_1) { +        assert(_comp_obj_heading_.parent_lev_markup <= DocStructMarkupHeading.h_sect_D); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_text_2) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_text_1); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_text_3) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_text_2); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_text_4) { +        assert(_comp_obj_heading_.parent_lev_markup == DocStructMarkupHeading.h_text_3); +      } else if  (_comp_obj_heading_.heading_lev_markup == DocStructMarkupHeading.h_text_5) { +      } +    } +    return _comp_obj_heading_; +  } +  invariant() { +  } +#+END_SRC + +***** metadata node struct close + +#+name: ao_emitters_metadata +#+BEGIN_SRC d +} +#+END_SRC + +*** function assertions                                        :assertions: +**** mixin template: assertions on markup document structure :doc_structure: + +#+name: abs_functions_assertions +#+BEGIN_SRC d +auto assertions_doc_structure(O,Lv)( +  O  an_object, +  Lv lv +) { +  debug(asserts){ +    static assert(is(typeof(an_object) == string[string])); +    static assert(is(typeof(lv)        == int[string])); +  } +  if (lv["h3"] > State.off) { +    assert(lv["h0"] > State.off); +    assert(lv["h1"] > State.off); +    assert(lv["h2"] > State.off); +  } else if (lv["h2"] > State.off) { +    assert(lv["h0"] > State.off); +    assert(lv["h1"] > State.off); +    assert(lv["h3"] == State.off); +  } else if (lv["h1"] > State.off) { +    assert(lv["h0"] > State.off); +    assert(lv["h2"] == State.off); +    assert(lv["h3"] == State.off); +  } else if (lv["h0"] > State.off) { +    assert(lv["h1"] == State.off); +    assert(lv["h2"] == State.off); +    assert(lv["h3"] == State.off); +  } else { +    assert(lv["h0"] == State.off); +    assert(lv["h1"] == State.off); +    assert(lv["h2"] == State.off); +    assert(lv["h3"] == State.off); +  } +  if (lv["h7"] > State.off) { +    assert(lv["h4"] > State.off); +    assert(lv["h5"] > State.off); +    assert(lv["h6"] > State.off); +  } else if (lv["h6"] > State.off) { +    assert(lv["h4"] > State.off); +    assert(lv["h5"] > State.off); +    assert(lv["h7"] == State.off); +  } else if (lv["h5"] > State.off) { +    assert(lv["h4"] > State.off); +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } else if (lv["h4"] > State.off) { +    assert(lv["h5"] == State.off); +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } else { +    assert(lv["h4"] == State.off); +    assert(lv["h5"] == State.off); +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } +  if (lv["h0"] == State.off) { +    assert(lv["h1"] == State.off); +    assert(lv["h2"] == State.off); +    assert(lv["h3"] == State.off); +    assert(lv["h4"] == State.off); +    assert(lv["h5"] == State.off); +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } +  if (lv["h1"] == State.off) { +    assert(lv["h2"] == State.off); +    assert(lv["h3"] == State.off); +  } +  if (lv["h2"] == State.off) { +    assert(lv["h3"] == State.off); +  } +  if (lv["h3"] == State.off) { +  } +  if (lv["h4"] == State.off) { +    assert(lv["h5"] == State.off); +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } +  if (lv["h5"] == State.off) { +    assert(lv["h6"] == State.off); +    assert(lv["h7"] == State.off); +  } +  if (lv["h6"] == State.off) { +    assert(lv["h7"] == State.off); +  } +  if (lv["h7"] == State.off) { +  } +  switch (to!string(an_object["lev"])) { +  case "A": +    if (lv["h0"] == State.off) { +      assert(lv["h1"] == State.off); +      assert(lv["h2"] == State.off); +      assert(lv["h3"] == State.off); +      assert(lv["h4"] == State.off); +      assert(lv["h5"] == State.off); +      assert(lv["h6"] == State.off); +      assert(lv["h7"] == State.off); +    } else {                       // (lv["h0"] > State.off) +      assert(lv["h0"] == State.off,"error should not enter level A a second time"); +    } +    break; +  case "B": +    if (lv["h1"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h2"] == State.off); +      assert(lv["h3"] == State.off); +    } else {                       // (lv["h1"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h1"] > State.off); +    } +    break; +  case "C": +    if (lv["h2"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h1"] > State.off); +      assert(lv["h3"] == State.off); +    } else {                       // (lv["h2"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h1"] > State.off); +      assert(lv["h2"] > State.off); +    } +    break; +  case "D": +    if (lv["h3"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h1"] > State.off); +      assert(lv["h2"] > State.off); +    } else {                      // (lv["h3"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h1"] > State.off); +      assert(lv["h2"] > State.off); +      assert(lv["h3"] > State.off); +    } +    break; +  case "1": +    if (lv["h4"] == State.off) { +      assert(lv["h0"] > State.off); +    } else {                      // (lv["h4"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +    } +    break; +  case "2": +    if (lv["h5"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +    } else {                      // (lv["h5"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +      assert(lv["h5"] > State.off); +    } +    break; +  case "3": +    if (lv["h6"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +      assert(lv["h5"] > State.off); +    } else {                      // (lv["h6"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +      assert(lv["h5"] > State.off); +      assert(lv["h6"] > State.off); +    } +    break; +  case "4": +    if (lv["h7"] == State.off) { +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +      assert(lv["h5"] > State.off); +      assert(lv["h6"] > State.off); +    } else {                      // (lv["h7"] > State.off) +      assert(lv["h0"] > State.off); +      assert(lv["h4"] > State.off); +      assert(lv["h5"] > State.off); +      assert(lv["h6"] > State.off); +      assert(lv["h7"] > State.off); +    } +    break; +  default: +    break; +  } +} +#+END_SRC + +**** mixin template: assertions on blocks                         :blocks: + +#+name: abs_functions_assertions +#+BEGIN_SRC d +auto assertions_flag_types_block_status_none_or_closed(T)(T type) { +  debug(asserts){ +    static assert(is(typeof(type) == int[string])); +  } +  assert( +    (type["code"] == TriState.off) +    || (type["code"] == TriState.closing), +    "code block status: off or closing"); +  assert( +    (type["poem"] == TriState.off) +    || (type["poem"] == TriState.closing), +    "poem status: off or closing"); +  assert( +    (type["table"] == TriState.off) +    || (type["table"] == TriState.closing), +    "table status: off or closing"); +  assert( +    (type["group"] == TriState.off) +    || (type["group"] == TriState.closing), +    "group block status: off or closing"); +  assert( +    (type["block"] == TriState.off) +    || (type["block"] == TriState.closing), +    "block status: off or closing"); +} +#+END_SRC + +* 2. Object Setter                                          :abstract:object: + +set abstracted objects for downstream processing + +** 0. ao object setter:                                   :ao_object_setter: + +#+BEGIN_SRC d :tangle ../src/sdp/ao_object_setter.d +/++ +  object setter: +  setting of sisu objects for downstream processing +  ao_object_setter.d ++/ +template ObjectSetter() { +  /+ structs +/ +  <<ao_structs_init>> +} +#+END_SRC + +** 1. initialize structs                                            :struct: +*** heading attribute + +#+name: ao_structs_init +#+BEGIN_SRC d +struct HeadingAttrib { +  string lev                            = "9"; +  int    heading_lev_markup             = 9; +  int    heading_lev_collapsed          = 9; +  int[]  closes_lev_collapsed           = []; +  int[]  closes_lev_markup              = []; +  int    array_ptr                      = 0; +  int    heading_array_ptr_segments     = 0; +} +#+END_SRC + +*** TODO composite object + +#+name: ao_structs_init +#+BEGIN_SRC d +struct ObjGenericComposite { +  // size_t id; +  string                 use                          = ""; +  string                 is_of                        = ""; +  string                 is_a                         = ""; +  string                 text                         = ""; +  string                 obj_cite_number              = ""; +  string[]               anchor_tags                  = []; +  string                 marked_up_level              = "9"; +  int[]                  closes_lev_collapsed         = []; +  int[]                  closes_lev_markup            = []; +  int                    indent_base                  = 0; +  int                    indent_hang                  = 0; +  bool                   bullet                       = false; +  string                 syntax                       = ""; +  int                    ocn                          = 0; +  string                 segment_anchor_tag           = ""; +  string                 segname_prev                 = ""; +  string                 segname_next                 = ""; +  int                    parent_lev_markup            = 0; +  int                    parent_ocn                   = 0; +  int[]                  ancestors                    = []; +  int                    heading_lev_markup           = 9; +  int                    heading_lev_collapsed        = 9; +  int[]                  heading_closes_lev_collapsed = []; +  int[]                  heading_closes_lev_markup    = []; +  string[]               heading_ancestors_text       = [ "", "", "", "", "", "", "", "", ]; +  int                    heading_array_ptr            = 0; +  int                    ptr_doc_object               = 0; +  int                    ptr_html_segnames            = 0; +  int                    ptr_heading                  = 0; +  int                    array_ptr                    = 0; +  int                    heading_array_ptr_segments   = 0; +  string[]               lev4_subtoc                  = []; +  string[string][string] node; +  int[]                  dom_markedup                 = [ 0, 0, 0, 0, 0, 0, 0, 0,]; +  int[]                  dom_collapsed                = [ 0, 0, 0, 0, 0, 0, 0, 0,]; +} +#+END_SRC + +*** The Objects: generic composite object array + +#+name: ao_structs_init +#+BEGIN_SRC d +struct TheObjects { +  ObjGenericComposite[] oca; +} +#+END_SRC  | 
