diff options
| author | Ralph Amissah <ralph.amissah@gmail.com> | 2026-08-30 13:28:10 -0400 |
|---|---|---|
| committer | Ralph Amissah <ralph.amissah@gmail.com> | 2026-08-30 13:28:10 -0400 |
| commit | 8944b13ecdfeb4908cb70974e57d905775055ccf (patch) | |
| tree | af039241a98863e7eeeb2ba0cd852838419422a3 | |
| parent | file rename: out_src_abstraction_ocda_peg_ssp.org (diff) | |
abstraction/.ssp: fix doc structure representation
fix to --abstraction/.ssp: fix document structure, representation
parent, ancestors, children. Make parent_ocn, the marked-up and
collapsed ancestor arrays, and the children correctly represent
the document structure. fixed
(assisted by Claude-Code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01836BxBb8LvVKJ8sBg7Dx6U
| -rw-r--r-- | org/ocda.org | 80 | ||||
| -rw-r--r-- | org/ocda_functions.org | 132 | ||||
| -rw-r--r-- | org/ocda_obj_setter.org | 1 | ||||
| -rw-r--r-- | org/out_metadata.org | 4 | ||||
| -rw-r--r-- | org/out_xmls.org | 2 | ||||
| -rw-r--r-- | src/sisudoc/ocda/meta/metadoc_from_src.d | 80 | ||||
| -rw-r--r-- | src/sisudoc/ocda/meta/metadoc_from_src_functions.d | 132 | ||||
| -rw-r--r-- | src/sisudoc/ocda/meta/metadoc_object_setter.d | 1 | ||||
| -rw-r--r-- | src/sisudoc/outputs/io_out/metadata.d | 4 |
9 files changed, 325 insertions, 111 deletions
diff --git a/org/ocda.org b/org/ocda.org index 3a287e8..25a5d8e 100644 --- a/org/ocda.org +++ b/org/ocda.org @@ -1039,16 +1039,11 @@ ST_endnotes en_st = note_section.backmatter_endnote_objects(obj_cite_digits, opt the_document_head_section ~= the_document_body_section[0]; the_document_body_section = the_document_body_section[1..$]; } -{ // document ancestors - ST_ancestors get_ancestors; - get_ancestors = the_document_body_section.after_doc_determine_ancestors(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section); - the_document_body_section = get_ancestors.the_document_body_section; - the_document_endnotes_section = get_ancestors.the_document_endnotes_section; - the_document_glossary_section = get_ancestors.the_document_glossary_section; - the_document_bibliography_section = get_ancestors.the_document_bibliography_section; - the_document_bookindex_section = get_ancestors.the_document_bookindex_section; - the_document_blurb_section = get_ancestors.the_document_blurb_section; -} +/+ ↓ document ancestors: moved to run after every sections ocn have been + generated (the backmatter section headings are given their ocn in the + per section loops below) and ahead of descendants & children which + depend on parent_ocn ++/ { // document segnames ST_segnames get_segnames; get_segnames = the_document_body_section.after_doc_determine_segnames(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section, segnames, html_segnames_ptr_cntr, html_segnames_ptr); @@ -1338,6 +1333,25 @@ if (the_document_blurb_section.length > 1) { // writeln("blurb"); obj = _links(obj); } } +{ // document ancestors + ST_ancestors get_ancestors; + get_ancestors = + the_document_body_section.after_doc_determine_ancestors( + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + the_document_head_section + ); + the_document_body_section = get_ancestors.the_document_body_section; + the_document_head_section = get_ancestors.the_document_head_section; + the_document_endnotes_section = get_ancestors.the_document_endnotes_section; + the_document_glossary_section = get_ancestors.the_document_glossary_section; + the_document_bibliography_section = get_ancestors.the_document_bibliography_section; + the_document_bookindex_section = get_ancestors.the_document_bookindex_section; + the_document_blurb_section = get_ancestors.the_document_blurb_section; +} // get descendants if (the_document_body_section.length > 1) { auto pairs = after_doc_get_descendants( @@ -1449,19 +1463,43 @@ if (the_document_body_section.length > 1) { /+ ↓ compute children_headings for heading objects +/ { int[][int] heading_children; - foreach (obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.parent_ocn != 0) { - heading_children[obj.metainfo.parent_ocn] ~= obj.metainfo.ocn; - } - } - foreach (ref obj; the_document_head_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { - obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + /+ ↓ substantive headings only (ocn 0 is an author suppressed heading and + is not citable, it does not have a place in the citation structure), + gathered across every section not the body alone + +/ + foreach (section; [ + the_document_head_section, + the_document_body_section, + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + ]) { + foreach (obj; section) { + if (obj.metainfo.is_a == "heading" + && obj.metainfo.ocn != 0 + && obj.metainfo.parent_ocn != 0 + && obj.metainfo.parent_ocn != obj.metainfo.ocn + ) { + heading_children[obj.metainfo.parent_ocn] ~= obj.metainfo.ocn; + } } } - foreach (ref obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { - obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + /+ ↓ slice copies, the elements written to are the same elements +/ + foreach (section; [ + the_document_head_section, + the_document_body_section, + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + ]) { + foreach (ref obj; section) { + if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { + obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + } } } // if (opt_action.vox_gt_2) { diff --git a/org/ocda_functions.org b/org/ocda_functions.org index bda15b7..21a6105 100644 --- a/org/ocda_functions.org +++ b/org/ocda_functions.org @@ -4580,9 +4580,6 @@ ST_the_section build_the_blurb_section(Opt) ( } } foreach (ref obj; the_document_endnotes_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4595,9 +4592,6 @@ ST_the_section build_the_blurb_section(Opt) ( segnames["epub"] ~= "glossary"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_glossary_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4610,9 +4604,6 @@ ST_the_section build_the_blurb_section(Opt) ( segnames["epub"] ~= "bibliography"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bibliography_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4625,9 +4616,6 @@ ST_the_section build_the_blurb_section(Opt) ( segnames["epub"] ~= "bookindex"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bookindex_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4640,9 +4628,6 @@ ST_the_section build_the_blurb_section(Opt) ( segnames["epub"] ~= "blurb"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_blurb_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4757,10 +4742,19 @@ struct NodeStructureMetadata { // "\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; - lv0 = obj_cite_digit; + /+ ↓ 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; @@ -4823,6 +4817,10 @@ struct NodeStructureMetadata { 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; @@ -4918,6 +4916,7 @@ struct NodeStructureMetadata { 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") { @@ -5084,30 +5083,95 @@ struct NodeStructureMetadata { debug(ancestor_collapsed) { writeln("collapsed: ", _ancestors_collapsed); } return _ancestors_collapsed; } - // multiple 1~ levels, loop through document body - if (the_document_body_section.length > 1) { - int[] _ancestors_markup = [0,0,0,0,0,0,0,0]; - int[][] _ancestors_markup_; - _ancestors_markup = [1,0,0,0,0,0,0,0]; - _ancestors_markup_ ~= _ancestors_markup; - int[] _ancestors_collapsed = [0,0,0,0,0,0,0,0]; - int[][] _ancestors_collapsed_; - _ancestors_collapsed = [1,0,0,0,0,0,0,0]; - _ancestors_collapsed_ ~= _ancestors_collapsed; - foreach (ref obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.markedup_ancestors = _get_ancestors_markup(obj, _ancestors_markup); - obj.metainfo.collapsed_ancestors = _get_ancestors_collapsed(obj, _ancestors_collapsed); - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; + /+ ↓ 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]; } - debug(ancestors) { - writeln("ancestors markup o_n: ", obj.metainfo.markedup_ancestors); - writeln("ancestors collapsed o_n: ", obj.metainfo.markedup_ancestors); + } + /+ ↓ 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; diff --git a/org/ocda_obj_setter.org b/org/ocda_obj_setter.org index 9cc9598..60d138e 100644 --- a/org/ocda_obj_setter.org +++ b/org/ocda_obj_setter.org @@ -248,6 +248,7 @@ struct ST_biblio_section { } struct ST_ancestors { ObjGenericComposite[] the_document_body_section; + ObjGenericComposite[] the_document_head_section; ObjGenericComposite[] the_document_endnotes_section; ObjGenericComposite[] the_document_glossary_section; ObjGenericComposite[] the_document_bibliography_section; diff --git a/org/out_metadata.org b/org/out_metadata.org index dcd7c51..8606c69 100644 --- a/org/out_metadata.org +++ b/org/out_metadata.org @@ -176,6 +176,10 @@ if (doc_matters.opt.action.html_link_markup_source) { ~ " 🫛 zipped </a>| " ~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/\" class=\"lnkicon\">" ~ " 🫛 tree </a>] "; + /+ .ssp peg parsable source, interesting (path may be of interest for downloading) but renders poorly visually in browser +/ + // metadata_ ~= "<p class=\"lev1\">● .ssp [peg parsable source]:" + // ~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/media/abstraction/" ~ doc_matters.src.filename_base ~ "." ~ doc_matters.src.language ~ ".ssp\" class=\"lnkicon\">" + // ~ " 🗎 .ssp [peg parsable source] </a>]</p>"; metadata_ ~= "<p class=\"lev1\">● source digests:" ~ " [ <a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ ".digests.txt\" class=\"lnkizipcon\">" ~ " # digests </a>]</p>"; diff --git a/org/out_xmls.org b/org/out_xmls.org index 353ad31..52ab735 100644 --- a/org/out_xmls.org +++ b/org/out_xmls.org @@ -421,7 +421,7 @@ string inline_search_form(M)( ***** html head & head banner -▣ ▤ ⁜ ☀ ፨ ፠ ※ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ 〓 ⚏ ⚏ ⌘ 🫛 ⌥ ⟰ +▣ ▤ ⁜ ☀ ፨ ፠ ※ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ 〓 ⚏ ⚏ ⌘ 🫛 🗎 ⌥ ⟰ #+NAME: xhtml_format_objects_html_head #+BEGIN_SRC d diff --git a/src/sisudoc/ocda/meta/metadoc_from_src.d b/src/sisudoc/ocda/meta/metadoc_from_src.d index 7fcf3bb..dec00c6 100644 --- a/src/sisudoc/ocda/meta/metadoc_from_src.d +++ b/src/sisudoc/ocda/meta/metadoc_from_src.d @@ -933,16 +933,11 @@ template docAbstraction() { the_document_head_section ~= the_document_body_section[0]; the_document_body_section = the_document_body_section[1..$]; } - { // document ancestors - ST_ancestors get_ancestors; - get_ancestors = the_document_body_section.after_doc_determine_ancestors(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section); - the_document_body_section = get_ancestors.the_document_body_section; - the_document_endnotes_section = get_ancestors.the_document_endnotes_section; - the_document_glossary_section = get_ancestors.the_document_glossary_section; - the_document_bibliography_section = get_ancestors.the_document_bibliography_section; - the_document_bookindex_section = get_ancestors.the_document_bookindex_section; - the_document_blurb_section = get_ancestors.the_document_blurb_section; - } + /+ ↓ document ancestors: moved to run after every sections ocn have been + generated (the backmatter section headings are given their ocn in the + per section loops below) and ahead of descendants & children which + depend on parent_ocn + +/ { // document segnames ST_segnames get_segnames; get_segnames = the_document_body_section.after_doc_determine_segnames(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section, segnames, html_segnames_ptr_cntr, html_segnames_ptr); @@ -1232,6 +1227,25 @@ template docAbstraction() { obj = _links(obj); } } + { // document ancestors + ST_ancestors get_ancestors; + get_ancestors = + the_document_body_section.after_doc_determine_ancestors( + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + the_document_head_section + ); + the_document_body_section = get_ancestors.the_document_body_section; + the_document_head_section = get_ancestors.the_document_head_section; + the_document_endnotes_section = get_ancestors.the_document_endnotes_section; + the_document_glossary_section = get_ancestors.the_document_glossary_section; + the_document_bibliography_section = get_ancestors.the_document_bibliography_section; + the_document_bookindex_section = get_ancestors.the_document_bookindex_section; + the_document_blurb_section = get_ancestors.the_document_blurb_section; + } // get descendants if (the_document_body_section.length > 1) { auto pairs = after_doc_get_descendants( @@ -1343,19 +1357,43 @@ template docAbstraction() { /+ ↓ compute children_headings for heading objects +/ { int[][int] heading_children; - foreach (obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.parent_ocn != 0) { - heading_children[obj.metainfo.parent_ocn] ~= obj.metainfo.ocn; - } - } - foreach (ref obj; the_document_head_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { - obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + /+ ↓ substantive headings only (ocn 0 is an author suppressed heading and + is not citable, it does not have a place in the citation structure), + gathered across every section not the body alone + +/ + foreach (section; [ + the_document_head_section, + the_document_body_section, + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + ]) { + foreach (obj; section) { + if (obj.metainfo.is_a == "heading" + && obj.metainfo.ocn != 0 + && obj.metainfo.parent_ocn != 0 + && obj.metainfo.parent_ocn != obj.metainfo.ocn + ) { + heading_children[obj.metainfo.parent_ocn] ~= obj.metainfo.ocn; + } } } - foreach (ref obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { - obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + /+ ↓ slice copies, the elements written to are the same elements +/ + foreach (section; [ + the_document_head_section, + the_document_body_section, + the_document_endnotes_section, + the_document_glossary_section, + the_document_bibliography_section, + the_document_bookindex_section, + the_document_blurb_section, + ]) { + foreach (ref obj; section) { + if (obj.metainfo.is_a == "heading" && obj.metainfo.ocn in heading_children) { + obj.metainfo.children_headings = heading_children[obj.metainfo.ocn]; + } } } // if (opt_action.vox_gt_2) { diff --git a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d index cf46fda..4d3d372 100644 --- a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d +++ b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d @@ -4359,9 +4359,6 @@ template docAbstractionFunctions() { } } foreach (ref obj; the_document_endnotes_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4374,9 +4371,6 @@ template docAbstractionFunctions() { segnames["epub"] ~= "glossary"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_glossary_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4389,9 +4383,6 @@ template docAbstractionFunctions() { segnames["epub"] ~= "bibliography"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bibliography_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4404,9 +4395,6 @@ template docAbstractionFunctions() { segnames["epub"] ~= "bookindex"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_bookindex_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4419,9 +4407,6 @@ template docAbstractionFunctions() { segnames["epub"] ~= "blurb"; html_segnames_ptr = html_segnames_ptr_cntr; foreach (ref obj; the_document_blurb_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; - } if (obj.metainfo.heading_lev_markup == 4) { obj.ptr.html_segnames = html_segnames_ptr; break; @@ -4529,10 +4514,19 @@ template docAbstractionFunctions() { // "\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; - lv0 = obj_cite_digit; + /+ ↓ 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; @@ -4595,6 +4589,10 @@ template docAbstractionFunctions() { 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; @@ -4690,6 +4688,7 @@ template docAbstractionFunctions() { 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") { @@ -4856,30 +4855,95 @@ template docAbstractionFunctions() { debug(ancestor_collapsed) { writeln("collapsed: ", _ancestors_collapsed); } return _ancestors_collapsed; } - // multiple 1~ levels, loop through document body - if (the_document_body_section.length > 1) { - int[] _ancestors_markup = [0,0,0,0,0,0,0,0]; - int[][] _ancestors_markup_; - _ancestors_markup = [1,0,0,0,0,0,0,0]; - _ancestors_markup_ ~= _ancestors_markup; - int[] _ancestors_collapsed = [0,0,0,0,0,0,0,0]; - int[][] _ancestors_collapsed_; - _ancestors_collapsed = [1,0,0,0,0,0,0,0]; - _ancestors_collapsed_ ~= _ancestors_collapsed; - foreach (ref obj; the_document_body_section) { - if (obj.metainfo.is_a == "heading") { - obj.metainfo.markedup_ancestors = _get_ancestors_markup(obj, _ancestors_markup); - obj.metainfo.collapsed_ancestors = _get_ancestors_collapsed(obj, _ancestors_collapsed); - obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup]; + /+ ↓ 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]; } - debug(ancestors) { - writeln("ancestors markup o_n: ", obj.metainfo.markedup_ancestors); - writeln("ancestors collapsed o_n: ", obj.metainfo.markedup_ancestors); + } + /+ ↓ 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; diff --git a/src/sisudoc/ocda/meta/metadoc_object_setter.d b/src/sisudoc/ocda/meta/metadoc_object_setter.d index 9fcc2b9..a1f6a86 100644 --- a/src/sisudoc/ocda/meta/metadoc_object_setter.d +++ b/src/sisudoc/ocda/meta/metadoc_object_setter.d @@ -237,6 +237,7 @@ template ObjectSetter() { } struct ST_ancestors { ObjGenericComposite[] the_document_body_section; + ObjGenericComposite[] the_document_head_section; ObjGenericComposite[] the_document_endnotes_section; ObjGenericComposite[] the_document_glossary_section; ObjGenericComposite[] the_document_bibliography_section; diff --git a/src/sisudoc/outputs/io_out/metadata.d b/src/sisudoc/outputs/io_out/metadata.d index f951dde..ff9c72f 100644 --- a/src/sisudoc/outputs/io_out/metadata.d +++ b/src/sisudoc/outputs/io_out/metadata.d @@ -510,6 +510,10 @@ string theme_light_1 = format(q"┃ ~ " 🫛 zipped </a>| " ~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/\" class=\"lnkicon\">" ~ " 🫛 tree </a>] "; + /+ .ssp peg parsable source, interesting (path may be of interest for downloading) but renders poorly visually in browser +/ + // metadata_ ~= "<p class=\"lev1\">● .ssp [peg parsable source]:" + // ~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/media/abstraction/" ~ doc_matters.src.filename_base ~ "." ~ doc_matters.src.language ~ ".ssp\" class=\"lnkicon\">" + // ~ " 🗎 .ssp [peg parsable source] </a>]</p>"; metadata_ ~= "<p class=\"lev1\">● source digests:" ~ " [ <a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ ".digests.txt\" class=\"lnkizipcon\">" ~ " # digests </a>]</p>"; |
