aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-08-30 13:28:10 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-08-30 13:28:10 -0400
commit8944b13ecdfeb4908cb70974e57d905775055ccf (patch)
treeaf039241a98863e7eeeb2ba0cd852838419422a3
parentfile 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.org80
-rw-r--r--org/ocda_functions.org132
-rw-r--r--org/ocda_obj_setter.org1
-rw-r--r--org/out_metadata.org4
-rw-r--r--org/out_xmls.org2
-rw-r--r--src/sisudoc/ocda/meta/metadoc_from_src.d80
-rw-r--r--src/sisudoc/ocda/meta/metadoc_from_src_functions.d132
-rw-r--r--src/sisudoc/ocda/meta/metadoc_object_setter.d1
-rw-r--r--src/sisudoc/outputs/io_out/metadata.d4
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) {
~ "&nbsp;🫛&nbsp;zipped&nbsp;</a>|&nbsp;"
~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/\" class=\"lnkicon\">"
~ "&nbsp;🫛&nbsp;tree&nbsp;</a>]&nbsp;";
+ /+ .ssp peg parsable source, interesting (path may be of interest for downloading) but renders poorly visually in browser +/
+ // metadata_ ~= "<p class=\"lev1\">●&nbsp;&nbsp;.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\">"
+ // ~ "&nbsp;🗎&nbsp;.ssp [peg parsable source]&nbsp;</a>]</p>";
metadata_ ~= "<p class=\"lev1\">●&nbsp;&nbsp;source digests:"
~ "&nbsp;[&nbsp;<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ ".digests.txt\" class=\"lnkizipcon\">"
~ "&nbsp;#&nbsp;digests&nbsp;</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"┃
~ "&nbsp;🫛&nbsp;zipped&nbsp;</a>|&nbsp;"
~ "<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/\" class=\"lnkicon\">"
~ "&nbsp;🫛&nbsp;tree&nbsp;</a>]&nbsp;";
+ /+ .ssp peg parsable source, interesting (path may be of interest for downloading) but renders poorly visually in browser +/
+ // metadata_ ~= "<p class=\"lev1\">●&nbsp;&nbsp;.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\">"
+ // ~ "&nbsp;🗎&nbsp;.ssp [peg parsable source]&nbsp;</a>]</p>";
metadata_ ~= "<p class=\"lev1\">●&nbsp;&nbsp;source digests:"
~ "&nbsp;[&nbsp;<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ ".digests.txt\" class=\"lnkizipcon\">"
~ "&nbsp;#&nbsp;digests&nbsp;</a>]</p>";