aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-08-26 18:25:08 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-08-28 09:01:12 -0400
commit0456cf8f767124e0a0033fac09d7ae3b666e389d (patch)
tree6e08c0fa00d44f7d7dda610618f743341040c279
parentsha summary, mostly cosmetic, some work on images (diff)
.ssp: image as repeatable self-describing property
a repeatable record, one line per image, filename first: .image: won_benkler_2_1.png sha256:5BA492C2...D128 bytes:93861 an object embedding more than one image emits more than one .image line. (assisted by Claude-Code)
-rw-r--r--org/out_src_abstraction_ocda_ssp.org38
-rw-r--r--src/sisudoc/ocda/abstraction/ssp.d40
2 files changed, 27 insertions, 51 deletions
diff --git a/org/out_src_abstraction_ocda_ssp.org b/org/out_src_abstraction_ocda_ssp.org
index 32ffdab..2d8b128 100644
--- a/org/out_src_abstraction_ocda_ssp.org
+++ b/org/out_src_abstraction_ocda_ssp.org
@@ -31,7 +31,6 @@ rename source_abstraction_peg_txt.d
<<doc_header_including_copyright_and_license>>
module sisudoc.ocda.abstraction.ssp;
@safe:
-
/+ ↓ write document abstraction as human-readable .ssp text file +/
template spineAbstractionTxt() {
import std.conv : to;
@@ -41,17 +40,14 @@ template spineAbstractionTxt() {
import std.stdio;
import std.string;
import std.array;
-
void spineAbstractionTxt(D)(D doc) {
auto doc_abstraction = doc.abstraction;
auto doc_matters = doc.matters;
string[] output;
-
/+ ↓ header comment +/
output ~= "% SiSU Document Abstraction v0.1";
output ~= "% Source: " ~ doc_matters.src.filename;
output ~= "";
-
/+ ↓ @meta block +/
output ~= "@meta {";
auto meta = doc_matters.conf_make_meta.meta;
@@ -115,7 +111,6 @@ template spineAbstractionTxt() {
output ~= " notes.summary: " ~ meta.notes_summary;
output ~= "}";
output ~= "";
-
/+ ↓ @make block +/
output ~= "@make {";
auto make = doc_matters.conf_make_meta.make;
@@ -127,7 +122,6 @@ template spineAbstractionTxt() {
output ~= " auto_num_depth: " ~ make.auto_num_depth.to!string;
output ~= "}";
output ~= "";
-
/+ ↓ @doc_has block +/
output ~= "@doc_has {";
output ~= " inline_links: " ~ doc_matters.has.inline_links.to!string;
@@ -142,23 +136,18 @@ template spineAbstractionTxt() {
output ~= " quotes: " ~ doc_matters.has.quotes.to!string;
output ~= "}";
output ~= "";
-
/+ ↓ document sections +/
string[] section_order = ["head", "toc", "body", "endnotes",
"glossary", "bibliography", "bookindex", "blurb"];
-
foreach (section; section_order) {
if (section !in doc_abstraction) continue;
auto section_objs = doc_abstraction[section];
if (section_objs.length == 0) continue;
-
output ~= "@" ~ section ~ " {";
output ~= "";
-
foreach (obj; section_objs) {
/+ ↓ object declaration line +/
string obj_decl = "[" ~ obj.metainfo.ocn.to!string ~ "] ";
-
if (obj.metainfo.is_a == "heading") {
string lev = obj.metainfo.marked_up_level;
obj_decl ~= "heading :" ~ lev;
@@ -170,7 +159,6 @@ template spineAbstractionTxt() {
obj_decl ~= obj.metainfo.is_a;
}
output ~= obj_decl;
-
/+ ↓ properties (only non-default values) +/
if (obj.metainfo.is_of_part.length > 0)
output ~= ".part: " ~ obj.metainfo.is_of_part;
@@ -181,7 +169,6 @@ template spineAbstractionTxt() {
output ~= ".parent: " ~ obj.metainfo.parent_ocn.to!string;
if (obj.metainfo.last_descendant_ocn != 0)
output ~= ".last_descendant: " ~ obj.metainfo.last_descendant_ocn.to!string;
-
/+ ↓ child headings (from pre-computed map) +/
if (obj.metainfo.children_headings.length > 0) {
string[] ch;
@@ -190,7 +177,6 @@ template spineAbstractionTxt() {
}
output ~= ".children: " ~ ch.join(" ");
}
-
/+ ↓ ancestors (only if non-zero) +/
{
bool has_anc = false;
@@ -250,7 +236,6 @@ template spineAbstractionTxt() {
output ~= ".dom_status_collapsed: " ~ ds;
}
}
-
if (obj.metainfo.heading_lev_collapsed < 9)
output ~= ".heading_lev_collapsed: " ~ obj.metainfo.heading_lev_collapsed.to!string;
if (obj.metainfo.parent_lev_markup != 0)
@@ -269,7 +254,6 @@ template spineAbstractionTxt() {
output ~= ".meta_lang: " ~ obj.metainfo.lang;
if (obj.metainfo.syntax.length > 0)
output ~= ".meta_syntax: " ~ obj.metainfo.syntax;
-
/+ ↓ sha256 digest +/
{
bool has_sha = false;
@@ -283,6 +267,19 @@ template spineAbstractionTxt() {
output ~= ".sha256: " ~ obj.metainfo.sha256.text.toHexString.to!string;
}
}
+ /+ ↓ images, repeatable record, one per image in order of appearance:
+ .image: <filename> sha256:<HEX> bytes:<n>
+ filename first (the object's handle on the image), remaining fields
+ self-describing key:value tokens so that further fields (e.g. dim:)
+ can be added later without invalidating existing readers
+ +/
+ if (obj.metainfo.sha256.images.length > 0) {
+ foreach (i; obj.metainfo.sha256.images) {
+ output ~= ".image: " ~ i.fileName
+ ~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
+ ~ " bytes:" ~ i.fileSize.to!string;
+ }
+ }
/+ ↓ text attributes +/
if (obj.attrib.indent_base != 0 || obj.attrib.indent_hang != 0)
output ~= ".indent: " ~ obj.attrib.indent_base.to!string
@@ -291,7 +288,6 @@ template spineAbstractionTxt() {
output ~= ".bullet: true";
if (obj.attrib.language.length > 0)
output ~= ".lang: " ~ obj.attrib.language;
-
/+ ↓ has flags +/
{
string[] has_flags;
@@ -303,7 +299,6 @@ template spineAbstractionTxt() {
if (has_flags.length > 0)
output ~= ".has: " ~ has_flags.join(" ");
}
-
/+ ↓ table properties +/
if (obj.metainfo.is_a == "table" && obj.table.number_of_columns > 0) {
output ~= ".table_cols: " ~ obj.table.number_of_columns.to!string;
@@ -320,7 +315,6 @@ template spineAbstractionTxt() {
if (obj.table.walls)
output ~= ".table_walls: true";
}
-
/+ ↓ code block properties +/
if (obj.metainfo.is_a == "code") {
if (obj.code_block.syntax.length > 0)
@@ -328,7 +322,6 @@ template spineAbstractionTxt() {
if (obj.code_block.linenumbers)
output ~= ".code_linenumbers: true";
}
-
/+ ↓ stow (extracted links) +/
if (obj.stow.link.length > 0) {
foreach (lnk; obj.stow.link) {
@@ -336,7 +329,6 @@ template spineAbstractionTxt() {
output ~= ".stow_link: " ~ lnk;
}
}
-
/+ ↓ tag properties +/
if (obj.tags.in_segment_html.length > 0)
output ~= ".segment: " ~ obj.tags.in_segment_html;
@@ -375,21 +367,17 @@ template spineAbstractionTxt() {
output ~= ".anchor_tag: " ~ at;
}
}
-
/+ ↓ text content +/
if (obj.text.length > 0) {
foreach (line; obj.text.split("\n")) {
output ~= "| " ~ line;
}
}
-
output ~= "";
}
-
output ~= "}";
output ~= "";
}
-
/+ ↓ write to file +/
/+ path: <output_path>/<language>/abstraction/<doc_uid_out>.ssp +/
string out_root = (doc_matters.output_path.length > 0)
diff --git a/src/sisudoc/ocda/abstraction/ssp.d b/src/sisudoc/ocda/abstraction/ssp.d
index 4f9dd45..95f7fda 100644
--- a/src/sisudoc/ocda/abstraction/ssp.d
+++ b/src/sisudoc/ocda/abstraction/ssp.d
@@ -49,7 +49,6 @@
+/
module sisudoc.ocda.abstraction.ssp;
@safe:
-
/+ ↓ write document abstraction as human-readable .ssp text file +/
template spineAbstractionTxt() {
import std.conv : to;
@@ -59,17 +58,14 @@ template spineAbstractionTxt() {
import std.stdio;
import std.string;
import std.array;
-
void spineAbstractionTxt(D)(D doc) {
auto doc_abstraction = doc.abstraction;
auto doc_matters = doc.matters;
string[] output;
-
/+ ↓ header comment +/
output ~= "% SiSU Document Abstraction v0.1";
output ~= "% Source: " ~ doc_matters.src.filename;
output ~= "";
-
/+ ↓ @meta block +/
output ~= "@meta {";
auto meta = doc_matters.conf_make_meta.meta;
@@ -133,7 +129,6 @@ template spineAbstractionTxt() {
output ~= " notes.summary: " ~ meta.notes_summary;
output ~= "}";
output ~= "";
-
/+ ↓ @make block +/
output ~= "@make {";
auto make = doc_matters.conf_make_meta.make;
@@ -145,7 +140,6 @@ template spineAbstractionTxt() {
output ~= " auto_num_depth: " ~ make.auto_num_depth.to!string;
output ~= "}";
output ~= "";
-
/+ ↓ @doc_has block +/
output ~= "@doc_has {";
output ~= " inline_links: " ~ doc_matters.has.inline_links.to!string;
@@ -160,23 +154,18 @@ template spineAbstractionTxt() {
output ~= " quotes: " ~ doc_matters.has.quotes.to!string;
output ~= "}";
output ~= "";
-
/+ ↓ document sections +/
string[] section_order = ["head", "toc", "body", "endnotes",
"glossary", "bibliography", "bookindex", "blurb"];
-
foreach (section; section_order) {
if (section !in doc_abstraction) continue;
auto section_objs = doc_abstraction[section];
if (section_objs.length == 0) continue;
-
output ~= "@" ~ section ~ " {";
output ~= "";
-
foreach (obj; section_objs) {
/+ ↓ object declaration line +/
string obj_decl = "[" ~ obj.metainfo.ocn.to!string ~ "] ";
-
if (obj.metainfo.is_a == "heading") {
string lev = obj.metainfo.marked_up_level;
obj_decl ~= "heading :" ~ lev;
@@ -188,7 +177,6 @@ template spineAbstractionTxt() {
obj_decl ~= obj.metainfo.is_a;
}
output ~= obj_decl;
-
/+ ↓ properties (only non-default values) +/
if (obj.metainfo.is_of_part.length > 0)
output ~= ".part: " ~ obj.metainfo.is_of_part;
@@ -199,7 +187,6 @@ template spineAbstractionTxt() {
output ~= ".parent: " ~ obj.metainfo.parent_ocn.to!string;
if (obj.metainfo.last_descendant_ocn != 0)
output ~= ".last_descendant: " ~ obj.metainfo.last_descendant_ocn.to!string;
-
/+ ↓ child headings (from pre-computed map) +/
if (obj.metainfo.children_headings.length > 0) {
string[] ch;
@@ -208,7 +195,6 @@ template spineAbstractionTxt() {
}
output ~= ".children: " ~ ch.join(" ");
}
-
/+ ↓ ancestors (only if non-zero) +/
{
bool has_anc = false;
@@ -268,7 +254,6 @@ template spineAbstractionTxt() {
output ~= ".dom_status_collapsed: " ~ ds;
}
}
-
if (obj.metainfo.heading_lev_collapsed < 9)
output ~= ".heading_lev_collapsed: " ~ obj.metainfo.heading_lev_collapsed.to!string;
if (obj.metainfo.parent_lev_markup != 0)
@@ -287,7 +272,6 @@ template spineAbstractionTxt() {
output ~= ".meta_lang: " ~ obj.metainfo.lang;
if (obj.metainfo.syntax.length > 0)
output ~= ".meta_syntax: " ~ obj.metainfo.syntax;
-
/+ ↓ sha256 digest +/
{
bool has_sha = false;
@@ -296,11 +280,24 @@ template spineAbstractionTxt() {
}
if (has_sha) {
if (doc_matters.opt.action.vox_gt_3) {
- writeln(obj.metainfo.sha256.summary); // USE check
+ writeln(obj.metainfo.sha256.summary);
}
output ~= ".sha256: " ~ obj.metainfo.sha256.text.toHexString.to!string;
}
}
+ /+ ↓ images, repeatable record, one per image in order of appearance:
+ .image: <filename> sha256:<HEX> bytes:<n>
+ filename first (the object's handle on the image), remaining fields
+ self-describing key:value tokens so that further fields (e.g. dim:)
+ can be added later without invalidating existing readers
+ +/
+ if (obj.metainfo.sha256.images.length > 0) {
+ foreach (i; obj.metainfo.sha256.images) {
+ output ~= ".image: " ~ i.fileName
+ ~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
+ ~ " bytes:" ~ i.fileSize.to!string;
+ }
+ }
/+ ↓ text attributes +/
if (obj.attrib.indent_base != 0 || obj.attrib.indent_hang != 0)
output ~= ".indent: " ~ obj.attrib.indent_base.to!string
@@ -309,7 +306,6 @@ template spineAbstractionTxt() {
output ~= ".bullet: true";
if (obj.attrib.language.length > 0)
output ~= ".lang: " ~ obj.attrib.language;
-
/+ ↓ has flags +/
{
string[] has_flags;
@@ -321,7 +317,6 @@ template spineAbstractionTxt() {
if (has_flags.length > 0)
output ~= ".has: " ~ has_flags.join(" ");
}
-
/+ ↓ table properties +/
if (obj.metainfo.is_a == "table" && obj.table.number_of_columns > 0) {
output ~= ".table_cols: " ~ obj.table.number_of_columns.to!string;
@@ -338,7 +333,6 @@ template spineAbstractionTxt() {
if (obj.table.walls)
output ~= ".table_walls: true";
}
-
/+ ↓ code block properties +/
if (obj.metainfo.is_a == "code") {
if (obj.code_block.syntax.length > 0)
@@ -346,7 +340,6 @@ template spineAbstractionTxt() {
if (obj.code_block.linenumbers)
output ~= ".code_linenumbers: true";
}
-
/+ ↓ stow (extracted links) +/
if (obj.stow.link.length > 0) {
foreach (lnk; obj.stow.link) {
@@ -354,7 +347,6 @@ template spineAbstractionTxt() {
output ~= ".stow_link: " ~ lnk;
}
}
-
/+ ↓ tag properties +/
if (obj.tags.in_segment_html.length > 0)
output ~= ".segment: " ~ obj.tags.in_segment_html;
@@ -393,21 +385,17 @@ template spineAbstractionTxt() {
output ~= ".anchor_tag: " ~ at;
}
}
-
/+ ↓ text content +/
if (obj.text.length > 0) {
foreach (line; obj.text.split("\n")) {
output ~= "| " ~ line;
}
}
-
output ~= "";
}
-
output ~= "}";
output ~= "";
}
-
/+ ↓ write to file +/
/+ path: <output_path>/<language>/abstraction/<doc_uid_out>.ssp +/
string out_root = (doc_matters.output_path.length > 0)