#+TITLE: sdp document abstraction #+AUTHOR: Ralph Amissah #+EMAIL: ralph.amissah@gmail.com #+STARTUP: indent #+LANGUAGE: en #+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t #+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc #+OPTIONS: author:nil email:nil creator:nil timestamp:nil #+PROPERTY: header-args :padline no :exports code :noweb yes #+EXPORT_SELECT_TAGS: export #+EXPORT_EXCLUDE_TAGS: noexport #+FILETAGS: :sdp:rel:ao: #+TAGS: assert(a) class(c) debug(d) mixin(m) sdp(s) tangle(T) template(t) WEB(W) noexport(n) [[./sdp.org][sdp]] [[./][org/]] * Document Abstraction :abstract:process: Process markup document, create document abstraction. ** _1. pre loop processing_ :pre: *** imports :imports: [[./ao_defaults.org][ao_defaults]] #+name: abs_imports #+BEGIN_SRC d import ao_defaults, // sdp/ao_defaults.d ao_object_setter, // sdp/ao_object_setter.d ao_rgx; // sdp/ao_rgx.d #+END_SRC *** mixins :mixins: #+name: abs_mixins #+BEGIN_SRC d mixin ObjectSetter; mixin InternalMarkup; #+END_SRC *** initialize :initialize: #+name: abs_init_struct #+BEGIN_SRC d /+ initialize +/ auto rgx = Rgx(); ObjComposite[][string] the_table_of_contents_section; ObjComposite[] the_document_head_section, the_document_body_section, the_bibliography_section, the_glossary_section, the_blurb_section; string[string] an_object, processing; string an_object_key; string[] anchor_tags; string segment_object_belongs_to; auto set_abstract_object = ObjectAbstractSet(); auto note_section = NotesSection(); /+ enum +/ enum State { off, on } enum TriState { off, on, closing } // make aware, possibility of third state enum DocStructMarkupHeading { h_sect_A, h_sect_B, h_sect_C, h_sect_D, h_text_1, h_text_2, h_text_3, h_text_4, h_text_5, // extra level, drop content_non_header } // header section A-D; header text 1-4 enum DocStructCollapsedHeading { lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7 } // not yet used /+ 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 +/ long counter, previous_count, previous_length; int[string] line_occur; int verse_line, heading_pointer; /+ paragraph attributes +/ int[string] indent; bool bullet = true; string content_non_header = "8"; auto obj_im = ObjInlineMarkup(); auto obj_att = ObjAttributes(); /+ ocn +/ int obj_cite_number, obj_cite_number_; auto object_citation_number = OCNemitter(); int obj_cite_number_emit(int obj_cite_number_status_flag) { return object_citation_number.obj_cite_number_emitter(obj_cite_number_status_flag); } /+ book index variables +/ string book_idx_tmp; string[][string][string] bookindex_unordered_hashes; auto bookindex_extract_hash = BookIndexNuggetHash(); string[][string][string] bkidx_hash(string bookindex_section, int obj_cite_number) { return bookindex_extract_hash.bookindex_nugget_hash(bookindex_section, obj_cite_number); } /+ node +/ string _node; auto node_construct = NodeStructureMetadata(); #+END_SRC *** scope #+name: abs_init_rest #+BEGIN_SRC d scope(success) { } scope(failure) { } scope(exit) { destroy(the_document_head_section); destroy(the_table_of_contents_section); destroy(the_document_body_section); destroy(the_bibliography_section); destroy(an_object); destroy(processing); destroy(biblio_arr_json); } #+END_SRC *** init rest #+name: abs_init_rest #+BEGIN_SRC d line_occur = [ "heading" : 0, "para" : 0, "glossary" : 0, "blurb" : 0, ]; auto type = flags_type_init; void tell_lo(int obj_cite_number, in char[] line) { writefln( "* %s %s", to!string(obj_cite_number), to!string(line) ); } string[string] obj_cite_number_poem = [ "start" : "", "end" : "" ]; int[string] lv = [ "lv" : State.off, "h0" : State.off, "h1" : State.off, "h2" : State.off, "h3" : State.off, "h4" : State.off, "h5" : State.off, "h6" : State.off, "h7" : State.off, "lev_collapsed_number" : 0, ]; int[string] collapsed_lev = [ "h0" : State.off, "h1" : State.off, "h2" : State.off, "h3" : State.off, "h4" : State.off, "h5" : State.off, "h6" : State.off, "h7" : State.off ]; string[string] heading_match_str = [ "h_A": "^(none)", "h_B": "^(none)", "h_C": "^(none)", "h_D": "^(none)", "h_1": "^(none)", "h_2": "^(none)", "h_3": "^(none)", "h_4": "^(none)" ]; auto heading_match_rgx = [ "h_A": regex(r"^(none)"), "h_B": regex(r"^(none)"), "h_C": regex(r"^(none)"), "h_D": regex(r"^(none)"), "h_1": regex(r"^(none)"), "h_2": regex(r"^(none)"), "h_3": regex(r"^(none)"), "h_4": regex(r"^(none)") ]; string _anchor_tag; string toc_txt_; an_object["glossary_nugget"] = ""; an_object["blurb_nugget"] = ""; auto toc_head = set_abstract_object.contents_heading( "Table of Contents", // nugget/object "", // attrib 0, // obj_cite_number ["toc"], // anchor tag "1", // lev 4, // lev_markup_number 2, // lev_collapsed_number ); the_table_of_contents_section = [ "seg": [toc_head], "scroll": [toc_head], ]; auto mkup = InlineMarkup(); auto munge = ObjInlineMarkupMunge(); #+END_SRC ** _2. loop: process document body_ [+6] :loop: *** loop scope :scope: #+name: abs_in_loop_body_00 #+BEGIN_SRC d /+ scope +/ scope(exit) { } scope(failure) { stderr.writefln( "%s\n%s\n%s:%s failed here:\n line: %s", __MODULE__, __FUNCTION__, __FILE__, __LINE__, line, ); } line = replaceAll(line, rgx.true_dollar, "$$$$"); // dollar represented as $$ needed to stop submatching on $ // (substitutions using ${identifiers} must take into account (i.e. happen earlier)) debug(source) { // source lines writeln(line); } debug(srclines) { if (!line.empty) { // source lines, not empty writefln( "* %s", line ); } } #+END_SRC *** check whether obj_cite_number is on or turned off :ocn: #+name: abs_in_loop_body_00 #+BEGIN_SRC d if (!line.empty) { _check_obj_cite_number_status_(line, type); } #+END_SRC *** [#A] separate regular markup text from code blocks [+5] **** code blocks :block:code: #+name: abs_in_loop_body_00_code_block #+BEGIN_SRC d /+ block object: code +/ _code_block_(line, an_object, type); continue; #+END_SRC **** non code objects (other blocks or regular text) [+4] :non_code: ***** in section (biblio, glossary, blurb) (block group) [+1] :block:active: ****** DONE within block group: biblio :biblio: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d if ((matchFirst(line, rgx.heading_biblio) || (type["biblio_section"] == State.on)) && (!matchFirst(line, rgx.heading)) && (!matchFirst(line, rgx.comment))) { /+ within section (block object): biblio +/ _biblio_block_(line, type, bib_entry, biblio_entry_str_json, biblio_arr_json); type["glossary_section"] = State.off; type["biblio_section"] = State.on; type["blurb_section"] = State.off; debug(bibliobuild) { writeln("- ", biblio_entry_str_json); writeln("-> ", biblio_arr_json.length); } continue; #+END_SRC ****** TODO within section: glossary :glossary: if there is a glossary section you need to: - extract it - create standard headings - markup contents in standard way like regular paragraphs - need indentation and regular paragraph inline markup - reconstitute the document with the glossary section following the endnotes #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if ((matchFirst(line, rgx.heading_glossary) || (type["glossary_section"] == State.on)) && (!matchFirst(line, rgx.heading)) && (!matchFirst(line, rgx.comment))) { /+ within section (block object): glossary +/ debug(glossary) { writeln(__LINE__); writeln(line); } // _glossary_block_(line, type); type["glossary_section"] = State.on; type["biblio_section"] = State.off; type["blurb_section"] = State.off; indent=[ "hang_position" : 0, "base_position" : 0, ]; bullet = false; type["para"] = State.on; line_occur["para"] = State.off; an_object_key="glossary_nugget"; // if (matchFirst(line, rgx.heading_glossary)) { the_glossary_section ~= set_abstract_object.contents_heading( "Glossary", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); the_glossary_section ~= set_abstract_object.contents_heading( "Glossary", // nugget/object "", // attrib 0, // obj_cite_number ["glossary"], // anchor tag "1", // lev 4, // lev_markup_number 2, // lev_collapsed_number ); // } else if (matchFirst(line, rgx.heading)) { // _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); // levels? } else { _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); the_glossary_section ~= set_abstract_object.contents_para( "para", // an_object["is"], to!string(line), // an_object["substantive"], "", // attrib 0, // obj_cite_number, indent, bullet ); } type["obj_cite_number_status"] = TriState.off; continue; #+END_SRC ****** TODO within section: blurb :blurb: if there is a blurb section you need to: - extract it - create standard headings (or use line provided in 1~ heading) - markup contents in standard way like regular paragraphs - need regular paragraph inline markup - reconstitute the document with the blurb section at the very end of the doucment #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if ((matchFirst(line, rgx.heading_blurb) || (type["blurb_section"] == State.on)) && (!matchFirst(line, rgx.heading)) && (!matchFirst(line, rgx.comment))) { /+ within section (block object): blurb +/ debug(blurb) { writeln(__LINE__); writeln(line); } // _blurb_block_(line, type); type["glossary_section"] = State.off; type["biblio_section"] = State.off; type["blurb_section"] = State.on; indent=[ "hang_position" : 0, "base_position" : 0, ]; bullet = false; type["para"] = State.on; line_occur["para"] = State.off; an_object_key="blurb_nugget"; if (matchFirst(line, rgx.heading_blurb)) { the_blurb_section ~= set_abstract_object.contents_heading( "Blurb", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); the_blurb_section ~= set_abstract_object.contents_heading( "Blurb", // nugget/object "", // attrib 0, // obj_cite_number ["blurb"], // anchor tag "1", // lev 4, // lev_markup_number 2, // lev_collapsed_number ); } else if (matchFirst(line, rgx.heading)) { _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); the_blurb_section ~= set_abstract_object.contents_heading( to!string(line), // an_object["substantive"], "", // attrib 0, // obj_cite_number [""], // anchor tag to!string(an_object["lev"]), to!int(an_object["lev_markup_number"]), to!int(an_object["lev_collapsed_number"]), ); } else { _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); the_blurb_section ~= set_abstract_object.contents_para( "para", // an_object["is"], to!string(line), // an_object["substantive"], "", // attrib obj_cite_number, indent, bullet ); } type["obj_cite_number_status"] = TriState.off; continue; #+END_SRC ***** in block group [+1] :block:active: ****** within block group: poem :poem: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if (type["poem"] == TriState.on) { /+ within block object: poem +/ _poem_block_(line, an_object, type, counter, obj_cite_number_poem, dochead_make_aa); continue; #+END_SRC ****** within block group: group :group: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d /+ within block object: group +/ } else if (type["group"] == TriState.on) { /+ within block object: group +/ _group_block_(line, an_object, type); continue; #+END_SRC ****** within block group: block :block: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if (type["block"] == TriState.on) { /+ within block object: block +/ _block_block_(line, an_object, type); continue; #+END_SRC ****** within block group: quote :quote: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if (type["quote"] == TriState.on) { /+ within block object: quote +/ _quote_block_(line, an_object, type); continue; #+END_SRC ****** within block group: table :table: #+name: abs_in_loop_body_non_code_obj #+BEGIN_SRC d } else if (type["table"] == TriState.on) { /+ within block object: table +/ _table_block_(line, an_object, type); continue; #+END_SRC ***** not identified as being within block group (could still be, or not) [+3] ****** assert #+name: abs_in_loop_body_open_block_obj_assert #+BEGIN_SRC d assert( (type["blocks"] == TriState.off) || (type["blocks"] == TriState.closing), "block status: none or closed" ); assertions_flag_types_block_status_none_or_closed(type); #+END_SRC ****** block open #+name: abs_in_loop_body_open_block_obj #+BEGIN_SRC d if (matchFirst(line, (rgx.block_poem_open))) { /+ poem to verse exceptions! +/ object_reset(an_object); processing.remove("verse"); obj_cite_number_poem["start"] = to!string(obj_cite_number); } _start_block_(line, type, obj_cite_number_poem); continue; #+END_SRC ****** line not empty [+2] ******* asserts :assert: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d assert( !line.empty, "line tested, line not empty surely" ); assert( (type["blocks"] == TriState.off) || (type["blocks"] == TriState.closing), "code block status: none or closed" ); if (type["blocks"] == TriState.closing) { // blocks closed, unless followed by book index debug(check) { // block writeln(__LINE__); writeln(line); } assert( matchFirst(line, rgx.book_index) || matchFirst(line, rgx.book_index_open) || type["book_index"] == State.on ); } #+END_SRC ******* book index :bookindex: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d if ((matchFirst(line, rgx.book_index)) || (matchFirst(line, rgx.book_index_open)) || (type["book_index"] == State.on )) { /+ book_index +/ _book_index_(line, book_idx_tmp, an_object, type); #+END_SRC ******* not book index [+1] #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d } else { /+ not book_index +/ #+END_SRC ******** matched: comment :comment:match: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d an_object_key="body_nugget"; if (auto m = matchFirst(line, rgx.comment)) { /+ matched comment +/ debug(comment) { writeln(line); } an_object[an_object_key] ~= line ~= "\n"; the_document_body_section ~= set_abstract_object.contents_comment(strip(an_object[an_object_key])); _common_reset_(line_occur, an_object, type); processing.remove("verse"); ++counter; #+END_SRC ******** flag not set & line not exist: heading or para :heading:paragraph: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d } else if (((line_occur["para"] == State.off) && (line_occur["heading"] == State.off)) && ((type["para"] == State.off) && (type["heading"] == State.off))) { /+ heading or para but neither flag nor line exists +/ if ((dochead_make_aa["make"]["headings"].length > 2) && (type["make_headings"] == State.off)) { /+ heading found +/ _heading_found_(line, dochead_make_aa["make"]["headings"], heading_match_str, heading_match_rgx, type); } if ((type["make_headings"] == State.on) && ((line_occur["para"] == State.off) && (line_occur["heading"] == State.off)) && ((type["para"] == State.off) && (type["heading"] == State.off))) { /+ heading make set +/ _heading_make_set_(line, line_occur, heading_match_rgx, type); } /+ TODO node info: all headings identified at this point, - extract node info here?? - how long can it wait? - should be incorporated in composite objects - should happen before endnote links set (they need to be moved down?) // node_construct.node_emitter_heading segment anchor tag +/ if (matchFirst(line, rgx.heading)) { /+ heading match +/ _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); } else if (line_occur["para"] == State.off) { /+ para match +/ an_object_key="body_nugget"; _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur); } #+END_SRC ******** line exist: heading :heading: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d } else if (line_occur["heading"] > State.off) { /+ heading +/ debug(heading) { // heading writeln(line); } an_object[an_object_key] ~= line ~= "\n"; ++line_occur["heading"]; #+END_SRC ******** line exist: para :para: #+name: abs_in_loop_body_not_block_obj #+BEGIN_SRC d } else if (line_occur["para"] > State.off) { /+ paragraph +/ debug(para) { writeln(line); } an_object[an_object_key] ~= " " ~ line; ++line_occur["para"]; } } #+END_SRC ****** line empty, with block flag #+name: abs_in_loop_body_not_block_obj_line_empty_blocks_flags #+BEGIN_SRC d _block_flag_line_empty_( line, an_object, the_document_body_section, bookindex_unordered_hashes, obj_cite_number, _node, counter, type, obj_cite_number_poem, dochead_make_aa ); // watch #+END_SRC ****** line empty [+1] ******* assert line empty :assert: #+name: abs_in_loop_body_not_block_obj_line_empty #+BEGIN_SRC d assert( line.empty, "line should be empty" ); assert( (type["blocks"] == State.off), "code block status: none" ); #+END_SRC ******* heading object :heading:object: #+name: abs_in_loop_body_not_block_obj_line_empty #+BEGIN_SRC d if ((type["heading"] == State.on) && (line_occur["heading"] > State.off)) { /+ heading object (current line empty) +/ obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "heading"; an_object_key="body_nugget"; auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); // tuple this with anchor tags? an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; if (to!int(an_object["lev_markup_number"]) == 4) { segment_object_belongs_to = anchor_tags[0]; } else if (to!int(an_object["lev_markup_number"]) < 4) { segment_object_belongs_to = ""; } _anchor_tag=to!string(obj_cite_number); the_table_of_contents_section = obj_im.table_of_contents_gather_headings( an_object, dochead_make_aa, segment_object_belongs_to, _anchor_tag, the_table_of_contents_section, ); _node = node_construct.node_emitter_heading( an_object["lev_markup_number"], an_object["lev_collapsed_number"], segment_object_belongs_to, obj_cite_number, counter, heading_pointer, an_object["is"] ); // heading an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); ++heading_pointer; debug(segments) { writeln(an_object["lev_markup_number"]); writeln(segment_object_belongs_to); } the_document_body_section ~= set_abstract_object.contents_heading( an_object["substantive"], an_object["attrib"], obj_cite_number, anchor_tags, to!string(an_object["lev"]), to!int(an_object["lev_markup_number"]), to!int(an_object["lev_collapsed_number"]), ); // track previous heading and make assertions debug(objectrelated1) { // check writeln(line); } _common_reset_(line_occur, an_object, type); an_object.remove("lev"); an_object.remove("lev_markup_number"); processing.remove("verse"); ++counter; #+END_SRC ******* paragraph object :paragraph:object: #+name: abs_in_loop_body_not_block_obj_line_empty #+BEGIN_SRC d } else if ((type["para"] == State.on) && (line_occur["para"] > State.off)) { /+ paragraph object (current line empty) +/ obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "para"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); // ... an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_para( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number, indent, bullet ); _common_reset_(line_occur, an_object, type); indent=[ "hang_position" : 0, "base_position" : 0, ]; bullet = false; processing.remove("verse"); ++counter; } else { assert( line == null, "line variable should be empty, should not occur" ); // check what happens when paragraph separated by 2 newlines } #+END_SRC *** close non code objects (regular text) *** regular text objects :text:paragraph: #+name: abs_in_loop_body_01 #+BEGIN_SRC d /+ unless (the_document_body_section.length == 0) ? +/ if (the_document_body_section.length > 0) { if (((the_document_body_section[$-1].is_a == "para") || (the_document_body_section[$-1].is_a == "heading") || (the_document_body_section[$-1].is_a == "group")) && (the_document_body_section.length > previous_length) ) { if ((the_document_body_section[$-1].is_a == "heading") && (the_document_body_section[$-1].heading_attrib.lev_markup_number < 5)) { type["biblio_section"] = State.off; type["glossary_section"] = State.off; type["blurb_section"] = State.off; } previous_length = the_document_body_section.length; if ( match(the_document_body_section[$-1].object, rgx.inline_notes_delimiter_al_regular_number_note) ) { previous_count=the_document_body_section.length -1; note_section.gather_notes_for_endnote_section( the_document_body_section, segment_object_belongs_to, the_document_body_section.length-1 ); } } } #+END_SRC ** _3. post loop processing_ :post: *** misc #+name: abs_post #+BEGIN_SRC d debug(objectrelated2) { // check writeln(line); } /+ Backmatter: * endnotes * glossary * references / bibliography * book index +/ // TODO FIGURE OUT, you need this possibility // obj_im.obj_inline_markup_and_anchor_tags("doc_end_reset", an_object_key, "", dochead_make_aa); #+END_SRC *** document sections **** DONE endnotes section (scroll & seg) :endnotes: #+name: abs_post #+BEGIN_SRC d auto en_tuple = note_section.endnote_objects(obj_cite_number); static assert(!isTypeTuple!(en_tuple)); auto the_endnotes_section = en_tuple[0]; obj_cite_number = en_tuple[1]; debug(endnotes) { writefln( "%s %s", __LINE__, the_endnotes_section["seg"].length ); foreach (o; the_endnotes_section["seg"]) { writeln(o); } } #+END_SRC **** DONE glossary section? #+name: abs_post #+BEGIN_SRC d if (an_object["glossary_nugget"].length == 0) { writeln("no gloss"); the_glossary_section ~= set_abstract_object.contents_heading( "(skip) there is no Glossary section", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); } else { writeln("gloss"); } debug(glossary) { foreach (gloss; the_glossary_section) { writeln(gloss.object); } } #+END_SRC **** DONE [#B] bibliography section (objects) :bibliography: #+name: abs_post #+BEGIN_SRC d auto biblio_unsorted_incomplete = biblio_arr_json.dup; // destroy(biblio_arr_json); auto biblio = Bibliography(); auto biblio_ordered = biblio._bibliography_(biblio_unsorted_incomplete, bib_arr_json); #+END_SRC #+name: abs_post #+BEGIN_SRC d if (biblio_ordered.length > 0) { the_bibliography_section ~= set_abstract_object.contents_heading( "Bibliography", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); the_bibliography_section ~= set_abstract_object.contents_heading( "Bibliography", // nugget/object "", // attrib 0, // obj_cite_number ["bibliography"], // anchor tag "1", // lev 4, // lev_markup_number 2, // lev_collapsed_number ); } else { the_bibliography_section ~= set_abstract_object.contents_heading( "(skip) there is no Bibliography", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); } #+END_SRC ***** format biblio string #+name: abs_post #+BEGIN_SRC d string out_; foreach (entry; biblio_ordered) { out_ = format( "%s \"%s\"%s%s%s%s%s%s%s%s%s.", ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str), entry["fulltitle"].str, ((entry["journal"].str.empty) ? "" : ", /{" ~ entry["journal"].str ~ "}/"), ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str), ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str), ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""), ", " ~ entry["year"].str, ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str), ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str), ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str), ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"), ); the_bibliography_section ~= set_abstract_object.contents_para( "bibliography", out_, // nugget/object "", // attrib 0, // obj_cite_number ([ "hang_position" : 0, "base_position" : 1, ]), // indent false ); } #+END_SRC #+name: abs_post #+BEGIN_SRC d debug(bibliosection) { foreach (o; the_bibliography_section) { writeln(o.object); } } #+END_SRC ***** bibliography components auto biblio_entry_tags_jsonstr = `{ "is" : "", "sortby_deemed_author_year_title" : "", "deemed_author" : "", "author_raw" : "", "author" : "", "author_arr" : [ "" ], "editor_raw" : "", "editor" : "", "editor_arr" : [ "" ], "title" : "", "subtitle" : "", "fulltitle" : "", "language" : "", "trans" : "", "src" : "", "journal" : "", "in" : "", "volume" : "", "edition" : "", "year" : "", "place" : "", "publisher" : "", "url" : "", "pages" : "", "note" : "", "short_name" : "", "id" : "" }`; // is: book, article, magazine, newspaper, blog, other **** DONE [#B] bookindex section (scroll & seg) :book:index: #+name: abs_post #+BEGIN_SRC d auto bi = BookIndexReportSection(); auto bi_tuple = bi.bookindex_build_section( bookindex_unordered_hashes, obj_cite_number, segment_object_belongs_to ); static assert(!isTypeTuple!(bi_tuple)); auto the_bookindex_section = bi_tuple[0]; obj_cite_number = bi_tuple[1]; debug(bookindex) { // bookindex foreach (bi_entry; the_bookindex_section["seg"]) { writeln(bi_entry); } } #+END_SRC **** DONE blurb section? #+name: abs_post #+BEGIN_SRC d if (an_object["blurb_nugget"].length == 0) { writeln("no blurb"); the_blurb_section ~= set_abstract_object.contents_heading( "(skip) there is no Blurb section", // nugget/object "", // attrib 0, // obj_cite_number [""], // anchor tag "B", // lev 1, // lev_markup_number 1, // lev_collapsed_number ); } else { writeln("blurb"); } debug(blurb) { foreach (blurb; the_blurb_section) { writeln(blurb.object); } } #+END_SRC **** DONE [#B] toc, table of contents section (scroll & seg) :contents: #+name: abs_post #+BEGIN_SRC d indent=[ "hang_position" : 1, "base_position" : 1, ]; if (the_endnotes_section["seg"].length > 1) { toc_txt_ = format( "{ %s }../%s.fn_suffix", "Endnotes", "endnotes", // segment_object_belongs_to ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_endnotes_section["scroll"].length > 1) { toc_txt_ = format( "{ %s }#%s", "Endnotes", "endnotes", // _anchor_tag ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_glossary_section.length > 1) { toc_txt_ = format( "{ %s }../%s.fn_suffixs", "Glossary", "glossary", // segment_object_belongs_to ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); toc_txt_ = format( "{ %s }#%s", "Glossary", "glossary", // _anchor_tag ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_bibliography_section.length > 1){ toc_txt_ = format( "{ %s }../%s.fn_suffix", "Bibliography", "bibliography", // segment_object_belongs_to ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); toc_txt_ = format( "{ %s }#%s", "Bibliography", "bibliography", // _anchor_tag ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_bookindex_section["seg"].length > 1) { toc_txt_ = format( "{ %s }../%s.fn_suffix", "Book Index", "bookindex", // segment_object_belongs_to ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_bookindex_section["scroll"].length > 1) { toc_txt_ = format( "{ %s }#%s", "Book Index", "bookindex", // _anchor_tag ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } if (the_blurb_section.length > 1) { toc_txt_ = format( "{ %s }../%s.fn_suffix", "Blurb", "blurb", // segment_object_belongs_to ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); toc_txt_ = format( "{ %s }#%s", "Blurb", "blurb", // _anchor_tag ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } debug(toc) { writefln( "%s %s", __LINE__, the_table_of_contents_section["seg"].length ); foreach (toc_linked_heading; the_table_of_contents_section["seg"]) { writeln(mkup.indent_by_spaces_provided(toc_linked_heading.para_attrib.indent_start), toc_linked_heading.object); } } #+END_SRC *** [#B] the document :document: #+name: abs_post #+BEGIN_SRC d the_document_head_section ~= the_document_body_section[0]; the_document_body_section=the_document_body_section[1..$]; auto document_the = [ "head": the_document_head_section, "toc_seg": the_table_of_contents_section["seg"], "toc_scroll": the_table_of_contents_section["scroll"], "body": the_document_body_section, "endnotes_seg": the_endnotes_section["seg"], "endnotes_scroll": the_endnotes_section["scroll"], "glossary": the_glossary_section, "bibliography": the_bibliography_section, "bookindex_scroll": the_bookindex_section["scroll"], "bookindex_seg": the_bookindex_section["seg"], "blurb": the_blurb_section, ]; #+END_SRC *** misc heading #+name: abs_post destroy(the_document_body_section); destroy(the_endnotes_section); destroy(the_bookindex_section); #+END_SRC *** [#A] return document tuple :return:tuple: #+name: abs_post #+BEGIN_SRC d auto t = tuple( document_the, bookindex_unordered_hashes, biblio_ordered ); return t; #+END_SRC * Functions :abstract:function: functions used in document abstraction ** set & resets :reset: *** object reset: remove (clean) :object:remove: #+name: abs_functions_object_reset #+BEGIN_SRC d auto object_reset(ref 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"); } #+END_SRC *** set, initialize or re-initialize :set: #+name: abs_functions_header_set_common #+BEGIN_SRC d auto _common_reset_( ref int[string] line_occur, ref string[string] an_object, ref int[string] type ) { line_occur["heading"] = State.off; line_occur["para"]= State.off; type["heading"] = State.off; type["para"] = State.off; object_reset(an_object); } #+END_SRC ** check obj_cite_number status in document :ocn: #+name: abs_functions_ocn_status #+BEGIN_SRC d void _check_obj_cite_number_status_( char[] line, ref int[string] type ) { if ((!line.empty) && (type["obj_cite_number_status_multi_obj"] == TriState.off)) { /+ not multi-line object, check whether obj_cite_number is on or turned off +/ if (matchFirst(line, rgx.obj_cite_number_block_marks)) { /+ switch off obj_cite_number +/ if (matchFirst(line, rgx.obj_cite_number_off_block)) { type["obj_cite_number_status_multi_obj"] = TriState.on; debug(ocnoff) { writeln(line); } } if (matchFirst(line, rgx.obj_cite_number_off_block_dh)) { type["obj_cite_number_status_multi_obj"] = TriState.closing; debug(ocnoff) { writeln(line); } } } else { if (type["obj_cite_number_status_multi_obj"] == TriState.off) { if (matchFirst(line, rgx.obj_cite_number_off)) { type["obj_cite_number_status"] = TriState.on; } else if (matchFirst(line, rgx.obj_cite_number_off_dh)) { type["obj_cite_number_status"] = TriState.closing; } else { type["obj_cite_number_status"] = TriState.off; } } else { type["obj_cite_number_status"] = type["obj_cite_number_status_multi_obj"]; } } } else if ((!line.empty) && (type["obj_cite_number_status_multi_obj"] > TriState.off)) { if (matchFirst(line, rgx.obj_cite_number_off_block_close)) { type["obj_cite_number_status_multi_obj"] = TriState.off; type["obj_cite_number_status"] = TriState.off; debug(ocnoff) { writeln(line); } } } } #+END_SRC ** block :block: *** block start (open) block :start: **** function open for block starts #+name: abs_functions_block #+BEGIN_SRC d void _start_block_( char[] line, ref int[string] type, string[string] obj_cite_number_poem ) { #+END_SRC **** block (various) curly open :curly: #+name: abs_functions_block #+BEGIN_SRC d if (matchFirst(line, rgx.block_curly_code_open)) { /+ curly code open +/ debug(code) { // code (curly) open writefln( "* [code curly] %s", line ); } type["blocks"] = TriState.on; type["code"] = TriState.on; type["curly_code"] = TriState.on; } else if (matchFirst(line, rgx.block_curly_poem_open)) { /+ curly poem open +/ debug(poem) { // poem (curly) open writefln( "* [poem curly] %s", line ); } obj_cite_number_poem["start"] = to!string(obj_cite_number); type["blocks"] = TriState.on; type["verse_new"] = State.on; type["poem"] = TriState.on; type["curly_poem"] = TriState.on; } else if (matchFirst(line, rgx.block_curly_group_open)) { /+ curly group open +/ debug(group) { // group (curly) open writefln( "* [group curly] %s", line ); } type["blocks"] = TriState.on; type["group"] = TriState.on; type["curly_group"] = TriState.on; } else if (matchFirst(line, rgx.block_curly_block_open)) { /+ curly block open +/ debug(block) { // block (curly) open writefln( "* [block curly] %s", line ); } type["blocks"] = TriState.on; type["block"] = TriState.on; type["curly_block"] = TriState.on; } else if (matchFirst(line, rgx.block_curly_quote_open)) { /+ curly quote open +/ debug(quote) { // quote (curly) open writefln( "* [quote curly] %s", line ); } type["blocks"] = TriState.on; type["quote"] = TriState.on; type["curly_quote"] = TriState.on; } else if (matchFirst(line, rgx.block_curly_table_open)) { /+ curly table open +/ debug(table) { // table (curly) open writefln( "* [table curly] %s", line ); } type["blocks"] = TriState.on; type["table"] = TriState.on; type["curly_table"] = TriState.on; #+END_SRC **** block (various) tic open :tic: #+name: abs_functions_block #+BEGIN_SRC d } else if (matchFirst(line, rgx.block_tic_code_open)) { /+ tic code open +/ debug(code) { // code (tic) open writefln( "* [code tic] %s", line ); } type["blocks"] = TriState.on; type["code"] = TriState.on; type["tic_code"] = TriState.on; } else if (matchFirst(line, rgx.block_tic_poem_open)) { /+ tic poem open +/ debug(poem) { // poem (tic) open writefln( "* [poem tic] %s", line ); } obj_cite_number_poem["start"] = to!string(obj_cite_number); type["blocks"] = TriState.on; type["verse_new"] = State.on; type["poem"] = TriState.on; type["tic_poem"] = TriState.on; } else if (matchFirst(line, rgx.block_tic_group_open)) { /+ tic group open +/ debug(group) { // group (tic) open writefln( "* [group tic] %s", line ); } type["blocks"] = TriState.on; type["group"] = TriState.on; type["tic_group"] = TriState.on; } else if (matchFirst(line, rgx.block_tic_block_open)) { /+ tic block open +/ debug(block) { // block (tic) open writefln( "* [block tic] %s", line ); } type["blocks"] = TriState.on; type["block"] = TriState.on; type["tic_block"] = TriState.on; } else if (matchFirst(line, rgx.block_tic_quote_open)) { /+ tic quote open +/ debug(quote) { // quote (tic) open writefln( "* [quote tic] %s", line ); } type["blocks"] = TriState.on; type["quote"] = TriState.on; type["tic_quote"] = TriState.on; } else if (matchFirst(line, rgx.block_tic_table_open)) { /+ tic table open +/ debug(table) { // table (tic) open writefln( "* [table tic] %s", line ); } type["blocks"] = TriState.on; type["table"] = TriState.on; type["tic_table"] = TriState.on; } #+END_SRC **** function close for block starts #+name: abs_functions_block #+BEGIN_SRC d } #+END_SRC *** block continue (an open block) :continue: **** code block (special status, deal with first) :code: #+name: abs_functions_block_code #+BEGIN_SRC d void _code_block_( char[] line, ref string[string] an_object, ref int[string] type ) { if (type["curly_code"] == TriState.on) { if (matchFirst(line, rgx.block_curly_code_close)) { debug(code) { // code (curly) close writeln(line); } type["blocks"] = TriState.closing; type["code"] = TriState.closing; type["curly_code"] = TriState.off; } else { debug(code) { // code (curly) line writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // code (curly) line } } else if (type["tic_code"] == TriState.on) { if (matchFirst(line, rgx.block_tic_close)) { debug(code) { // code (tic) close writeln(line); } type["blocks"] = TriState.closing; type["code"] = TriState.closing; type["tic_code"] = TriState.off; } else { debug(code) { // code (tic) line writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // code (tic) line } } } #+END_SRC **** biblio block :biblio: ***** biblio tag map #+name: abs_functions_block_biblio #+BEGIN_SRC d final string biblio_tag_map(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]; } #+END_SRC ****** +consider+ #+name: none #+BEGIN_SRC d final string biblio_tag_map_(string abr) { string name; switch (abr) { case "au": name="author_raw"; break; case "ed": name="editor_raw"; break; case "ti": name="fulltitle"; break; case "lng": name="language"; break; case "jo": name="journal"; break; case "vol": name="volume"; break; case "edn": name="edition"; break; case "yr": name="year"; break; case "pl": name="place"; break; case "pb": name="publisher"; break; case "pub": name="publisher"; break; case "pg": name="pages"; break; case "pgs": name="pages"; break; case "sn": name="short_name"; break; default: name=abr; break; } return name; } #+END_SRC ***** biblio block #+name: abs_functions_block_biblio #+BEGIN_SRC d void _biblio_block_( char[] line, ref int[string] type, ref int bib_entry, ref string biblio_entry_str_json, ref string[] biblio_arr_json ) { if (matchFirst(line, rgx.heading_biblio)) { type["biblio_section"] = TriState.on; type["blurb_section"] = State.off; type["glossary_section"] = State.off; } if (line.empty) { debug { debug(biblioblock) { writeln("---"); } debug(biblioblockinclude) { writeln(biblio_entry_str_json.length); } } if ((bib_entry == State.off) && (biblio_entry_str_json.empty)) { bib_entry = State.on; biblio_entry_str_json = biblio_entry_tags_jsonstr; } else if (!(biblio_entry_str_json.empty)) { bib_entry = State.off; if (!(biblio_entry_str_json == 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 = biblio_entry_tags_jsonstr; } } else { // CHECK ERROR writeln("?? 2. ERROR ", biblio_entry_str_json, "??"); biblio_entry_str_json = ""; } } else if (matchFirst(line, rgx.biblio_tags)) { debug(biblioblock) { writeln(line); } auto bt = match(line, rgx.biblio_tags); bib_entry = State.off; st=to!string(bt.captures[1]); auto header_tag_value=to!string(bt.captures[2]); JSONValue j = parseJSON(biblio_entry_str_json); biblio_tag_name = (match(st, rgx.biblio_abbreviations)) ? (biblio_tag_map(st)) : st; j.object[biblio_tag_name] = header_tag_value; debug(bibliounsortedcheckduplicates) { writeln(biblio_tag_name, ": ", header_tag_value); writeln("--"); } switch (biblio_tag_name) { case "author_raw": // author_arr author (fn sn) j["author_arr"] = split(header_tag_value, rgx.arr_delimiter); string tmp; biblioAuthorLoop: foreach (au; j["author_arr"].array) { if (auto x = match(au.str, rgx.name_delimiter)) { tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; } else { tmp ~= au.str; } } tmp = replace(tmp, rgx.trailing_comma, ""); j["author"].str = tmp; goto default; case "editor_raw": // editor_arr editor (fn sn) j["editor_arr"] = split(header_tag_value, rgx.arr_delimiter); string tmp; biblioEditorLoop: foreach (ed; j["editor_arr"].array) { if (auto x = match(ed.str, rgx.name_delimiter)) { tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", "; } else { tmp ~= ed.str; } } tmp = replace(tmp, rgx.trailing_comma, ""); j["editor"].str = tmp; goto default; case "fulltitle": // title & subtitle goto default; default: break; } auto s = j.toString(); debug(biblio1) { writefln( "* %s: %s\n%s", biblio_tag_name, biblio_tag_entry, j[biblio_tag_name] ); } if ((match(line, rgx.comment))) { writeln("ERROR", line, "COMMENT"); writeln("ERROR", s, "%%"); } if (!(match(line, rgx.comment))) { debug(biblioblockinclude) { writeln(line); } biblio_entry_str_json = s; } else { biblio_entry_str_json = ""; } header_tag_value=""; } } #+END_SRC **** TODO poem block, verse objects :poem:verse: why extra object stuff only in poem/verse? #+name: abs_functions_block_poem #+BEGIN_SRC d void _poem_block_( char[] line, ref string[string] an_object, ref int[string] type, ref long counter, string[string] obj_cite_number_poem, string[string][string] dochead_make_aa, ) { if (type["curly_poem"] == TriState.on) { if (matchFirst(line, rgx.block_curly_poem_close)) { an_object[an_object_key]="verse"; // check that this is as you please debug(poem) { // poem (curly) close writefln( "* [poem curly] %s", line ); } if (processing.length > 0) { an_object[an_object_key] = processing["verse"]; } debug(poem) { // poem (curly) close writeln(__LINE__); writefln( "* %s %s", obj_cite_number, line ); } if (an_object.length > 0) { debug(poem) { // poem (curly) close writeln( obj_cite_number, an_object[an_object_key] ); } an_object["is"] = "verse"; auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; } obj_cite_number_poem["end"] = to!string(obj_cite_number); type["blocks"] = TriState.closing; type["poem"] = TriState.closing; type["curly_poem"] = TriState.off; } else { processing["verse"] ~= line ~= "\n"; if (type["verse_new"] == State.on) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); type["verse_new"] = State.off; } else if (matchFirst(line, rgx.newline_eol_delimiter_only)) { verse_line = TriState.off; type["verse_new"] = State.on; } if (type["verse_new"] == State.on) { verse_line=1; an_object[an_object_key] = processing["verse"]; debug(poem) { // poem verse writefln( "* %s curly\n%s", obj_cite_number, an_object[an_object_key] ); } processing.remove("verse"); an_object["is"] = "verse"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; } } } else if (type["tic_poem"] == TriState.on) { if (auto m = matchFirst(line, rgx.block_tic_close)) { // tic_poem_close an_object[an_object_key]="verse"; // check that this is as you please debug(poem) { // poem (curly) close writefln( "* [poem tic] %s", line ); } if (processing.length > 0) { // needs looking at an_object[an_object_key] = processing["verse"]; } if (an_object.length > 0) { debug(poem) { // poem (tic) close writeln(__LINE__); writeln(obj_cite_number, line); } processing.remove("verse"); an_object["is"] = "verse"; auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); obj_cite_number_poem["end"] = to!string(obj_cite_number); object_reset(an_object); processing.remove("verse"); ++counter; } type["blocks"] = TriState.closing; type["poem"] = TriState.closing; type["tic_poem"] = TriState.off; } else { processing["verse"] ~= line ~= "\n"; if (type["verse_new"] == State.on) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); type["verse_new"] = State.off; } else if (matchFirst(line, rgx.newline_eol_delimiter_only)) { type["verse_new"] = State.on; verse_line = TriState.off; } if (type["verse_new"] == State.on) { verse_line=1; an_object[an_object_key] = processing["verse"]; debug(poem) { // poem (tic) close writefln( "* %s tic\n%s", obj_cite_number, an_object[an_object_key] ); } processing.remove("verse"); an_object["is"] = "verse"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; } } } } #+END_SRC **** group block :group: #+name: abs_functions_block_group #+BEGIN_SRC d void _group_block_( char[] line, ref string[string] an_object, ref int[string] type ) { if (type["curly_group"] == State.on) { if (matchFirst(line, rgx.block_curly_group_close)) { debug(group) { // group (curly) close writeln(line); } type["blocks"] = TriState.closing; type["group"] = TriState.closing; type["curly_group"] = TriState.off; } else { debug(group) { // group writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build group array (or string) } } else if (type["tic_group"] == TriState.on) { if (matchFirst(line, rgx.block_tic_close)) { debug(group) { // group (tic) close writeln(line); } type["blocks"] = TriState.closing; type["group"] = TriState.closing; type["tic_group"] = TriState.off; } else { debug(group) { // group writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build group array (or string) } } } #+END_SRC **** block block :block: #+name: abs_functions_block_block #+BEGIN_SRC d void _block_block_( char[] line, ref string[string] an_object, ref int[string] type ) { if (type["curly_block"] == TriState.on) { if (matchFirst(line, rgx.block_curly_block_close)) { debug(block) { // block (curly) close writeln(line); } type["blocks"] = TriState.closing; type["block"] = TriState.closing; type["curly_block"] = TriState.off; } else { debug(block) { // block writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build block array (or string) } } else if (type["tic_block"] == TriState.on) { if (matchFirst(line, rgx.block_tic_close)) { debug(block) { // block (tic) close writeln(line); } type["blocks"] = TriState.closing; type["block"] = TriState.closing; type["tic_block"] = TriState.off; } else { debug(block) { // block writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build block array (or string) } } } #+END_SRC **** quote block :quote: #+name: abs_functions_block_quote #+BEGIN_SRC d void _quote_block_( char[] line, ref string[string] an_object, ref int[string] type ) { if (type["curly_quote"] == TriState.on) { if (matchFirst(line, rgx.block_curly_quote_close)) { debug(quote) { // quote (curly) close writeln(line); } type["blocks"] = TriState.closing; type["quote"] = TriState.closing; type["curly_quote"] = TriState.off; } else { debug(quote) { // quote writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build quote array (or string) } } else if (type["tic_quote"] == TriState.on) { if (matchFirst(line, rgx.block_tic_close)) { debug(quote) { // quote (tic) close writeln(line); } type["blocks"] = TriState.closing; type["quote"] = TriState.closing; type["tic_quote"] = TriState.off; } else { debug(quote) { // quote writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build quote array (or string) } } } #+END_SRC **** table block :table: #+name: abs_functions_block_table #+BEGIN_SRC d void _table_block_( char[] line, ref string[string] an_object, ref int[string] type ) { if (type["curly_table"] == TriState.on) { if (matchFirst(line, rgx.block_curly_table_close)) { debug(table) { // table (curly) close writeln(line); } type["blocks"] = TriState.closing; type["table"] = TriState.closing; type["curly_table"] = TriState.off; } else { debug(table) { // table writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build table array (or string) } } else if (type["tic_table"] == TriState.on) { if (matchFirst(line, rgx.block_tic_close)) { debug(table) { // table (tic) close writeln(line); } type["blocks"] = TriState.closing; type["table"] = TriState.closing; type["tic_table"] = TriState.off; } else { debug(table) { // table writeln(line); } an_object[an_object_key] ~= line ~= "\n"; // build table array (or string) } } } #+END_SRC *** block end (close an open block): line empty, block flag :close: #+name: abs_functions_block_line_status_empty #+BEGIN_SRC d void _block_flag_line_empty_( char[] line, ref string[string] an_object, ref ObjComposite[] the_document_body_section, ref string[][string][string] bookindex_unordered_hashes, ref int obj_cite_number, ref string _node, ref long counter, ref int[string] type, string[string] obj_cite_number_poem, string[string][string] dochead_make_aa, ) { // line.empty, post contents, empty variables --------------- assert( line.empty, "line should be empty" ); assert( (type["blocks"] == TriState.closing), "code block status: closed" ); assertions_flag_types_block_status_none_or_closed(type); if (type["code"] == TriState.closing) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "code"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block_code( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; type["blocks"] = TriState.off; type["code"] = TriState.off; } else if (type["poem"] == TriState.closing) { an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "verse"; // check also _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); the_document_body_section ~= set_abstract_object.contents_block_obj_cite_number_string( "poem", "", (obj_cite_number_poem["start"], obj_cite_number_poem["end"]), _node ); // bookindex object_reset(an_object); processing.remove("verse"); type["blocks"] = TriState.off; type["poem"] = TriState.off; } else if (type["table"] == TriState.closing) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "table"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; type["blocks"] = TriState.off; type["table"] = TriState.off; } else if (type["group"] == TriState.closing) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "group"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; type["blocks"] = TriState.off; type["group"] = TriState.off; } else if (type["block"] == TriState.closing) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "block"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; type["blocks"] = TriState.off; type["block"] = TriState.off; } else if (type["quote"] == TriState.closing) { obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]); an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : ""; bookindex_unordered_hashes = bkidx_hash(an_object["bookindex_nugget"], obj_cite_number); an_object["is"] = "quote"; _node = node_construct.node_emitter( content_non_header, segment_object_belongs_to, obj_cite_number, counter, heading_pointer-1, an_object["is"] ); auto substantive_object_and_anchor_tags_tuple = obj_im.obj_inline_markup_and_anchor_tags(an_object, an_object_key, dochead_make_aa); an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0]; anchor_tags = substantive_object_and_anchor_tags_tuple[1]; an_object["attrib"] = obj_att.obj_attributes(an_object["is"], an_object[an_object_key], _node); the_document_body_section ~= set_abstract_object.contents_block( an_object["is"], an_object["substantive"], an_object["attrib"], obj_cite_number ); object_reset(an_object); processing.remove("verse"); ++counter; type["blocks"] = TriState.off; type["quote"] = TriState.off; } } #+END_SRC ** book index :bookindex: #+name: abs_functions_book_index #+BEGIN_SRC d auto _book_index_( char[] line, ref string book_idx_tmp, ref string[string] an_object, ref int[string] type ) { if (auto m = match(line, rgx.book_index)) { /+ match book_index +/ debug(bookindexmatch) { // book index writefln( "* [bookindex] %s\n", to!string(m.captures[1]), ); } an_object["bookindex_nugget"] = to!string(m.captures[1]); } else if (auto m = match(line, rgx.book_index_open)) { /+ match open book_index +/ type["book_index"] = State.on; book_idx_tmp = to!string(m.captures[1]); debug(bookindexmatch) { // book index writefln( "* [bookindex] %s\n", book_idx_tmp, ); } } else if (type["book_index"] == State.on ) { /+ book_index flag set +/ if (auto m = match(line, rgx.book_index_close)) { type["book_index"] = State.off; an_object["bookindex_nugget"] = book_idx_tmp ~ to!string(m.captures[1]); debug(bookindexmatch) { // book index writefln( "* [bookindex] %s\n", book_idx_tmp, ); } book_idx_tmp = ""; } else { book_idx_tmp ~= line; } } } #+END_SRC ** heading or paragraph :heading:paragraph: *** heading found :heading: #+name: abs_functions_heading #+BEGIN_SRC d auto _heading_found_( char[] line, string dochead_make_identify_unmarked_headings, ref string[string] heading_match_str, ref Regex!(char)[string] heading_match_rgx, ref int[string] type ) { if ((dochead_make_identify_unmarked_headings.length > 2) && (type["make_headings"] == State.off)) { /+ headings found +/ debug(headingsfound) { writeln(dochead_make_identify_unmarked_headings); } char[][] make_headings_spl = split( cast(char[]) dochead_make_identify_unmarked_headings, rgx.make_heading_delimiter); debug(headingsfound) { writeln(make_headings_spl.length); writeln(make_headings_spl); } switch (make_headings_spl.length) { case 7 : if (!empty(make_headings_spl[6])) { heading_match_str["h_4"] = "^(" ~ to!string(make_headings_spl[6]) ~ ")"; heading_match_rgx["h_4"] = regex(heading_match_str["h_4"]); } goto case; case 6 : if (!empty(make_headings_spl[5])) { heading_match_str["h_3"] = "^(" ~ to!string(make_headings_spl[5]) ~ ")"; heading_match_rgx["h_3"] = regex(heading_match_str["h_3"]); } goto case; case 5 : if (!empty(make_headings_spl[4])) { heading_match_str["h_2"] = "^(" ~ to!string(make_headings_spl[4]) ~ ")"; heading_match_rgx["h_2"] = regex(heading_match_str["h_2"]); } goto case; case 4 : if (!empty(make_headings_spl[3])) { heading_match_str["h_1"] = "^(" ~ to!string(make_headings_spl[3]) ~ ")"; heading_match_rgx["h_1"] = regex(heading_match_str["h_1"]); } goto case; case 3 : if (!empty(make_headings_spl[2])) { heading_match_str["h_D"] = "^(" ~ to!string(make_headings_spl[2]) ~ ")"; heading_match_rgx["h_D"] = regex(heading_match_str["h_D"]); } goto case; case 2 : if (!empty(make_headings_spl[1])) { heading_match_str["h_C"] = "^(" ~ to!string(make_headings_spl[1]) ~ ")"; heading_match_rgx["h_C"] = regex(heading_match_str["h_C"]); } goto case; case 1 : if (!empty(make_headings_spl[0])) { heading_match_str["h_B"] = "^(" ~ to!string(make_headings_spl[0]) ~ ")"; heading_match_rgx["h_B"] = regex(heading_match_str["h_B"]); } break; default: break; } type["make_headings"] = State.on; } } #+END_SRC *** TODO heading make set :heading: #+name: abs_functions_heading #+BEGIN_SRC d auto _heading_make_set_( ref char[] line, ref int[string] line_occur, ref Regex!(char)[string] heading_match_rgx, ref int[string] type ) { if ((type["make_headings"] == State.on) && ((line_occur["para"] == State.off) && (line_occur["heading"] == State.off)) && ((type["para"] == State.off) && (type["heading"] == State.off))) { /+ heading make set +/ if (matchFirst(line, heading_match_rgx["h_B"])) { line = "B~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_C"])) { line = "C~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_D"])) { line = "D~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_1"])) { line = "1~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_2"])) { line = "2~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_3"])) { line = "3~ " ~ line; debug(headingsfound) { writeln(line); } } if (matchFirst(line, heading_match_rgx["h_4"])) { line = "4~ " ~ line; debug(headingsfound) { writeln(line); } } } } #+END_SRC *** heading match :heading: #+name: abs_functions_heading #+BEGIN_SRC d auto _heading_matched_( char[] line, ref int[string] line_occur, ref string[string] an_object, ref string an_object_key, ref int[string] lv, ref int[string] collapsed_lev, ref int[string] type, ref string[string][string] dochead_meta_aa ) { if (auto m = match(line, rgx.heading)) { /+ heading match +/ type["heading"] = State.on; if (match(line, rgx.heading_seg_and_above)) { type["biblio_section"] = State.off; type["glossary_section"] = State.off; type["blurb_section"] = State.off; } type["para"] = State.off; ++line_occur["heading"]; an_object[an_object_key] ~= line ~= "\n"; an_object["lev"] ~= m.captures[1]; assertions_doc_structure(an_object, lv); // includes most of the logic for collapsed levels switch (an_object["lev"]) { case "A": an_object[an_object_key]=replaceFirst(an_object[an_object_key], rgx.variable_doc_title, (dochead_meta_aa["title"]["full"] ~ ",")); an_object[an_object_key]=replaceFirst(an_object[an_object_key], rgx.variable_doc_author, dochead_meta_aa["creator"]["author"]); collapsed_lev["h0"] = 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h0"]); lv["lv"] = DocStructMarkupHeading.h_sect_A; ++lv["h0"]; lv["h1"] = State.off; lv["h2"] = State.off; lv["h3"] = State.off; lv["h4"] = State.off; lv["h5"] = State.off; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "B": collapsed_lev["h1"] = collapsed_lev["h0"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h1"]); lv["lv"] = DocStructMarkupHeading.h_sect_B; ++lv["h1"]; lv["h2"] = State.off; lv["h3"] = State.off; lv["h4"] = State.off; lv["h5"] = State.off; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "C": collapsed_lev["h2"] = collapsed_lev["h1"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h2"]); lv["lv"] = DocStructMarkupHeading.h_sect_C; ++lv["h2"]; lv["h3"] = State.off; lv["h4"] = State.off; lv["h5"] = State.off; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "D": collapsed_lev["h3"] = collapsed_lev["h2"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h3"]); lv["lv"] = DocStructMarkupHeading.h_sect_D; ++lv["h3"]; lv["h4"] = State.off; lv["h5"] = State.off; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "1": if (lv["h3"] > State.off) { collapsed_lev["h4"] = collapsed_lev["h3"] + 1; } else if (lv["h2"] > State.off) { collapsed_lev["h4"] = collapsed_lev["h2"] + 1; } else if (lv["h1"] > State.off) { collapsed_lev["h4"] = collapsed_lev["h1"] + 1; } else if (lv["h0"] > State.off) { collapsed_lev["h4"] = collapsed_lev["h0"] + 1; } an_object["lev_collapsed_number"] = to!string(collapsed_lev["h4"]); lv["lv"] = DocStructMarkupHeading.h_text_1; ++lv["h4"]; lv["h5"] = State.off; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "2": if (lv["h5"] > State.off) { an_object["lev_collapsed_number"] = to!string(collapsed_lev["h5"]); } else if (lv["h4"] > State.off) { collapsed_lev["h5"] = collapsed_lev["h4"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h5"]); } lv["lv"] = DocStructMarkupHeading.h_text_2; ++lv["h5"]; lv["h6"] = State.off; lv["h7"] = State.off; goto default; case "3": if (lv["h6"] > State.off) { an_object["lev_collapsed_number"] = to!string(collapsed_lev["h6"]); } else if (lv["h5"] > State.off) { collapsed_lev["h6"] = collapsed_lev["h5"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h6"]); } lv["lv"] = DocStructMarkupHeading.h_text_3; ++lv["h6"]; lv["h7"] = State.off; goto default; case "4": if (lv["h7"] > State.off) { an_object["lev_collapsed_number"] = to!string(collapsed_lev["h7"]); } else if (lv["h6"] > State.off) { collapsed_lev["h7"] = collapsed_lev["h6"] + 1; an_object["lev_collapsed_number"] = to!string(collapsed_lev["h7"]); } lv["lv"] = DocStructMarkupHeading.h_text_4; ++lv["h7"]; goto default; default: an_object["lev_markup_number"] = to!string(lv["lv"]); } debug(heading) { // heading writeln(strip(line)); } } } #+END_SRC *** para match :para: #+name: abs_functions_para #+BEGIN_SRC d auto _para_match_( char[] line, ref string[string] an_object, ref string an_object_key, ref int[string] indent, ref bool bullet, ref int[string] type, ref int[string] line_occur, ) { if (line_occur["para"] == State.off) { /+ para matches +/ type["para"] = State.on; an_object[an_object_key] ~= line; // body_nugget indent=[ "hang_position" : 0, "base_position" : 0, ]; bullet = false; if (auto m = matchFirst(line, rgx.para_indent)) { debug(paraindent) { // para indent writeln(line); } indent["hang_position"] = to!int(m.captures[1]); indent["base_position"] = 0; } else if (matchFirst(line, rgx.para_bullet)) { debug(parabullet) { // para bullet writeln(line); } bullet = true; } else if (auto m = matchFirst(line, rgx.para_indent_hang)) { debug(paraindenthang) { // para indent hang writeln(line); } indent=[ "hang_position" : to!int(m.captures[1]), "base_position" : to!int(m.captures[2]), ]; } else if (auto m = matchFirst(line, rgx.para_bullet_indent)) { debug(parabulletindent) { // para bullet indent writeln(line); } indent=[ "hang_position" : to!int(m.captures[1]), "base_position" : 0, ]; bullet = true; } ++line_occur["para"]; } } #+END_SRC ** function emitters :emitters: *** object :object: **** ocn :ocn: #+name: ao_emitters_ocn #+BEGIN_SRC d struct OCNemitter { int obj_cite_number, obj_cite_number_; int obj_cite_number_emitter(int obj_cite_number_status_flag) in { assert(obj_cite_number_status_flag <= 2); } body { obj_cite_number=(obj_cite_number_status_flag == 0) ? ++obj_cite_number_ : 0; assert(obj_cite_number >= 0); return obj_cite_number; } invariant() { } } #+END_SRC **** object inline markup munge :markup:inline: #+name: ao_emitters_obj_inline_markup_munge #+BEGIN_SRC d struct ObjInlineMarkupMunge { string[string] obj_txt; int n_foot, n_foot_reg, n_foot_sp_asterisk, n_foot_sp_plus; string asterisks_; string obj_txt_out, tail, note; auto rgx = Rgx(); auto mkup = InlineMarkup(); private auto initialize_note_numbers() { n_foot = 0; n_foot_reg = 0; n_foot_sp_asterisk = 0; n_foot_sp_plus = 0; } string url_links(string obj_txt_in) { /+ url matched +/ if (auto m = matchAll(obj_txt_in, rgx.inline_url)) { /+ link: naked url: http://url +/ if (match(obj_txt_in, rgx.inline_link_naked_url)) { obj_txt_in = replaceAll( obj_txt_in, rgx.inline_link_naked_url, ("$1" ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ "$3") // ("$1{ $2 }$2$3") ); } /+ link with helper for endnote including the url: {~^ link which includes url as footnote }http://url maps to: { link which includes url as footnote }http://url~{ { http://url }http://url }~ +/ if (match(obj_txt_in, rgx.inline_link_endnote_url_helper)) { obj_txt_in = replaceAll( obj_txt_in, rgx.inline_link_endnote_url_helper_punctuated, (mkup.lnk_o ~ " $1 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ "~{ " ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ " }~$3") // ("{ $1 }$2~{ { $2 }$2 }~$3") ); obj_txt_in = replaceAll( obj_txt_in, rgx.inline_link_endnote_url_helper, (mkup.lnk_o ~ " $1 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ "~{ " ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$2" ~ mkup.url_c ~ " }~") // ("{ $1 }$2~{ { $2 }$2 }~") ); } /+ link with regular markup: { linked text or image }http://url +/ if (match(obj_txt_in, rgx.inline_link_markup_regular)) { obj_txt_in = replaceAll( obj_txt_in, rgx.inline_link_markup_regular, ("$1" ~ mkup.lnk_o ~ " $2 " ~ mkup.lnk_c ~ mkup.url_o ~ "$3" ~ mkup.url_c ~ "$4") // ("$1{ $2 }$3$4") ); } } return obj_txt_in; } string footnotes_endnotes_markup_and_number_or_stars(string obj_txt_in) { /+ endnotes (regular) +/ obj_txt_in = replaceAll( obj_txt_in, rgx.inline_notes_curly, (mkup.en_a_o ~ " $1" ~ mkup.en_a_c) ); if (match(obj_txt_in, rgx.inline_notes_al_gen)) { if (auto m = matchAll(obj_txt_in, rgx.inline_text_and_note_al_)) { foreach(n; m) { if (match(to!string(n.hit), rgx.inline_al_delimiter_open_symbol_star)) { ++n_foot_sp_asterisk; asterisks_ = "*"; n_foot=n_foot_sp_asterisk; obj_txt_out ~= (replaceFirst( to!string(n.hit), rgx.inline_al_delimiter_open_symbol_star, (mkup.en_a_o ~ replicate(asterisks_, n_foot_sp_asterisk) ~ " ") ) ~ "\n"); } else if (match(to!string(n.hit), rgx.inline_al_delimiter_open_regular)) { ++n_foot_reg; n_foot=n_foot_reg; obj_txt_out ~= (replaceFirst( to!string(n.hit), rgx.inline_al_delimiter_open_regular, (mkup.en_a_o ~ to!string(n_foot) ~ " ") ) ~ "\n"); } else { obj_txt_out ~= to!string(n.hit) ~ "\n"; } } } } else { obj_txt_out = obj_txt_in; } return obj_txt_out; } private auto object_notes_(string obj_txt_in) in { } body { obj_txt_out = ""; tail = ""; /+ special endnotes +/ obj_txt_in = replaceAll( obj_txt_in, rgx.inline_notes_curly_sp_asterisk, (mkup.en_a_o ~ "*" ~ " $1" ~ mkup.en_a_c) ); obj_txt_in = replaceAll( obj_txt_in, rgx.inline_notes_curly_sp_plus, (mkup.en_a_o ~ "+" ~ " $1" ~ mkup.en_a_c) ); /+ url matched +/ if (auto m = matchAll(obj_txt_in, rgx.inline_url)) { obj_txt_in = url_links(obj_txt_in); } obj_txt_out = footnotes_endnotes_markup_and_number_or_stars(obj_txt_in); debug(footnotes) { writeln(obj_txt_out, tail); } obj_txt_out = obj_txt_out ~ tail; debug(footnotesdone) { foreach(m; matchAll(obj_txt_out, (mkup.en_a_o ~ `\s*(.+?)` ~ mkup.en_a_c))) { writeln(m.captures[1]); writeln(m.hit); } } return obj_txt_out; } string para(string obj_txt_in) in { } body { auto rgx = Rgx(); obj_txt["munge"]=obj_txt_in; obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.para_attribs, ""); obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, ""); obj_txt["munge"]=object_notes_(obj_txt["munge"]); debug(munge) { writeln(__LINE__); writeln(obj_txt_in); writeln(__LINE__); writeln(to!string(obj_txt["munge"])); } return obj_txt["munge"]; } string heading(string obj_txt_in) in { } body { auto rgx = Rgx(); obj_txt["munge"]=obj_txt_in; obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.heading, ""); obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, ""); obj_txt["munge"]=strip(obj_txt["munge"]); obj_txt["munge"]=object_notes_(obj_txt["munge"]); debug(munge) { writeln(__LINE__); writeln(obj_txt_in); writeln(__LINE__); writeln(to!string(obj_txt["munge"])); } return obj_txt["munge"]; } invariant() { } /+ revisit +/ string code(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; return obj_txt["munge"]; } invariant() { } string group(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; obj_txt["munge"]=object_notes_(obj_txt["munge"]); return obj_txt["munge"]; } invariant() { } string block(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; obj_txt["munge"]=object_notes_(obj_txt["munge"]); return obj_txt["munge"]; } invariant() { } string verse(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; obj_txt["munge"]=object_notes_(obj_txt["munge"]); return obj_txt["munge"]; } invariant() { } string quote(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; return obj_txt["munge"]; } invariant() { } string table(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; return obj_txt["munge"]; } invariant() { } string comment(string obj_txt_in) in { } body { obj_txt["munge"]=obj_txt_in; return obj_txt["munge"]; } invariant() { } } #+END_SRC **** object inline markup :markup:inline: ***** open #+name: ao_emitters_obj_inline_markup #+BEGIN_SRC d struct ObjInlineMarkup { auto munge = ObjInlineMarkupMunge(); string[string] obj_txt; #+END_SRC ***** object inline markup and anchor tags :markup:inline: #+name: ao_emitters_obj_inline_markup_and_anchor_tags #+BEGIN_SRC d auto obj_inline_markup_and_anchor_tags( string[string] obj_, string obj_key_, string[string][string] dochead_make_aa ) in { } body { obj_txt["munge"]=obj_[obj_key_].dup; obj_txt["munge"]=(match(obj_["is"], ctRegex!(`verse|code`))) ? obj_txt["munge"] : strip(obj_txt["munge"]); static __gshared string[] anchor_tags_ = []; switch (obj_["is"]) { case "heading": static __gshared string anchor_tag = ""; // TODO WORK ON, you still need to ensure that level 1 anchor_tags are unique obj_txt["munge"]=_configured_auto_heading_numbering_and_segment_anchor_tags(obj_txt["munge"], obj_, dochead_make_aa); obj_txt["munge"]=_make_segment_anchor_tags_if_none_provided(obj_txt["munge"], obj_["lev"]); if (auto m = match(obj_txt["munge"], rgx.heading_anchor_tag)) { anchor_tag = m.captures[1]; anchor_tags_ ~=anchor_tag; } else if (obj_["lev"] == "1") { writeln("heading anchor tag missing: ", obj_txt["munge"]); } obj_txt["munge"]=munge.heading(obj_txt["munge"]); break; case "para": obj_txt["munge"]=munge.para(obj_txt["munge"]); break; case "code": obj_txt["munge"]=munge.code(obj_txt["munge"]); break; case "group": obj_txt["munge"]=munge.group(obj_txt["munge"]); break; case "block": obj_txt["munge"]=munge.block(obj_txt["munge"]); break; case "verse": obj_txt["munge"]=munge.verse(obj_txt["munge"]); break; case "quote": obj_txt["munge"]=munge.quote(obj_txt["munge"]); break; case "table": obj_txt["munge"]=munge.table(obj_txt["munge"]); break; case "comment": obj_txt["munge"]=munge.comment(obj_txt["munge"]); break; case "doc_end_reset": munge.initialize_note_numbers(); break; default: break; } auto t = tuple( obj_txt["munge"], anchor_tags_, ); anchor_tags_=[]; return t; } invariant() { } #+END_SRC ***** table of contents objects :markup:inline: #+name: ao_emitters_obj_inline_markup_table_of_contents #+BEGIN_SRC d auto _clean_heading_toc_( char[] heading_toc_, ) { auto m = matchFirst(cast(char[]) heading_toc_, rgx.heading); heading_toc_ = replaceAll( m.post, rgx.inline_notes_curly_gen, ("") ); return heading_toc_; }; auto table_of_contents_gather_headings( string[string] obj_, string[string][string] dochead_make_aa, string segment_object_belongs_to, string _anchor_tag, ObjComposite[][string] the_table_of_contents_section, ) in { } body { char[] heading_toc_ = to!(char[])(obj_["body_nugget"].dup.strip); heading_toc_ = _clean_heading_toc_(heading_toc_); auto attrib=""; string toc_txt_; int[string] indent; auto set_abstract_object = ObjectAbstractSet(); if (to!int(obj_["lev_markup_number"]) > 0) { toc_txt_ = format( "{ %s }#%s", heading_toc_, _anchor_tag, ); toc_txt_= munge.url_links(toc_txt_); indent=[ "hang_position" : to!int(obj_["lev_markup_number"]), "base_position" : to!int(obj_["lev_markup_number"]), ]; toc_txt_ = format( "{ %s }#%s", heading_toc_, _anchor_tag, ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); } else { indent=[ "hang_position" : 0, "base_position" : 0, ]; the_table_of_contents_section["scroll"] ~= set_abstract_object.contents_toc( "toc", "Table of Contents", "", // attrib 0, indent, false ); } switch (to!int(obj_["lev_markup_number"])) { case 0: indent=[ "hang_position" : 0, "base_position" : 0, ]; toc_txt_ = "{ Table of Contents }../toc.fn_suffix"; toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); break; case 1: .. case 3: indent=[ "hang_position" : to!int(obj_["lev_markup_number"]), "base_position" : to!int(obj_["lev_markup_number"]), ]; toc_txt_ = format( "%s", heading_toc_, ); toc_txt_= munge.url_links(toc_txt_); the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); break; case 4: toc_txt_ = format( "{ %s }../%s.fn_suffix", heading_toc_, segment_object_belongs_to, ); toc_txt_= munge.url_links(toc_txt_); indent=[ "hang_position" : to!int(obj_["lev_markup_number"]), "base_position" : to!int(obj_["lev_markup_number"]), ]; the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); break; case 5: .. case 7: toc_txt_ = format( "{ %s }../%s.fn_suffix#%s", heading_toc_, segment_object_belongs_to, _anchor_tag, ); toc_txt_= munge.url_links(toc_txt_); indent=[ "hang_position" : to!int(obj_["lev_markup_number"]), "base_position" : to!int(obj_["lev_markup_number"]), ]; the_table_of_contents_section["seg"] ~= set_abstract_object.contents_toc( "toc", toc_txt_, "", // attrib 0, indent, false ); break; default: break; } return the_table_of_contents_section; } invariant() { } #+END_SRC ***** private: #+name: ao_emitters_obj_inline_markup_private #+BEGIN_SRC d private: #+END_SRC ****** make heading number and segment anchor tags if instructed :markup:inline:segment:anchor:tags: #+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags #+BEGIN_SRC d static string _configured_auto_heading_numbering_and_segment_anchor_tags(string munge_, string[string] obj_, string[string][string] dochead_make_aa) { if (dochead_make_aa["make"]["num_top"].length > 0) { if (!(match(munge_, rgx.heading_anchor_tag))) { static __gshared uint heading_num_top_level=9; static __gshared uint heading_num_depth=2; static __gshared uint heading_num_0 = 0; static __gshared uint heading_num_1 = 0; static __gshared uint heading_num_2 = 0; static __gshared uint heading_num_3 = 0; static __gshared string heading_number_auto_composite = ""; if (heading_num_top_level==9) { if (dochead_make_aa["make"]["num_depth"].length > 0) { heading_num_depth = to!uint(dochead_make_aa["make"]["num_depth"]); } switch (dochead_make_aa["make"]["num_top"]) { case "A": break; case "B": heading_num_top_level=1; break; case "C": heading_num_top_level=2; break; case "D": heading_num_top_level=3; break; case "1": heading_num_top_level=4; break; case "2": heading_num_top_level=5; break; case "3": heading_num_top_level=6; break; case "4": heading_num_top_level=7; break; default: break; } } /+ num_depth minimum 0 (1.) default 2 (1.1.1) max 3 (1.1.1.1) implement +/ if (heading_num_top_level > to!uint(obj_["lev_markup_number"])) { heading_num_0 = 0; heading_num_1 = 0; heading_num_2 = 0; heading_num_3 = 0; } else if (heading_num_top_level == to!uint(obj_["lev_markup_number"])) { heading_num_0 ++; heading_num_1 = 0; heading_num_2 = 0; heading_num_3 = 0; } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 1)) { heading_num_1 ++; heading_num_2 = 0; heading_num_3 = 0; } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 2)) { heading_num_2 ++; heading_num_3 = 0; } else if (heading_num_top_level == (to!uint(obj_["lev_markup_number"]) - 3)) { heading_num_3 ++; } if (heading_num_3 > 0) { heading_number_auto_composite = (heading_num_depth == 3) ? ( to!string(heading_num_0) ~ "." ~ to!string(heading_num_1) ~ "." ~ to!string(heading_num_2) ~ "." ~ to!string(heading_num_3) ) : ""; } else if (heading_num_2 > 0) { heading_number_auto_composite = ((heading_num_depth >= 2) && (heading_num_depth <= 3)) ? ( to!string(heading_num_0) ~ "." ~ to!string(heading_num_1) ~ "." ~ to!string(heading_num_2) ) : ""; } else if (heading_num_1 > 0) { heading_number_auto_composite = ((heading_num_depth >= 1) && (heading_num_depth <= 3)) ? ( to!string(heading_num_0) ~ "." ~ to!string(heading_num_1) ) : ""; } else if (heading_num_0 > 0) { heading_number_auto_composite = ((heading_num_depth >= 0) && (heading_num_depth <= 3)) ? (to!string(heading_num_0)) : ""; } else { heading_number_auto_composite = ""; } debug(heading_number_auto) { writeln(heading_number_auto_composite); } if (!empty(heading_number_auto_composite)) { munge_=replaceFirst(munge_, rgx.heading, "$1~$2 " ~ heading_number_auto_composite ~ ". "); munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, "$1~" ~ heading_number_auto_composite ~ " "); } } } return munge_; } #+END_SRC ******* unittests #+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags #+BEGIN_SRC d #+END_SRC ****** make segment anchor tags if not provided :markup:inline:segment:anchor:tags: #+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags #+BEGIN_SRC d static string _make_segment_anchor_tags_if_none_provided(string munge_, string lev_) { if (!(match(munge_, rgx.heading_anchor_tag))) { // if (anchor_tags_.length == 0) { if (match(munge_, rgx.heading_identify_anchor_tag)) { if (auto m = match(munge_, rgx.heading_extract_named_anchor_tag)) { munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, "$1~" ~ toLower(m.captures[1]) ~ "_" ~ m.captures[2] ~ " "); } else if (auto m = match(munge_, rgx.heading_extract_unnamed_anchor_tag)) { munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, "$1~" ~ "s" ~ m.captures[1] ~ " "); } } else if (lev_ == "1") { // (if not successful) manufacture a unique anchor tag for lev=="1" static __gshared uint heading_num_lev1 = 0; heading_num_lev1 ++; munge_=replaceFirst(munge_, rgx.heading_marker_missing_tag, "$1~" ~ "x" ~ to!string(heading_num_lev1) ~ " "); } } return munge_; } #+END_SRC ******* unittests #+name: ao_emitters_obj_inline_markup_heading_numbering_segment_anchor_tags #+BEGIN_SRC d unittest { string txt_lev="1"; string txt_in, txt_out; txt_in = "1~copyright Copyright"; txt_out ="1~copyright Copyright"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in = "1~ 6. Writing Copyright Licenses"; txt_out ="1~s6 6. Writing Copyright Licenses"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ 1. Reinforcing trends"; txt_out= "1~s1 1. Reinforcing trends"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ 11 SCIENCE AS A COMMONS"; txt_out= "1~s11 11 SCIENCE AS A COMMONS"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ Chapter 1"; txt_out="1~chapter_1 Chapter 1"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ Chapter 1."; txt_out="1~chapter_1 Chapter 1."; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ Chapter 1: Done"; txt_out="1~chapter_1 Chapter 1: Done"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ Chapter 11 - The Battle Over the Institutional Ecology of the Digital Environment"; txt_out= "1~chapter_11 Chapter 11 - The Battle Over the Institutional Ecology of the Digital Environment"; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ CHAPTER I."; txt_out="1~x1 CHAPTER I."; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); txt_in= "1~ CHAPTER II."; txt_out="1~x2 CHAPTER II."; assert(_make_segment_anchor_tags_if_none_provided(txt_in, txt_lev) == txt_out); } #+END_SRC ***** close #+name: ao_emitters_obj_inline_markup_close #+BEGIN_SRC d } #+END_SRC **** object attrib :attributes: ***** attributes structure open, public #+name: ao_emitters_obj_attributes #+BEGIN_SRC d struct ObjAttributes { string[string] _obj_attrib; #+END_SRC ***** attributes structure open, public #+name: ao_emitters_obj_attributes_public #+BEGIN_SRC d string obj_attributes(string obj_is_, string obj_raw, string _node) in { } body { scope(exit) { destroy(obj_is_); destroy(obj_raw); destroy(_node); } _obj_attrib.remove("json"); _obj_attrib["json"] ="{"; switch (obj_is_) { case "heading": _obj_attrib["json"] ~= _heading(obj_raw); break; case "para": _obj_attrib["json"] ~= _para_and_blocks(obj_raw) ~ _para(obj_raw); break; case "code": _obj_attrib["json"] ~= _code(obj_raw); break; case "group": _obj_attrib["json"] ~= _para_and_blocks(obj_raw) ~ _group(obj_raw); break; case "block": _obj_attrib["json"] ~= _para_and_blocks(obj_raw) ~ _block(obj_raw); break; case "verse": _obj_attrib["json"] ~= _verse(obj_raw); break; case "quote": _obj_attrib["json"] ~= _quote(obj_raw); break; case "table": _obj_attrib["json"] ~= _table(obj_raw); break; case "comment": _obj_attrib["json"] ~= _comment(obj_raw); break; default: _obj_attrib["json"] ~= _para(obj_raw); break; } _obj_attrib["json"] ~=" }"; _obj_attrib["json"]=_set_additional_values_parse_as_json(_obj_attrib["json"], obj_is_, _node); debug(structattrib) { if (oa_j["is"].str() == "heading") { writeln(_obj_attrib["json"]); writeln( "is: ", oa_j["is"].str(), "; obj_cite_number: ", oa_j["obj_cite_number"].integer() ); } } return _obj_attrib["json"]; } invariant() { } #+END_SRC ***** private #+name: ao_emitters_obj_attributes_private #+BEGIN_SRC d private: string _obj_attributes; #+END_SRC ****** attrubutes ******* para and block #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _para_and_blocks(string obj_txt_in) in { } body { auto rgx = Rgx(); if (matchFirst(obj_txt_in, rgx.para_bullet)) { _obj_attributes =" \"bullet\": \"true\"," ~ " \"indent_start\": 0," ~ " \"indent_rest\": 0,"; } else if (auto m = matchFirst(obj_txt_in, rgx.para_bullet_indent)) { _obj_attributes =" \"bullet\": \"true\"," ~ " \"indent_start\": " ~ to!string(m.captures[1]) ~ "," ~ " \"indent_rest\": " ~ to!string(m.captures[1]) ~ ","; } else if (auto m = matchFirst(obj_txt_in, rgx.para_indent_hang)) { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_start\": " ~ to!string(m.captures[1]) ~ "," ~ " \"indent_rest\": " ~ to!string(m.captures[2]) ~ ","; } else if (auto m = matchFirst(obj_txt_in, rgx.para_indent)) { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_start\": " ~ to!string(m.captures[1]) ~ "," ~ " \"indent_rest\": " ~ to!string(m.captures[1]) ~ ","; } else { _obj_attributes =" \"bullet\": \"false\"," ~ " \"indent_start\": 0," ~ " \"indent_rest\": 0,"; } return _obj_attributes; } #+END_SRC ******* para #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _para(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"para\"," ~ " \"is\": \"para\""; return _obj_attributes; } invariant() { } #+END_SRC ******* heading #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _heading(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"para\"," ~ " \"is\": \"heading\""; return _obj_attributes; } invariant() { } #+END_SRC ******* code #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _code(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"code\""; return _obj_attributes; } invariant() { } #+END_SRC ******* group #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _group(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"group\""; return _obj_attributes; } invariant() { } #+END_SRC ******* block #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _block(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"block\""; return _obj_attributes; } invariant() { } #+END_SRC ******* verse #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _verse(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"verse\""; return _obj_attributes; } invariant() { } #+END_SRC ******* quote #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _quote(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"quote\""; return _obj_attributes; } invariant() { } #+END_SRC ******* table #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _table(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"content\"," ~ " \"of\": \"block\"," ~ " \"is\": \"table\""; return _obj_attributes; } invariant() { } #+END_SRC ******* comment #+name: ao_emitters_obj_attributes_private_an_attribute #+BEGIN_SRC d string _comment(string obj_txt_in) in { } body { _obj_attributes = " \"use\": \"comment\"," ~ " \"of\": \"comment\"," ~ " \"is\": \"comment\""; return _obj_attributes; } invariant() { } #+END_SRC ****** set additional attribute values, parse as json #+name: ao_emitters_obj_attributes_private_json #+BEGIN_SRC d string _set_additional_values_parse_as_json(string _obj_attrib, string obj_is_, string _node) { JSONValue oa_j = parseJSON(_obj_attrib); JSONValue node_j = parseJSON(_node); assert( (oa_j.type == JSON_TYPE.OBJECT) && (node_j.type == JSON_TYPE.OBJECT) ); if (obj_is_ == "heading") { oa_j.object["obj_cite_number"] = node_j["obj_cite_number"]; oa_j.object["lev_markup_number"] = node_j["lev_markup_number"]; oa_j.object["lev_collapsed_number"] = node_j["lev_collapsed_number"]; oa_j.object["heading_pointer"] = node_j["heading_pointer"]; // check oa_j.object["doc_object_pointer"] = node_j["doc_object_pointer"]; // check } oa_j.object["parent_obj_cite_number"] = node_j["parent_obj_cite_number"]; oa_j.object["parent_lev_markup_number"] = node_j["parent_lev_markup_number"]; _obj_attrib = oa_j.toString(); return _obj_attrib; } #+END_SRC ***** close #+name: ao_emitters_obj_attributes_private_close #+BEGIN_SRC d } #+END_SRC *** book index :book:index: **** book index nugget hash :hash:nugget: #+name: ao_emitters_book_index_nugget #+BEGIN_SRC d struct BookIndexNuggetHash { string main_term, sub_term, sub_term_bits; int obj_cite_number_offset, obj_cite_number_endpoint; string[] obj_cite_numbers; string[][string][string] bi; string[][string][string] hash_nugget; string[] bi_main_terms_split_arr; string[][string][string] bookindex_nugget_hash(string bookindex_section, int obj_cite_number) in { debug(bookindexraw) { if (!bookindex_section.empty) { writeln( "* [bookindex] ", "[", to!string(obj_cite_number), "] ", bookindex_section ); } } } body { auto rgx = Rgx(); if (!bookindex_section.empty) { auto bi_main_terms_split_arr = split(bookindex_section, rgx.bi_main_terms_split); foreach (bi_main_terms_content; bi_main_terms_split_arr) { auto bi_main_term_and_rest = split(bi_main_terms_content, rgx.bi_main_term_plus_rest_split); if (auto m = match( bi_main_term_and_rest[0], rgx.bi_term_and_obj_cite_numbers_match) ) { main_term = strip(m.captures[1]); obj_cite_number_offset = to!int(m.captures[2]); obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset); obj_cite_numbers ~= (to!string(obj_cite_number) ~ "-" ~ to!string(obj_cite_number_endpoint)); } else { main_term = strip(bi_main_term_and_rest[0]); obj_cite_numbers ~= to!string(obj_cite_number); } bi[main_term]["_a"] ~= obj_cite_numbers; obj_cite_numbers=null; if (bi_main_term_and_rest.length > 1) { auto bi_sub_terms_split_arr = split( bi_main_term_and_rest[1], rgx.bi_sub_terms_plus_obj_cite_number_offset_split ); foreach (sub_terms_bits; bi_sub_terms_split_arr) { if (auto m = match(sub_terms_bits, rgx.bi_term_and_obj_cite_numbers_match)) { sub_term = strip(m.captures[1]); obj_cite_number_offset = to!int(m.captures[2]); obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset); obj_cite_numbers ~= (to!string(obj_cite_number) ~ " - " ~ to!string(obj_cite_number_endpoint)); } else { sub_term = strip(sub_terms_bits); obj_cite_numbers ~= to!string(obj_cite_number); } if (!empty(sub_term)) { bi[main_term][sub_term] ~= obj_cite_numbers; } obj_cite_numbers=null; } } } } hash_nugget = bi; return hash_nugget; } invariant() { } } #+END_SRC **** book index (sort &) report indented :report:indented: #+name: ao_emitters_book_index_report_indented #+BEGIN_SRC d struct BookIndexReportIndent { int mkn, skn; auto bookindex_report_indented( string[][string][string] bookindex_unordered_hashes ) { auto mainkeys= bookindex_unordered_hashes.byKey.array.sort().release; foreach (mainkey; mainkeys) { debug(bookindex) { writeln(mainkey); } auto subkeys= bookindex_unordered_hashes[mainkey].byKey.array.sort().release; foreach (subkey; subkeys) { debug(bookindex) { writeln(" ", subkey); writeln(" ", to!string( bookindex_unordered_hashes[mainkey][subkey] )); } ++skn; } ++mkn; } } } #+END_SRC **** book index (sort &) report section :report:section: ***** book index struct open #+name: ao_emitters_book_index_report_section #+BEGIN_SRC d struct BookIndexReportSection { int mkn, skn; auto rgx = Rgx(); auto munge = ObjInlineMarkupMunge(); #+END_SRC ***** bookindex write section #+name: ao_emitters_book_index_report_section #+BEGIN_SRC d auto bookindex_write_section( string[][string][string] bookindex_unordered_hashes ) { auto mainkeys=bookindex_unordered_hashes.byKey.array.sort().release; foreach (mainkey; mainkeys) { write("_0_1 !{", mainkey, "}! "); foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { auto go = replaceAll(ref_, rgx.book_index_go, "$1"); write(" {", ref_, "}#", go, ", "); } writeln(" \\\\"); bookindex_unordered_hashes[mainkey].remove("_a"); auto subkeys= bookindex_unordered_hashes[mainkey].byKey.array.sort().release; foreach (subkey; subkeys) { write(" ", subkey, ", "); foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { auto go = replaceAll(ref_, rgx.book_index_go, "$1"); write(" {", ref_, "}#", go, ", "); } writeln(" \\\\"); ++skn; } ++mkn; } } #+END_SRC ***** book index (sort &) build section :report:section: #+name: ao_emitters_book_index_report_section #+BEGIN_SRC d auto bookindex_build_section( string[][string][string] bookindex_unordered_hashes, int obj_cite_number, string segment_object_belongs_to, ) { string type; string lev; int lev_markup_number, lev_collapsed_number; string attrib; int[string] indent; auto set_abstract_object = ObjectAbstractSet(); auto mainkeys = bookindex_unordered_hashes.byKey.array.sort().release; ObjComposite[][string] bookindex_section; if (mainkeys.length > 0) { string bi_tmp_seg, bi_tmp_scroll; attrib=""; lev="B"; lev_markup_number=1; lev_collapsed_number=1; bookindex_section["scroll"] ~= set_abstract_object.contents_heading( "Book Index", attrib, obj_cite_number, [], to!string(lev), lev_markup_number, lev_collapsed_number ); bookindex_section["seg"] ~= set_abstract_object.contents_heading( "Book Index", attrib, obj_cite_number, [], to!string(lev), lev_markup_number, lev_collapsed_number ); ++obj_cite_number; ++mkn; // 1~ Index attrib=""; lev="1"; lev_markup_number=4; lev_collapsed_number=2; bookindex_section["scroll"] ~= set_abstract_object.contents_heading( "Index", attrib, obj_cite_number, ["book_index"], to!string(lev), lev_markup_number, lev_collapsed_number ); bookindex_section["seg"] ~= set_abstract_object.contents_heading( "Index", attrib, obj_cite_number, ["book_index"], to!string(lev), lev_markup_number, lev_collapsed_number ); ++obj_cite_number; ++mkn; foreach (mainkey; mainkeys) { bi_tmp_scroll = "!{" ~ mainkey ~ "}! "; bi_tmp_seg = "!{" ~ mainkey ~ "}! "; foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) { auto go = replaceAll(ref_, rgx.book_index_go, "$1"); bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", "); bi_tmp_seg ~= (segment_object_belongs_to.empty) ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ") : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_object_belongs_to ~ ".fn_suffix#" ~ go ~ ", "); } bi_tmp_scroll ~= " \\\\\n "; bi_tmp_seg ~= " \\\\\n "; bookindex_unordered_hashes[mainkey].remove("_a"); auto subkeys = bookindex_unordered_hashes[mainkey].byKey.array.sort().release; foreach (subkey; subkeys) { bi_tmp_scroll ~= subkey ~ ", "; bi_tmp_seg ~= subkey ~ ", "; foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) { auto go = replaceAll(ref_, rgx.book_index_go, "$1"); bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", "); bi_tmp_seg ~= (segment_object_belongs_to.empty) ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ") : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_object_belongs_to ~ ".fn_suffix#" ~ go ~ ", "); } bi_tmp_scroll ~= " \\\\\n "; bi_tmp_seg ~= " \\\\\n "; ++skn; } bi_tmp_scroll = replaceFirst(bi_tmp_scroll, rgx.trailing_linebreak, ""); bi_tmp_seg = replaceFirst(bi_tmp_seg, rgx.trailing_linebreak, ""); type="para"; attrib=""; indent=[ "hang_position" : 0, "base_position" : 1, ]; bookindex_section["scroll"] ~= set_abstract_object.contents_para( type, bi_tmp_scroll, attrib, obj_cite_number, indent, false ); bookindex_section["seg"] ~= set_abstract_object.contents_para( type, bi_tmp_seg, attrib, obj_cite_number, indent, false ); ++obj_cite_number; ++mkn; } } else { // no book index, (figure out what to do here) bookindex_section["scroll"] ~= set_abstract_object.contents_heading( "(skip) there is no Book Index", "", // attrib, 0, [""], "B", 1, 1 ); bookindex_section["seg"] ~= set_abstract_object.contents_heading( "(skip) there is no Book Index", "", // attrib, 0, [""], "B", 1, 1 ); } auto t = tuple(bookindex_section, obj_cite_number); return t; } #+END_SRC ***** book index struct close #+name: ao_emitters_book_index_report_section #+BEGIN_SRC d } #+END_SRC *** (end)notes section :endnotes:section: #+name: ao_emitters_endnotes #+BEGIN_SRC d struct NotesSection { string[string] object_notes; long previous_count; int mkn; auto rgx = Rgx(); #+END_SRC **** gather notes for endnote section struct open #+name: ao_emitters_endnotes #+BEGIN_SRC d private auto gather_notes_for_endnote_section( ObjComposite[] contents_am, string segment_object_belongs_to, ulong counter ) in { // endnotes/ footnotes for // doc objects other than paragraphs & headings // various forms of grouped text assert((contents_am[counter].is_a == "para") || (contents_am[counter].is_a == "heading") || (contents_am[counter].is_a == "group")); assert(counter >= previous_count); previous_count=counter; assert( match(contents_am[counter].object, rgx.inline_notes_delimiter_al_regular_number_note) ); } body { auto munge = ObjInlineMarkupMunge(); foreach( m; matchAll( contents_am[counter].object, rgx.inline_notes_delimiter_al_regular_number_note ) ) { debug(endnotes_build) { writeln( "{^{", m.captures[1], ".}^}../", segment_object_belongs_to, ".fn_suffix#noteref_\n ", m.captures[1], " ", m.captures[2]); // sometimes need segment name (segmented html & epub) } // TODO NEXT you need anchor for segments at this point -> object_notes["anchor"] ~= "#note_" ~ m.captures[1] ~ "』"; object_notes["seg"] ~= (segment_object_belongs_to.empty) ? (munge.url_links( "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~ m.captures[1]) ~ " " ~ m.captures[2] ~ "』" ) : (munge.url_links( "{^{" ~ m.captures[1] ~ ".}^}../" ~ segment_object_belongs_to ~ ".fn_suffix#noteref_" ~ m.captures[1]) ~ " " ~ m.captures[2] ~ "』" ); object_notes["scroll"] ~= munge.url_links( "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~ m.captures[1] ) ~ " " ~ m.captures[2] ~ "』"; } return object_notes; } #+END_SRC **** gathered notes #+name: ao_emitters_endnotes #+BEGIN_SRC d private auto gathered_notes() in { } body { string[][string] endnotes_; if (object_notes.length > 1) { endnotes_["seg"] = (split(object_notes["seg"], rgx.break_string))[0..$-1]; endnotes_["scroll"] = (split(object_notes["scroll"], rgx.break_string))[0..$-1]; endnotes_["anchor"] = (split(object_notes["anchor"], rgx.break_string))[0..$-1]; } else { endnotes_["seg"] = []; endnotes_["scroll"] = []; endnotes_["anchor"] = []; } return endnotes_; } #+END_SRC **** endnote objects #+name: ao_emitters_endnotes #+BEGIN_SRC d private auto endnote_objects(int obj_cite_number) in { } body { auto set_abstract_object = ObjectAbstractSet(); ObjComposite[][string] the_endnotes_section; auto endnotes_ = gathered_notes(); string type; string lev, lev_markup_number, lev_collapsed_number; string attrib; int[string] indent; if (endnotes_["seg"].length > 0) { attrib=""; lev="B"; lev_markup_number="1"; lev_collapsed_number="1"; the_endnotes_section["seg"] ~= set_abstract_object.contents_heading( "Endnotes", attrib, obj_cite_number, [], to!string(lev), to!int(lev_markup_number), to!int(lev_collapsed_number) ); the_endnotes_section["scroll"] ~= set_abstract_object.contents_heading( "Endnotes", attrib, obj_cite_number, [], to!string(lev), to!int(lev_markup_number), to!int(lev_collapsed_number) ); ++obj_cite_number; ++mkn; attrib=""; lev="1"; lev_markup_number="4"; lev_collapsed_number="2"; the_endnotes_section["seg"] ~= set_abstract_object.contents_heading( "Endnotes", attrib, obj_cite_number, ["endnotes"], to!string(lev), to!int(lev_markup_number), to!int(lev_collapsed_number) ); the_endnotes_section["scroll"] ~= set_abstract_object.contents_heading( "Endnotes", attrib, obj_cite_number, ["endnotes"], to!string(lev), to!int(lev_markup_number), to!int(lev_collapsed_number) ); ++obj_cite_number; ++mkn; } else { the_endnotes_section["seg"] ~= set_abstract_object.contents_heading( "(skip) there are no Endnotes", "", // attrib, 0, [""], "B", 1, 1 ); the_endnotes_section["scroll"] ~= set_abstract_object.contents_heading( "(skip) there are no Endnotes", "", // attrib, 0, [""], "B", 1, 1 ); } foreach (i, endnote; endnotes_["seg"]) { attrib=""; the_endnotes_section["seg"] ~= set_abstract_object.contents_endnote(endnote, endnotes_["anchor"][i]); } foreach (i, endnote; endnotes_["scroll"]) { attrib=""; the_endnotes_section["scroll"] ~= set_abstract_object.contents_endnote(endnote, endnotes_["anchor"][i]); } auto t = tuple(the_endnotes_section, obj_cite_number); return t; } #+END_SRC **** gather notes for endnote section struct close #+name: ao_emitters_endnotes #+BEGIN_SRC d } #+END_SRC *** bibliography :bibliography: **** biblio struct open #+name: ao_emitters_bibliography #+BEGIN_SRC d struct Bibliography { #+END_SRC **** biblio #+name: ao_emitters_bibliography #+BEGIN_SRC d public JSONValue[] _bibliography_( ref string[] biblio_unsorted_incomplete, ref JSONValue[] bib_arr_json ) in { } body { JSONValue[] biblio_unsorted = _biblio_unsorted_complete_(biblio_unsorted_incomplete, bib_arr_json); JSONValue[] biblio_sorted__ = biblio_sort(biblio_unsorted); biblio_debug(biblio_sorted__); debug(biblio0) { writeln("---"); writeln("unsorted incomplete: ", biblio_unsorted_incomplete.length); writeln("json: ", bib_arr_json.length); writeln("unsorted: ", biblio_unsorted.length); writeln("sorted: ", biblio_sorted__.length); int counter; int[7] x; while (counter < x.length) { writeln(counter, ": ", biblio_sorted__[counter]["fulltitle"]); counter++; } } return biblio_sorted__; } #+END_SRC **** biblio unsorted complete #+name: ao_emitters_bibliography #+BEGIN_SRC d final private JSONValue[] _biblio_unsorted_complete_( string[] biblio_unordered, ref 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; } JSONValue[] biblio_unsorted_array_of_json_objects = bib_arr_json.dup; return biblio_unsorted_array_of_json_objects; } #+END_SRC **** biblio sort #+name: ao_emitters_bibliography #+BEGIN_SRC d final private JSONValue[] biblio_sort(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_; } #+END_SRC **** biblio debug #+name: ao_emitters_bibliography #+BEGIN_SRC d void biblio_debug(JSONValue[] biblio_sorted) { debug(biblio0) { foreach (j; biblio_sorted) { if (!empty(j["fulltitle"].str)) { writeln(j["sortby_deemed_author_year_title"]); } } } } #+END_SRC **** biblio struct close #+name: ao_emitters_bibliography #+BEGIN_SRC d } #+END_SRC *** node structure metadata :structure:metadata:node: **** metadata node struct open #+name: ao_emitters_metadata #+BEGIN_SRC d struct NodeStructureMetadata { int lv, lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7; int obj_cite_number; int[string] p_; // p_ parent_ string _node; #+END_SRC **** TODO metadata node emitter #+name: ao_emitters_metadata #+BEGIN_SRC d string node_emitter( string lev_markup_number, string segment_anchor_tag, int obj_cite_number_, long counter_, int pointer_, string is_ ) in { auto rgx = Rgx(); assert(is_ != "heading"); assert(to!int(obj_cite_number_) >= 0); } body { assert(is_ != "heading"); // should not be necessary assert(to!int(obj_cite_number_) >= 0); // should not be necessary int obj_cite_number=to!int(obj_cite_number_); if (lv7 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_4; p_["obj_cite_number"] = lv7; } else if (lv6 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3; p_["obj_cite_number"] = lv6; } else if (lv5 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2; p_["obj_cite_number"] = lv5; } else { p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1; p_["obj_cite_number"] = lv4; } _node=("{ " ~ "\"is\": \"" ~ is_ ~ "\"" ~ ", \"heading_pointer\": " ~ to!string(pointer_) ~ ", \"doc_object_pointer\": " ~ to!string(counter_) ~ ", \"obj_cite_number\": " ~ to!string(obj_cite_number_) ~ ", \"segment_anchor_tag\": \"" ~ segment_anchor_tag ~ "\"" ~ ", \"parent_obj_cite_number\": " ~ to!string(p_["obj_cite_number"]) ~ ", \"parent_lev_markup_number\": " ~ to!string(p_["lev_markup_number"]) ~ " }" ); debug(node) { if (match(lev_markup_number, rgx.levels_numbered_headings)) { writeln("* ", to!string(_node)); } else { writeln("* ", to!string(_node)); } } JSONValue j = parseJSON(_node); assert(j["parent_lev_markup_number"].integer >= 4); assert(j["parent_lev_markup_number"].integer <= 7); assert(j["parent_obj_cite_number"].integer >= 0); return _node; } invariant() { } #+END_SRC **** TODO metadata emitter heading #+name: ao_emitters_metadata #+BEGIN_SRC d string node_emitter_heading( string lev_markup_number, string lev_collapsed_number, string segment_anchor_tag, int obj_cite_number_, long counter_, int pointer_, string is_ ) in { auto rgx = Rgx(); assert(is_ == "heading"); assert(to!int(obj_cite_number_) >= 0); assert( match(lev_markup_number, rgx.levels_numbered), ("not a valid heading level: " ~ lev_markup_number ~ " at " ~ to!string(obj_cite_number_)) ); if (match(lev_markup_number, rgx.levels_numbered)) { if (to!int(lev_markup_number) == 0) { assert(to!int(obj_cite_number_) == 1); } } } body { auto rgx = Rgx(); int obj_cite_number = to!int(obj_cite_number_); switch (lev_markup_number) { // switch (to!string(lv)) { case "0": lv = DocStructMarkupHeading.h_sect_A; lv0 = obj_cite_number; lv1=0; lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; p_["lev_markup_number"] = 0; p_["obj_cite_number"] = 0; break; case "1": lv = DocStructMarkupHeading.h_sect_B; lv1 = obj_cite_number; lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_A; p_["obj_cite_number"] = lv0; break; case "2": lv = DocStructMarkupHeading.h_sect_C; lv2 = obj_cite_number; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_B; p_["obj_cite_number"] = lv1; break; case "3": lv = DocStructMarkupHeading.h_sect_D; lv3=obj_cite_number; lv4=0; lv5=0; lv6=0; lv7=0; p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_C; p_["obj_cite_number"] = lv2; break; case "4": lv = DocStructMarkupHeading.h_text_1; lv4 = obj_cite_number; lv5=0; lv6=0; lv7=0; if (lv3 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_D; p_["obj_cite_number"] = lv3; } else if (lv2 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_C; p_["obj_cite_number"] = lv2; } else if (lv1 > State.off) { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_B; p_["obj_cite_number"] = lv1; } else { p_["lev_markup_number"] = DocStructMarkupHeading.h_sect_A; p_["obj_cite_number"] = lv0; } break; case "5": lv = DocStructMarkupHeading.h_text_2; lv5 = obj_cite_number; lv6=0; lv7=0; p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1; p_["obj_cite_number"] = lv4; break; case "6": lv = DocStructMarkupHeading.h_text_3; lv6 = obj_cite_number; lv7=0; p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2; p_["obj_cite_number"] = lv5; break; case "7": lv = DocStructMarkupHeading.h_text_4; lv7 = obj_cite_number; p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3; p_["obj_cite_number"] = lv6; break; default: break; } _node=("{ " ~ "\"is\": \"" ~ is_ ~ "\"" ~ ", \"heading_pointer\": " ~ to!string(pointer_) ~ ", \"doc_object_pointer\": " ~ to!string(counter_) ~ ", \"obj_cite_number\": " ~ to!string(obj_cite_number_) ~ ", \"lev_markup_number\": " ~ to!string(lev_markup_number) ~ ", \"lev_collapsed_number\": " ~ to!string(lev_collapsed_number) ~ ", \"segment_anchor_tag\": \"" ~ segment_anchor_tag ~ "\"" ~ ", \"parent_obj_cite_number\": " ~ to!string(p_["obj_cite_number"]) ~ ", \"parent_lev_markup_number\": " ~ to!string(p_["lev_markup_number"]) ~ " }" ); debug(heading) { if (match(lev_markup_number, rgx.levels_numbered_headings)) { writeln("* ", to!string(_node)); } } debug(node) { if (match(lev_markup_number, rgx.levels_numbered_headings)) { writeln("* ", to!string(_node)); } else { writeln("* ", to!string(_node)); } } JSONValue j = parseJSON(_node); assert(j["parent_lev_markup_number"].integer <= 7); assert(j["parent_obj_cite_number"].integer >= 0); if (match(lev_markup_number, rgx.levels_numbered_headings)) { assert(j["lev_markup_number"].integer <= 7); assert(j["obj_cite_number"].integer >= 0); if (j["parent_lev_markup_number"].integer > 0) { assert(j["parent_lev_markup_number"].integer < j["lev_markup_number"].integer); if (j["obj_cite_number"].integer != 0) { assert(j["parent_obj_cite_number"].integer < j["obj_cite_number"].integer); } } if (j["lev_markup_number"].integer == 0) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_A); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_B) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_A); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_C) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_B); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_D) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_C); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_1) { assert(j["parent_lev_markup_number"].integer <= DocStructMarkupHeading.h_sect_D); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_2) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_1); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_3) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_2); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_4) { assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_3); } else if (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_5) { } } return _node; } invariant() { } #+END_SRC **** metadata node struct close #+name: ao_emitters_metadata #+BEGIN_SRC d } #+END_SRC ** function assertions :assertions: *** mixin template: assertions on markup document structure :doc_structure: #+name: abs_functions_assertions #+BEGIN_SRC d auto assertions_doc_structure(string[string] an_object, int[string] lv) { if (lv["h3"] > State.off) { assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h2"] > State.off); } else if (lv["h2"] > State.off) { assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h3"] == State.off); } else if (lv["h1"] > State.off) { assert(lv["h0"] > State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); } else if (lv["h0"] > State.off) { assert(lv["h1"] == State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); } else { assert(lv["h0"] == State.off); assert(lv["h1"] == State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); } if (lv["h7"] > State.off) { assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); assert(lv["h6"] > State.off); } else if (lv["h6"] > State.off) { assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); assert(lv["h7"] == State.off); } else if (lv["h5"] > State.off) { assert(lv["h4"] > State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } else if (lv["h4"] > State.off) { assert(lv["h5"] == State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } else { assert(lv["h4"] == State.off); assert(lv["h5"] == State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } if (lv["h0"] == State.off) { assert(lv["h1"] == State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); assert(lv["h4"] == State.off); assert(lv["h5"] == State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } if (lv["h1"] == State.off) { assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); } if (lv["h2"] == State.off) { assert(lv["h3"] == State.off); } if (lv["h3"] == State.off) { } if (lv["h4"] == State.off) { assert(lv["h5"] == State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } if (lv["h5"] == State.off) { assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } if (lv["h6"] == State.off) { assert(lv["h7"] == State.off); } if (lv["h7"] == State.off) { } switch (to!string(an_object["lev"])) { case "A": if (lv["h0"] == State.off) { assert(lv["h1"] == State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); assert(lv["h4"] == State.off); assert(lv["h5"] == State.off); assert(lv["h6"] == State.off); assert(lv["h7"] == State.off); } else { // (lv["h0"] > State.off) assert(lv["h0"] == State.off,"error should not enter level A a second time"); } break; case "B": if (lv["h1"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h2"] == State.off); assert(lv["h3"] == State.off); } else { // (lv["h1"] > State.off) assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); } break; case "C": if (lv["h2"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h3"] == State.off); } else { // (lv["h2"] > State.off) assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h2"] > State.off); } break; case "D": if (lv["h3"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h2"] > State.off); } else { // (lv["h3"] > State.off) assert(lv["h0"] > State.off); assert(lv["h1"] > State.off); assert(lv["h2"] > State.off); assert(lv["h3"] > State.off); } break; case "1": if (lv["h4"] == State.off) { assert(lv["h0"] > State.off); } else { // (lv["h4"] > State.off) assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); } break; case "2": if (lv["h5"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); } else { // (lv["h5"] > State.off) assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); } break; case "3": if (lv["h6"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); } else { // (lv["h6"] > State.off) assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); assert(lv["h6"] > State.off); } break; case "4": if (lv["h7"] == State.off) { assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); assert(lv["h6"] > State.off); } else { // (lv["h7"] > State.off) assert(lv["h0"] > State.off); assert(lv["h4"] > State.off); assert(lv["h5"] > State.off); assert(lv["h6"] > State.off); assert(lv["h7"] > State.off); } break; default: break; } } #+END_SRC *** mixin template: assertions on blocks :blocks: #+name: abs_functions_assertions #+BEGIN_SRC d auto assertions_flag_types_block_status_none_or_closed(int[string] type) { assert( (type["code"] == TriState.off) || (type["code"] == TriState.closing), "code block status: off or closing"); assert( (type["poem"] == TriState.off) || (type["poem"] == TriState.closing), "poem status: off or closing"); assert( (type["table"] == TriState.off) || (type["table"] == TriState.closing), "table status: off or closing"); assert( (type["group"] == TriState.off) || (type["group"] == TriState.closing), "group block status: off or closing"); assert( (type["block"] == TriState.off) || (type["block"] == TriState.closing), "block status: off or closing"); } #+END_SRC * Object Setter :abstract:object: set abstracted objects for downstream processing ** initialize structs :struct: *** heading attribute #+name: ao_structs_init #+BEGIN_SRC d struct HeadingAttrib { string lev = "9"; int lev_markup_number = 9; int lev_collapsed_number = 9; } #+END_SRC *** paragraph attribute #+name: ao_structs_init #+BEGIN_SRC d struct ParaAttrib { int indent_start = 0; int indent_rest = 0; bool bullet = false; } #+END_SRC *** block attribute #+name: ao_structs_init #+BEGIN_SRC d struct BlockAttrib { string syntax = ""; } #+END_SRC *** comment attribute #+name: ao_structs_init #+BEGIN_SRC d struct Comment { // no .attrib and no .obj_cite_number } #+END_SRC *** TODO node #+name: ao_structs_init #+BEGIN_SRC d struct Node { int ocn = 0; int parent_lev = 0; int parent_ocn = 0; string node = ""; } #+END_SRC *** TODO composite object #+name: ao_structs_init #+BEGIN_SRC d struct ObjComposite { string use = ""; string of = ""; string is_a = ""; string object = ""; string obj_cite_number = ""; // not used for calculations? output only? else int string[] anchor_tags = []; HeadingAttrib heading_attrib; ParaAttrib para_attrib; BlockAttrib block_attrib; Node node_structure; } #+END_SRC *** object composite array #+name: ao_structs_init #+BEGIN_SRC d struct ObjCompositeArr { ObjComposite[] oca; } #+END_SRC ** object setter :set: *** comment :comment: #+name: ao_object_setter_comment #+BEGIN_SRC d auto contents_comment(in string object) { ObjComposite object_set; object_set.use = "comment"; object_set.of = "comment"; object_set.is_a = "comment"; object_set.object = object; return object_set; } #+END_SRC *** heading :heading: #+name: ao_object_setter_heading #+BEGIN_SRC d auto contents_heading( in string object, in string attrib, in int obj_cite_number, in string[] tags, in string lev, in int lev_markup_number, in int lev_collapsed_number, ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "para"; object_set.is_a = "heading"; object_set.object = object; object_set.obj_cite_number = (obj_cite_number==0) ? "" : to!string(obj_cite_number); object_set.anchor_tags ~= tags; object_set.heading_attrib.lev = lev; object_set.heading_attrib.lev_markup_number = lev_markup_number; object_set.heading_attrib.lev_collapsed_number = lev_collapsed_number; // object_set.node_structure.node = _node; return object_set; } #+END_SRC *** para :para: #+name: ao_object_setter_para #+BEGIN_SRC d auto contents_para( in string is_a, in string object, in string attrib, in int obj_cite_number, in int[string] indent, in bool bullet ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "para"; object_set.is_a = "para"; object_set.object = object.strip; object_set.obj_cite_number = (obj_cite_number==0) ? "" : to!string(obj_cite_number); object_set.para_attrib.indent_start = to!int(indent["hang_position"]); object_set.para_attrib.indent_rest = to!int(indent["base_position"]); object_set.para_attrib.bullet = false; // bullet; // object_set.node_structure.node = _node; return object_set; } #+END_SRC *** toc :para: #+name: ao_object_setter_para #+BEGIN_SRC d auto contents_toc( in string is_a, in string object, in string attrib, in int obj_cite_number, in int[string] indent, in bool bullet ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "para"; object_set.is_a = "toc"; object_set.object = object.strip; object_set.obj_cite_number = (obj_cite_number==0) ? "" : to!string(obj_cite_number); object_set.para_attrib.indent_start = to!int(indent["hang_position"]); object_set.para_attrib.indent_rest = to!int(indent["base_position"]); object_set.para_attrib.bullet = false; // bullet; return object_set; } #+END_SRC *** para_endnote :para: #+name: ao_object_setter_endnote #+BEGIN_SRC d auto contents_endnote( in string object, in string tag, ) { auto m = (matchFirst(object, rgx.note_ref)); string notenumber = to!string(m.captures[1]); string anchor_tag = "note_" ~ notenumber; ObjComposite object_set; object_set.use = "content"; object_set.of = "para"; object_set.is_a = "endnote"; object_set.object = object.strip; object_set.obj_cite_number = ""; object_set.anchor_tags ~= [ tag ]; object_set.para_attrib.indent_start = 0; object_set.para_attrib.indent_rest = 0; object_set.para_attrib.bullet = false; return object_set; } #+END_SRC *** block :block: #+name: ao_object_setter_block #+BEGIN_SRC d auto contents_block( in string type, in string object, in string attrib, in int obj_cite_number ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "block"; object_set.is_a = type; object_set.object = object; object_set.obj_cite_number = (obj_cite_number==0) ? "" : to!string(obj_cite_number); // object_set.node_structure.node = _node; return object_set; } #+END_SRC *** block code :block:code: #+name: ao_object_setter_block_code #+BEGIN_SRC d auto contents_block_code( in string type, in string object, in string attrib_language_syntax, in int obj_cite_number ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "block"; object_set.is_a = type; object_set.block_attrib.syntax = attrib_language_syntax; object_set.object = object; object_set.obj_cite_number = (obj_cite_number==0) ? "" : to!string(obj_cite_number); // object_set.node_structure.node = _node; return object_set; } #+END_SRC *** block obj_cite_number string :block: #+name: ao_object_setter_block_obj_cite_number_string #+BEGIN_SRC d auto contents_block_obj_cite_number_string( in string type, in string object, in string obj_cite_number, in string _node ) { ObjComposite object_set; object_set.use = "content"; object_set.of = "block"; object_set.is_a = type; object_set.object = object; object_set.obj_cite_number = obj_cite_number; object_set.node_structure.node = _node; return object_set; } #+END_SRC * Tangles (code structure) :tangle:io:file: ** ao abstract doc source: :ao_abstract_doc_source.d: #+BEGIN_SRC d :tangle ../src/sdp/ao_abstract_doc_source.d /++ document abstraction: abstraction of sisu markup for downstream processing ao_abstract_doc_source.d +/ template SiSUdocAbstraction() { private: struct Abstraction { /+ ↓ abstraction imports +/ <> /+ ↓ abstraction mixins +/ <> /+ ↓ abstraction struct init +/ <> /+ ↓ abstract marked up document +/ auto abstract_doc_source( char[][] markup_sourcefile_content, string[string][string] dochead_make_aa, string[string][string] dochead_meta_aa ) { /+ ↓ abstraction init +/ <> /+ abstraction init ↑ +/ /+ ↓ loop markup document/text line by line +/ srcDocLoop: foreach (line; markup_sourcefile_content) { /+ ↓ markup document/text line by line +/ <> if (type["code"] == TriState.on) { <> } else if (!matchFirst(line, rgx.skip_from_regular_parse)) { /+ object other than "code block" object (includes regular text paragraph, headings & blocks other than code) +/ <> } else { /+ not within a block group +/ <> if (matchFirst(line, rgx.block_open)) { <> } else if (!line.empty) { /+ line not empty +/ /+ non blocks (headings, paragraphs) & closed blocks +/ <> } else if (type["blocks"] == TriState.closing) { /+ line empty, with blocks flag +/ <> } else { /+ line empty +/ /+ line.empty, post contents, empty variables: +/ <> } // close else for line empty } // close else for not the above } // close after non code, other blocks or regular text <> } /+ ← closed: loop markup document/text line by line +/ /+ ↓ post loop markup document/text +/ <> /+ post loop markup document/text ↑ +/ } /+ ← closed: abstract doc source +/ /+ ↓ abstraction functions +/ <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> /+ abstraction functions ↑ +/ /+ ↓ abstraction function emitters +/ <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> /+ abstraction functions emitters ↑ +/ /+ ↓ abstraction functions assertions +/ <> /+ abstraction functions assertions ↑ +/ } /+ ← closed: struct Abstraction +/ } /+ ← closed: template SiSUdocAbstraction +/ #+END_SRC ** ao object setter: :ao_object_setter.d: #+BEGIN_SRC d :tangle ../src/sdp/ao_object_setter.d /++ object setter: setting of sisu objects for downstream processing ao_object_setter.d +/ template ObjectSetter() { /+ structs +/ <> /+ structs setter +/ struct ObjectAbstractSet { import std.conv : to; <> <> <> <> <> <> <> } } #+END_SRC * TODO work on - bespoke struct for sisu objects to replace JSON strings - book index *sort* fix (Aa-Zz instead of A-Za-z) - determine what goes in node info - understand collapsed level - convert file utf8 for processing from to utf32 - general concepts - ranges - templates - unitest? |---------------------+------------------------------------------+------------------------+--------| | header | sisu /header markup/ | markup | | | - metadata | | | | | - make instructions | | | | |---------------------+------------------------------------------+------------------------+--------| | table of contents | markup of headings | (regular content) | output | |---------------------+------------------------------------------+------------------------+--------| | substantive content | sisu /content markup/ | markup | output | | | headings (providing document structure), | (regular content) | | | | paragraphs, blocks | | | | | blocks (code, poem, group, table) | | | |---------------------+------------------------------------------+------------------------+--------| | endnotes | markup within substantive content | markup | output | | | (extracted from sisu /content markup/) | (from regular content) | | |---------------------+------------------------------------------+------------------------+--------| | glossary | identify special section | markup | output | | | regular /content markup/ | | | |---------------------+------------------------------------------+------------------------+--------| | bibliography | identify section, | markup (special) | output | | | special /bibliography markup/ | | | |---------------------+------------------------------------------+------------------------+--------| | book index | extracted from markup attached to | markup | output | | | related substantive content objects | | | | | (special tags in sisu /content markup/) | (from regular content) | | |---------------------+------------------------------------------+------------------------+--------| | metadata | | (from regular header) | output | |---------------------+------------------------------------------+------------------------+--------|