-*- mode: org -*- #+TITLE: sisudoc spine (doc_reform) object-centric document abstraction #+DESCRIPTION: documents - structuring, publishing in multiple formats & search #+FILETAGS: :spine:abstraction: #+AUTHOR: Ralph Amissah #+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]] #+COPYRIGHT: Copyright (C) 2015 (continuously updated, current 2026) Ralph Amissah #+LANGUAGE: en #+STARTUP: content hideblocks hidestars noindent entitiespretty #+PROPERTY: header-args+ :eval never-export :exports code #+PROPERTY: header-args+ :noweb yes :padline no #+PROPERTY: header-args+ :results silent :cache no #+PROPERTY: header-args+ :mkdirp yes #+OPTIONS: H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t - magic single double-quote → " ← FIX changes hilighting behavior (occuring after it) in org document. INVESTIGATE (org-mode CONFIG?) FIND & FIX - [[./doc-reform.org][doc-reform.org]] [[./][org/]] * (Object-Centric) Document Abstraction Process markup document, create document abstraction. ** _module + templates_ :module:metadoc_from_src: #+HEADER: :tangle "../src/sisudoc/ocda/meta/metadoc_from_src_functions.d" #+HEADER: :noweb yes #+BEGIN_SRC d <> // document abstraction: // abstraction of sisu markup for downstream processing // metadoc_from_src.d module sisudoc.ocda.meta.metadoc_from_src_functions; @safe: template docAbstractionFunctions() { <> <> } template docSectKeysSeq() { <> } #+END_SRC ** template docAbstraction (related) Functions *** ocda initialize #+NAME: docInitialize #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ abstraction imports // ↓ abstraction mixins mixin ObjectSetter; mixin InternalMarkup; mixin spineRgxIn; static auto rgx = RgxI(); // initialize string[string] an_object, processing, object_notes; string an_object_key; string[] anchor_tags; string anchor_tag; string anchor_tag_; string[string] tag_in_seg; bool[string] _heading_anchor_tags_seen; /+ ↓ the segment names spine makes for itself, which a heading in the document may not also claim. . A document that writes "1~endnotes Endnote" asks for the name spine gives the gathered endnotes. Both then wrote into endnotes.xhtml, and the navigation listed that file twice, the second time behind its own previous entry in reading order. Seeding the seen set with these names means the document's heading is disambiguated the same way a repeated anchor tag is, and the generated section keeps the name that the table of contents links to. +/ bool[string] _reserved_heading_anchor_tags() { bool[string] _reserved; foreach (_name; [ "toc", "endnotes", "glossary", "bibliography", "bookindex", "blurb", "_the_title", ]) { _reserved[_name] = true; } return _reserved; } string lev_anchor_tag; string[string][string] tag_assoc; string[] lv0to3_tags; // enum // 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; bool reset_note_numbers = true; int[string] line_occur; 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"; // ocn OCNset obj_cite_digits; int obj_cite_digit_, obj_cite_digit_off, obj_cite_digit_bkidx, obj_cite_digit_type; static auto obj_im = ObjInlineMarkup(); static auto obj_att = ObjAttributes(); auto object_citation_number = OCNemitter(); auto node_construct = NodeStructureMetadata(); #+END_SRC *** ocda functions **** ϝ [overview/index] #+NAME: docAbstractionRelatedFunctions #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ abstraction function emitters <> // ↓ abstraction functions <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> #+END_SRC **** ϝ emitters #+NAME: ocdaFunc_emitters #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - emitters pure struct OCNemitter { int ocn_digit, ocn_object_number, ocn_on_, ocn_off_, ocn_bkidx, ocn_bkidx_; string object_identifier; bool ocn_is_off; auto ocn_emitter(int ocn_status_flag) { OCNset ocn; assert(ocn_status_flag <= eN.ocn.reset); ocn_object_number = ocn_bkidx = 0; object_identifier = ""; ocn_is_off = false; switch(ocn_status_flag) with (eN.ocn) { case reset: ocn_digit = ocn_on_ = 1; object_identifier = "1"; ocn_is_off = false; ocn_off_ = ocn_bkidx_ = 0; break; case on: ocn_digit = ocn_object_number = ++ocn_on_; object_identifier = ocn_digit.to!string; ocn_is_off = false; break; case off: ocn_digit = 0; ocn_off_ = ++ocn_off_; object_identifier = "a" ~ ocn_off_.to!string; ocn_is_off = true; break; case bkidx: ocn_bkidx = ++ocn_bkidx_; break; case closing: // unused? break; default: ocn_digit = 0; } assert(ocn_digit >= 0); ocn.digit = ocn_digit; ocn.object_number = ocn_object_number; // difference between .object_number and .digit? ocn.identifier = object_identifier; ocn.off = ocn_is_off; ocn.bkidx = ocn_bkidx; ocn.type = ocn_status_flag; return ocn; } invariant() { } } /+ ↓ a heading's text as it is used for navigation, in tags.heading_ancestors_text and in the lev4 subtoc entries. . these are one line labels, so what is dropped is what cannot be shown on one line and means nothing there: the note itself (the reference marker goes with it), the line break markers, and a line break that came from a heading wrapped over two lines in the source. what is kept is the text and its inline markup. +/ string heading_text_for_navigation()(string _txt) { mixin InternalMarkup; static auto mkup = InlineMarkup(); static auto rgx = RgxI(); string _out = _txt .replaceAll(rgx.inline_notes_al, "") // 【...】 and its marker .replaceAll(rgx.inline_notes_curly_gen, "") // ~{...}~ if any remains .replace(mkup.br_line, " ") .replace(mkup.br_line_inline, " ") .replace(mkup.br_line_spaced, " ") .replace("\n", " ") .replace("\r", " "); while (_out.canFind(" ")) { _out = _out.replace(" ", " "); } return _out.strip; } ObjGenericComposite obj_heading_ancestors()( ObjGenericComposite obj, string[] lv_ancestors_txt, ) { switch (obj.metainfo.heading_lev_markup) { case 0: lv_ancestors_txt[0] = heading_text_for_navigation(obj.text.to!string); foreach(k; 1..8) { lv_ancestors_txt[k] = ""; } goto default; case 1: lv_ancestors_txt[1] = heading_text_for_navigation(obj.text.to!string); foreach(k; 2..8) { lv_ancestors_txt[k] = ""; } goto default; case 2: lv_ancestors_txt[2] = heading_text_for_navigation(obj.text.to!string); foreach(k; 3..8) { lv_ancestors_txt[k] = ""; } goto default; case 3: lv_ancestors_txt[3] = heading_text_for_navigation(obj.text.to!string); foreach(k; 4..8) { lv_ancestors_txt[k] = ""; } goto default; case 4: lv_ancestors_txt[4] = heading_text_for_navigation(obj.text.to!string); foreach(k; 5..8) { lv_ancestors_txt[k] = ""; } goto default; case 5: lv_ancestors_txt[5] = heading_text_for_navigation(obj.text.to!string); foreach(k; 6..8) { lv_ancestors_txt[k] = ""; } goto default; case 6: lv_ancestors_txt[6] = heading_text_for_navigation(obj.text.to!string); lv_ancestors_txt[7] = ""; goto default; case 7: lv_ancestors_txt[7] = heading_text_for_navigation(obj.text.to!string); goto default; default: obj.tags.heading_ancestors_text = lv_ancestors_txt.dup; } return obj; } static OCNset ocn_emit(int ocn_status_flag) { return object_citation_number.ocn_emitter(ocn_status_flag); } static uint[string] _check_ocn_status_()( char[] line, uint[string] pith, ) { static auto rgx = RgxI(); if (!(line.empty)) { if (pith["no_ocn_multiple_objects"] == eN.bi.off) { // not multi-line object, check whether object_number is on or turned off if (line.matchFirst(rgx.object_number_block_marks)) { // switch off object_number if (line.matchFirst(rgx.object_number_off_block)) { pith["no_ocn_multiple_objects"] = eN.bi.on; pith["ocn"] = eN.ocn.off; debug(ocnoff) { writeln(line); } } if (line.matchFirst(rgx.object_number_off_block_dummy_heading)) { pith["no_ocn_multiple_objects"] = eN.bi.on; pith["dummy_heading_multiple_objects"] = eN.bi.on; pith["ocn"] = eN.ocn.off; debug(ocnoff) { writeln(line); } } } else if (pith["no_ocn_multiple_objects"] == eN.bi.off) { pith["dummy_heading_status"] = eN.bi.off; if (pith["dummy_heading_multiple_objects"]) { pith["dummy_heading_status"] = eN.bi.on; } if (line.matchFirst(rgx.object_number_off)) { pith["ocn"] = eN.ocn.off; } else if (line.matchFirst(rgx.object_number_off_dummy_heading)) { pith["ocn"] = eN.ocn.off; pith["dummy_heading_status"] = eN.bi.on; } else { pith["ocn"] = eN.ocn.on; pith["dummy_heading_status"] = eN.bi.off; } } else { pith["ocn"] = pith["no_ocn_multiple_objects"]; } } else if (pith["no_ocn_multiple_objects"] == eN.bi.on) { if (line.matchFirst(rgx.object_number_off_block_close)) { pith["no_ocn_multiple_objects"] = eN.bi.off; pith["ocn"] = eN.ocn.on; pith["dummy_heading_status"] = eN.bi.off; pith["dummy_heading_multiple_objects"] = eN.bi.off; debug(ocnoff) { writeln(line); } } } } return pith; } // ↑ - emitters ↑ #+END_SRC **** ϝ resets (by line & object) #+NAME: ocdaFunc_resets #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - reset text by line @system ST_txt_by_line_common_reset txt_by_line_common_reset_()( int[string] line_occur, string[string] an_object, uint[string] pith, ) { line_occur["heading"] = eN.bi.off; line_occur["para"] = eN.bi.off; pith["txt_is"] = eN.txt_is.off; an_object = an_object.object_reset; ST_txt_by_line_common_reset ret; { ret.line_occur = line_occur; ret.this_object = an_object; ret.pith = pith; } return ret; } // ↓ - reset object static string[string] object_reset()(string[string] an_object) { an_object.remove("body_nugget"); an_object.remove("substantive"); an_object.remove("is"); an_object.remove("attrib"); an_object.remove("bookindex_nugget"); return an_object; } // ↑ - resets #+END_SRC **** ϝ by line ***** ϝ line markup #+NAME: ocdaFunc_line_markup #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - markup text by line char[] font_faces_line()(char[] textline) { static auto rgx = RgxI(); static auto mkup = InlineMarkup(); if (textline.match(rgx.inline_faces_line)) { textline = textline .replaceFirst(rgx.inline_emphasis_line, format(q"┃%s%s%s%s%s%s%s┃", mkup.ff_i, mkup.emph, mkup.ff_o, "$1", mkup.ff_c, mkup.emph, "$2")) .replaceFirst(rgx.inline_bold_line, format(q"┃%s%s%s%s%s%s%s┃", mkup.ff_i, mkup.bold, mkup.ff_o, "$1", mkup.ff_c, mkup.bold, "$2")) .replaceFirst(rgx.inline_underscore_line, format(q"┃%s%s%s%s%s%s%s┃", mkup.ff_i, mkup.underscore, mkup.ff_o, "$1", mkup.ff_c, mkup.underscore, "$2")) .replaceFirst(rgx.inline_italics_line, format(q"┃%s%s%s%s%s%s%s┃", mkup.ff_i, mkup.italic, mkup.ff_o, "$1", mkup.ff_c, mkup.italic, "$2")); } return textline; } auto inline_markup_faces(L)(L line) { static auto rgx = RgxI(); static auto mkup = InlineMarkup(); line = replaceAll!(m => mkup.quote_o ~ m[1] ~ mkup.quote_c)(line, rgx.within_quotes); line = replaceAll!(m => mkup.ff_i ~ mkup.mono ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ mkup.mono)(line, rgx.inline_mark_mono); line = replaceAll!(m => mkup.ff_i ~ mkup.cite ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ mkup.cite)(line, rgx.inline_mark_cite); foreach (regx; [rgx.inline_mark_emphasis, rgx.inline_mark_bold, rgx.inline_mark_underscore, rgx.inline_mark_italics, rgx.inline_mark_superscript, rgx.inline_mark_subscript, rgx.inline_mark_strike, rgx.inline_mark_insert]) { line = replaceAll!(m => mkup.ff_i ~ m["mark"] ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ m["mark"])(line, regx); } return line; } static string links_and_images()(string obj_txt) { static auto rgx = RgxI(); static auto mkup = InlineMarkup(); if (obj_txt.match(rgx.smid_inline_url_generic)) { if ( obj_txt.match(rgx.smid_inline_link_endnote_url_helper) || obj_txt.match(rgx.smid_inline_link_endnote_url_helper_punctuated) ) { obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s %s%s%s%s%s%s %s%s", mkup.lnk_o, m["content"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c, mkup.en_a_o, mkup.lnk_o, m["link"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c, mkup.en_a_c, m[3] ))(obj_txt, rgx.smid_inline_link_endnote_url_helper_punctuated); obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s %s%s%s%s%s%s %s", mkup.lnk_o, m["content"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c, mkup.en_a_o, mkup.lnk_o, m["link"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c, mkup.en_a_c ))(obj_txt, rgx.smid_inline_link_endnote_url_helper); } else { obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s", m["pre"], mkup.lnk_o, m["content"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c ))(obj_txt, rgx.smid_inline_link_markup_regular); } obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s", m["pre"], mkup.lnk_o, m["link"].strip, mkup.lnk_c, mkup.url_o, m["link"], mkup.url_c ))(obj_txt, rgx.smid_inline_link_naked_url); // } return obj_txt; } char[] _doc_header_and_make_substitutions_(CMM)( char[] line, CMM conf_make_meta, ) { enum Substitute { match, markup, } if (conf_make_meta.make.substitute) { foreach(substitution_pair; conf_make_meta.make.substitute) { line = line.replaceAll( regex("\b" ~ substitution_pair[Substitute.match]), substitution_pair[Substitute.markup] ); } } return line; } char[] _doc_header_and_make_substitutions_fontface_(CMM)( char[] line, CMM conf_make_meta, ) { enum Substitute { match, markup, } if ( conf_make_meta.make.bold) { line = line.replaceAll( regex("\b" ~ conf_make_meta.make.bold[Substitute.match]), conf_make_meta.make.bold[Substitute.markup] ); } if (conf_make_meta.make.emphasis) { line = line.replaceAll( regex("\b" ~ conf_make_meta.make.emphasis[Substitute.match]), conf_make_meta.make.emphasis[Substitute.markup] ); } if (conf_make_meta.make.italics) { line = line.replaceAll( regex("\b" ~ conf_make_meta.make.italics[Substitute.match]), conf_make_meta.make.italics[Substitute.markup] ); } return line; } // ↑ - markup by line #+END_SRC ***** ϝ para #+NAME: ocdaFunc_para #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - para string[string][string] inline_para_link_anchor()( string[string] an_object, string[string] tag_in_seg, string[string][string] tag_assoc ) { static auto rgx = RgxI(); if (auto m = an_object["substantive"].match(rgx.inline_link_anchor)) { if (m.captures[1] !in tag_assoc) { tag_assoc[(m.captures[1])]["seg_lv4"] = tag_in_seg["seg_lv4"]; tag_assoc[(m.captures[1])]["seg_lv1to4"] = tag_in_seg["seg_lv1to4"]; } else { writeln("a tag named already exists, check text line\n ", an_object["substantive"]); } } return tag_assoc; } ST_flow_para_match flow_para_match_()( char[] line, string[string] an_object, string an_object_key, int[string] indent, bool bullet, uint[string] pith, int[string] line_occur, ) { static auto rgx = RgxI(); if (line_occur["para"] == eN.bi.off) { line = font_faces_line(line); // para matches pith["txt_is"] = eN.txt_is.para; an_object[an_object_key] ~= line; indent = [ "hang_position" : 0, "base_position" : 0, ]; bullet = false; if (auto m = line.matchFirst(rgx.para_indent)) { debug(paraindent) { writeln(line); } indent["hang_position"] = (m["indent"]).to!int; indent["base_position"] = (m["indent"]).to!int; } else if (line.matchFirst(rgx.para_bullet)) { debug(parabullet) { writeln(line); } bullet = true; } else if (auto m = line.matchFirst(rgx.para_indent_hang)) { debug(paraindenthang) { writeln(line); } indent = [ "hang_position" : (m["hang"]).to!int, "base_position" : (m["indent"]).to!int, ]; } else if (auto m = line.matchFirst(rgx.para_bullet_indent)) { debug(parabulletindent) { writeln(line); } indent = [ "hang_position" : (m["indent"]).to!int, "base_position" : (m["indent"]).to!int, ]; bullet = true; } ++line_occur["para"]; } ST_flow_para_match ret; { ret.pith = pith; ret.this_object = an_object; ret.this_object_key = an_object_key; ret.indent = indent; ret.bullet = bullet; ret.line_occur = line_occur; } return ret; } // ↑ - para #+END_SRC ***** ϝ heading #+NAME: ocdaFunc_heading #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - heading ST_flow_heading_found flow_heading_found_()( char[] line, string[string] heading_match_str, string[] _make_unmarked_headings, Regex!(char)[string] heading_match_rgx, uint[string] pith, ) { static auto rgx = RgxI(); if ((_make_unmarked_headings.length > 2) && (pith["make_headings"] == eN.bi.off)) { // headings found debug(headingsfound) { writeln(_make_unmarked_headings); } debug(headingsfound) { writeln(_make_unmarked_headings.length); writeln(_make_unmarked_headings); } switch (_make_unmarked_headings.length) { case 7 : if (!empty(_make_unmarked_headings[6])) { heading_match_str["h_4"] = "^(" ~ _make_unmarked_headings[6].to!string ~ ")"; heading_match_rgx["h_4"] = regex(heading_match_str["h_4"]); } goto case; case 6 : if (!empty(_make_unmarked_headings[5])) { heading_match_str["h_3"] = "^(" ~ _make_unmarked_headings[5].to!string ~ ")"; heading_match_rgx["h_3"] = regex(heading_match_str["h_3"]); } goto case; case 5 : if (!empty(_make_unmarked_headings[4])) { heading_match_str["h_2"] = "^(" ~ _make_unmarked_headings[4].to!string ~ ")"; heading_match_rgx["h_2"] = regex(heading_match_str["h_2"]); } goto case; case 4 : if (!empty(_make_unmarked_headings[3])) { heading_match_str["h_1"] = "^(" ~ _make_unmarked_headings[3].to!string ~ ")"; heading_match_rgx["h_1"] = regex(heading_match_str["h_1"]); } goto case; case 3 : if (!empty(_make_unmarked_headings[2])) { heading_match_str["h_D"] = "^(" ~ _make_unmarked_headings[2].to!string ~ ")"; heading_match_rgx["h_D"] = regex(heading_match_str["h_D"]); } goto case; case 2 : if (!empty(_make_unmarked_headings[1])) { heading_match_str["h_C"] = "^(" ~ _make_unmarked_headings[1].to!string ~ ")"; heading_match_rgx["h_C"] = regex(heading_match_str["h_C"]); } goto case; case 1 : if (!empty(_make_unmarked_headings[0])) { heading_match_str["h_B"] = "^(" ~ _make_unmarked_headings[0].to!string ~ ")"; heading_match_rgx["h_B"] = regex(heading_match_str["h_B"]); } break; default: break; } pith["make_headings"] = eN.bi.on; } ST_flow_heading_found ret; { ret.heading_match_str = heading_match_str; ret.heading_match_rgx = heading_match_rgx; ret.pith = pith; } return ret; } ST_flow_heading_make_set flow_heading_make_set_()( char[] line, int[string] line_occur, return ref Regex!(char)[string] heading_match_rgx, return ref uint[string] pith, ) { if (pith["make_headings"] == eN.bi.on && (line_occur["para"] == eN.bi.off && line_occur["heading"] == eN.bi.off) && pith["txt_is"] == eN.txt_is.off ) { // heading make set if (line.matchFirst(heading_match_rgx["h_B"])) { line = "B~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_C"])) { line = "C~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_D"])) { line = "D~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_1"])) { line = "1~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_2"])) { line = "2~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_3"])) { line = "3~ " ~ line; debug(headingsfound) { writeln(line); } } if (line.matchFirst(heading_match_rgx["h_4"])) { line = "4~ " ~ line; debug(headingsfound) { writeln(line); } } } ST_flow_heading_make_set ret; { ret.line = line; ret.pith = pith; ret.this_object = an_object; } return ret; } auto flow_heading_matched_(CMM)( char[] line, string[string] an_object, int[string] line_occur, string an_object_key, int[string] lv, int[string] collapsed_lev, uint[string] pith, CMM conf_make_meta, ) { static auto rgx = RgxI(); static auto mkup = InlineMarkup(); if (auto m = line.match(rgx.headings)) { // heading match ++line_occur["heading"]; pith["txt_is"] = eN.txt_is.heading; if (line.match(rgx.heading_seg_and_above)) { pith["section"] = eN.sect.unset; } an_object[an_object_key] ~= line ~= "\n"; an_object["lev"] ~= m.captures[1]; assertions_doc_structure(an_object, an_object_key, lv); // includes most of the logic for collapsed levels switch (an_object["lev"]) { case "A": // Title set if ((an_object[an_object_key].match(rgx.variable_doc_title_author_date)) || (an_object[an_object_key].match(rgx.variable_doc_title) && an_object[an_object_key].match(rgx.variable_doc_author) && an_object[an_object_key].match(rgx.variable_doc_date))) { an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.variable_doc_title_author_date, (conf_make_meta.meta.title_full ~ mkup.br_line_inline ~ conf_make_meta.meta.creator_author ~ " (" ~ (conf_make_meta.meta.date_published.replaceFirst(regex(r"(?:-00)+"),"")) ~ ")")) .replaceFirst(rgx.variable_doc_title, (conf_make_meta.meta.title_full ~ mkup.br_line_inline)) .replaceFirst(rgx.variable_doc_author, conf_make_meta.meta.creator_author) .replaceFirst(rgx.variable_doc_date, " (" ~ (conf_make_meta.meta.date_published.replaceFirst(regex(r"(?:-00)+"),"")) ~ ")"); } else if ((an_object[an_object_key].match(rgx.variable_doc_title_author)) || (an_object[an_object_key].match(rgx.variable_doc_title) && an_object[an_object_key].match(rgx.variable_doc_author))) { an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.variable_doc_title_author_date, (conf_make_meta.meta.title_full ~ mkup.br_line_inline ~ conf_make_meta.meta.creator_author)) .replaceFirst(rgx.variable_doc_title, (conf_make_meta.meta.title_full ~ mkup.br_line_inline)) .replaceFirst(rgx.variable_doc_author, conf_make_meta.meta.creator_author); } else if (an_object[an_object_key].match(rgx.variable_doc_title)) { an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.variable_doc_title, conf_make_meta.meta.title_full); } collapsed_lev["h0"] = 0; an_object["lev_collapsed_number"] = collapsed_lev["h0"].to!string; lv["lv"] = DocStructMarkupHeading.h_sect_A; ++lv["h0"]; lv["h1"] = eN.bi.off; lv["h2"] = eN.bi.off; lv["h3"] = eN.bi.off; lv["h4"] = eN.bi.off; lv["h5"] = eN.bi.off; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "B": collapsed_lev["h1"] = collapsed_lev["h0"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h1"].to!string; lv["lv"] = DocStructMarkupHeading.h_sect_B; ++lv["h1"]; lv["h2"] = eN.bi.off; lv["h3"] = eN.bi.off; lv["h4"] = eN.bi.off; lv["h5"] = eN.bi.off; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "C": collapsed_lev["h2"] = collapsed_lev["h1"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h2"].to!string; lv["lv"] = DocStructMarkupHeading.h_sect_C; ++lv["h2"]; lv["h3"] = eN.bi.off; lv["h4"] = eN.bi.off; lv["h5"] = eN.bi.off; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "D": collapsed_lev["h3"] = collapsed_lev["h2"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h3"].to!string; lv["lv"] = DocStructMarkupHeading.h_sect_D; ++lv["h3"]; lv["h4"] = eN.bi.off; lv["h5"] = eN.bi.off; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "1": if (lv["h3"] > eN.bi.off) { collapsed_lev["h4"] = collapsed_lev["h3"] + 1; } else if (lv["h2"] > eN.bi.off) { collapsed_lev["h4"] = collapsed_lev["h2"] + 1; } else if (lv["h1"] > eN.bi.off) { collapsed_lev["h4"] = collapsed_lev["h1"] + 1; } else if (lv["h0"] > eN.bi.off) { collapsed_lev["h4"] = collapsed_lev["h0"] + 1; } an_object["lev_collapsed_number"] = collapsed_lev["h4"].to!string; lv["lv"] = DocStructMarkupHeading.h_text_1; ++lv["h4"]; lv["h5"] = eN.bi.off; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "2": if (lv["h5"] > eN.bi.off) { an_object["lev_collapsed_number"] = collapsed_lev["h5"].to!string; } else if (lv["h4"] > eN.bi.off) { collapsed_lev["h5"] = collapsed_lev["h4"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h5"].to!string; } lv["lv"] = DocStructMarkupHeading.h_text_2; ++lv["h5"]; lv["h6"] = eN.bi.off; lv["h7"] = eN.bi.off; goto default; case "3": if (lv["h6"] > eN.bi.off) { an_object["lev_collapsed_number"] = collapsed_lev["h6"].to!string; } else if (lv["h5"] > eN.bi.off) { collapsed_lev["h6"] = collapsed_lev["h5"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h6"].to!string; } lv["lv"] = DocStructMarkupHeading.h_text_3; ++lv["h6"]; lv["h7"] = eN.bi.off; goto default; case "4": if (lv["h7"] > eN.bi.off) { an_object["lev_collapsed_number"] = collapsed_lev["h7"].to!string; } else if (lv["h6"] > eN.bi.off) { collapsed_lev["h7"] = collapsed_lev["h6"] + 1; an_object["lev_collapsed_number"] = collapsed_lev["h7"].to!string; } lv["lv"] = DocStructMarkupHeading.h_text_4; ++lv["h7"]; goto default; default: an_object["lev_markup_number"] = lv["lv"].to!string; } an_object["dummy_heading_status"] = (pith["dummy_heading_status"] == eN.bi.off) ? "f" : "t"; debug(heading) { writeln(line.strip); } } struct ST_flow_heading_matched { string[string] this_object; int[string] line_occur; string an_object_key; int[string] lv; int[string] collapsed_lev; uint[string] pith; CMM conf_make_meta; } ST_flow_heading_matched ret; { ret.this_object = an_object; ret.line_occur = line_occur; ret.an_object_key = an_object_key; ret.lv = lv; ret.collapsed_lev = collapsed_lev; ret.pith = pith; ret.conf_make_meta = conf_make_meta; } return ret; } // ↑ - heading #+END_SRC ***** ϝ table #+NAME: ocdaFunc_table #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - table ObjGenericComposite flow_table_instructions(H)( ObjGenericComposite table_object, H table_head, ) { static auto rgx = RgxI(); table_object.metainfo.is_of_part = "body"; table_object.metainfo.is_of_section = "body"; table_object.metainfo.is_of_type = "block"; table_object.metainfo.is_a = "table"; table_object.has.inline_notes_reg = false; table_object.has.inline_notes_star = false; table_object.has.inline_links = false; if (auto m = table_head.matchFirst(rgx.table_head_instructions)) { table_object.table.heading = ((m["c_heading"].length > 0) && (m["c_heading"] == "h")) ? true : false; table_object.table.number_of_columns = ((m["c_num"].length > 0) && (m["c_num"].to!int > 0)) ? m["c_num"].to!int : 0; foreach (cw; m["c_widths"].matchAll(rgx.table_col_widths)) { auto x = cw.hit.matchFirst(rgx.table_col_widths_and_alignment); table_object.table.column_widths ~= x["width"].to!int; table_object.table.column_aligns ~= (x["align"].empty) ? "" : x["align"]; } } return table_object; } ST_flow_table_array_munge flow_table_array_munge()( ObjGenericComposite table_object, string[][] table_array, ) { static auto rgx = RgxI(); static auto mng = InlineMarkup(); string _table_substantive; ulong col_num; ulong col_num_; ulong col_num_chk = 0; foreach(idx_r, row; table_array) { debug(table_dev) { writeln("row ", idx_r); } col_num_ = 0; if (col_num == 0 || col_num < row.length) { col_num = row.length; } if (col_num_chk == 0) { col_num_chk = col_num; } else if (col_num == 1) { debug(table_dev) { writeln("table note: "); } } else if (col_num_chk != col_num) { debug(table_dev) { writeln("warning irregular number of columns: ", col_num_chk, " != ", col_num); } } else { } foreach(idx_c, col; row) { debug(table_dev) { write(idx_c, ", "); } col_num_ = idx_c; _table_substantive ~= col ~ mng.tc_s; if (idx_r == 0 && table_object.table.heading) { } else if (col.match(rgx.numeric_col) && idx_r == 1) { // conditions reversed to avoid: gdc compiled program run segfault if ((table_object.table.column_aligns.length > idx_c) && (table_object.table.column_aligns[idx_c].matchFirst(rgx.table_col_align_match))) { table_object.table.column_aligns[idx_c] = table_object.table.column_aligns[idx_c]; } else if (table_object.table.column_aligns.length > idx_c) { table_object.table.column_aligns[idx_c] = "r"; } else { table_object.table.column_aligns ~= "r"; } } else if (idx_r == 1) { if ((table_object.table.column_aligns.length > idx_c) && (table_object.table.column_aligns[idx_c].matchFirst(rgx.table_col_align_match))) { table_object.table.column_aligns[idx_c] = table_object.table.column_aligns[idx_c]; } else if (table_object.table.column_aligns.length > idx_c) { table_object.table.column_aligns[idx_c] = "l"; } else { table_object.table.column_aligns ~= "l"; } } } debug(table_dev) { writeln(""); } if (col_num_chk > 0 && (col_num != col_num_chk)) { } else if (col_num == col_num_chk){ } else { col_num_chk = col_num; } _table_substantive = _table_substantive.replaceFirst(rgx.table_col_separator_nl, "\n"); } if (table_object.table.number_of_columns != col_num) { if (table_object.table.number_of_columns == 0) { table_object.table.number_of_columns = (col_num).to!int; } else { debug(table_dev) { writeln(table_object.table.number_of_columns, " != ", col_num); } } } if (table_object.table.number_of_columns == 0 && table_object.table.column_widths.length > 0) { writeln(__LINE__, " ERROR"); } if (table_object.table.number_of_columns > 0 && table_object.table.column_widths.length == 0) { double col_w = (100.00 / table_object.table.number_of_columns); foreach (i; 0..table_object.table.number_of_columns) { table_object.table.column_widths ~= col_w; } } else if (table_object.table.number_of_columns != table_object.table.column_widths.length) { debug(table_dev) { writeln(m.hit); } // further logic required if (table_object.table.number_of_columns > table_object.table.column_widths.length) { double col_w = (100.00 - (table_object.table.column_widths).sum) / (table_object.table.number_of_columns - table_object.table.column_widths.length); foreach (i; 0..table_object.table.column_widths.length) { table_object.table.column_widths ~= col_w; } foreach (i; 0..(table_object.table.number_of_columns - table_object.table.column_widths.length)) { table_object.table.column_widths ~= col_w; } } else if (table_object.table.number_of_columns < table_object.table.column_widths.length) { writeln(__LINE__, " warning, ERROR"); } } if (table_object.table.column_widths.sum > 101 || table_object.table.column_widths.sum < 95 ) { writeln("sum: ", table_object.table.column_widths.sum, ", array: ", table_object.table.column_widths, ", cols: ", table_object.table.number_of_columns); writeln(_table_substantive); } debug(table_res) { writeln("aligns: ", table_object.table.column_aligns, "\n", "no. of columns: ", table_object.table.number_of_columns, "\n", "col widths: ", table_object.table.column_widths, " sum: ", table_object.table.column_widths.sum, "\n", _table_substantive); } table_object.text = _table_substantive; ST_flow_table_array_munge ret; { ret.table_object = table_object; ret.table_array = table_array; } return ret; } @system ST_flow_table_substantive_munge flow_table_substantive_munge()( ObjGenericComposite table_object, string table_substantive, ) { static auto rgx = RgxI(); static auto munge = ObjInlineMarkupMunge(); string[] _table_rows = (table_substantive).split(rgx.table_row_delimiter); string[] _table_cols; string[][] _table_array; foreach(col; _table_rows) { _table_cols = col.split(rgx.table_col_delimiter); _table_array ~= _table_cols; } { auto _get = table_object.flow_table_array_munge(_table_array); { table_object = _get.table_object; _table_array = _get.table_array; // what do you do with this? how is this passed down? } } ST_flow_table_substantive_munge ret; { ret.table_object = table_object; ret.table_substantive = table_substantive; // has anything been changed here? } return ret; } @system ST_flow_table_substantive_munge flow_table_substantive_munge_special()( ObjGenericComposite table_object, string table_substantive, ) { static auto rgx = RgxI(); static auto munge = ObjInlineMarkupMunge(); string[] _table_rows = (table_substantive).split(rgx.table_row_delimiter_special); string[] _table_cols; string[][] _table_array; foreach(col; _table_rows) { _table_cols = col.split(rgx.table_col_delimiter_special); _table_array ~= _table_cols; } { auto _get = table_object.flow_table_array_munge(_table_array); { table_object = _get.table_object; _table_array = _get.table_array; } } ST_flow_table_substantive_munge ret; { ret.table_object = table_object; ret.table_substantive = table_substantive; } return ret; } @system ST_flow_table_closed_make_special_notation_table flow_table_closed_make_special_notation_table_(CMM)( char[] line, string[string] an_object, ObjGenericComposite[] the_document_body_section, OCNset obj_cite_digits, ObjGenericComposite comp_obj_, int cntr, uint[string] pith, CMM conf_make_meta ) { comp_obj_ = comp_obj_.init; obj_cite_digits = ocn_emit(pith["ocn"]); auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, "table" ); an_object["is"] = "table"; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, "body_nugget", conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; comp_obj_.metainfo.ocn = obj_cite_digits.object_number; comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_ = comp_obj_.flow_table_instructions(an_object["table_head"]); { auto _get = comp_obj_.flow_table_substantive_munge_special(an_object["substantive"]); { comp_obj_ = _get.table_object; an_object["substantive"] = _get.table_substantive; } } the_document_body_section ~= comp_obj_; object_reset(an_object); processing.remove("verse"); ++cntr; ST_flow_table_closed_make_special_notation_table ret; { ret.this_object = an_object; ret.the_document_body_section = the_document_body_section; ret.obj_cite_digits = obj_cite_digits; ret.comp_obj_ = comp_obj_; ret.cntr = cntr; ret.pith = pith; } return ret; } // ↑ - table #+END_SRC ***** ϝ block line empty #+NAME: ocdaFunc_block_line_empty #+HEADER: :noweb yes #+BEGIN_SRC d @system ST_flow_block_flag_line_empty flow_block_flag_line_empty_(B,CMM,Ts)( char[] line, string[string] an_object, B bookindex_extract_hash, ObjGenericComposite[] the_document_body_section, string[][string][string] bookindex_unordered_hashes, OCNset obj_cite_digits, ObjGenericComposite comp_obj_, int cntr, uint[string] pith, string[string] object_number_poem, CMM conf_make_meta, Ts tag_in_seg, ) { assert( line.empty, "\nline should be empty:\n \"" ~ line ~ "\"" ); assert( (pith["block_state"] == eN.blk_state.closing), "code block status: closed" ); static auto rgx = RgxI(); if (pith["block_state"] == eN.blk_state.closing) { if (pith["block_is"] == eN.blk_is.quote) { obj_cite_digits = ocn_emit(pith["ocn"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "quote"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "quote", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digit_type; comp_obj_.metainfo.lang = an_object["lang"]; comp_obj_.metainfo.attrib = an_object["attrib"]; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); ++cntr; } else if (pith["block_is"] == eN.blk_is.group) { obj_cite_digits = ocn_emit(pith["ocn"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "group"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "group", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.metainfo.lang = an_object["lang"]; comp_obj_.metainfo.attrib = an_object["attrib"]; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); ++cntr; } else if (pith["block_is"] == eN.blk_is.block) { obj_cite_digits = ocn_emit(pith["ocn"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "block"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; // anchor_tag = substantive_obj_misc_struct.anchor_tag; // check comp_obj_ = set_object_generic("body", "body", "block", "block", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digit_type; comp_obj_.metainfo.lang = an_object["lang"]; comp_obj_.metainfo.attrib = an_object["attrib"]; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); ++cntr; } else if (pith["block_is"] == eN.blk_is.poem) { an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "verse"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); comp_obj_poem_ocn = set_object_generic("body", "body", "block", "poem", "", obj_cite_digits.object_number); comp_obj_poem_ocn.metainfo.identifier = obj_cite_digits.identifier; comp_obj_poem_ocn.metainfo.object_number_off = obj_cite_digits.off; comp_obj_poem_ocn.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_poem_ocn.metainfo.object_number_type = obj_cite_digits.type; the_document_body_section ~= comp_obj_poem_ocn; pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); } else if (pith["block_is"] == eN.blk_is.code) { obj_cite_digits = ocn_emit(pith["ocn"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "code"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "code", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.metainfo.syntax = an_object["syntax"]; comp_obj_.metainfo.attrib = an_object["attrib"]; comp_obj_.code_block.linenumbers = (an_object["attrib"].match(rgx.code_numbering)) ? true : false; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); ++cntr; } else if (pith["block_is"] == eN.blk_is.table) { comp_obj_ = comp_obj_.init; obj_cite_digits = ocn_emit(pith["ocn"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash( an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg ); an_object["is"] = "table"; auto comp_obj_location = node_construct.node_location_emitter( content_non_header, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; comp_obj_ = comp_obj_.init; comp_obj_.metainfo.ocn = obj_cite_digits.object_number; comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_ = comp_obj_.flow_table_instructions(an_object["table_head"]); { auto _get = comp_obj_.flow_table_substantive_munge(an_object["substantive"]); { comp_obj_ = _get.table_object; an_object["substantive"] = _get.table_substantive; } } the_document_body_section ~= comp_obj_; pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; object_reset(an_object); processing.remove("verse"); ++cntr; } } ST_flow_block_flag_line_empty ret; { ret.this_object = an_object; ret.the_document_body_section = the_document_body_section; ret.bookindex_unordered_hashes = bookindex_unordered_hashes; ret.obj_cite_digits = obj_cite_digits; ret.comp_obj_ = comp_obj_; // ret.cntr = cntr; ret.pith = pith; } return ret; } #+END_SRC ***** ϝ images #+NAME: ocdaFunc_images #+HEADER: :noweb yes #+BEGIN_SRC d /+ ↓ - images, the images an object shows. matched on the internal markup an image has become by this stage (┥☼name.png,w640h447 ┝┤├), so a filename-shaped word in prose is not taken for one, and over every match rather than the first, so a paragraph showing two images reports two. +/ string[] extract_images()(string content_block) { static auto rgx = RgxI(); string[] images_; foreach (m; content_block.matchAll(rgx.image_in_object_text)) { images_ ~= m["image"].to!string; } return images_; } @system auto _image_dimensions(O,M)(O obj, M manifested) { static auto rgx = RgxI(); if (obj.has.image_without_dimensions) { import std.math; import imageformats; int w, h, chans; real _w, _h; int max_width = 640; foreach (img; obj.text.matchAll(rgx.inline_image_without_dimensions)) { try { read_image_info(manifested.src.image_dir_path ~ "/" ~ img["img"], w, h, chans); } catch (Exception ex) { writeln("WARNING, image not found: ", img["img"], "\n ", manifested.src.image_dir_path ~ "/" ~ img["img"]); } // calculate, decide max width and proportionally reduce to keep w & h within it debug(images) { writeln("width: ", w, ", height: ", h); } if (w > max_width) { _w = max_width; _h = round((max_width / w.to!real) * h.to!real); } else { _w = w; _h = h; } obj.text = obj.text.replaceFirst( rgx.inline_image_without_dimensions, format(q"┃%s☼%s,w%sh%s %s┃", "$1", "$3", _w.to!string, _h.to!string, "$6", ) ); } debug(images) { writeln("image without dimensions: ", obj.text); } } return obj; } // ↑ - images #+END_SRC ***** ϝ links #+NAME: ocdaFunc_links #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - links auto _links(O)(O obj) { static auto rgx = RgxI(); if (auto m = obj.text.match(rgx.inline_link_stow_uri)) { debug(links) { writeln("number of link matches to stow: ", (obj.text.match(rgx.inline_link_stow_uri)).count); writeln("links to stow: ", (obj.text.match(rgx.inline_link_stow_uri))); } int _n_matches = (obj.text.match(rgx.inline_link_stow_uri)).count.to!int; for(int i = 0; i < _n_matches; ++i) { if (obj.text.match(rgx.inline_link_stow_uri)) { obj.stow.link ~= obj.text.matchFirst(rgx.inline_link_stow_uri)[2]; obj.text = obj.text.replaceFirst( rgx.inline_link_stow_uri, format(q"┃┥%s┝┤%s├┃", "$1", i) ); } } } return obj; } // ↑ - links #+END_SRC ***** ϝ text by line #+NAME: ocdaFunc_text_by_line #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - text by line (blocks etc.) ST_txt_by_line_block_start txt_by_line_block_start()( char[] line, uint[string] pith, uint[string] dochas, string[string] object_number_poem ) { static auto rgx = RgxI(); if (auto m = line.matchFirst(rgx.block_curly_code_open)) { dochas["codeblock"]++; an_object["lang"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["syntax"] = (m["syntax"]) ? m["syntax"].to!string : ""; debug(codecurly) { writefln( "* [code curly] %s", line); } // code (curly) open pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; } else if (auto m = line.matchFirst(rgx.block_curly_poem_open)) { dochas["poem"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(poem) { writefln( "* [poem curly] %s", line); } // poem (curly) open object_number_poem["start"] = obj_cite_digits.object_number.to!string; pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; pith["verse_new"] = eN.bi.on; } else if (auto m = line.matchFirst(rgx.block_curly_group_open)) { dochas["group"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(group) { writefln( "* [group curly] %s", line); } // group (curly) open pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; } else if (auto m = line.matchFirst(rgx.block_curly_block_open)) { dochas["block"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(block) { writefln( "* [block curly] %s", line); } pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; } else if (auto m = line.matchFirst(rgx.block_curly_quote_open)) { dochas["quote"]++; an_object["syntax"] = ""; an_object["attrib"] = m["attrib"].to!string; an_object["lang"] = m["lang"].to!string; debug(quote) { writefln( "* [quote curly] %s", line); } pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; } else if (auto m = line.matchFirst(rgx.block_curly_table_open)) { // curly table open debug(table) { writefln( "* [table curly] %s", line); } dochas["table"] ++; an_object["table_head"] = m["attrib"].to!string; an_object["block_type"] = "curly"; pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly; } else if (auto m = line.matchFirst(rgx.block_curly_table_special_markup)) { // table: special table block markup syntax! dochas["table"]++; an_object["table_head"] = m["attrib"].to!string; an_object["block_type"] = "special"; pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.curly_special; } else if (auto m = line.matchFirst(rgx.block_quotemarks_code_open)) { dochas["codeblock"]++; an_object["lang"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["syntax"] = (m["syntax"]) ? m["syntax"].to!string : ""; debug(codequotemarks) { writefln( "* [code quotemarks] %s", line); } pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; // } else if (auto m = line.matchFirst(rgx.block_quotemarks_poem_open)) { dochas["poem"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(poem) { writefln( "* [poem quotemarks] %s", line); } object_number_poem["start"] = obj_cite_digits.object_number.to!string; pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; // pith["verse_new"] = eN.bi.on; } else if (auto m = line.matchFirst(rgx.block_quotemarks_group_open)) { dochas["group"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(group) { writefln( "* [group quotemarks] %s", line); } pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; } else if (auto m = line.matchFirst(rgx.block_quotemarks_block_open)) { dochas["block"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(block) { writefln( "* [block quotemarks] %s", line); } pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; } else if (auto m = line.matchFirst(rgx.block_quotemarks_quote_open)) { dochas["quote"]++; an_object["syntax"] = ""; an_object["attrib"] = m["attrib"].to!string; an_object["lang"] = m["lang"].to!string; debug(quote) { writefln( "* [quote quotemarks] %s", line); // quote (quotemarks) open } pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; } else if (auto m = line.matchFirst(rgx.block_quotemarks_table_open)) { // quotemarks table open debug(table) { writefln( "* [table quotemarks] %s", line); } dochas["table"] ++; an_object["table_head"] = m["attrib"].to!string; an_object["block_type"] = "quotemarks"; pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.quotemarks; } else if (auto m = line.matchFirst(rgx.block_tic_code_open)) { dochas["codeblock"]++; an_object["lang"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["syntax"] = (m["syntax"]) ? m["syntax"].to!string : ""; debug(codetic) { writefln( "* [code tic] %s", line); } pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; } else if (auto m = line.matchFirst(rgx.block_tic_poem_open)) { dochas["poem"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(poem) { writefln( "* [poem tic] %s", line); } object_number_poem["start"] = obj_cite_digits.object_number.to!string; pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; pith["verse_new"] = eN.bi.on; } else if (auto m = line.matchFirst(rgx.block_tic_group_open)) { dochas["group"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(group) { writefln( "* [group tic] %s", line); } pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; } else if (auto m = line.matchFirst(rgx.block_tic_block_open)) { dochas["block"]++; an_object["syntax"] = ""; an_object["attrib"] = (m["attrib"]) ? m["attrib"].to!string : ""; an_object["lang"] = (m["lang"]) ? m["lang"].to!string : ""; debug(block) { writefln( "* [block tic] %s", line); } pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; } else if (auto m = line.matchFirst(rgx.block_tic_quote_open)) { dochas["quote"]++; an_object["syntax"] = ""; an_object["attrib"] = m["attrib"].to!string; an_object["lang"] = m["lang"].to!string; debug(quote) { writefln( "* [quote tic] %s", line); // quote (tic) open } pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; } else if (auto m = line.matchFirst(rgx.block_tic_table_open)) { // tic table open debug(table) { writefln( "* [table tic] %s", line); } dochas["table"] ++; an_object["table_head"] = m["attrib"].to!string; an_object["block_type"] = "tic"; pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.on; pith["block_delim"] = eN.blk_delim.tic; } ST_txt_by_line_block_start ret; { ret.pith = pith; ret.dochas = dochas; ret.object_number_poem = object_number_poem; } return ret; } ST_txt_by_line_block_generic txt_by_line_block_group()( char[] line, string[string] an_object, uint[string] pith, ) { static auto rgx = RgxI(); if (pith["block_is"] == eN.blk_is.group) { if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_group_close)) { debug(group) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(group) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (line.matchFirst(rgx.block_quotemarks_close)) { debug(group) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(group) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (line.matchFirst(rgx.block_tic_close)) { debug(group) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.group; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(group) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } } ST_txt_by_line_block_generic ret; { ret.pith = pith; ret.this_object = an_object; } return ret; } ST_txt_by_line_block_generic txt_by_line_block_block()( char[] line, string[string] an_object, uint[string] pith, ) { static auto rgx = RgxI(); if (pith["block_is"] == eN.blk_is.block) { if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_block_close)) { debug(block) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(block) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (line.matchFirst(rgx.block_quotemarks_close)) { debug(block) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(block) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (line.matchFirst(rgx.block_tic_close)) { debug(block) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.block; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(block) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } } ST_txt_by_line_block_generic ret; { ret.pith = pith; ret.this_object = an_object; } return ret; } ST_txt_by_line_block_poem txt_by_line_block_poem(CMM)( char[] line, string[string] an_object, uint[string] pith, int cntr, string[string] object_number_poem, CMM conf_make_meta, string[string] tag_in_seg, ) { static auto rgx = RgxI(); if (pith["block_is"] == eN.blk_is.poem) { if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_poem_close)) { if (an_object_key in an_object || processing.length > 0) { an_object[an_object_key] = ""; debug(poem) { writefln( "* [poem curly] %s", line); } if (processing.length > 0) { an_object[an_object_key] = processing["verse"]; } debug(poem) { writeln(__LINE__); writefln( "* %s %s", obj_cite_digits.object_number, line); } if (an_object.length > 0) { debug(poem) { writeln( obj_cite_digits.object_number, an_object[an_object_key]); } an_object["is"] = "verse"; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); } object_reset(an_object); processing.remove("verse"); ++cntr; } object_number_poem["end"] = obj_cite_digits.object_number.to!string; pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { processing["verse"] ~= line ~= "\n"; if (pith["verse_new"] == eN.bi.on) { obj_cite_digits = ocn_emit(pith["ocn"]); pith["verse_new"] = eN.bi.off; } else if (line.matchFirst(rgx.newline_eol_delimiter_only)) { processing["verse"] = processing["verse"].stripRight; verse_line = eN.bi.off; pith["verse_new"] = eN.bi.on; } if (pith["verse_new"] == eN.bi.on) { verse_line = 1; an_object[an_object_key] = processing["verse"]; debug(poem) { writefln( "* %s curly\n%s", obj_cite_digits.object_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, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); object_reset(an_object); processing.remove("verse"); ++cntr; } } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (auto m = line.matchFirst(rgx.block_quotemarks_close)) { an_object[an_object_key] = "verse"; debug(poem) { writefln( "* [poem quotemarks] %s", line); } if (processing.length > 0) { an_object[an_object_key] = processing["verse"]; } if (an_object.length > 0) { debug(poem) { writeln(__LINE__); writeln(obj_cite_digits.object_number, line); } processing.remove("verse"); an_object["is"] = "verse"; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); object_number_poem["end"] = obj_cite_digits.object_number.to!string; object_reset(an_object); processing.remove("verse"); ++cntr; } pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { processing["verse"] ~= line ~= "\n"; if (pith["verse_new"] == eN.bi.on) { obj_cite_digits = ocn_emit(pith["ocn"]); pith["verse_new"] = eN.bi.off; } else if (line.matchFirst(rgx.newline_eol_delimiter_only)) { processing["verse"] = processing["verse"].stripRight; pith["verse_new"] = eN.bi.on; verse_line = eN.bi.off; } if (pith["verse_new"] == eN.bi.on) { verse_line = 1; an_object[an_object_key] = processing["verse"]; debug(poem) { writefln( "* %s tic\n%s", obj_cite_digits.object_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, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); object_reset(an_object); processing.remove("verse"); ++cntr; } } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (auto m = line.matchFirst(rgx.block_tic_close)) { an_object[an_object_key] = "verse"; debug(poem) { writefln( "* [poem tic] %s", line); } if (processing.length > 0) { an_object[an_object_key] = processing["verse"]; } if (an_object.length > 0) { debug(poem) { writeln(__LINE__); writeln(obj_cite_digits.object_number, line); } processing.remove("verse"); an_object["is"] = "verse"; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); object_number_poem["end"] = obj_cite_digits.object_number.to!string; object_reset(an_object); processing.remove("verse"); ++cntr; } pith["block_is"] = eN.blk_is.poem; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { processing["verse"] ~= line ~= "\n"; if (pith["verse_new"] == eN.bi.on) { obj_cite_digits = ocn_emit(pith["ocn"]); pith["verse_new"] = eN.bi.off; } else if (line.matchFirst(rgx.newline_eol_delimiter_only)) { processing["verse"] = processing["verse"].stripRight; pith["verse_new"] = eN.bi.on; verse_line = eN.bi.off; } if (pith["verse_new"] == eN.bi.on) { verse_line = 1; an_object[an_object_key] = processing["verse"]; debug(poem) { writefln( "* %s tic\n%s", obj_cite_digits.object_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, tag_in_seg, lev_anchor_tag, tag_assoc, obj_cite_digits, cntr, heading_ptr-1, an_object["is"] ); ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc); an_object["substantive"] = substantive_obj_misc_struct.obj_txt; anchor_tag = substantive_obj_misc_struct.anchor_tag; comp_obj_ = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number); comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.has.inline_notes_reg = substantive_obj_misc_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_obj_misc_struct.has_notes_star; comp_obj_.has.inline_links = substantive_obj_misc_struct.has_links; comp_obj_.has.images = substantive_obj_misc_struct.has_images; the_document_body_section ~= comp_obj_; tag_assoc = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc); object_reset(an_object); processing.remove("verse"); ++cntr; } } } } ST_txt_by_line_block_poem ret; { ret.cntr = cntr; ret.pith = pith; ret.this_object = an_object; } return ret; } ST_txt_by_line_block_generic txt_by_line_block_code()( char[] line, string[string] an_object, uint[string] pith, ) { static auto rgx = RgxI(); if ( pith["block_is"] == eN.blk_is.code) { if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_code_close)) { debug(codecurly) { writeln(line); } an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.newline_eol_delimiter_only, "") .stripRight; pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(codecurly) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (line.matchFirst(rgx.block_quotemarks_close)) { debug(codequotemarks) { writeln(line); } an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.newline_eol_delimiter_only, "") .stripRight; pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(codequotemarks) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (line.matchFirst(rgx.block_tic_close)) { debug(codetic) { writeln(line); } an_object[an_object_key] = an_object[an_object_key] .replaceFirst(rgx.newline_eol_delimiter_only, "") .stripRight; pith["block_is"] = eN.blk_is.code; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(codetic) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } } ST_txt_by_line_block_generic ret; { ret.pith = pith; ret.this_object = an_object; } return ret; } @system auto txt_by_line_block_table(CMM)( char[] line, string[string] an_object, uint[string] pith, CMM conf_make_meta, ) { static auto rgx = RgxI(); if (pith["block_is"] == eN.blk_is.table) { if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_table_close)) { debug(table) { writeln(line); } pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(table) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.curly_special) { if (line.empty) { pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.off; pith["block_delim"] = eN.blk_delim.off; { auto _get = line.flow_table_closed_make_special_notation_table_( an_object, the_document_body_section, obj_cite_digits, comp_obj_, cntr, pith, conf_make_meta, ); { an_object = _get.this_object; the_document_body_section = _get.the_document_body_section; obj_cite_digits = _get.obj_cite_digits; comp_obj_ = _get.comp_obj_; cntr = _get.cntr; pith = _get.pith; } } } else { debug(table) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (line.matchFirst(rgx.block_quotemarks_close)) { debug(table) { writeln(line); } pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(table) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (line.matchFirst(rgx.block_tic_close)) { debug(table) { writeln(line); } pith["block_is"] = eN.blk_is.table; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(table) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } } struct ST_txt_by_line_block_table { CMM conf_make_meta; uint[string] pith; string[string] this_object; } ST_txt_by_line_block_table ret; { ret.conf_make_meta = conf_make_meta, ret.pith = pith; ret.this_object = an_object; } return ret; } ST_txt_by_line_block_generic txt_by_line_block_quote()( char[] line, string[string] an_object, uint[string] pith, ) { static auto rgx = RgxI(); if (pith["block_is"] == eN.blk_is.quote){ if (pith["block_delim"] == eN.blk_delim.curly) { if (line.matchFirst(rgx.block_curly_quote_close)) { debug(quote) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(quote) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.quotemarks) { if (line.matchFirst(rgx.block_quotemarks_close)) { debug(quote) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(quote) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } else if (pith["block_delim"] == eN.blk_delim.tic) { if (line.matchFirst(rgx.block_tic_close)) { debug(quote) { writeln(line); } an_object[an_object_key] = an_object[an_object_key].stripRight; pith["block_is"] = eN.blk_is.quote; pith["block_state"] = eN.blk_state.closing; pith["block_delim"] = eN.blk_delim.off; } else { debug(quote) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; } } } ST_txt_by_line_block_generic ret; { ret.pith = pith; ret.this_object = an_object; } return ret; } @system ST_txt_by_line_block_biblio txt_by_line_block_biblio( char[] line, uint[string] pith, int bib_entry, string biblio_entry_str_json, string[] biblio_arr_json, ) { mixin spineBiblio; auto jsn = BibJsnStr(); static auto rgx = RgxI(); string biblio_tag_map()(string abr) { 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]; } if (line.matchFirst(rgx.heading_biblio)) { pith["section"] = eN.sect.bibliography; } if (line.empty) { debug { debug(biblioblock) { writeln("---"); } debug(biblioblockinclude) { writeln(biblio_entry_str_json.length); } } if ((bib_entry == eN.bi.off) && (biblio_entry_str_json.empty)) { bib_entry = eN.bi.on; biblio_entry_str_json = jsn.biblio_entry_tags_jsonstr; } else if (!(biblio_entry_str_json.empty)) { bib_entry = eN.bi.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 { writeln("?? 2. ERROR ", biblio_entry_str_json, "??"); biblio_entry_str_json = ""; } } else if (line.matchFirst(rgx.biblio_tags)) { debug(biblioblock) { writeln(line); } auto bt = line.match(rgx.biblio_tags); bib_entry = eN.bi.off; st = bt.captures[1].to!string; auto header_tag_value = (bt.captures[2]).to!string; JSONValue j = parseJSON(biblio_entry_str_json); biblio_tag_name = (st.match(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"] = header_tag_value.split(rgx.arr_delimiter); string tmp; biblioAuthorLoop: foreach (au; j["author_arr"].array) { if (auto x = au.str.match(rgx.name_delimiter)) { tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; } else { tmp ~= au.str; } } tmp = tmp.replace(rgx.trailing_comma, ""); j["author"].str = tmp; goto default; case "editor_raw": // editor_arr editor (fn sn) j["editor_arr"] = header_tag_value.split(rgx.arr_delimiter); string tmp; biblioEditorLoop: foreach (ed; j["editor_arr"].array) { if (auto x = ed.str.match(rgx.name_delimiter)) { tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; } else { tmp ~= ed.str; } } tmp = tmp.replace(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 (line.match(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 = ""; } ST_txt_by_line_block_biblio ret; { ret.pith = pith; ret.bib_entry = bib_entry; ret.biblio_entry_str_json = biblio_entry_str_json; ret.biblio_arr_json = biblio_arr_json; } return ret; } // ↑ - text by line #+END_SRC **** ϝ object ***** ϝ object set (heading & generic) #+NAME: ocdaFunc_obj_set #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object set ObjGenericComposite set_object_heading()( string level, string part, string section, string text, ) { ObjGenericComposite comp_obj; { comp_obj = comp_obj.init; comp_obj.metainfo.is_of_part = part; comp_obj.metainfo.is_of_section = section; comp_obj.metainfo.is_of_type = "para"; comp_obj.metainfo.is_a = "heading"; comp_obj.text = text; comp_obj.metainfo.ocn = 0; if (level == "lev1") { comp_obj.metainfo.heading_lev_markup = 1; comp_obj.metainfo.heading_lev_collapsed = 1; comp_obj.metainfo.parent_ocn = 1; comp_obj.metainfo.parent_lev_markup = 0; } else if (level == "lev4") { comp_obj.metainfo.heading_lev_markup = 4; comp_obj.metainfo.heading_lev_collapsed = 1; comp_obj.metainfo.parent_ocn = 1; comp_obj.metainfo.parent_lev_markup = 0; comp_obj.metainfo.dom_structure_markedup_tags_status = [ 1, 1, 0, 0, 1, 0, 0, 0]; comp_obj.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 1, 0, 0, 0, 0, 0]; } } return comp_obj; } ObjGenericComposite set_object_generic()( string part, string section, string type, string is_a, string text, int ocn, ) { ObjGenericComposite comp_obj; { comp_obj = comp_obj.init; comp_obj.metainfo.is_of_part = part; comp_obj.metainfo.is_of_section = section; comp_obj.metainfo.is_of_type = type; comp_obj.metainfo.is_a = is_a; comp_obj.text = text; comp_obj.metainfo.ocn = ocn; } return comp_obj; } // ↑ - object set #+END_SRC ***** ϝ object string inline munge #+NAME: ocdaFunc_obj_inline_munge #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object inline munge static struct ObjInlineMarkupMunge { string[string] obj_txt; int n_foot, n_foot_reg, n_foot_sp_asterisk, n_foot_sp_plus; string asterisks_, plus_; string obj_txt_out, tail, note; static auto rgx = RgxI(); static auto mkup = InlineMarkup(); int stage_reset_note_numbers = true; private auto initialize_note_numbers() { n_foot = 0; n_foot_reg = 0; n_foot_sp_asterisk = 0; n_foot_sp_plus = 0; } static auto images()(string obj_txt_in) { static auto mng = InlineMarkup(); // url matched obj_txt_in = obj_txt_in.replaceAll(rgx.inline_notes_al_special, ""); // TODO reinstate when special footnotes are implemented if (obj_txt_in.match(rgx.smid_image_generic)) { // images with and without links debug(images) { writeln("Image: ", obj_txt_in); } if (obj_txt_in.match(rgx.smid_image_with_dimensions)) { obj_txt_in = obj_txt_in .replaceAll(rgx.smid_image_with_dimensions, ("$1" ~ mkup.img ~ "$2,w$3h$4 " ~ "$5")) .replaceAll(rgx.smid_image_delimit, ("$1" ~ mkup.lnk_o ~ "$2".strip ~ mkup.lnk_c ~ mkup.url_o ~ mkup.url_c)); debug(images) { writeln("IMAGE with size: ", obj_txt_in); } } else if (obj_txt_in.match(rgx.smid_image)) { obj_txt_in = obj_txt_in .replaceAll(rgx.smid_image, ("$1" ~ mkup.img ~ "$2,w0h0" ~ "$3")) .replaceAll(rgx.smid_image_delimit, ("$1" ~ mkup.lnk_o ~ "$2".strip ~ mkup.lnk_c ~ mkup.url_o ~ mkup.url_c)); debug(images) { writeln("IMAGE: ", obj_txt_in); } // decide on representation } } return obj_txt_in; } ST_txtPlusHasFootnotes footnotes_endnotes_markup_and_number_or_stars()(string obj_txt_in, bool reset_note_numbers) { // endnotes (regular) bool flg_notes_reg = false; bool flg_notes_star = false; bool flg_notes_plus = false; obj_txt_in = obj_txt_in.replaceAll( rgx.inline_notes_curly, (mkup.en_a_o ~ " $1" ~ mkup.en_a_c) ); if (!(stage_reset_note_numbers) && reset_note_numbers) { stage_reset_note_numbers = true; } obj_txt_out = ""; if (obj_txt_in.match(rgx.inline_notes_al_gen)) { string[] _tmp_txt; foreach (x; obj_txt_in.split("\n")) { if (auto m = x.matchAll(rgx.inline_text_and_note_al_)) { if (stage_reset_note_numbers) { n_foot = 0; n_foot_reg = 0; n_foot_sp_asterisk = 0; n_foot_sp_plus = 0; } stage_reset_note_numbers = false; foreach(n; m) { if (n.hit.to!string.match(rgx.inline_al_delimiter_open_symbol_star)) { flg_notes_star = true; ++n_foot_sp_asterisk; asterisks_ = "*"; n_foot = n_foot_sp_asterisk; _tmp_txt ~= n.hit.to!string.replaceFirst( rgx.inline_al_delimiter_open_symbol_star, (mkup.en_a_o ~ replicate(asterisks_, n_foot_sp_asterisk) ~ " ") ); } else if (n.hit.to!string.match(rgx.inline_al_delimiter_open_symbol_plus)) { flg_notes_plus = true; ++n_foot_sp_plus; plus_ = "*"; n_foot = n_foot_sp_plus; _tmp_txt ~= n.hit.to!string.replaceFirst( rgx.inline_al_delimiter_open_symbol_plus, (mkup.en_a_o ~ replicate(plus_, n_foot_sp_plus) ~ " ") ); } else if (n.hit.to!string.matchFirst(rgx.inline_al_delimiter_open_regular)) { string _tmp_str = n.hit.to!string; flg_notes_reg = true; foreach (q; n.hit.to!string.matchAll(rgx.inline_al_delimiter_open_regular)) { ++n_foot_reg; n_foot = n_foot_reg; _tmp_str = replaceFirst!(m => mkup.en_a_o ~ n_foot.to!string ~ " ") (_tmp_str, rgx.inline_al_delimiter_open_regular); } _tmp_txt ~= _tmp_str; } else { _tmp_txt ~= n.hit.to!string; } } obj_txt_out = _tmp_txt.join("\n"); } } } else { obj_txt_out = obj_txt_in; } ST_txtPlusHasFootnotes ret; { ret.obj_txt = obj_txt_out; ret.has_notes_reg = flg_notes_reg; ret.has_notes_star = flg_notes_star; ret.has_notes_plus = flg_notes_plus; } return ret; } private ST_txtPlusHasFootnotesUrlsImages object_notes_and_links_()( string obj_txt_in, bool reset_note_numbers = false ) { obj_txt_out = ""; bool urls = false; bool images_present = false; bool images_without_dimensions = false; tail = ""; // special endnotes obj_txt_in = obj_txt_in.replaceAll( rgx.inline_notes_curly_sp_asterisk, (mkup.en_a_o ~ "*" ~ " $1" ~ mkup.en_a_c) ); obj_txt_in = obj_txt_in.replaceAll( rgx.inline_notes_curly_sp_plus, (mkup.en_a_o ~ "+" ~ " $1" ~ mkup.en_a_c) ); // image matched if (obj_txt_in.match(rgx.smid_image_generic)) { images_present = true; obj_txt_in = images(obj_txt_in); if (obj_txt_in.match(rgx.smid_mod_image_without_dimensions)) { images_without_dimensions = true; } } // url matched if (obj_txt_in.match(rgx.smid_inline_url)) { urls = true; obj_txt_in = obj_txt_in.links_and_images; } if (auto m = obj_txt_in.match(rgx.para_inline_link_anchor)) { obj_txt_in = obj_txt_in .replaceAll(rgx.para_inline_link_anchor, "┃$1┃"); } ST_txtPlusHasFootnotes ftn = footnotes_endnotes_markup_and_number_or_stars(obj_txt_in, reset_note_numbers); obj_txt_out = ftn.obj_txt; 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[1]); writeln(m.hit); } } ST_txtPlusHasFootnotesUrlsImages ret; { ret.obj_txt = obj_txt_out; ret.has_notes_reg = ftn.has_notes_reg; ret.has_notes_star = ftn.has_notes_star; ret.has_notes_plus = ftn.has_notes_plus; ret.has_urls = urls; ret.has_images = images_present; ret.has_images_without_dimensions = images_without_dimensions; } return ret; } private ST_txtPlusHasFootnotesUrlsImages object_only_()( string obj_txt_in, bool reset_note_numbers = false ) { ST_txtPlusHasFootnotesUrlsImages ret; { ret.obj_txt = obj_txt_in; ret.has_notes_reg = false; ret.has_notes_star = false; ret.has_notes_plus = false; ret.has_urls = false; ret.has_images = false; ret.has_images_without_dimensions = false; } return ret; } ST_txtPlusHasFootnotesUrlsImages init() { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(""); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_heading()( string obj_txt_in, bool reset_note_numbers = false ) { obj_txt["munge"] = obj_txt_in .replaceFirst(rgx.headings, "") .replaceFirst(rgx.object_number_off_all, "") .replaceFirst(rgx.markup_inline_linebreak, mkup.br_line_inline) .strip; ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt["munge"], reset_note_numbers); debug(munge) { writeln(__LINE__); writeln(obj_txt_in); writeln(__LINE__); writeln(obj_txt["munge"].to!string); } return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_para()(string obj_txt_in) { obj_txt["munge"] = (obj_txt_in) .replaceFirst(rgx.para_attribs, "") .replaceFirst(rgx.object_number_off_all, "") .replaceFirst(rgx.markup_inline_linebreak, mkup.br_line_inline); ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt["munge"]); debug(munge) { writeln(__LINE__); writeln(obj_txt_in); writeln(__LINE__); writeln(obj_txt["munge"].to!string); } return ret; } ST_txtPlusHasFootnotesUrlsImages munge_quote()(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in.split("\n\n").join(" \\\\\n \\\\\n")); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_group(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in.split("\n\n").join("\n" ~ mkup.br_line_spaced ~ "\n")); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_block()(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in); return ret; } invariant() { } auto munge_verse()(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_code()(string obj_txt_in) { obj_txt_in = obj_txt_in.replaceAll(rgx.space, mkup.nbsp); ST_txtPlusHasFootnotesUrlsImages ret = object_only_(obj_txt_in); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_table()(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in); return ret; } invariant() { } ST_txtPlusHasFootnotesUrlsImages munge_comment()(string obj_txt_in) { ST_txtPlusHasFootnotesUrlsImages ret = object_only_(obj_txt_in); return ret; } invariant() { } } // ↑ - object inline munge #+END_SRC ***** ϝ object inline markup #+NAME: ocdaFunc_obj_inline_markup #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object inline markup static struct ObjInlineMarkup { static auto rgx = RgxI(); static auto munge = ObjInlineMarkupMunge(); string[string] obj_txt; string anchor_tag = ""; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages obj_inline_markup_and_anchor_tags_and_misc(CMM)( string[string] obj_, string obj_key_, CMM conf_make_meta, Flag!"_new_doc" _new_doc ) { obj_txt["munge"] = obj_[obj_key_].dup; obj_txt["munge"] = (obj_["is"].match(ctRegex!(`verse|code`))) ? obj_txt["munge"] : obj_txt["munge"].strip; if (_new_doc) { anchor_tag = ""; } auto x = munge.init; ST_txtAndAnchorTagPlusHasFootnotesUrlsImages ret; ret.obj_txt = ""; ret.anchor_tag = ""; ret.has_notes_reg = false; ret.has_notes_star = false; ret.has_notes_plus = false; ret.has_links = false; ret.has_images = false; ret.has_images_without_dimensions = false; if ((obj_["is"] == "para") || (obj_["is"] == "heading") || (obj_["is"] == "quote") || (obj_["is"] == "group") || (obj_["is"] == "block") || (obj_["is"] == "verse")) { obj_txt["munge"] = (obj_txt["munge"]).inline_markup_faces; obj_txt["munge"] = (obj_txt["munge"]).links_and_images; } switch (obj_["is"]) { case "heading": if (_new_doc) { anchor_tag = ""; } obj_txt["munge"] = _configured_auto_heading_numbering_and_segment_anchor_tags(obj_txt["munge"], obj_, conf_make_meta, _new_doc); obj_txt["munge"] = _make_segment_anchor_tags_if_none_provided(obj_txt["munge"], obj_["lev"], _new_doc); if (auto m = obj_txt["munge"].match(rgx.heading_anchor_tag)) { anchor_tag = m.captures[1]; } else if (obj_["lev"] == "1") { writeln("heading anchor tag missing: ", obj_txt["munge"]); } x = munge.munge_heading(obj_txt["munge"], reset_note_numbers); reset_note_numbers = false; goto default; case "para": x = munge.munge_para(obj_txt["munge"]); goto default; case "group": x = munge.munge_group(obj_txt["munge"]); goto default; case "block": x = munge.munge_block(obj_txt["munge"]); goto default; case "quote": x = munge.munge_quote(obj_txt["munge"]); goto default; case "verse": x = munge.munge_verse(obj_txt["munge"]); goto default; case "code": x = munge.munge_code(obj_txt["munge"]); goto default; case "table": x = munge.munge_table(obj_txt["munge"]); goto default; case "comment": x = munge.munge_comment(obj_txt["munge"]); goto default; case "doc_end_reset": munge.initialize_note_numbers(); break; default: // para, heading, group, block, verse ret.obj_txt = x.obj_txt; ret.anchor_tag = anchor_tag; ret.has_notes_reg = x.has_notes_reg; ret.has_notes_star = x.has_notes_star; ret.has_notes_plus = x.has_notes_plus; ret.has_links = x.has_urls; ret.has_images = x.has_images; ret.has_images_without_dimensions = x.has_images_without_dimensions; break; } anchor_tag = ""; return ret; } invariant() { } auto _clean_heading_toc_()( char[] heading_toc_, ) { auto m = (cast(char[]) heading_toc_).matchFirst(rgx.heading); heading_toc_ = (m.post).replaceAll(rgx.inline_notes_curly_gen, ""); return heading_toc_; }; ST_flow_table_of_contents_gather_headings flow_table_of_contents_gather_headings(CMM)( // string[string] obj_, CMM conf_make_meta, string[string] tag_in_seg, string _anchor_tag, string[][string] lev4_subtoc, ObjGenericComposite[] the_document_toc_section, ) { ObjGenericComposite comp_obj_; mixin InternalMarkup; static auto mkup = InlineMarkup(); char[] heading_toc_ = (obj_["substantive"].dup.strip.to!(char[])) .replaceAll(rgx.inline_notes_al, ""); heading_toc_ = _clean_heading_toc_(heading_toc_); heading_toc_ = heading_text_for_navigation(heading_toc_.to!string).to!(char[]); auto attrib = ""; string toc_txt_, subtoc_txt_; int[string] indent; if (obj_["lev_markup_number"].to!int > 0) { indent = [ "hang_position" : obj_["lev_markup_number"].to!int, "base_position" : obj_["lev_markup_number"].to!int, ]; toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, heading_toc_.strip, mkup.lnk_c, mkup.url_o, _anchor_tag, mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_ = set_object_generic("frontmatter", "toc", "para", "toc", toc_txt_.to!string.strip, 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.metainfo.dummy_heading = (an_object["dummy_heading_status"] == "t") ? true: false; comp_obj_.attrib.indent_hang = indent["hang_position"]; comp_obj_.attrib.indent_base = indent["base_position"]; comp_obj_.attrib.bullet = false; comp_obj_.has.inline_links = true; the_document_toc_section ~= comp_obj_; } comp_obj_ = comp_obj_.init; comp_obj_.metainfo.is_of_part = "frontmatter"; comp_obj_.metainfo.is_of_section = "toc"; comp_obj_.metainfo.is_of_type = "para"; comp_obj_.metainfo.is_a = "toc"; comp_obj_.metainfo.ocn = 0; comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.metainfo.dummy_heading = (an_object["dummy_heading_status"] == "t") ? true: false; comp_obj_.attrib.bullet = false; comp_obj_.has.inline_links = true; switch (obj_["lev_markup_number"].to!int) { case 0: .. case 3: break; case 4: lev4_subtoc[tag_in_seg["seg_lv4"]] = []; break; case 5: .. case 7: subtoc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, heading_toc_.strip, mkup.lnk_c, mkup.url_o, _anchor_tag, mkup.url_c, ); lev4_subtoc[tag_in_seg["seg_lv4"]] ~= links_and_images(obj_["lev_markup_number"] ~ "~ " ~ subtoc_txt_.to!string.strip ); break; default: break; } ST_flow_table_of_contents_gather_headings ret; { ret.the_document_toc_section = the_document_toc_section; ret.lev4_subtoc = lev4_subtoc; } return ret; } invariant() { } private: static int[] heading_num = [ 0, 0, 0, 0 ]; static string heading_number_auto_composite = ""; static string heading_number_auto_composite_segname = ""; static bool[] auto_heading_numbering = [ true, true, true, true]; static string _configured_auto_heading_numbering_and_segment_anchor_tags(CMM)( string munge_, string[string] obj_, CMM conf_make_meta, bool _new_doc, ) { if (_new_doc) { heading_num = [ 0, 0, 0, 0 ]; heading_number_auto_composite = ""; auto_heading_numbering = [ true, true, true, true]; } if (conf_make_meta.make.auto_num_top_lv) { if (obj_["lev_markup_number"].to!int == 0) { heading_num[0] = 0; heading_num[1] = 0; heading_num[2] = 0; heading_num[3] = 0; heading_number_auto_composite = ""; } // auto_num_depth minimum 0 // (1.) default 2 (1.1.1) max 3 (1.1.1.1) implement if ( conf_make_meta.make.auto_num_top_lv > obj_["lev_markup_number"].to!uint ) { heading_num[1] = 0; heading_num[2] = 0; heading_num[3] = 0; } else if ( conf_make_meta.make.auto_num_top_lv == obj_["lev_markup_number"].to!uint ) { auto_heading_numbering[0] = (munge_.match(rgx.auto_heading_numbering_off_lv1)) ? false : true; if (auto_heading_numbering[0]) { heading_num[0] ++; } heading_num[1] = 0; heading_num[2] = 0; heading_num[3] = 0; } else if ( conf_make_meta.make.auto_num_top_lv == (obj_["lev_markup_number"].to!uint - 1) ) { auto_heading_numbering[1] = (munge_.match(rgx.auto_heading_numbering_off_lv2)) ? false : true; if (auto_heading_numbering[0] && auto_heading_numbering[1]) { heading_num[1] ++; } heading_num[2] = 0; heading_num[3] = 0; } else if ( conf_make_meta.make.auto_num_top_lv == (obj_["lev_markup_number"].to!uint - 2) ) { auto_heading_numbering[2] = (munge_.match(rgx.auto_heading_numbering_off_lv3)) ? false : true; if (auto_heading_numbering[0] && auto_heading_numbering[1] && auto_heading_numbering[2]) { heading_num[2] ++; } heading_num[3] = 0; } else if ( conf_make_meta.make.auto_num_top_lv == (obj_["lev_markup_number"].to!uint - 3) ) { auto_heading_numbering[3] = (munge_.match(rgx.auto_heading_numbering_off_lv4)) ? false : true; if (auto_heading_numbering[0] && auto_heading_numbering[1] && auto_heading_numbering[2] && auto_heading_numbering[3]) { heading_num[3] ++; } } if (auto_heading_numbering[0]) { if (heading_num[3] > 0) { heading_number_auto_composite = (conf_make_meta.make.auto_num_depth.to!uint == 3 && auto_heading_numbering[3]) ? (format(q"┃%s.%s.%s.%s┃", heading_num[0].to!string, heading_num[1].to!string, heading_num[2].to!string, heading_num[3].to!string )) : ""; } else if (heading_num[2] > 0) { heading_number_auto_composite = ((conf_make_meta.make.auto_num_depth.to!uint >= 2) && (conf_make_meta.make.auto_num_depth.to!uint <= 3) && auto_heading_numbering[2]) ? (format(q"┃%s.%s.%s┃", heading_num[0].to!string, heading_num[1].to!string, heading_num[2].to!string )) : ""; } else if (heading_num[1] > 0) { heading_number_auto_composite = ((conf_make_meta.make.auto_num_depth.to!uint >= 1) && (conf_make_meta.make.auto_num_depth.to!uint <= 3) && auto_heading_numbering[1]) ? (format(q"┃%s.%s┃", heading_num[0].to!string, heading_num[1].to!string )) : ""; } else if (heading_num[0] > 0 && munge_.match(rgx.auto_heading_numbering_lv1) ) { heading_number_auto_composite = ((conf_make_meta.make.auto_num_depth.to!uint >= 0) && (conf_make_meta.make.auto_num_depth.to!uint <= 3) && auto_heading_numbering[0]) ? (format(q"┃%s┃", heading_num[0].to!string )) : ""; } else { heading_number_auto_composite = ""; } } heading_number_auto_composite_segname = (heading_number_auto_composite.empty) ? "" : "seg_" ~ heading_number_auto_composite; debug(heading_number_auto) { writeln(heading_number_auto_composite); } if ((!empty(heading_number_auto_composite)) && (obj_["lev_markup_number"].to!uint >= conf_make_meta.make.auto_num_top_lv)) { munge_ = munge_ .replaceFirst(rgx.heading, "$1~$2 " ~ heading_number_auto_composite ~ ". ") .replaceFirst(rgx.heading_marker_missing_tag, "$1~" ~ heading_number_auto_composite_segname ~ " "); } } return munge_; } static int heading_num_lev1 = 0; static string _make_segment_anchor_tags_if_none_provided()( string munge_, string lev_, bool _new_doc ) { if (!(munge_.match(rgx.heading_anchor_tag))) { if (lev_ == "A") { // (_new_doc) heading_num_lev1 = 0; } if (munge_.match(rgx.heading_identify_anchor_tag)) { if (auto m = munge_.match(rgx.heading_extract_named_anchor_tag)) { munge_ = munge_.replaceFirst( rgx.heading_marker_missing_tag, "$1~" ~ m.captures[1].toLower ~ "_" ~ m.captures[2] ~ " "); if (auto n = munge_.match(rgx.heading_anchor_tag_plus_colon)) { auto tag_remunge_ = n.captures[2] .replaceAll(rgx.heading_marker_tag_has_colon, ".."); munge_ = munge_.replaceFirst(rgx.heading_anchor_tag_plus_colon, n.captures[1] ~ tag_remunge_ ~ " "); } } else if (auto m = munge_.match(rgx.heading_extract_unnamed_anchor_tag)) { munge_ = munge_.replaceFirst( 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" heading_num_lev1 ++; munge_ = munge_.replaceFirst( rgx.heading_marker_missing_tag, "$1~" ~ "x" ~ heading_num_lev1.to!string ~ " "); } } return munge_; } } // ↑ - object inline markup #+END_SRC ***** ϝ object attributes #+NAME: ocdaFunc_obj_attributes #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object attributes struct ObjAttributes { string[string] _obj_attrib; string obj_attributes()( string obj_is_, string obj_raw, ObjGenericComposite comp_obj_, ) { scope(exit) { destroy(obj_is_); destroy(obj_raw); destroy(comp_obj_); } _obj_attrib["json"] ="{"; switch (obj_is_) { case "heading": _obj_attrib["json"] ~= txt_heading(obj_raw); break; case "para": _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw) ~ txt_para(obj_raw); break; case "code": _obj_attrib["json"] ~= txt_code(obj_raw); break; case "group": _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw) ~ txt_group(obj_raw); break; case "block": _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw) ~ txt_block(obj_raw); break; case "verse": _obj_attrib["json"] ~= txt_verse(obj_raw); break; case "quote": _obj_attrib["json"] ~= txt_quote(obj_raw); break; case "table": _obj_attrib["json"] ~= txt_table(obj_raw); break; case "comment": _obj_attrib["json"] ~= txt_comment(obj_raw); break; default: _obj_attrib["json"] ~= txt_para(obj_raw); break; } _obj_attrib["json"] ~= " }"; _obj_attrib["json"] = _set_additional_values_parse_as_json(_obj_attrib["json"], obj_is_, comp_obj_); debug(structattrib) { if (oa_j["is"].str() == "heading") { writeln(_obj_attrib["json"]); writeln( "is: ", oa_j["is"].str(), "; object_number: ", oa_j["object_number"].integer() ); } } return _obj_attrib["json"]; } invariant() { } private: string _obj_attributes; string txt_para_and_blocks()(string obj_txt_in) { if (obj_txt_in.matchFirst(rgx.para_bullet)) { _obj_attributes =" \"bullet\": \"true\"," ~ " \"indent_hang\": 0," ~ " \"indent_base\": 0,"; } else if (auto m = obj_txt_in.matchFirst(rgx.para_bullet_indent)) { _obj_attributes =" \"bullet\": \"true\"," ~ " \"indent_hang\": " ~ m["indent"].to!string ~ "," ~ " \"indent_base\": " ~ m["indent"].to!string ~ ","; } else if (auto m = obj_txt_in.matchFirst(rgx.para_indent_hang)) { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_hang\": " ~ m["hang"].to!string ~ "," ~ " \"indent_base\": " ~ m["indent"].to!string ~ ","; } else if (auto m = obj_txt_in.matchFirst(rgx.para_indent)) { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_hang\": " ~ m["indent"].to!string ~ "," ~ " \"indent_base\": " ~ m["indent"].to!string ~ ","; } else { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_hang\": 0," ~ " \"indent_base\": 0,"; } return _obj_attributes; } string txt_heading()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"para\"," ~ " \"is\": \"heading\""; return _obj_attributes; } invariant() { } string txt_para()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"para\"," ~ " \"is\": \"para\""; return _obj_attributes; } invariant() { } string txt_quote()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"quote\""; return _obj_attributes; } invariant() { } string txt_group()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"group\""; return _obj_attributes; } invariant() { } string txt_block()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"block\""; return _obj_attributes; } invariant() { } string txt_verse()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"verse\""; return _obj_attributes; } invariant() { } string txt_code()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"code\""; return _obj_attributes; } invariant() { } string txt_table()(string obj_txt_in) { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"table\""; return _obj_attributes; } invariant() { } string txt_comment()(string obj_txt_in) { _obj_attributes = " \"use\": \"comment\"," ~ " \"of\": \"comment\"," ~ " \"is\": \"comment\""; return _obj_attributes; } invariant() { } string _set_additional_values_parse_as_json()( string _obj_attrib, string obj_is_, ObjGenericComposite comp_obj_, ) { JSONValue oa_j = parseJSON(_obj_attrib); assert( (oa_j.type == JSON_TYPE.OBJECT) ); if (obj_is_ == "heading") { oa_j.object["object_number"] = comp_obj_.metainfo.ocn; oa_j.object["lev_markup_number"] = comp_obj_.metainfo.heading_lev_markup; oa_j.object["lev_collapsed_number"] = comp_obj_.metainfo.heading_lev_collapsed; oa_j.object["heading_ptr"] = comp_obj_.ptr.heading; oa_j.object["doc_object_ptr"] = comp_obj_.ptr.doc_object; } oa_j.object["parent_object_number"] = comp_obj_.metainfo.parent_ocn; oa_j.object["parent_lev_markup_number"] = comp_obj_.metainfo.parent_lev_markup; _obj_attrib = oa_j.toString(); return _obj_attrib; } } // ↑ - object attributes #+END_SRC ***** ϝ object level tags #+NAME: ocdaFunc_obj_set_markup_level_tags #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object tags pure ObjGenericComposite obj_dom_structure_set_markup_tags()( ObjGenericComposite obj, 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_magic_numbers) { writeln("marked up: ", lev, ": ", dom); } obj.metainfo.dom_structure_markedup_tags_status = dom.dup; return obj; } pure ObjGenericComposite obj_dom_set_collapsed_tags()( ObjGenericComposite obj, 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_magic_numbers) { writeln("collapsed: ", lev, ": ", dom); } obj.metainfo.dom_structure_collapsed_tags_status = dom.dup; return obj; } // ↑ - object tags #+END_SRC ***** ϝ object digest #+NAME: ocdaFunc_obj_digest #+HEADER: :noweb yes #+BEGIN_SRC d <> #+END_SRC ****** return object digest - body text digests - extract image digests - object digest (program generated abstract object text body digest) (programs object hash stamp, abstract source verification available to associate with other generated formats) - image/filename digest [filesize] 1 - (verification of content of associated external file, document resiliance) - image/filename digest [filesize] 2 - (verification of content of associated external file, document resiliance) - you may want a "has_images" (do first) - CONSIDER having text body separate from (foot|end)notes - object digest (program generated abstract object text body digest) - note digest 1 - note digest 2 - currently text body includes inline notes - may not be worth it, but - notes then could be altered independently of the text, - and it gives a little more insight into document structure, which notes belong to which objects - but if going this route, some solution related to external links which may change might be more significant, consider, i think for now keep as is. #+NAME: ocdaFunc_obj_digest_return #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - object digest // pure SHA_256_Hashes_ obj_digest(M)( ObjGenericComposite obj, M manifested, ) { ST_file_name_hash_size_ safeComputeHashAndSize(N,P)(N filename, P file_path) @trusted { string file_with_path = (file_path ~ filename).to!string; /+ ↓ read & hash each image file once: an image referenced from several objects (or from several documents sharing an image directory) was otherwise re-read and re-hashed for every reference. static is thread-local in D, so the cache needs no synchronisation +/ static ST_file_name_hash_size_[string] _image_file_info_cache; if (auto _cached = file_with_path in _image_file_info_cache) { return *_cached; } ST_file_name_hash_size_ _file_info; _file_info.fileName = filename; /+ ↓ a referenced image that is absent or unreadable is recorded as such rather than aborting the abstraction (compare the WARNING issued by _image_dimensions for the same situation) +/ try { auto file_read = File(file_with_path, "r"); ubyte[32] file_sha256 = digest!SHA256(file_read.byChunk(4096 * 1024)); ulong fileSize = file_read.size; _file_info.fileHash_sha256 = file_sha256; _file_info.fileSize = fileSize; } catch (Exception ex) { _file_info.fileMissing = true; writeln("WARNING, image not found or unreadable: ", filename, "\n ", file_with_path); } /+ ↓ the image file's own pixel dimensions, which are not the display dimensions carried by the markup (w##h##): those are author set, or where given as w0h0 are derived by _image_dimensions and capped to a maximum display width. Header read only, no decode. +/ if (!_file_info.fileMissing) { import imageformats; int _w, _h, _chans; try { read_image_info(file_with_path, _w, _h, _chans); _file_info.imageWidth = _w; _file_info.imageHeight = _h; } catch (Exception ex) { debug(images) { writeln("image dimensions not read: ", filename); } } } _image_file_info_cache[file_with_path] = _file_info; return _file_info; } obj.metainfo.sha256.text = obj.text.sha256Of; string image_with_path; string image_path = manifested.src.image_dir_path ~ "/"; char[64] image_hash; int n = 0; /+ ↓ images, scanned for in every object type: the markup does not forbid an image in a heading, and an object type excluded from the scan would carry neither digest nor record, silently +/ if ((obj.text).match(rgx.inline_image)) { foreach (m; (obj.text).matchAll(rgx.inline_image)) { image_with_path = image_path ~ m["img"]; ST_file_name_hash_size_ _file_info = safeComputeHashAndSize(m["img"], image_path); obj.metainfo.sha256.images ~= [_file_info]; } } char[] image_summary; if (obj.metainfo.sha256.images.length > 0) { foreach (i; obj.metainfo.sha256.images) { image_summary ~= (i.fileMissing) ? "\n - " ~ "MISSING OR UNREADABLE" ~ " - " ~ i.fileName : "\n - " ~ i.fileHash_sha256.toHexString ~ "::" ~ i.fileSize.to!string ~ " - " ~ i.fileName; } } if (obj.metainfo.is_a == "heading") { obj.metainfo.sha256.summary ~= "• - " ~ obj.metainfo.sha256.text.toHexString ~ " " ~ obj.metainfo.ocn.to!string ~ " " ~ obj.metainfo.is_a ~ " " ~ obj.metainfo.marked_up_level ~ "~ " ~ obj.text ~ image_summary; } else { obj.metainfo.sha256.summary ~= " - " ~ obj.metainfo.sha256.text.toHexString ~ " " ~ obj.metainfo.ocn.to!string ~ " " ~ obj.metainfo.is_a ~ image_summary; } // writeln(obj.metainfo.sha256.summary); // WRONG DEBUG REMOVE return obj.metainfo.sha256; } // ↑ - object digest #+END_SRC **** ϝ section ***** ϝ section toc - table of contents #+NAME: ocdaFunc_section_toc #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - table of contents @system ObjGenericComposite[] backmatter_gather_table_of_contents( ObjGenericComposite[] the_document_endnotes_section, ObjGenericComposite[] the_document_glossary_section, ObjGenericComposite[] the_document_bibliography_section, ObjGenericComposite[] the_document_bookindex_section, ObjGenericComposite[] the_document_blurb_section, ) { ObjGenericComposite[] toc_section_backmatter; string toc_txt_; static auto mkup = InlineMarkup(); ObjGenericComposite comp_obj_; int[string] indent = [ "hang_position" : 1, "base_position" : 1, ]; comp_obj_ = set_object_generic("frontmatter", "toc", "para", "toc", "", 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.attrib.indent_hang = indent["hang_position"]; comp_obj_.attrib.indent_base = indent["base_position"]; comp_obj_.attrib.bullet = false; if (the_document_endnotes_section.length > 1) { toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, "Endnotes", mkup.lnk_c, mkup.url_o, "endnotes", mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_.text = toc_txt_.to!string.strip; comp_obj_.has.inline_links = true; toc_section_backmatter ~= comp_obj_; } if (the_document_glossary_section.length > 1) { toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, "Glossary", mkup.lnk_c, mkup.url_o, "glossary", mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_.text = toc_txt_.to!string.strip; comp_obj_.has.inline_links = true; toc_section_backmatter ~= comp_obj_; } if (the_document_bibliography_section.length > 1){ toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, "Bibliography", mkup.lnk_c, mkup.url_o, "bibliography", mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_.text = toc_txt_.to!string.strip; comp_obj_.has.inline_links = true; toc_section_backmatter ~= comp_obj_; } if (the_document_bookindex_section.length > 1) { toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, "Book Index", mkup.lnk_c, mkup.url_o, "bookindex", mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_.text = toc_txt_.to!string.strip; comp_obj_.has.inline_links = true; toc_section_backmatter ~= comp_obj_; } if (the_document_blurb_section.length > 1) { toc_txt_ = format("%s%s%s%s#%s%s", mkup.lnk_o, "Blurb", mkup.lnk_c, mkup.url_o, "blurb", mkup.url_c, ); toc_txt_= toc_txt_.links_and_images; comp_obj_.has.inline_links = true; comp_obj_.text = toc_txt_.to!string.strip; toc_section_backmatter ~= comp_obj_; } debug(toc) { writefln( "%s %s", __LINE__,); foreach (toc_linked_heading; toc_section_backmatter) { writeln(mkup.indent_by_spaces_provided(toc_linked_heading.attrib.indent_hang), toc_linked_heading.text); } } return toc_section_backmatter; } // ↑ - table of contents #+END_SRC ***** ϝ section endnotes #+NAME: ocdaFunc_section_endnotes #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - endnotes struct NotesSection { string[string] object_notes; int previous_count; int mkn; static auto rgx = RgxI(); private auto gather_notes_for_endnote_section( ObjGenericComposite[] contents_am, string[string] tag_in_seg, int cntr, ) { assert((contents_am[cntr].metainfo.is_a == "para") || (contents_am[cntr].metainfo.is_a == "heading") || (contents_am[cntr].metainfo.is_a == "quote") || (contents_am[cntr].metainfo.is_a == "group") || (contents_am[cntr].metainfo.is_a == "block") || (contents_am[cntr].metainfo.is_a == "verse")); assert(cntr >= previous_count); assert( (contents_am[cntr].text).match( rgx.inline_notes_al_all_note) ); mixin InternalMarkup; previous_count = cntr; static auto mkup = InlineMarkup(); static auto munge = ObjInlineMarkupMunge(); foreach(m; (contents_am[cntr].text).matchAll( rgx.inline_notes_al_special_char_note) ) { debug(endnotes_build) { writeln( "{", mkup.ff_i, mkup.superscript, mkup.ff_o, m["char"], ".", mkup.ff_c, mkup.superscript, "}" ~ mkup.mark_internal_site_lnk, tag_in_seg["seg_lv4"], ".fnSuffix#noteref_\n ", m["char"], " ", m["note"]); // sometimes need segment name (segmented html & epub) } // you need anchor for segments at this point -> object_notes["anchor"] ~= "note_" ~ m["char"] ~ "』"; object_notes["notes"] ~= (tag_in_seg["seg_lv4"].empty) ? (links_and_images( "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["char"] ~ "." ~ mkup.ff_c ~ mkup.superscript ~ "}#noteref_" ~ m["char"]) ~ " " ~ m["note"] ~ "』" ) : (links_and_images( "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["char"] ~ "." ~ mkup.ff_c ~ mkup.superscript ~ "}" ~ mkup.mark_internal_site_lnk ~ tag_in_seg["seg_lv4"] ~ ".fnSuffix#noteref_" ~ m["char"]) ~ " " ~ m["note"] ~ "』" ); } foreach(m; (contents_am[cntr].text).matchAll( rgx.inline_notes_al_regular_number_note) ) { debug(endnotes_build) { writeln( "{", mkup.ff_i, mkup.superscipt, mkup.ff_o, m["num"], ".", mkup.ff_c, mkup.superscipt, "}" ~ mkup.mark_internal_site_lnk, tag_in_seg["seg_lv4"], ".fnSuffix#noteref_\n ", m["num"], " ", m["note"]); // sometimes need segment name (segmented html & epub) } // you need anchor for segments at this point -> object_notes["anchor"] ~= "note_" ~ m["num"] ~ "』"; object_notes["notes"] ~= (tag_in_seg["seg_lv4"].empty) ? (links_and_images( "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["num"] ~ "." ~ mkup.ff_c ~ mkup.superscript ~ "}#noteref_" ~ m["num"]) ~ " " ~ m["note"] ~ "』" ) : (links_and_images( "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["num"] ~ "." ~ mkup.ff_c ~ mkup.superscript ~ "}" ~ mkup.mark_internal_site_lnk ~ tag_in_seg["seg_lv4"] ~ ".fnSuffix#noteref_" ~ m["num"]) ~ " " ~ m["note"] ~ "』" ); } return object_notes; } private auto gathered_notes() { string[][string] endnotes_; if (object_notes.length > 1) { endnotes_["notes"] = (object_notes["notes"].split(rgx.break_string))[0..$-1]; endnotes_["anchor"] = (object_notes["anchor"].split(rgx.break_string))[0..$-1]; } else { endnotes_["notes"] = []; endnotes_["anchor"] = []; } return endnotes_; } private ST_endnotes backmatter_endnote_objects(O)( OCNset obj_cite_digits, O opt_action, ) { mixin spineNode; ObjGenericComposite[] the_document_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_; if ((endnotes_["notes"].length > 0) && (opt_action.backmatter && opt_action.section_endnotes)) { { comp_obj_ = set_object_heading("lev1", "backmatter", "endnotes", "Endnotes"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = false; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "_part_endnotes"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = "endnotes"; comp_obj_.tags.anchor_tags = ["section_endnotes"]; the_document_endnotes_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; ++mkn; } { comp_obj_ = set_object_heading("lev4", "backmatter", "endnotes", "Endnotes"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "endnotes"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.tags.anchor_tags = ["endnotes"]; the_document_endnotes_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; ++mkn; } } else { comp_obj_ = set_object_heading("lev1", "empty", "empty", "(skip) there are no Endnotes"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; the_document_endnotes_section ~= comp_obj_; } if (opt_action.backmatter && opt_action.section_endnotes) { ObjGenericComposite comp_obj_endnote_; comp_obj_endnote_ = set_object_generic("backmatter", "endnotes", "para", "endnote", "", 0); comp_obj_endnote_.metainfo.identifier = ""; // comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_endnote_.attrib.indent_hang = 0; comp_obj_endnote_.attrib.indent_base = 0; comp_obj_endnote_.attrib.bullet = false; foreach (i, endnote; endnotes_["notes"]) { auto m = endnote.matchFirst(rgx.note_ref); string notenumber = m["ref"].to!string; string anchor_tag = "note_" ~ notenumber; comp_obj_endnote_.tags.anchor_tags = [ endnotes_["anchor"][i] ]; comp_obj_endnote_.has.inline_links = true; comp_obj_endnote_.text = endnote.inline_markup_faces.strip; the_document_endnotes_section ~= comp_obj_endnote_; } } ST_endnotes ret; { ret.endnotes = the_document_endnotes_section; ret.ocn = obj_cite_digits; } return ret; } } // ↑ - endnotes #+END_SRC ***** ϝ section book index #+NAME: ocdaFunc_section_book_index #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - section book index @system ST_flow_book_index flow_book_index_(B)( char[] line, string[string] an_object, string book_idx_tmp, uint[string] pith, B opt_action, ) { static auto rgx = RgxI(); if (auto m = line.match(rgx.book_index_item)) { // match book_index debug(bookindexmatch) { writefln( "* [bookindex] %s\n", m["bookindex"].to!string, ); } an_object["bookindex_nugget"] = m.captures[1].to!string; } else if (auto m = line.match(rgx.book_index_item_open)) { // match open book_index pith["section"] = eN.sect.book_index; if (opt_action.backmatter && opt_action.section_bookindex) { book_idx_tmp = m.captures[1].to!string; debug(bookindexmatch) { writefln( "* [bookindex] %s\n", book_idx_tmp,); } } } else if (pith["section"] == eN.sect.book_index) { // book_index flag set if (auto m = line.match(rgx.book_index_item_close)) { pith["section"] = eN.sect.unset; if (opt_action.backmatter && opt_action.section_bookindex) { an_object["bookindex_nugget"] = book_idx_tmp ~ m.captures[1].to!string; debug(bookindexmatch) { writefln( "* [bookindex] %s\n", book_idx_tmp,); } } book_idx_tmp = ""; } else { if (opt_action.backmatter && opt_action.section_bookindex) { book_idx_tmp ~= line; } } } ST_flow_book_index ret; { ret.this_object = an_object; ret.pith = pith; ret.book_idx_tmp = book_idx_tmp; } return ret; } struct BookIndexNuggetHash { string main_term, sub_term, sub_term_bits; int object_number_offset, object_number_endpoint; string[] object_numbers; string[][string][string] bi_hash_nugget; string[] bi_main_terms_split_arr; string[][string][string] bookindex_nugget_hash(S)( string bookindex_section, OCNset obj_cite_digits, S tag_in_seg, ) { debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); } debug(bookindexraw) { if (!bookindex_section.empty) { writeln( "* [bookindex] ", "[", obj_cite_digits.object_number.to!string, ": ", tag_in_seg["seg_lv4"], "] ", bookindex_section, " - - - ", "[", obj_cite_digits.object_number.to!string, "] ", bookindex_section ); } } static auto rgx = RgxI(); if (!bookindex_section.empty) { auto bi_main_terms_split_arr = bookindex_section.split(rgx.bi_main_terms_split); foreach (bi_main_terms_content; bi_main_terms_split_arr) { auto bi_main_term_and_rest = bi_main_terms_content.split(rgx.bi_main_term_plus_rest_split); if (auto m = bi_main_term_and_rest[0].match( rgx.bi_term_and_object_numbers_match) ) { main_term = m.captures[1].strip; object_number_offset = m.captures[2].to!int; object_number_endpoint = (obj_cite_digits.object_number + object_number_offset); object_numbers ~= (obj_cite_digits.object_number.to!string ~ "-" ~ object_number_endpoint.to!string); } else { main_term = bi_main_term_and_rest[0].strip; object_numbers ~= obj_cite_digits.object_number.to!string; } bi_hash_nugget[main_term]["_a"] ~= object_numbers; object_numbers = null; if (bi_main_term_and_rest.length > 1) { auto bi_sub_terms_split_arr = bi_main_term_and_rest[1].split( rgx.bi_sub_terms_plus_object_number_offset_split ); foreach (sub_terms_bits; bi_sub_terms_split_arr) { if (auto m = sub_terms_bits.match(rgx.bi_term_and_object_numbers_match)) { sub_term = m.captures[1].strip; object_number_offset = m.captures[2].to!int; object_number_endpoint = (obj_cite_digits.object_number + object_number_offset); object_numbers ~= (obj_cite_digits.object_number.to!string ~ " - " ~ object_number_endpoint.to!string); } else { sub_term = sub_terms_bits.strip; object_numbers ~= obj_cite_digits.object_number.to!string; } if (!empty(sub_term)) { bi_hash_nugget[main_term][sub_term] ~= object_numbers; } object_numbers = null; } } } } return bi_hash_nugget; } invariant() { } } struct BookIndexReportIndent { int mkn, skn; void bookindex_report_indented()( string[][string][string] bookindex_unordered_hashes ) { auto mainkeys = bookindex_unordered_hashes.byKey.array.sort().release; foreach (mainkey; mainkeys) { debug(bookindex1) { writeln(mainkey); } auto subkeys = bookindex_unordered_hashes[mainkey].byKey.array.sort().release; foreach (subkey; subkeys) { debug(bookindex1) { writeln(" ", subkey); writeln(" ", to!string( bookindex_unordered_hashes[mainkey][subkey] )); } ++skn; } ++mkn; } } } struct BookIndexReportSection { int mkn, skn; static auto rgx = RgxI(); static auto munge = ObjInlineMarkupMunge(); void bookindex_write_section()( string[][string][string] bookindex_unordered_hashes ) { auto mainkeys = bookindex_unordered_hashes.byKey.array .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release; foreach (mainkey; mainkeys) { write("_0_1 ⑆!┨", mainkey, "┣! "); foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { auto go = ref_.replaceAll(rgx.book_index_go, "$1"); write(" {", ref_, "}#", go, ", "); } writeln(" \\\\"); bookindex_unordered_hashes[mainkey].remove("_a"); auto subkeys = bookindex_unordered_hashes[mainkey].byKey.array .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release; foreach (subkey; subkeys) { write(" ", subkey, ", "); foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { auto go = ref_.replaceAll(rgx.book_index_go, "$1"); write(" {", ref_, "}#", go, ", "); } writeln(" \\\\"); ++skn; } ++mkn; } } @system ST_bookindex backmatter_bookindex_build_abstraction_section(B)( string[][string][string] bookindex_unordered_hashes, OCNset obj_cite_digits, B opt_action, ) { debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); } mixin spineNode; mixin InternalMarkup; static 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!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release; ObjGenericComposite[] bookindex_section; ObjGenericComposite comp_obj_; auto node_para_int_ = node_metadata_para_int; auto node_para_str_ = node_metadata_para_str; if ((mainkeys.length > 0) && (opt_action.backmatter && opt_action.section_bookindex)) { string bi_tmp; string[] bi_tmp_tags; { comp_obj_ = set_object_heading("lev1", "backmatter", "bookindex", "Book Index"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = false; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "_part_book_index"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = "bookindex"; comp_obj_.tags.anchor_tags = ["section_bookindex"]; comp_obj_.has.inline_links = true; bookindex_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; ++mkn; } { comp_obj_ = set_object_heading("lev4", "backmatter", "bookindex", "Index"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "bookindex"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.metainfo.heading_lev_collapsed = 2; comp_obj_.has.inline_links = false; comp_obj_.tags.anchor_tags = ["bookindex"]; bookindex_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; ++mkn; } import std.array : appender; auto buffer = appender!(char[])(); string[dchar] transTable = [' ' : "_"]; foreach (mainkey; mainkeys) { bi_tmp_tags = [""]; bi_tmp = mkup.ff_i ~ mkup.bold ~ mkup.ff_o ~ mainkey ~ mkup.ff_c ~ mkup.bold ~ " "; buffer.clear(); bi_tmp_tags ~= translate(mainkey, transTable); auto bkidx_lnk(string locs) { string markup = ""; if (auto m = locs.matchFirst(rgx.book_index_go)) { markup = links_and_images("{ " ~ m["link"] ~ " }" ~ "#" ~ m["ocn"] ~ ", "); } else { writeln(__LINE__, ": ", locs); } return markup; } foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { bi_tmp ~= bkidx_lnk(ref_); } bi_tmp ~= " \\\\\n "; bookindex_unordered_hashes[mainkey].remove("_a"); auto subkeys = bookindex_unordered_hashes[mainkey].byKey.array .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release; foreach (subkey; subkeys) { bi_tmp ~= subkey ~ ", "; buffer.clear(); bi_tmp_tags ~= translate(subkey, transTable); foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { bi_tmp ~= bkidx_lnk(ref_); } bi_tmp ~= " \\\\\n "; ++skn; } bi_tmp = bi_tmp.replaceFirst(rgx.trailing_linebreak, ""); comp_obj_ = set_object_generic("backmatter", "bookindex", "para", "bookindex", bi_tmp.to!string.strip, 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.anchor_tags = bi_tmp_tags; comp_obj_.attrib.indent_hang = 0; comp_obj_.attrib.indent_base = 1; comp_obj_.attrib.bullet = false; comp_obj_.has.inline_links = true; comp_obj_.text = bi_tmp.to!string.strip; bookindex_section ~= comp_obj_; ++mkn; } } else { // no book index, (figure out what to do here) comp_obj_ = set_object_heading("lev1", "backmatter", "bookindex", "(skip) there is no Book Index"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; bookindex_section ~= comp_obj_; } ST_bookindex ret; { ret.bookindex = bookindex_section; ret.ocn = obj_cite_digits; } return ret; } } // ↑ - section book index #+END_SRC ***** ϝ section glossary #+NAME: ocdaFunc_section_glossary #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - section glossary // ↓ build ST_the_section build_the_glossary_section( char[] line, // line is immutable, not necessary to return unchanged uint[string] pith, // double check, should not be necessary to pass pith string[string][string] tag_assoc, // only for headings: html & epub ) { static auto rgx = RgxI(); ObjGenericComposite comp_obj_; ObjGenericComposite[] add_to_current_document_section; indent = [ "hang_position" : 0, "base_position" : 0, ]; bullet = false; pith["txt_is"] = eN.txt_is.para; line_occur["para"] = eN.bi.off; an_object_key = "glossary_nugget"; ST_the_section ret; if (line.matchFirst(rgx.heading_glossary)) { { comp_obj_ = set_object_heading("lev1", "backmatter", "glossary", "Glossary"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = false; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "_part_glossary"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = "glossary"; comp_obj_.tags.anchor_tags = ["section_glossary"]; comp_obj_.metainfo.dom_structure_markedup_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; add_to_current_document_section ~= comp_obj_; // tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } { comp_obj_ = set_object_heading("lev4", "backmatter", "glossary", "Glossary"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "glossary"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.metainfo.heading_lev_collapsed = 2; comp_obj_.tags.anchor_tags = ["glossary"]; add_to_current_document_section ~= comp_obj_; // tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; pith["ocn"] = eN.ocn.on; } { ret.comp_section_obj ~= add_to_current_document_section; ret.pith = pith; ret.tag_assoc = tag_assoc; // only for headings: html & epub } } else { // para { ST_flow_para_match _get = line.flow_para_match_(an_object, an_object_key, indent, bullet, pith, line_occur); { an_object = _get.this_object; an_object_key = _get.this_object_key; pith = _get.pith; indent = _get.indent; bullet = _get.bullet; line_occur = _get.line_occur; } } comp_obj_ = set_object_generic("backmatter", "glossary", "para", "glossary", links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, ""), 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.attrib.indent_hang = indent["hang_position"]; comp_obj_.attrib.indent_base = indent["base_position"]; comp_obj_.attrib.bullet = bullet; add_to_current_document_section ~= comp_obj_; // pith["ocn"] = eN.ocn.on; { ret.comp_section_obj = add_to_current_document_section; ret.pith = pith; ret.tag_assoc = tag_assoc; // NO CHANGE here, only for headings: html & epub } } return ret; } // ↑ - section glossary #+END_SRC ***** ϝ section bibliography #+NAME: ocdaFunc_section_bibliography #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - section bibliography @system ST_biblio_section backmatter_make_the_bibliography_section()( string[] biblio_unsorted_incomplete, JSONValue[] bib_arr_json, ) { Bibliography biblio = Bibliography(); ObjGenericComposite comp_obj_; static auto mkup = InlineMarkup(); ST_flow_bibliography _get = biblio.flow_bibliography_(biblio_unsorted_incomplete, bib_arr_json); JSONValue[] biblio_ordered; biblio_ordered = _get.biblio_sorted; if (biblio_ordered.length > 0) { { comp_obj_ = set_object_heading("lev1", "backmatter", "bibliography", "Bibliography"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = false; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "_part_bibliography"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = "bibliography"; comp_obj_.tags.anchor_tags = ["section_bibliography"]; comp_obj_.metainfo.dom_structure_markedup_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; the_document_bibliography_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } { comp_obj_ = set_object_heading("lev4", "backmatter", "bibliography", "Bibliography"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "bibliography"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.tags.anchor_tags = ["bibliography"]; the_document_bibliography_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } { string out_; foreach (entry; biblio_ordered) { out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.", ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str), entry["fulltitle"].str, ((entry["journal"].str.empty) ? "" : ", " ~ mkup.ff_i ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic), ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str), ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str), ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""), ", " ~ entry["year"].str, ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str), ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str), ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str), ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"), ); comp_obj_ = set_object_generic("backmatter", "bibliography", "para", "bibliography", out_.to!string.strip, 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.attrib.indent_hang = 0; comp_obj_.attrib.indent_base = 1; comp_obj_.attrib.bullet = bullet; comp_obj_.tags.anchor_tags = [anchor_tag]; the_document_bibliography_section ~= comp_obj_; } } } else { comp_obj_ = set_object_heading("lev1", "empty", "empty", "(skip) there is no Bibliography"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; the_document_bibliography_section ~= comp_obj_; } debug(bibliosection) { foreach (o; the_document_bibliography_section) { writeln(o.text); } } ST_biblio_section ret; { ret.bibliography_section = the_document_bibliography_section; ret.tag_assoc = tag_assoc; // } return ret; } struct Bibliography { @system ST_flow_bibliography flow_bibliography_()( string[] biblio_unsorted_incomplete, JSONValue[] bib_arr_json ) { JSONValue[] biblio_unsorted = biblio_make_unsorted_array_of_json_objects(biblio_unsorted_incomplete, bib_arr_json); // TODO lookat returns biblio_arr_json = []; biblio_unsorted_incomplete = []; JSONValue[] biblio_sorted__ = biblio_sort(biblio_unsorted); debug(biblio0) { biblio_debug(biblio_sorted__); 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++; } } ST_flow_bibliography ret; { ret.biblio_sorted = biblio_sorted__; ret.bib_arr_json = bib_arr_json; ret.biblio_unsorted_incomplete = biblio_unsorted_incomplete; } return ret; } @system final private JSONValue[] biblio_make_unsorted_array_of_json_objects()( string[] biblio_unordered, JSONValue[] bib_arr_json ) { 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; } return bib_arr_json.dup; } @system final private JSONValue[] biblio_sort()(JSONValue[] biblio_unordered) { 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_; } @system void biblio_debug()(JSONValue[] biblio_sorted) { debug(biblio0) { foreach (j; biblio_sorted) { if (!empty(j["fulltitle"].str)) { writeln(j["sortby_deemed_author_year_title"]); } } } } } // ↑ - section bibliography #+END_SRC ***** ϝ section blurb #+NAME: ocdaFunc_section_blurb #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - section blurb ST_the_section build_the_blurb_section(Opt) ( char[] line, // line is immutable, not necessary to return unchanged uint[string] pith, // double check, should not be necessary to pass pith string[string][string] tag_assoc, // only for headings: html & epub Opt opt_action, ) { static auto rgx = RgxI(); ObjGenericComposite comp_obj_; ObjGenericComposite[] add_to_current_document_section; // assert (opt_action.backmatter && opt_action.section_blurb); indent = [ "hang_position" : 0, "base_position" : 0, ]; bullet = false; if (auto m = line.matchFirst(rgx.para_indent)) { debug(paraindent) { writeln(line); } indent["hang_position"] = (m["indent"]).to!int; indent["base_position"] = (m["indent"]).to!int; } else if (line.matchFirst(rgx.para_bullet)) { debug(parabullet) { writeln(line); } bullet = true; } else if (auto m = line.matchFirst(rgx.para_indent_hang)) { debug(paraindenthang) { writeln(line); } indent = [ "hang_position" : (m["hang"]).to!int, "base_position" : (m["indent"]).to!int, ]; } else if (auto m = line.matchFirst(rgx.para_bullet_indent)) { debug(parabulletindent) { writeln(line); } indent = [ "hang_position" : (m["indent"]).to!int, "base_position" : (m["indent"]).to!int, ]; bullet = true; } pith["txt_is"] = eN.txt_is.para; line_occur["para"] = eN.bi.off; an_object_key = "blurb_nugget"; ST_the_section ret; if (line.matchFirst(rgx.heading_blurb) && (opt_action.backmatter && opt_action.section_blurb)) { { comp_obj_ = set_object_heading("lev1", "backmatter", "blurb", "Blurb"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = false; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "_part_blurb"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = "blurb"; comp_obj_.tags.anchor_tags = ["section_blurb"]; comp_obj_.metainfo.dom_structure_markedup_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0]; add_to_current_document_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } { comp_obj_ = set_object_heading("lev4", "backmatter", "blurb", "Blurb"); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = true; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "blurb"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.metainfo.heading_lev_collapsed = 2; comp_obj_.tags.anchor_tags = ["blurb"]; add_to_current_document_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } } else if (line.matchFirst(rgx.headings) && (opt_action.backmatter && opt_action.section_blurb)) { comp_obj_ = comp_obj_.init; comp_obj_.metainfo.is_of_part = "backmatter"; comp_obj_.metainfo.is_of_section = "blurb"; comp_obj_.metainfo.is_of_type = "para"; comp_obj_.metainfo.is_a = "heading"; comp_obj_.text = line.to!string; comp_obj_.metainfo.ocn = 0; comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.dummy_heading = false; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.tags.segment_anchor_tag_epub = "blurb"; comp_obj_.tags.anchor_tag_html = comp_obj_.tags.segment_anchor_tag_epub; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.metainfo.heading_lev_markup = an_object["lev_markup_number"].to!int; // make int, remove need to conv comp_obj_.metainfo.heading_lev_collapsed = an_object["lev_collapsed_number"].to!int; // make int, remove need to conv comp_obj_.metainfo.parent_ocn = 1; comp_obj_.metainfo.parent_lev_markup = 0; add_to_current_document_section ~= comp_obj_; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; } else if (!(line.empty)) { { ST_flow_para_match _get = line.flow_para_match_(an_object, an_object_key, indent, bullet, pith, line_occur); { an_object = _get.this_object; an_object_key = _get.this_object_key; pith = _get.pith; indent = _get.indent; bullet = _get.bullet; line_occur = _get.line_occur; } } comp_obj_ = set_object_generic("backmatter", "blurb", "para", "blurb", links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, ""), 0); comp_obj_.metainfo.identifier = ""; comp_obj_.metainfo.object_number_off = true; comp_obj_.metainfo.object_number_type = 0; comp_obj_.attrib.indent_hang = indent["hang_position"]; comp_obj_.attrib.indent_base = indent["base_position"]; comp_obj_.has.inline_links = true; comp_obj_.attrib.bullet = bullet; add_to_current_document_section ~= comp_obj_; } pith["ocn"] = eN.ocn.on; { ret.comp_section_obj = add_to_current_document_section; ret.pith = pith; ret.tag_assoc = tag_assoc; // NO CHANGE here, only for headings: html & epub } return ret; } // ↑ - section blurb #+END_SRC **** ϝ structure (segments, ancestors, descendants) ***** ϝ segnames #+NAME: ocdaFunc_segnames #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - segnames @system ST_segnames after_doc_determine_segnames( ObjGenericComposite[] the_document_body_section, ObjGenericComposite[] the_document_endnotes_section, ObjGenericComposite[] the_document_glossary_section, ObjGenericComposite[] the_document_bibliography_section, ObjGenericComposite[] the_document_bookindex_section, ObjGenericComposite[] the_document_blurb_section, string[][string] segnames, int html_segnames_ptr_cntr, int html_segnames_ptr, ) { string[string][string] notes_; if (the_document_body_section.length > 1) { string _notes; foreach (ref obj; the_document_body_section) { if (obj.has.inline_notes_reg) { if ((obj.text).matchFirst(rgx.inline_notes_al_gen)) { foreach (m; (obj.text).matchAll(rgx.inline_notes_al_regular_number_note)) { _notes ~= "\n\n" ~ m["num"] ~ ". " ~ m["note"]; notes_[(m["num"])]["ocn"] = obj.metainfo.ocn.to!string; } } } } } if (the_document_endnotes_section.length > 1) { segnames["html"] ~= "endnotes"; segnames["epub"] ~= "endnotes"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_endnotes_section) { auto matches = (obj.text).matchAll(rgx.endnote_section_note); foreach (m; matches) { obj.metainfo.parent_ocn = notes_[(m["notenumber"])]["ocn"].to!int; } } foreach (ref obj; the_document_endnotes_section) { if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; } } html_segnames_ptr_cntr++; } if (the_document_glossary_section.length > 1) { segnames["html"] ~= "glossary"; segnames["epub"] ~= "glossary"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_glossary_section) { if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; } } html_segnames_ptr_cntr++; } if (the_document_bibliography_section.length > 1) { segnames["html"] ~= "bibliography"; segnames["epub"] ~= "bibliography"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bibliography_section) { if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; } } html_segnames_ptr_cntr++; } if (the_document_bookindex_section.length > 1) { segnames["html"] ~= "bookindex"; segnames["epub"] ~= "bookindex"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bookindex_section) { if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; } } html_segnames_ptr_cntr++; } if (the_document_blurb_section.length > 1) { segnames["html"] ~= "blurb"; segnames["epub"] ~= "blurb"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_blurb_section) { if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; } } html_segnames_ptr_cntr++; } ST_segnames ret; ret.segnames = segnames; ret.html_segnames_ptr_cntr = html_segnames_ptr_cntr; ret.html_segnames_ptr = html_segnames_ptr; return ret; } // ↑ - segnames #+END_SRC ***** ϝ structure ancestors #+NAME: ocdaFunc_structure_ancestors #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - ancestors descendants struct NodeStructureMetadata { int lv, lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7; int obj_cite_digit; int[string] p_; // p_ parent_ static auto rgx = RgxI(); ObjGenericComposite node_location_emitter(La,Ta)( string lev_markup_number, string[string] tag_in_seg, La lev_anchor_tag, Ta tag_assoc, OCNset obj_cite_digits, int cntr_, int ptr_, string is_ ) { debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); } assert(is_ != "heading"); assert(obj_cite_digits.object_number.to!int >= 0); assert(is_ != "heading"); // should not be necessary assert(obj_cite_digits.object_number.to!int >= 0); // should not be necessary if (lv7 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_4; p_["object_number"] = lv7; } else if (lv6 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3; p_["object_number"] = lv6; } else if (lv5 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2; p_["object_number"] = lv5; } else { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1; p_["object_number"] = lv4; } ObjGenericComposite comp_obj_location; comp_obj_location = comp_obj_location.init; comp_obj_location.metainfo.is_a = is_; comp_obj_location.metainfo.ocn = obj_cite_digits.object_number; comp_obj_location.metainfo.identifier = obj_cite_digits.identifier; comp_obj_location.tags.anchor_tag_html = tag_in_seg["seg_lv4"]; comp_obj_location.tags.segment_anchor_tag_epub = tag_in_seg["seg_lv1to4"]; comp_obj_location.tags.heading_lev_anchor_tag = lev_anchor_tag; comp_obj_location.metainfo.parent_ocn = p_["object_number"]; comp_obj_location.metainfo.parent_lev_markup = p_["lev_markup_number"]; debug(_node) { if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("x ", _node.to!string); } else { writeln("- ", _node.to!string); } } assert(comp_obj_location.metainfo.parent_lev_markup >= 4); assert(comp_obj_location.metainfo.parent_lev_markup <= 7); assert(comp_obj_location.metainfo.parent_ocn >= 0); return comp_obj_location; } invariant() { } ObjGenericComposite node_emitter_heading(O,TaL,TA,SOAT)( O an_object, string[string] tag_in_seg, TaL lev_anchor_tag, TA tag_assoc, OCNset obj_cite_digits, int cntr_, int ptr_, string[] lv_ancestors_txt, int html_segnames_ptr, SOAT substantive_object_and_anchor_tags_struct, ) { string _text = an_object["substantive"]; string lev_markup_number = an_object["lev_markup_number"]; string lev_collapsed_number = an_object["lev_collapsed_number"]; string dummy_heading_status = an_object["dummy_heading_status"]; string is_ = an_object["is"]; debug(asserts) { static assert(is(typeof(lev) == string)); static assert(is(typeof(obj_cite_digits.object_number) == int)); } assert(is_ == "heading"); assert((obj_cite_digits.object_number).to!int >= 0); assert( lev_markup_number.match(rgx.levels_numbered), ("not a valid heading level: " ~ lev_markup_number ~ " at " ~ obj_cite_digits.object_number.to!string) ); if (lev_markup_number.match(rgx.levels_numbered)) { if (lev_markup_number.to!int == 0) { // TODO first hit (of two) with this assertion failure, check, fix & reinstate // assert(obj_cite_digits.object_number.to!int == 1, // "ERROR header lev markup number is: " ~ // lev_markup_number.to!string ~ // " obj_cite_digits.object_number.to!int should == 1 but is: " ~ // obj_cite_digits.object_number.to!string ~ // "\n" ~ _text); } } /+ ↓ ensure obj_cite_digit is assigned, else default 0 kept for every lv0..lv7 (and every parent ocn derived from them, for headings here and for non-heading objects in node_location_emitter) +/ obj_cite_digit = obj_cite_digits.object_number; switch (lev_markup_number.to!int) { case 0: lv = DocStructMarkupHeading.h_sect_A; /+ ↓ document root ocn is 1 by definition; the ocn is force-set to 1 later (see metadoc_from_src.d head section) so guard against a root emitted here with ocn 0 +/ lv0 = (obj_cite_digit > eN.bi.off) ? obj_cite_digit : 1; lv1 = 0; lv2 = 0; lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0; p_["lev_markup_number"] = 0; p_["object_number"] = 0; break; case 1: lv = DocStructMarkupHeading.h_sect_B; lv1 = obj_cite_digit; lv2 = 0; lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_A; p_["object_number"] = lv0; break; case 2: lv = DocStructMarkupHeading.h_sect_C; lv2 = obj_cite_digit; lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_B; p_["object_number"] = lv1; break; case 3: lv = DocStructMarkupHeading.h_sect_D; lv3 = obj_cite_digit; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_C; p_["object_number"] = lv2; break; case 4: lv = DocStructMarkupHeading.h_text_1; lv4 = obj_cite_digit; lv5 = 0; lv6 = 0; lv7 = 0; if (lv3 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_D; p_["object_number"] = lv3; } else if (lv2 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_C; p_["object_number"] = lv2; } else if (lv1 > eN.bi.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_B; p_["object_number"] = lv1; } else { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_A; p_["object_number"] = lv0; } break; case 5: lv = DocStructMarkupHeading.h_text_2; lv5 = obj_cite_digit; lv6 = 0; lv7 = 0; p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1; p_["object_number"] = lv4; break; case 6: lv = DocStructMarkupHeading.h_text_3; lv6 = obj_cite_digit; lv7 = 0; /+ ↓ markup levels are not skipped, a 3~ is enclosed by a 2~ (see assertions_doc_structure), the parent is that 2~, lv5, whether or not its ocn is author suppressed (0) +/ p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2; p_["object_number"] = lv5; break; case 7: lv = DocStructMarkupHeading.h_text_4; lv7 = obj_cite_digit; p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3; p_["object_number"] = lv6; break; default: break; } ObjGenericComposite comp_obj_; comp_obj_ = comp_obj_.init; comp_obj_.metainfo.is_of_part = "body"; comp_obj_.metainfo.is_of_section = "body"; comp_obj_.metainfo.is_of_type = "para"; comp_obj_.metainfo.is_a = "heading"; comp_obj_.text = _text.to!string.strip; comp_obj_.metainfo.ocn = obj_cite_digits.object_number; comp_obj_.metainfo.identifier = obj_cite_digits.identifier; comp_obj_.metainfo.dummy_heading = (dummy_heading_status == "t") ? true: false; comp_obj_.metainfo.object_number_off = obj_cite_digits.off; // comp_obj_.metainfo.o_n_book_index = obj_cite_digits.bkidx; comp_obj_.metainfo.object_number_type = obj_cite_digits.type; comp_obj_.tags.segment_anchor_tag_epub = tag_in_seg["seg_lv1to4"]; comp_obj_.tags.anchor_tag_html = tag_in_seg["seg_lv4"]; comp_obj_.tags.in_segment_html = comp_obj_.tags.anchor_tag_html; comp_obj_.tags.heading_lev_anchor_tag = lev_anchor_tag; comp_obj_.tags.html_segment_anchor_tag_is = tag_in_seg["seg_lv4"]; comp_obj_.tags.epub_segment_anchor_tag_is = tag_in_seg["seg_lv1to4"]; comp_obj_.metainfo.heading_lev_markup = (!(lev_markup_number.empty) ? lev_markup_number.to!int : 0); comp_obj_.metainfo.heading_lev_collapsed = (!(lev_collapsed_number.empty) ? lev_collapsed_number.to!int : 0); comp_obj_.metainfo.parent_ocn = p_["object_number"]; comp_obj_.metainfo.parent_lev_markup = p_["lev_markup_number"]; comp_obj_.tags.heading_ancestors_text = lv_ancestors_txt; comp_obj_.ptr.doc_object = cntr_; comp_obj_.ptr.html_segnames = ((lev_markup_number == "4") ? html_segnames_ptr : 0); comp_obj_.ptr.heading = ptr_; comp_obj_.has.inline_notes_reg = substantive_object_and_anchor_tags_struct.has_notes_reg; comp_obj_.has.inline_notes_star = substantive_object_and_anchor_tags_struct.has_notes_star; comp_obj_.has.inline_links = substantive_object_and_anchor_tags_struct.has_links; comp_obj_.has.images = substantive_object_and_anchor_tags_struct.has_images; tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"] = comp_obj_.tags.in_segment_html; tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub; debug(_node) { if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("* ", _node.to!string); } } debug(nodeheading) { if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("* ", _node.to!string); } } assert(comp_obj_.metainfo.parent_lev_markup <= 7); assert(comp_obj_.metainfo.parent_ocn >= 0); if (lev_markup_number.match(rgx.levels_numbered_headings)) { assert(comp_obj_.metainfo.heading_lev_markup <= 7); assert(comp_obj_.metainfo.ocn >= 0); if (comp_obj_.metainfo.parent_lev_markup > 0) { assert(comp_obj_.metainfo.parent_lev_markup < comp_obj_.metainfo.heading_lev_markup); if (comp_obj_.metainfo.ocn != 0) { assert(comp_obj_.metainfo.parent_ocn < comp_obj_.metainfo.ocn); } } if (comp_obj_.metainfo.heading_lev_markup == 0) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_A); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_B) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_A); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_C) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_B); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_D) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_C); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_1) { assert(comp_obj_.metainfo.parent_lev_markup <= DocStructMarkupHeading.h_sect_D); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_2) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_1); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_3) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_2); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_4) { assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_3); } else if (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_5) { } } return comp_obj_; } invariant() { } } @system ST_ancestors after_doc_determine_ancestors( ObjGenericComposite[] the_document_body_section, ObjGenericComposite[] the_document_endnotes_section, ObjGenericComposite[] the_document_glossary_section, ObjGenericComposite[] the_document_bibliography_section, ObjGenericComposite[] the_document_bookindex_section, ObjGenericComposite[] the_document_blurb_section, ObjGenericComposite[] the_document_head_section, ) { int[] _get_ancestors_markup(ObjGenericComposite obj, int[] _ancestors_markup) { if (obj.metainfo.is_a == "heading") { debug(dom) { writeln(obj.text); } if (obj.metainfo.heading_lev_markup == 1) { _ancestors_markup = [ _ancestors_markup[0], 0,0,0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_markup == 2) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], 0,0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_markup == 3) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], 0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_markup == 4) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], _ancestors_markup[3], 0,0,0,0 ]; } if (obj.metainfo.heading_lev_markup == 5) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], _ancestors_markup[3], _ancestors_markup[4], 0,0,0 ]; } if (obj.metainfo.heading_lev_markup == 6) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], _ancestors_markup[3], _ancestors_markup[4], _ancestors_markup[5], 0,0 ]; } if (obj.metainfo.heading_lev_markup == 7) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], _ancestors_markup[3], _ancestors_markup[4], _ancestors_markup[5], _ancestors_markup[6], 0 ]; } if (obj.metainfo.heading_lev_markup == 8) { _ancestors_markup = [ _ancestors_markup[0], _ancestors_markup[1], _ancestors_markup[2], _ancestors_markup[3], _ancestors_markup[4], _ancestors_markup[5], _ancestors_markup[6], _ancestors_markup[7] ]; } _ancestors_markup[obj.metainfo.heading_lev_markup] = obj.metainfo.ocn; } debug(ancestor_markup) { writeln("marked up: ", _ancestors_markup); } return _ancestors_markup; } int[] _get_ancestors_collapsed(ObjGenericComposite obj, int[] _ancestors_collapsed) { if (obj.metainfo.is_a == "heading") { if (obj.metainfo.heading_lev_collapsed == 1) { _ancestors_collapsed = [ _ancestors_collapsed[0], 0,0,0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 2) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], 0,0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 3) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], 0,0,0,0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 4) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], _ancestors_collapsed[3], 0,0,0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 5) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], _ancestors_collapsed[3], _ancestors_collapsed[4], 0,0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 6) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], _ancestors_collapsed[3], _ancestors_collapsed[4], _ancestors_collapsed[5], 0,0 ]; } if (obj.metainfo.heading_lev_collapsed == 7) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], _ancestors_collapsed[3], _ancestors_collapsed[4], _ancestors_collapsed[5], _ancestors_collapsed[6], 0 ]; } if (obj.metainfo.heading_lev_collapsed == 8) { _ancestors_collapsed = [ _ancestors_collapsed[0], _ancestors_collapsed[1], _ancestors_collapsed[2], _ancestors_collapsed[3], _ancestors_collapsed[4], _ancestors_collapsed[5], _ancestors_collapsed[6], _ancestors_collapsed[7] ]; } _ancestors_collapsed[obj.metainfo.heading_lev_collapsed] = obj.metainfo.ocn; } debug(ancestor_collapsed) { writeln("collapsed: ", _ancestors_collapsed); } return _ancestors_collapsed; } /+ ↓ running ancestry state, carried across every object of the document in document order. _levels_open_ records which heading levels are currently open, kept separate from the ancestor ocn arrays because a non-substantive (author suppressed, ocn 0) heading opens a level while contributing an ocn of 0 to that slot +/ int[] _ancestors_markup = [1,0,0,0,0,0,0,0]; int[] _ancestors_collapsed = [1,0,0,0,0,0,0,0]; bool[] _levels_open_markup = [true,false,false,false,false,false,false,false]; bool[] _levels_open_collapsed = [true,false,false,false,false,false,false,false]; void _set_ancestry(ref ObjGenericComposite obj) { if (obj.metainfo.is_a == "heading" && obj.metainfo.heading_lev_markup <= 7 && obj.metainfo.heading_lev_collapsed <= 7 ) { /+ ↓ accumulate: the returned array must be fed back in, the helpers rebind their parameter and so cannot update the caller in place +/ _ancestors_markup = _get_ancestors_markup(obj, _ancestors_markup); _ancestors_collapsed = _get_ancestors_collapsed(obj, _ancestors_collapsed); if (obj.metainfo.heading_lev_markup == 0) { /+ ↓ document root ocn is 1 by definition, it is normalised to 1 later (head section, metadoc_from_src.d) so do not let a root emitted with ocn 0 zero the root slot for the whole document +/ _ancestors_markup[0] = (obj.metainfo.ocn > 0) ? obj.metainfo.ocn : 1; _ancestors_collapsed[0] = _ancestors_markup[0]; } foreach (_i; 0 .. 8) { _levels_open_markup[_i] = (_i < obj.metainfo.heading_lev_markup) ? _levels_open_markup[_i] : (_i == obj.metainfo.heading_lev_markup) ? true : false; _levels_open_collapsed[_i] = (_i < obj.metainfo.heading_lev_collapsed) ? _levels_open_collapsed[_i] : (_i == obj.metainfo.heading_lev_collapsed) ? true : false; } } /+ ↓ every object (heading or not) carries the ancestry it sits within, .dup: the helpers may return the running array itself +/ obj.metainfo.markedup_ancestors = _ancestors_markup.dup; obj.metainfo.collapsed_ancestors = _ancestors_collapsed.dup; /+ ↓ parent: nearest enclosing open heading level, for a heading that is the nearest level shallower than its own +/ int _parent_lev = 0; int _depth_limit = (obj.metainfo.is_a == "heading" && obj.metainfo.heading_lev_markup <= 7) ? obj.metainfo.heading_lev_markup - 1 : 7; foreach_reverse (_i; 0 .. (_depth_limit + 1)) { if (_levels_open_markup[_i]) { _parent_lev = _i; break; } } if (!(obj.metainfo.is_a == "heading" && obj.metainfo.heading_lev_markup == 0)) { obj.metainfo.parent_lev_markup = _parent_lev; obj.metainfo.parent_ocn = _ancestors_markup[_parent_lev]; } } /+ ↓ document order: the root (:A~) heading has been moved to the head section ahead of this pass, it seeds the ancestry for everything +/ foreach (ref obj; the_document_head_section) { _set_ancestry(obj); } foreach (ref obj; the_document_body_section) { _set_ancestry(obj); } /+ ↓ endnote objects: the ancestry given here is the heading ancestry of the endnotes section itself, but an endnote's parent is the object the note is called from, not a heading - that parent_ocn is set in after_doc_determine_segnames, which runs ahead of this, keep it +/ foreach (ref obj; the_document_endnotes_section) { int _parent_of_note = (obj.metainfo.is_a != "heading") ? obj.metainfo.parent_ocn : 0; _set_ancestry(obj); if (_parent_of_note != 0) { obj.metainfo.parent_ocn = _parent_of_note; } } foreach (ref obj; the_document_glossary_section) { _set_ancestry(obj); } foreach (ref obj; the_document_bibliography_section) { _set_ancestry(obj); } foreach (ref obj; the_document_bookindex_section) { _set_ancestry(obj); } foreach (ref obj; the_document_blurb_section) { _set_ancestry(obj); } debug(ancestors) { foreach (obj; the_document_body_section) { writeln("ocn: ", obj.metainfo.ocn, " parent: ", obj.metainfo.parent_ocn, " ancestors markup o_n: ", obj.metainfo.markedup_ancestors, " ancestors collapsed o_n: ", obj.metainfo.collapsed_ancestors); } } ST_ancestors ret; ret.the_document_body_section = the_document_body_section; ret.the_document_head_section = the_document_head_section; ret.the_document_endnotes_section = the_document_endnotes_section; ret.the_document_glossary_section = the_document_glossary_section; ret.the_document_bibliography_section = the_document_bibliography_section; ret.the_document_bookindex_section = the_document_bookindex_section; ret.the_document_blurb_section = the_document_blurb_section; return ret; } // ↑ - ancestors #+END_SRC ***** ϝ structure descendants #+NAME: ocdaFunc_structure_descendants #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - descendants // descendants auto after_doc_get_descendants()(ObjGenericComposite[] document_sections) { int[string] _heading_ocn_descendants; string[] _ocn_open_key = ["","","","","","","",""]; auto _doc_sect_length = document_sections.length - 1; int _last_ocn; foreach (_lg, ref obj; document_sections) { if (obj.metainfo.is_a == "heading") { foreach (_dts_lv, dom_tag_status; obj.metainfo.dom_structure_markedup_tags_status) { switch (dom_tag_status) with (DomTags) { case none: break; case open: _ocn_open_key[_dts_lv] = (obj.metainfo.ocn).to!string; _heading_ocn_descendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn; break; case close: if (_ocn_open_key[_dts_lv].empty) { _ocn_open_key[_dts_lv] = "0"; } _heading_ocn_descendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn - 1; _ocn_open_key[_dts_lv] = (0).to!string; break; case close_and_open: if (_ocn_open_key[_dts_lv].empty) { _ocn_open_key[_dts_lv] = "0"; } _heading_ocn_descendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn - 1; _ocn_open_key[_dts_lv] = (obj.metainfo.ocn).to!string; _heading_ocn_descendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn; break; case open_still: break; default: break; } } } if (obj.metainfo.ocn > 0) { _last_ocn = obj.metainfo.ocn; } if (_lg == _doc_sect_length) { _heading_ocn_descendants["1"] = _last_ocn; // close existing o_n key } } Tuple!(int, int)[] pairs; foreach (pair; _heading_ocn_descendants.byPair) { pairs ~= tuple(pair[0].to!int, pair[1]); } return pairs.sort; } // ↑ - descendants #+END_SRC **** ϝ assertions #+NAME: ocdaFunc_assertions #+HEADER: :noweb yes #+BEGIN_SRC d // ↓ - assertions pure void assertions_doc_structure()( string[string] an_object, string an_object_key, int[string] lv ) { string msg_error_doc_struct = "\nERROR in document structure, check markup (heading level relationships):\n"; if (lv["h3"] > eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h2"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h2"] > eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h1"] > eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h0"] > eN.bi.off) { assert(lv["h1"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else { assert(lv["h0"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h1"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h7"] > eN.bi.off) { assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h6"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h6"] > eN.bi.off) { assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h5"] > eN.bi.off) { assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else if (lv["h4"] > eN.bi.off) { assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } else { assert(lv["h4"] == eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ an_object[an_object_key] ); assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h0"] == eN.bi.off) { assert(lv["h1"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h4"] == eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ an_object[an_object_key] ); assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h1"] == eN.bi.off) { assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h2"] == eN.bi.off) { assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h3"] == eN.bi.off) { } if (lv["h4"] == eN.bi.off) { assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h5"] == eN.bi.off) { assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h6"] == eN.bi.off) { assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ an_object[an_object_key] ); } if (lv["h7"] == eN.bi.off) { } switch ((an_object["lev"]).to!string) { case "A": if (lv["h0"] == eN.bi.off) { assert(lv["h1"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h4"] == eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~\n" ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ "at level A~\n" ~ an_object[an_object_key] ); } else { // (lv["h0"] > eN.bi.off) assert(lv["h0"] == eN.bi.off, msg_error_doc_struct ~ "should not enter level A a second time\n" ~ "at level A~\n" ~ an_object[an_object_key] ); } break; case "B": if (lv["h1"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level B~\n" ~ an_object[an_object_key] ); assert(lv["h2"] == eN.bi.off, msg_error_doc_struct ~ "at level B~\n" ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ "at level B~\n" ~ an_object[an_object_key] ); } else { // (lv["h1"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level B~\n" ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ "at level B~\n" ~ an_object[an_object_key] ); } break; case "C": if (lv["h2"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level C~\n" ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ "level C should not follow level A\n" ~ "at level C~\n" ~ an_object[an_object_key] ); assert(lv["h3"] == eN.bi.off, msg_error_doc_struct ~ "at level C~\n" ~ an_object[an_object_key] ); } else { // (lv["h2"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level C~\n" ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ "at level C~\n" ~ an_object[an_object_key] ); assert(lv["h2"] > eN.bi.off, msg_error_doc_struct ~ "at level C~\n" ~ an_object[an_object_key] ); } break; case "D": if (lv["h3"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ "level D should not follow level A\n" ~ "at level D~\n" ~ an_object[an_object_key] ); assert(lv["h2"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); } else { // (lv["h3"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); assert(lv["h1"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); assert(lv["h2"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); assert(lv["h3"] > eN.bi.off, msg_error_doc_struct ~ "at level D~\n" ~ an_object[an_object_key] ); } break; case "1": if (lv["h4"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 1~\n" ~ an_object[an_object_key] ); assert(lv["h5"] == eN.bi.off, msg_error_doc_struct ~ "at level 1~\n" ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ "at level 1~\n" ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ "at level 1~\n" ~ an_object[an_object_key] ); } else { // (lv["h4"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 1~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 1~\n" ~ an_object[an_object_key] ); } break; case "2": if (lv["h5"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 2~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 2~\n" ~ an_object[an_object_key] ); assert(lv["h6"] == eN.bi.off, msg_error_doc_struct ~ "at level 2~\n" ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ "at level 2~\n" ~ an_object[an_object_key] ); } else { // (lv["h5"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 2~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 2~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ "at level 2~\n" ~ an_object[an_object_key] ); } break; case "3": if (lv["h6"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 2~ ?\n" ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h7"] == eN.bi.off, msg_error_doc_struct ~ "at level 3~\n" ~ an_object[an_object_key] ); } else { // (lv["h6"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ "at level 3~\n" ~ an_object[an_object_key] ); assert(lv["h6"] > eN.bi.off, msg_error_doc_struct ~ "at level 3~\n" ~ an_object[an_object_key] ); } break; case "4": if (lv["h7"] == eN.bi.off) { assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 2~ ?\n" ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h6"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 3~ ?\n" ~ "at level 4~\n" ~ an_object[an_object_key] ); } else { // (lv["h7"] > eN.bi.off) assert(lv["h0"] > eN.bi.off, msg_error_doc_struct ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h4"] > eN.bi.off, msg_error_doc_struct ~ "missing segment level 1~ ?\n" ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h5"] > eN.bi.off, msg_error_doc_struct ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h6"] > eN.bi.off, msg_error_doc_struct ~ "at level 4~\n" ~ an_object[an_object_key] ); assert(lv["h7"] > eN.bi.off, msg_error_doc_struct ~ "at level 4~\n" ~ an_object[an_object_key] ); } break; default: break; } } // ↑ - assertions #+END_SRC ** template docSectKeysSeq #+NAME: docSectKeysSeq #+HEADER: :noweb yes #+BEGIN_SRC d auto docSectKeysSeq(string[][string] document_section_keys_sequenced) { struct doc_sect_keys_seq { string[] scroll() { return document_section_keys_sequenced["scroll"]; } string[] seg() { return document_section_keys_sequenced["seg"]; } string[] sql() { return document_section_keys_sequenced["sql"]; } string[] latex() { return document_section_keys_sequenced["latex"]; } string[] text() { return document_section_keys_sequenced["text"]; } } return doc_sect_keys_seq(); } #+END_SRC * org includes ** project version #+NAME: spine_version #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_project_version()>> #+END_SRC ** year #+NAME: year #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:year()>> #+END_SRC ** document header including copyright & license #+NAME: doc_header_including_copyright_and_license #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_doc_header_including_copyright_and_license()>> #+END_SRC * __END__