From 90873fabd7451e1dd8c4b39303906e19bdc481f7 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Wed, 10 Apr 2024 22:24:34 -0400 Subject: 0.16.0 sisudoc (src/sisudoc sisudoc spine) - src/sisudoc (replaces src/doc_reform) - sisudoc spine (used more) --- src/sisudoc/io_out/latex.d | 1771 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1771 insertions(+) create mode 100644 src/sisudoc/io_out/latex.d (limited to 'src/sisudoc/io_out/latex.d') diff --git a/src/sisudoc/io_out/latex.d b/src/sisudoc/io_out/latex.d new file mode 100644 index 0000000..a6867cb --- /dev/null +++ b/src/sisudoc/io_out/latex.d @@ -0,0 +1,1771 @@ +/+ +- Name: SisuDoc Spine, Doc Reform [a part of] + - Description: documents, structuring, processing, publishing, search + - static content generator + + - Author: Ralph Amissah + [ralph.amissah@gmail.com] + + - Copyright: (C) 2015 - 2024 Ralph Amissah, All Rights Reserved. + + - License: AGPL 3 or later: + + Spine (SiSU), a framework for document structuring, publishing and + search + + Copyright (C) Ralph Amissah + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU AFERO General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see [https://www.gnu.org/licenses/]. + + If you have Internet connection, the latest version of the AGPL should be + available at these locations: + [https://www.fsf.org/licensing/licenses/agpl.html] + [https://www.gnu.org/licenses/agpl.html] + + - Spine (by Doc Reform, related to SiSU) uses standard: + - docReform markup syntax + - standard SiSU markup syntax with modified headers and minor modifications + - docReform object numbering + - standard SiSU object citation numbering & system + + - Homepages: + [https://www.sisudoc.org] + [https://www.doc-reform.org] + + - Git + [https://git.sisudoc.org/] + ++/ +module sisudoc.io_out.latex; +@safe: +template paperLaTeX() { + import + std.format, + std.conv : to; + auto paperLaTeX() { + string mm(uint mmi) { + string _mm = format(q"┃%smm┃", mmi.to!string); + return _mm; + } + struct PaperType { + auto a4() { + struct A4 { + auto portrait() { + struct V { + string stylesheet = "spineA4portrait"; + string papersize = "a4paper"; + string orient = "portrait"; + string fontsize = "11pt"; + const uint w = 170; + const uint h = 257; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 450; + bool is_portrait = true; + } + return V(); + } + auto landscape() { + struct H { + string stylesheet = "spineA4landscape"; + string papersize = "a4paper"; + string orient = "landscape"; + string fontsize = "11pt"; + const uint w = 238; + const uint h = 160; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 300; + bool is_portrait = false; + } + return H(); + } + } + return A4(); + } + auto a5() { + struct A5 { + auto portrait() { + struct V { + string stylesheet = "spineA5portrait"; + string papersize = "a5paper"; + string orient = "portrait"; + string fontsize = "11pt"; + const uint w = 112; + const uint h = 162; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 280; + bool is_portrait = true; + } + return V(); + } + auto landscape() { + struct H { + string stylesheet = "spineA5landscape"; + string papersize = "a5paper"; + string orient = "landscape"; + string fontsize = "11pt"; + const uint w = 152; + const uint h = 100; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 190; + bool is_portrait = false; + } + return H(); + } + } + return A5(); + } + auto b4() { + struct B4 { + auto portrait() { + struct V { + string stylesheet = "spineB4portrait"; + string papersize = "b4paper"; + string orient = "portrait"; + string fontsize = "11pt"; + const uint w = 140; + const uint h = 204; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 356; + bool is_portrait = true; + } + return V(); + } + auto landscape() { + struct H { + string stylesheet = "spineB4landsape"; + string papersize = "b4paper"; + string orient = "landscape"; + string fontsize = "11pt"; + const uint w = 200; + const uint h = 130; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 260; + bool is_portrait = false; + } + return H(); + } + } + return B4(); + } + auto letter() { + struct Letter { + auto portrait() { + struct V { + string stylesheet = "spineLetterPortrait"; + string papersize = "letterpaper"; + string orient = "portrait"; + string fontsize = "11pt"; + const uint w = 166; + const uint h = 212; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 468; + bool is_portrait = true; + } + return V(); + } + auto landscape() { + struct H { + string stylesheet = "spineLetterLandscape"; + string papersize = "letterpaper"; + string orient = "landscape"; + string fontsize = "11pt"; + const uint w = 226; + const uint h = 166; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 290; + bool is_portrait = false; + } + return H(); + } + } + return Letter(); + } + auto legal() { + struct Legal { + auto portrait() { + struct V { + string stylesheet = "spineLegalPortrait"; + string papersize = "legalpaper"; + string orient = "portrait"; + string fontsize = "11pt"; + const uint w = 168; + const uint h = 286; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 474; + bool is_portrait = true; + } + return V(); + } + auto landscape() { + struct H { + string stylesheet = "spineLegalLandscape"; + string papersize = "legalpaper"; + string orient = "landscape"; + string fontsize = "11pt"; + const uint w = 296; + const uint h = 166; + const uint l = 30; + const uint r = 20; + const uint t = 30; + const uint b = 30; + string width = mm(w); + string height = mm(h); + string margin_left = mm(l); + string margin_right = mm(r); + string margin_top = mm(t); + string margin_bottom = mm(b); + uint img_px = 420; + bool is_portrait = false; + } + return H(); + } + } + return Legal(); + } + } + return PaperType(); + } +} +template outputLaTeX() { + import + std.digest.sha, + std.file, + std.outbuffer, + std.uri, + std.conv : to; + import + sisudoc.io_out, + sisudoc.io_out.rgx, + sisudoc.io_out.rgx_latex; + mixin spineRgxOut; + static auto rgx = RgxO(); + mixin spineRgxLSC; + static auto rgx_sc = RgxLSC(); + mixin spineLanguageCodes; + auto lang = Lang(); + auto paper = paperLaTeX; + string sp_char_ops()( + string _txt, + ) { + string _unescape_sp_char_esc()(string _txt) { + _txt = _txt + .replaceAll(rgx_sc.latex_special_char_escaped, + format(q"┃%s┃", "$1")) + .replaceAll(rgx_sc.latex_special_char_escaped_braced, + format(q"┃%s┃", "$1")); + return _txt; + } + string _unescape_fontface_esc()(string _txt) { + _txt = _txt.replaceAll(rgx_sc.latex_identify_inline_fontface, + format(q"┃%s%s┃", "$1", "$2")); + return _txt; + } + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx_sc.latex_special_char_for_escape); + _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx_sc.latex_special_char_for_escape_and_braces); + _txt = replaceAll!(m => "''")(_txt, rgx.quotes_open_and_close); + _txt = replaceAll!(m => "$\\cdot$")(_txt, rgx.middle_dot); + _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx_sc.latex_identify_inline_link); + _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx_sc.latex_identify_inline_fontface); + return _txt; + } + string sp_char_esc(O)( + string _txt, + const O obj, + ) { + if (obj.metainfo.is_a != "code") { + _txt = _txt.sp_char_ops; + } + return _txt; + } + string sp_char_esc_txt()( + string _txt, + ) { + _txt = _txt.sp_char_ops; + return _txt; + } + string marked_linebreaks_newlines()( + string _txt, + ) { + _txt = _txt.split(rgx.br_linebreaks_newlines).join("\\br\n").strip; + // _txt = replaceAll!(m => "\\br " ~ m[1])(_txt, rgx.br_linebreaks_newlines); + return _txt; + } + string fontface()( + string _txt, + ) { + _txt = _txt + .replaceAll(rgx.inline_emphasis, format(q"┃\begin{bfseries}%s\end{bfseries}┃", "$1")) + .replaceAll(rgx.inline_bold, format(q"┃\begin{bfseries}%s\end{bfseries}┃", "$1")) + .replaceAll(rgx.inline_italics, format(q"┃\emph{%s}┃", "$1")) + .replaceAll(rgx.inline_italics, format(q"┃\uline{%s}┃", "$1")) + .replaceAll(rgx.inline_superscript, format(q"┃$$^{%s}$$┃", "$1")) + .replaceAll(rgx.inline_subscript, format(q"┃$$_{%s}$$┃", "$1")) + .replaceAll(rgx.inline_strike, format(q"┃\sout{%s}┃", "$1")) + .replaceAll(rgx.inline_insert, format(q"┃\uline{%s}┃", "$1")) + .replaceAll(rgx.inline_mono, format(q"┃\begin{monosp}%s\end{monosp}┃", "$1")) + .replaceAll(rgx.inline_italics, format(q"┃``%s''┃", "$1")); + return _txt; + } + string leading_hardspaces()( + string _txt, + ) { + string hardspaces(string _spaces) { + _spaces = _spaces + .replaceAll(rgx.space, "{\\s}"); + return _spaces; + } + _txt = replaceAll!(m => hardspaces(m[0]))(_txt, rgx.spaces_line_start); + return _txt; + } + string nbsp_char()(string _txt) { + if (_txt.match(rgx.nbsp_char)) { + foreach (m; _txt.matchAll(rgx.nbsp_chars)) { + int spaces_ = 0; + foreach (n; m[0].matchAll(rgx.nbsp_char)) { + spaces_ ++; + } + _txt = _txt.replaceFirst(rgx.nbsp_chars, "\\spaces{" ~ spaces_.to!string ~ "}"); + } + } + return _txt; + } + string spaces_to_nbsp()(string _txt) { + if (_txt.match(rgx.spaces_keep)) { + foreach (m; _txt.matchAll(rgx.spaces_keep)) { + int spaces_ = 0; + foreach (n; m[0].matchAll(rgx.space)) { + spaces_ ++; + } + _txt = _txt.replaceFirst(rgx.spaces_keep, "\\spaces{" ~ spaces_.to!string ~ "}"); + } + } + return _txt; + } + string nbsp_char_to_space()(string _txt) { + if (_txt.match(rgx.nbsp_char)) { + _txt = _txt.replaceAll(rgx.nbsp_char, " "); + } + return _txt; + } + string links_and_images(O,M)( + string _txt, + const O obj, + M doc_matters, + ) { + if (obj.has.inline_links) { // TODO some images do not have inline links ... image without link + string _width_adjust(string _width) { + if (_width.to!int > 300) { _width = "300"; } // will need to vary max with papersize & orientation + return _width; + } + string _latex_image_path(string _image_path) { + auto pth_latex = spinePathsLaTeX(doc_matters); + _image_path = pth_latex.latex_path_stuff ~ "/" ~ _image_path; + return _image_path; + } + string _if_images(string _linked_content) { + if (_linked_content.match(rgx.inline_image_info)) { + _linked_content = replaceAll!(m => + format(q"┃\includegraphics*[width=%spt]{%s}%s┃", + _width_adjust(m[2]), _latex_image_path(m[1]), " \\br\n") + )(_linked_content, rgx.inline_image_info); + } + return _linked_content; + } + string _check_link(string _link) { + _link = _link + .replaceFirst(rgx_sc.latex_clean_internal_link, "") + .replaceAll(rgx_sc.latex_special_char_for_escape_url, "\\$1"); + return _link; + } + if (obj.metainfo.is_a != "code") { + _txt = replaceAll!(m => + m[1] ~ "┤" ~ to!string((obj.stow.link[m[2].to!ulong])).encode ~ "├" + )(_txt, rgx.inline_link_number_only); + _txt = replaceAll!(m => + ((m[1] == m[2]) && (m[2].match(rgx.uri))) // url link (regular link with url) + ? format(q"┃\linkurl{%s}{%s}┃", _check_link(m[1]), (_check_link(m[1])).sp_char_esc_txt) + : ((m[2].match(rgx.uri)) && (m[1].match(rgx.inline_image_info))) // linked image + ? format(q"┃%s\href{%s}%s{%s}┃", "\\br ", _check_link(m[2]), "\n", _if_images(m[1])) // markup for images + : (m[2].match(rgx.uri)) // not linked image + ? format(q"┃%s\linktext{%s}{%s}┃", "\\br ", _check_link(m[2]), m[1]) // regular link with text + : format(q"┃\hyperlink{%s}{%s}┃", _check_link(m[2]), _if_images(m[1])) // internal links, like book index + )(_txt, rgx.inline_link); + } + } + return _txt; + } + string footnotes()( + string _txt, + ) { + if (_txt.match(rgx.inline_notes_al_gen)) { + string _tex_note = q"┃\hypertarget{noteref_%s}{}\footnote[%s]{%% + \label{note_%s}%s}┃"; + _txt = _txt.split(rgx.br_linebreaks).join("\\br ").replaceAll(rgx.inline_notes_al_regular_number_note, + format(_tex_note, + "$1", "$1", "$1", + "$2".strip + ).strip + ); + } + return _txt; + } + string remove_footnotes()( + string _txt, + ) { + if (_txt.match(rgx.inline_notes_al_gen)) { + _txt = replaceAll!(m => "")(_txt, rgx.inline_notes_al_gen); + } + return _txt; + } + string para(O)( + string _txt, + O obj, + ) { + if (obj.metainfo.is_of_type == "para") { + string _tex_para; + _tex_para = q"┃\ocn{%s}%s┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _txt.footnotes + ).strip; + } + return _txt; + } + string bookindex(O)( + string _txt, + O obj, + ) { + if (obj.metainfo.is_of_type == "para" + && obj.metainfo.is_a == "bookindex" + ) { + string _tex_para; + _tex_para = q"┃%s┃"; + _txt = format(_tex_para, + _txt.replaceAll(rgx_sc.latex_clean_bookindex_linebreak, "\n") ~ "\n\\brln\n" + ); + } + return _txt; + } + string heading(O,M)( + string _txt, + O obj, + M doc_matters, + string paper_size_orientation, + string _part = "" + ) { + struct latexMarks { + string pg_break = "\\clearpage\n"; + } + latexMarks manual_breaks( + latexMarks _ltx, + string test_for_break_level, + ) { + if ((!(doc_matters.conf_make_meta.make.breaks.empty) + && (matchFirst(doc_matters.conf_make_meta.make.breaks, test_for_break_level))) + ) { // manually override defaults + if ((matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) + && (matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) + ) { + if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) { + if (matchFirst(m.captures["breakpage"], test_for_break_level)) { + _ltx.pg_break = "\\clearpage\n"; + } else if (auto n = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) { + if (matchFirst(n.captures["breakcolumn"], test_for_break_level)) { + if ((paper_size_orientation == "a4.landscape") + || (paper_size_orientation == "b4.landscape") + || (paper_size_orientation == "a5.landscape") + || (paper_size_orientation == "letter.landscape") + || (paper_size_orientation == "legal.landscape") + ) { + _ltx.pg_break = "\\\\ \\columnbreak\n"; // "\\\\ \\newpage\n"; + } else { // portrait + _ltx.pg_break = "\\clearpage\n"; + } + } + } + } + } else if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) { + if (matchFirst(m.captures["breakpage"], test_for_break_level)) { + _ltx.pg_break = "\\clearpage\n"; + } + } else if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) { + if (matchFirst(m.captures["breakcolumn"], test_for_break_level)) { + if ((paper_size_orientation == "a4.landscape") + || (paper_size_orientation == "b4.landscape") + || (paper_size_orientation == "a5.landscape") + || (paper_size_orientation == "letter.landscape") + || (paper_size_orientation == "legal.landscape") + ) { + _ltx.pg_break = "\\\\ \\columnbreak\n"; // "\\\\ \\newpage\n"; + } else { // portrait + _ltx.pg_break = "\\clearpage\n"; + } + } + } + } else if (!(doc_matters.conf_make_meta.make.breaks.empty)) { + _ltx.pg_break = ""; + } + return _ltx; + } + if (obj.metainfo.is_a == "heading") { + string _tex_para; + latexMarks _ltx = latexMarks(); + string _pg_break; + string _sect; + string _post; + string _title_add; + string _columns = ""; + switch (obj.metainfo.heading_lev_markup) { + case 0: // A == TITLE + _pg_break = "\\begin{document}\n"; + goto default; + case 1: // B == part: section heading level + _pg_break = "\\clearpage\n"; + goto default; + case 2: // C == part: section heading level + _pg_break = "\\clearpage\n"; + goto default; + case 3: // D == part: section heading level + _pg_break = "\\clearpage\n"; + goto default; + case 4: // 1 == section + _columns = (_part != "bookindex") + ? "" : "\n\\br\n\\begin{multicols}{2}"; + if (doc_matters.conf_make_meta.make.doc_type == "article") { // defaults for article + _ltx.pg_break = ""; + } else if (doc_matters.conf_make_meta.make.doc_type == "book") { // defaults for book + _ltx.pg_break = "\\clearpage\n"; + } else { + _ltx.pg_break = "\\clearpage\n"; + } + _ltx = manual_breaks(_ltx, "1"); + _pg_break = _ltx.pg_break; + _sect = "section"; + _post = ""; + _title_add = format(q"┃ +\markboth{%s}{%s}┃", + doc_matters.conf_make_meta.meta.title_full, + doc_matters.conf_make_meta.meta.title_full, + ); + goto default; + case 5: // 2 == subsection + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "subsection"; + _post = " \\br\n"; + _title_add = ""; + goto default; + case 6: // 3 == subsubsection + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "subsubsection"; + _post = " \\br\n"; + _title_add = ""; + goto default; + case 7: // 4 == paragraph + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "paragraph"; + _post = " \\br\n"; + _title_add = ""; + goto default; + case 8: // 5 == subparagraph + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "subparagraph"; + _post = " \\br\n"; + _title_add = ""; + goto default; + default: + if (obj.metainfo.heading_lev_markup == 0) { + _tex_para = q"┃ +\begin{document} +\thispagestyle{empty} +\title{%s%s} +\author{ \textnormal{%s}} +\date{\begin{tiny}%s\end{tiny}} +\maketitle +\addcontentsline{toc}{part}{%s} +\newpage +\pagestyle{fancy} +\pagenumbering{alph} +\setcounter{page}{1} +\markboth{%s}{%s} +\br\linebreak Copyright {\begin{small}{\copyright\end{small}} %s \br\linebreak +%s +\clearpage┃"; + _txt = format(_tex_para, + (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, + doc_matters.conf_make_meta.meta.title_subtitle.empty ? "" + : " \\\\ - \\\\ " ~ (doc_matters.conf_make_meta.meta.title_subtitle).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.creator_author).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.date_published).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.rights_copyright).sp_char_esc_txt.marked_linebreaks_newlines, + (doc_matters.conf_make_meta.meta.rights_license).sp_char_esc_txt.marked_linebreaks_newlines, + ); + } else if (obj.metainfo.heading_lev_markup < 4) { + if (!(_txt.footnotes.strip == "Endnotes")) { + _tex_para = q"┃%s\part*{\ocn{%s}%s} +\addcontentsline{toc}{part}{%s} +\markboth{%s}┃"; + _txt = format(_tex_para, + _pg_break, + obj.metainfo.object_number, + _txt.strip.footnotes, + _txt.strip.remove_footnotes, + (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, + ); + } + } else if (obj.metainfo.heading_lev_markup > 3) { + if (obj.metainfo.heading_lev_markup == 4 + && _txt.match(regex(r"^Table of Contents$"))) { + _tex_para = q"┃ +\pagenumbering{arabic} +\setcounter{page}{1} +\markboth{ }{ } +\part*{\ocn{1}%s \newline %s} + +\clearpage +\pagenumbering{roman} +\setcounter{page}{1} +\renewcommand{\contentsname}{} +\tableofcontents + +\clearpage +\pagenumbering{arabic} +\setcounter{page}{2} +\clearpage +\markboth{%s}{%s} +%% \null +\clearpage +\setcounter{page}{2}┃"; + _txt = format(_tex_para, + (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.creator_author).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, + ); + } else if (obj.metainfo.heading_lev_markup == 4 + && _part == "bookindex" + && _txt.match(regex(r"^Index$")) + ) { + _tex_para = q"┃%s\%s*{\ocn{%s}%s} +\addcontentsline{toc}{%s}{%s%s}%s%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + _txt.footnotes.strip, + _sect, + _txt.remove_footnotes.strip, + _post, + _title_add, + _columns, + ); + } else if (obj.metainfo.dummy_heading + && obj.metainfo.heading_lev_markup == 4 + ) { /+ dummy headings completely omitted +/ + _txt = ""; + } else { + _tex_para = q"┃%s\%s*{\ocn{%s}%s} +\addcontentsline{toc}{%s}{%s%s}%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + _txt.footnotes.strip, + _sect, + _txt.remove_footnotes.strip, + _post, + _title_add, + ); + } + } + break; + } + } + return _txt.strip; + } + string group(O,M)( + string _txt, + O obj, + M doc_matters, + ) { + if (obj.metainfo.is_a == "group") { + string _tex_para; + _tex_para = q"┃\ocn{%s}\objGroupOpen +%s +\objGroupClose +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _txt.footnotes.split(rgx.br_line_spaced).join("\\brl{1}").strip // provides more control (more noise, not as tidy) + // _txt.footnotes.split(rgx.br_line_spaced).join("") // this works using a line-space, looks tidy, keep ref. + ).strip; + } + return _txt; + } + string block(O,M)( + string _txt, + O obj, + M doc_matters, + ) { + if (obj.metainfo.is_a == "block") { + string _tex_para; + _tex_para = q"┃\ocn{%s}\objBlockOpen +%s +\objBlockClose +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _txt.nbsp_char.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n").strip + ).strip; + } + return _txt; + } + string verse(O,M)( + string _txt, + O obj, + M doc_matters, + ) { + if (obj.metainfo.is_a == "verse") { + string _tex_para; + _tex_para = q"┃\ocn{%s}\objPoemVerseOpen +%s +\objPoemVerseClose +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _txt.spaces_to_nbsp.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n").strip + ).strip; + } + return _txt; + } + string codeblock(O,M)( + string _txt, + O obj, + M doc_matters, + ) { + if (obj.metainfo.is_a == "code") { + string _tex_para; + _tex_para = q"┃\ocn{%s}\begin{objCodeBlock}\begin{lstlisting} +%s +\end{lstlisting}\end{objCodeBlock} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _txt.nbsp_char_to_space + ).strip; + } + return _txt; + } + auto tablarize(O)( + string _txt, + const O obj, + ) { + string[] _table_rows = (_txt).split(rgx.table_delimiter_row); + string[] _table_cols; + string _table; + string _tablenote; + foreach(row_idx, row; _table_rows) { + _table_cols = row.split(rgx.table_delimiter_col); + _table ~= ""; + foreach(col_idx, cell; _table_cols) { + if ((_table_cols.length == 1) + && (_table_rows.length <= row_idx+2)) { // check row_idx+2 (rather than == ++row_idx) + _tablenote ~= cell; + } else { + // // _table ~= "\\bfseries "; + // _table ~= cell; + // _table ~= (_table_cols.length > (col_idx + 1)) ? "&" : ""; + _table ~= format(q"┃%s%s┃", + cell, + (_table_cols.length > (col_idx + 1)) ? "&" : "" + ); + } + } + _table ~= "\\\\"; + } + Tuple!(string, string) t = tuple( + _table, + _tablenote, + ); + return t; + } + string table(O,M)( + string _txt, + O obj, + M doc_matters, + string paper_size_orientation, + ) { + if (obj.metainfo.is_a == "table") { + auto _t = _txt.tablarize(obj); + string _table = _t[0]; + string _t_n = _t[1]; + uint pw = 0; + switch (paper_size_orientation) { + case "a4.portrait": pw = (paper.a4.portrait.w - 20); break; + case "a4.landscape": pw = (paper.a4.landscape.w - 20); break; + case "b4.portrait": pw = (paper.b4.portrait.w - 20); break; + case "b4.landscape": pw = (paper.b4.landscape.w - 20); break; + case "a5.portrait": pw = (paper.a5.portrait.w - 20); break; + case "a5.landscape": pw = (paper.a5.landscape.w - 20); break; + case "letter.portrait": pw = (paper.letter.portrait.w - 20); break; + case "letter.landscape": pw = (paper.letter.landscape.w - 20); break; + case "legal.portrait": pw = (paper.legal.portrait.w - 20); break; + case "legal.landscape": pw = (paper.legal.landscape.w - 20); break; + default: pw = 0; break; + } + // auto textwidth = (pw - 24); + string _colw = ""; + foreach (w; obj.table.column_widths) { + _colw ~= format(q"┃p{%.0fmm}┃", + (w * pw / 100) + // (w * (pw - 24)/ 100) + // (w * textwidth / 100) + ); + } + string _tex_para; + _tex_para = q"┃\ocn{%s}\objTableOpen{%s} +%s +\objTableClose +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + _colw, + _table, + ).strip; + } + return _txt; + } + string bullets_and_indentation(O)( + string _txt, + O obj, + ) { + string _tex_para; + string _hang; string _indent; + int _paper_margin = -10; + int _indent_increment = 8; // 5; 10; + if (obj.attrib.bullet) { + int _bullet_space = 5; + _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin + _bullet_space).to!string; + _txt = format(q"┃\begin{Bullet}{%smm}%s\end{Bullet}┃", + _indent, + _txt.footnotes + ).strip; + } else if ( + obj.attrib.indent_base != 0 + && obj.attrib.indent_base == obj.attrib.indent_hang + ) { + _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin).to!string; + _tex_para = q"┃\begin{ParagraphIndent}{%smm}%s \end{ParagraphIndent}┃"; + _txt = format(_tex_para, + _indent, + _txt.footnotes + ).strip; + } else if ( + obj.attrib.indent_base != 0 + || obj.attrib.indent_hang != 0 + ) { + _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin).to!string; + _hang = (((obj.attrib.indent_hang - obj.attrib.indent_base) * _indent_increment)).to!string; + _tex_para = q"┃\begin{ParagraphHang}{%smm}{%smm}%s \end{ParagraphHang}┃"; + _txt = format(_tex_para, + _indent, _hang, + _txt.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n") + ).strip; + } + return _txt; + } + string latex_head(M)( + M doc_matters, + string paper_size_orientation, + ) { + struct paperTypeLatex { + string a4_portrait; + string a4_landscape; + string b4_portrait; + string b4_landscape; + string a5_portrait; + string a5_landscape; + string us_letter_portrait; + string us_letter_landscape; + string us_legal_portrait; + string us_legal_landscape; + } + auto paper_type_latex = paperTypeLatex(); + string _footer(M)(M doc_matters) { + string _ft = "\\lfoot[\\textrm{\\thepage}]"; + string _ft_1 = format(q"┃{\tiny \href{%s}{%s}}┃", "https://sisudoc.org", "SiSU",); + string _ft_2 = format(q"┃ + \cfoot{\href{%s}{%s}}┃", "https://git.sisudoc.org", "git",); + if (doc_matters.conf_make_meta.make.footer.length > 0) { + if (doc_matters.conf_make_meta.make.footer.length > 0) { + if (doc_matters.conf_make_meta.make.footer[0].matchAll(rgx.inline_link)) { + _ft ~= doc_matters.conf_make_meta.make.footer[0] + .replace(rgx.inline_link, "{\\tiny \\href{$2}{$1}}"); + } else { + _ft ~= _ft_1; + } + } + if (doc_matters.conf_make_meta.make.footer.length > 1) { + if (doc_matters.conf_make_meta.make.footer[1].matchAll(rgx.inline_link)) { + _ft ~= doc_matters.conf_make_meta.make.footer[1] + .replace(rgx.inline_link, "\n\\cfoot{\\href{$2}{$1}}"); + } else { + _ft ~= _ft_2; + } + } + } else { + _ft ~= _ft_1; + _ft ~= _ft_2; + } + return _ft; + } + struct paperMargins { + string portrait; + string landscape; + } + auto margins = paperMargins(); + struct columnsMulti { + string portrait; + string landscape; + } + auto multicol = columnsMulti(); + multicol.landscape = ""; + struct colorLinks { + string mono; + string color; + } + auto links = colorLinks(); + links.mono = format(q"┃ + colorlinks=true, + urlcolor=black, + filecolor=black, + linkcolor=black, + citecolor=black, +┃", + ); + links.color = format(q"┃ + colorlinks=true, + urlcolor=myblue, %% \href{...}{...} external url + filecolor=mygreen, %% \href{...} local file + linkcolor=myred, %% \href{...} and \pageref{...} + citecolor=black, +┃", + ); + string set_paper(P)(P paper_set,) { + string paper_type_description; + if (paper_set.is_portrait) { + paper_type_description = format(q"┃ +\documentclass[%s,%s,titlepage,makeidx]{scrartcl} +\usepackage{%s} +\usepackage[%s,%s]{babel} +\usepackage[autostyle, english = american]{csquotes} +%% \MakeOuterQuote{"} %% not required, using '' as quote delimiter +\selectlanguage{%s} +\hypersetup{ + pdftitle={%s}, + pdfauthor={%s}, + pdfsubject={%s}, +} +\usepackage{fancyhdr} +\lhead[ ]{ } +\chead[ \fancyplain{} \bfseries \footnotesize \leftmark ]{ \fancyplain{} \bfseries \footnotesize \rightmark } +\rhead[ ]{ } +%s +\rfoot[\tiny \href{}{}]{\textrm{\thepage}} + ┃", + paper_set.fontsize, + paper_set.papersize, + "./sty/" ~ paper_set.stylesheet, + lang.codes[doc_matters.src.language]["xlp"], + "english", + lang.codes[doc_matters.src.language]["xlp"], + doc_matters.conf_make_meta.meta.title_full.strip, + doc_matters.conf_make_meta.meta.creator_author.strip, + doc_matters.conf_make_meta.meta.classify_subject.strip, + _footer(doc_matters), + ); + } else { + paper_type_description = format(q"┃ +\documentclass[%s,%s,landscape,titlepage,twocolumn,makeidx]{scrartcl} +\usepackage{%s} +\usepackage[english]{babel} +%% \usepackage{polyglossia} +\setmainlanguage{%s} +\setotherlanguage{%s} +\selectlanguage{%s} +\hypersetup{ + pdftitle={%s}, + pdfauthor={%s}, + pdfsubject={%s}, +} +\usepackage{fancyhdr} +\lhead[ ]{ } +\chead[ \fancyplain{} \bfseries \footnotesize \leftmark ]{ \fancyplain{} \bfseries \footnotesize \rightmark } +\rhead[ ]{ } +%s +\rfoot[\tiny \href{}{}]{\textrm{\thepage}} + ┃", + paper_set.fontsize, + paper_set.papersize, + "./sty/" ~ paper_set.stylesheet, + lang.codes[doc_matters.src.language]["xlp"], + "english", + lang.codes[doc_matters.src.language]["xlp"], + doc_matters.conf_make_meta.meta.title_full.strip, + doc_matters.conf_make_meta.meta.creator_author.strip, + doc_matters.conf_make_meta.meta.classify_subject.strip, + _footer(doc_matters), + ); + } + return paper_type_description; + } + string paper_size_orientation_latex; + switch (paper_size_orientation) { + case "a4.portrait": paper_size_orientation_latex = set_paper(paper.a4.portrait); break; + case "a4.landscape": paper_size_orientation_latex = set_paper(paper.a4.landscape); break; + case "b4.portrait": paper_size_orientation_latex = set_paper(paper.b4.portrait); break; + case "b4.landscape": paper_size_orientation_latex = set_paper(paper.b4.landscape); break; + case "a5.portrait": paper_size_orientation_latex = set_paper(paper.a5.portrait); break; + case "a5.landscape": paper_size_orientation_latex = set_paper(paper.a5.landscape); break; + case "letter.portrait": paper_size_orientation_latex = set_paper(paper.letter.portrait); break; + case "letter.landscape": paper_size_orientation_latex = set_paper(paper.letter.landscape); break; + case "legal.portrait": paper_size_orientation_latex = set_paper(paper.legal.portrait); break; + case "legal.landscape": paper_size_orientation_latex = set_paper(paper.legal.landscape); break; + default: paper_size_orientation_latex = paper_type_latex.a4_portrait; + } + string links_mono_or_color_set = links.mono.strip; + if ( + (doc_matters.opt.action.latex_color_links) + || (paper_size_orientation == + "a4.landscape" || + "a5.landscape" || + "b4.landscape" || + "letter.landscape" || + "legal.landscape") + ){ + links_mono_or_color_set = links.mono.strip; + } + string _latex_head = format(q"┃%%%% spine LaTeX output%s%s +%%%% %s %s +%s +%s + ┃", + doc_matters.opt.action.generated_by ? " " ~ doc_matters.generator_program.name_version_and_compiler : "", + doc_matters.opt.action.generated_by ? " (generated " ~ doc_matters.generator_program.time_output_generated ~ ")" : "", + doc_matters.generator_program.project_name.strip, + doc_matters.generator_program.url_home.strip, + paper_size_orientation_latex.strip, + margins.portrait.strip, + ); + return _latex_head.strip; + } + string latex_body(D,M)( + const D doc_abstraction, + M doc_matters, + string paper_size_orientation, + ) { + string _latex_body = ""; + bool _multicolumns = false; + string _txt; + foreach (part; doc_matters.has.keys_seq.latex) { + foreach (obj; doc_abstraction[part]) { + switch (obj.metainfo.is_of_part) { + case "frontmatter": assert(part == "head" || "toc"); + _txt = obj.text + .sp_char_esc(obj) + .fontface; + switch (obj.metainfo.is_of_type) { + case "para": + switch (obj.metainfo.is_a) { + case "heading": + _txt = _txt.heading(obj, doc_matters, paper_size_orientation); + goto default; + case "toc": + break; + default: + _latex_body ~= _txt ~ "\n\n"; + _txt = ""; + break; + } + break; + default: break; + } + break; + case "body": assert(part == "body" || "head"); // surprise + _txt = obj.text + .sp_char_esc(obj) + .fontface; + switch (obj.metainfo.is_of_type) { + case "para": + switch (obj.metainfo.is_a) { + case "heading": + _txt = _txt.heading(obj, doc_matters, paper_size_orientation); + goto default; + case "para": + _txt = _txt.para(obj) + .bullets_and_indentation(obj) + .links_and_images(obj, doc_matters); + goto default; + default: + _latex_body ~= _txt ~ "\n\n"; + _txt = ""; + break; + } + break; + case "block": + switch (obj.metainfo.is_a) { + case "quote": + goto default; // TODO + case "group": /+ (hardspaces not honored) [remove any hardspace marker] +/ + _txt = _txt.group(obj, doc_matters) + .links_and_images(obj, doc_matters); + goto default; + case "block": /+ (hardspace honored) \hardspace +/ + _txt = _txt.block(obj, doc_matters) + .links_and_images(obj, doc_matters); + goto default; + case "verse": /+ (hardspace honored) \hardspace +/ + _txt = _txt.verse(obj, doc_matters) + .links_and_images(obj, doc_matters); + goto default; + case "code": /+ (hardspace honored) \begin{lstlisting} clear hardspace marker +/ + _txt = _txt.codeblock(obj, doc_matters); + goto default; + case "table": + _txt = _txt.table(obj, doc_matters, paper_size_orientation); + goto default; // TODO + default: + _latex_body ~= _txt ~ "\n\n"; + _txt = ""; + break; + } + break; + default: break; + } + break; + case "backmatter": + assert(part == "endnotes" || "glossary" || "bibliography" || "bookindex" || "blurb" || "tail"); + _txt = obj.text + .sp_char_esc(obj) + .fontface; + switch (obj.metainfo.is_of_type) { + case "para": + if (part != "bookindex" && _multicolumns) { + _multicolumns = false; + _latex_body ~= "\n\\end{multicols}\n"; + } + switch (obj.metainfo.is_a) { + case "heading": + if (part == "bookindex") { + _multicolumns = true; + } + _txt = _txt.heading(obj, doc_matters, paper_size_orientation, part); + goto default; + case "endnote": assert(part == "endnotes"); + /* uncomment code to reinstate endnotes in endnote section */ + // _txt = _txt.para(obj) + // .bullets_and_indentation(obj) + // .links_and_images(obj, doc_matters); + // goto default; + break; + case "glossary": assert(part == "glossary"); + _txt = _txt.para(obj) + .bullets_and_indentation(obj) + .links_and_images(obj, doc_matters); + goto default; + case "bibliography": assert(part == "bibliography"); + _txt = _txt.para(obj) + .bullets_and_indentation(obj); + goto default; + case "bookindex": assert(part == "bookindex"); + /+ two column, special section +/ + _txt = _txt.bookindex(obj) + .links_and_images(obj, doc_matters); + goto default; + case "blurb": assert(part == "blurb"); + _txt = _txt.para(obj) + .bullets_and_indentation(obj) + .links_and_images(obj, doc_matters); + goto default; + default: + _latex_body ~= (part == "bookindex" && obj.metainfo.is_a != "heading") + ? _txt : (_txt ~ "\n\n"); + _txt = ""; + break; + } + break; + default: break; + } + break; + case "comment": + break; + default: + { /+ debug +/ + if (doc_matters.opt.action.debug_do_latex + && doc_matters.opt.action.vox_gt1) { + writeln(__FILE__, ":", __LINE__, ": ", obj.metainfo.is_of_part); + writeln(__FILE__, ":", __LINE__, ": ", obj.metainfo.is_a); + writeln(__FILE__, ":", __LINE__, ": ", obj.text); + } + } + break; + } + } + } + if (_multicolumns) { + _multicolumns = false; + _latex_body ~= "\n\\end{multicols}\n"; + } + return _latex_body; + } + string latex_tail(M)( + M doc_matters, + string paper_size_orientation, + ) { + string _latex_tail = format(q"┃ + +\end{document} + ┃", + // doc_matters.conf_make_meta.meta.title_full, + // doc_matters.conf_make_meta.meta.creator_author, + ); + return _latex_tail; + } + void writeOutputLaTeX(T,M)( + const T latex_content, + M doc_matters, + string paper_size_orientation, + ) { + auto pth_latex = spinePathsLaTeX(doc_matters); + try { + { /+ debug +/ + if (doc_matters.opt.action.debug_do_latex + && doc_matters.opt.action.vox_gt1) { + writeln(latex_content.head); + writeln(latex_content.content); + writeln(latex_content.tail); + } + } + if (!exists(pth_latex.latex_path_stuff)) { + (pth_latex.latex_path_stuff).mkdirRecurse; + } + if (doc_matters.opt.action.vox_gt0) { + writeln(" ", pth_latex.latex_file_with_path(paper_size_orientation)); + } + { + auto f = File(pth_latex.latex_file_with_path(paper_size_orientation), "w"); + f.writeln(latex_content.head); + f.writeln(latex_content.content); + f.writeln(latex_content.tail); + foreach (image; doc_matters.srcs.image_list) { + string fn_src_in = doc_matters.src.image_dir_path ~ "/" ~ image; + string fn_src_out_file = pth_latex.latex_path_stuff ~ "/" ~ image; + if (exists(fn_src_in)) { + fn_src_in.copy(fn_src_out_file); + } + } + } + if (!exists(pth_latex.latex_path_stuff ~ "/index.html")) { + import sisudoc.io_out.html_snippet; + mixin htmlSnippet; + auto f = File(pth_latex.latex_path_stuff ~"/index.html", "w"); + f.writeln(format_html_blank_page_guide_home( + "../../css/html_scroll.css", + (doc_matters.opt.action.webserver_url_doc_root.length > 0) + ? doc_matters.opt.action.webserver_url_doc_root + : doc_matters.conf_make_meta.conf.w_srv_data_root_url + , + "../../index.html", + )); + } + // should be in latex init and done just once, doc_matters not passed there though + if (!exists(pth_latex.base ~ "/index.html")) { + import sisudoc.io_out.html_snippet; + mixin htmlSnippet; + auto f = File(pth_latex.base ~"/index.html", "w"); + f.writeln(format_html_blank_page_guide_home( + "../css/html_scroll.css", + (doc_matters.opt.action.webserver_url_doc_root.length > 0) + ? doc_matters.opt.action.webserver_url_doc_root + : doc_matters.conf_make_meta.conf.w_srv_data_root_url, + "../index.html", + )); + } + if (!exists(pth_latex.base_sty ~ "/index.html")) { + import sisudoc.io_out.html_snippet; + mixin htmlSnippet; + auto f = File(pth_latex.base_sty ~"/index.html", "w"); + f.writeln(format_html_blank_page_guide_home( + "../../css/html_scroll.css", + (doc_matters.opt.action.webserver_url_doc_root.length > 0) + ? doc_matters.opt.action.webserver_url_doc_root + : doc_matters.conf_make_meta.conf.w_srv_data_root_url, + "../../index.html", + )); + } + } catch (ErrnoException ex) { + // handle error + } + } + void outputLaTeX(D,M)( + const D doc_abstraction, + M doc_matters, + ) { + struct LaTeX { + string head; + string content; + string tail; + } + auto latex = LaTeX(); + foreach (paper_size_orientation; doc_matters.conf_make_meta.conf.set_papersize) { + latex.head = latex_head(doc_matters, paper_size_orientation); + latex.content = latex_body(doc_abstraction, doc_matters, paper_size_orientation); + latex.tail = latex_tail(doc_matters, paper_size_orientation); + latex.writeOutputLaTeX(doc_matters, paper_size_orientation); + } + } +} +template outputLaTeXstyInit() { + import sisudoc.io_out; + auto paper = paperLaTeX; + void writeOutputLaTeXstyStatic( + string latex_sty, + string output_dir, + string filename, + ) { + if ((output_dir.length > 0) + && isValidPath(output_dir) + ) { + auto pth_latex = spinePathsLaTeXsty(output_dir); + try { + import std.file; + if (!exists(pth_latex.base_sty)) { + (pth_latex.base_sty).mkdirRecurse; + } + { + auto f = File(pth_latex.latex_document_header_sty(filename), "w"); + f.writeln(latex_sty); + } + } catch (ErrnoException ex) { + // handle error + } + } + } + void outputLaTeXstyInit()( + string output_dir, + bool generated_by, + string name_version_and_compiler, + string time_output_generated, + ) { + string latex_sty = outputLaTeXstyStatic!()(generated_by, name_version_and_compiler, time_output_generated); + latex_sty.writeOutputLaTeXstyStatic(output_dir, "spineShared.sty"); + auto sty_a4p = paper.a4.portrait; + auto latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a4p, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a4p.stylesheet ~ ".sty"); + auto sty_a4l = paper.a4.landscape; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a4l, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a4l.stylesheet ~ ".sty"); + auto sty_b4p = paper.b4.portrait; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_b4p, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_b4p.stylesheet ~ ".sty"); + auto sty_b4l = paper.b4.landscape; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_b4l, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_b4l.stylesheet ~ ".sty"); + auto sty_a5p = paper.a5.portrait; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a5p, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a5p.stylesheet ~ ".sty"); + auto sty_a5l = paper.a5.landscape; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a5l, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a5l.stylesheet ~ ".sty"); + auto sty_letter_p = paper.letter.portrait; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_letter_p, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_letter_p.stylesheet ~ ".sty"); + auto sty_letter_l = paper.letter.landscape; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_letter_l, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_letter_l.stylesheet ~ ".sty"); + auto sty_legal_p = paper.legal.portrait; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_legal_p, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_legal_p.stylesheet ~ ".sty"); + auto sty_legal_l = paper.legal.landscape; + latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_legal_l, generated_by, name_version_and_compiler, time_output_generated); + latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_legal_l.stylesheet ~ ".sty"); + } +} +template outputLaTeXstyStatic() { + import + std.format, + std.conv : to; + string outputLaTeXstyStatic( + bool generated_by, + string name_version_and_compiler, + string time_output_generated, + ) { + string latex_sty = format(q"┃%%%% spine LaTeX output%s%s +%% - called by the .sty containing the paper dimensions (size and orientation) to be used +%% - spineShared.sty used by all spine documents (called indirectly) +\ProvidesPackage{./sty/spineShared} +\usepackage{multicol} +\setlength{\marginparsep}{4mm} +\setlength{\marginparwidth}{8mm} +\usepackage[scaled]{dejavu} +\renewcommand*\familydefault{\sfdefault} +\usepackage{inconsolata} +\usepackage[T1]{fontenc} +\usepackage{newunicodechar} +%% \usepackage[utf8]{inputenc} +\usepackage{alltt} +\usepackage[ + unicode=true, + pdfusetitle, + pdfsubject={}, + pdfkeywords={}, %% keywords list {} {} {}, + pdftoolbar=true, + pdfmenubar=true, + pdfwindowui=true, + pdffitwindow=false, %% window fit to page when opened + pdfstartview={FitH}, %% fits the width of the page to the window + pdfnewwindow=true, %% links in new window + pdfborder={0 0 1}, + plainpages=false, %% was true + bookmarks=true, + bookmarksopen=false, + bookmarksnumbered=false, + backref=false, + breaklinks=false, + colorlinks=true, + urlcolor=black, + filecolor=black, + linkcolor=black, + citecolor=black, %% links_mono_or_color_set +]{hyperref} +\PassOptionsToPackage{hyphens}{url}\usepackage{hyperref} +\usepackage[usenames]{color} +\definecolor{myblack}{rgb}{0,0,0} +\definecolor{myred}{rgb}{0.75,0,0} +\definecolor{mygreen}{rgb}{0,0.5,0} +\definecolor{myblue}{rgb}{0,0,0.5} +\definecolor{mywhite}{rgb}{1,1,1} +\usepackage{textcomp} +\usepackage[parfill]{parskip} +\usepackage[normalem]{ulem} +\usepackage{soul} +\usepackage{longtable} +\usepackage{graphicx} +\usepackage[tc]{titlepic} +\usepackage{amssymb} +\usepackage{amsmath} +\usepackage[cm]{sfmath} +\usepackage{underscore} +\usepackage{listings} +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{4} +\usepackage{bookmark} +\usepackage{microtype} +\makeatletter +\usepackage[multiple,ragged]{footmisc} +\setlength\footnotemargin{12pt} +\usepackage[para]{manyfoot} +\DeclareNewFootnote{A} +\makeatother +\chardef\txtbullet="2022 +\chardef\tilde="7E +\def\asterisk{{\rm \char42} } +\definecolor{Light}{gray}{.92} +\definecolor{listinggray}{gray}{0.9} +\definecolor{lbcolor}{rgb}{0.9,0.9,0.9} +\lstset{ + backgroundcolor=\color{lbcolor}, + tabsize=4, + rulecolor=, + language=, + basicstyle={\ttfamily\scriptsize}, + upquote=true, + columns=fixed, + showstringspaces=false, + extendedchars=true, + breaklines=true, + prebreak = \raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}}, + frame=single, + showtabs=false, + showspaces=false, + showstringspaces=false, + identifierstyle=\ttfamily, + keywordstyle=\color[rgb]{0,0,1}, + commentstyle=\color[rgb]{0.133,0.545,0.133}, + stringstyle=\color[rgb]{0.627,0.126,0.941}, +} +\DeclareTOCStyleEntry[numwidth+=8pt]{part}{part} +\DeclareTOCStyleEntry[numwidth+=4pt]{section}{section} +\DeclareTOCStyleEntry[numwidth+=3pt]{section}{paragraph} +\DeclareTOCStyleEntry[numwidth+=3pt]{section}{subparagraph} +\DeclareTOCStyleEntry[numwidth+=3pt]{section}{subsection} +\DeclareTOCStyleEntries[indent+=4pt]{section}{section,subsection,subsubsection} +\DeclareTOCStyleEntries[numwidth+=3pt]{section}{paragraph,subparagraph} +\newenvironment{ParagraphIndent}[1]{%% + \begin{list}{}{%% + \setlength\topsep{0pt}%% + \addtolength{\leftmargin}{#1} + \setlength\parsep{0pt plus 1pt}%% + } + \item[] +} {\end{list}} +\newenvironment{ParagraphHang}[2]{%% + \begin{list}{}{%% + \setlength\topsep{0pt}%% + \addtolength{\leftmargin}{#1} + \itemindent=#2 + \setlength\parsep{0pt plus 1pt}%% + } + \item[] +} {\end{list}} +\newenvironment{Bullet}[1]{%% + \begin{list}{}{%% + \setlength\topsep{0pt}%% + \addtolength{\leftmargin}{#1} + \itemindent=-1em + \setlength\parsep{0pt plus 1pt}%% + } + \item[] + $\txtbullet$\hspace{\enspace} +} {\end{list}} +\newcommand{\monosp}[1]{\normaltext\ttfamily\texbackslash#1} +\newcommand{\br}{\hfill\break} +\newcommand{\brl}[1]{%% + \ifx&%% + \hfill\break + \else + \vspace{#1ex} + \fi +} +\newcommand{\brln}{\hspace*{\fill}\linebreak} +\newcommand{\objBlockOpen}{%% + \setlength{\parskip}{0.5ex plus0.2ex minus0.1ex}\raggedright + \begin{footnotesize} +} +\newcommand{\objBlockClose}{%% + \end{footnotesize} + \setlength{\parskip}{1ex plus0.5ex minus0.2ex} +} +\newcommand{\objGroupOpen}{%% + \setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} + \begin{footnotesize} +} +\newcommand{\objGroupClose}{%% + \end{footnotesize} +} +\newcommand{\objPoemVerseOpen}{%% + \setlength{\parskip}{0.1ex plus0.1ex minus0.1ex} + \begin{footnotesize} + +} +\newcommand{\objPoemVerseClose}{%% + + \end{footnotesize} + \setlength{\parskip}{1ex plus0.5ex minus0.2ex} + \linebreak +} +\newcommand{\parasep}{%% + \smallskip \begin{center}*\hspace{2em}*\hspace{2em}*\end{center} \br +} +\newcommand{\spaces}[1]{{\hspace*{#1ex}}} +\newcommand{\s}{\hspace*{1ex}} +\newcommand{\hardspace}{\hspace*{1ex}} +\newcommand{\-}{\hspace*{1ex}} +\newcommand{\caret}{{\^{~}}} +\newcommand{\pipe}{{\textbar}} +\newcommand{\curlyOpen}{{} +\newcommand{\curlyClose}{}} +\newcommand{\lt}{{UseTextSymbol{OML}{<}}} +\newcommand{\gt}{{UseTextSymbol{OML}{>}}} +\newcommand{\slash}{{/}} +\newcommand{\underscore}{\_} +\newcommand{\exclaim}{\Verbatim{!}} +\newcommand{\linktext}[2]{%% + {\href{#1} + {\;\ulcorner\,\textup{{#2}}\,\lrcorner}} +} +\newcommand{\linkurl}[2]{%% + \;{\href{#1} + {\;\scriptsize\ttfamily\ulcorner\,\textup{{#2}}\,\lrcorner}} +} +\newcommand{\link}[2]{%% + {\begin{scriptsize}\color{black}\urlstyle{tt}\href{#1} + {\;\ulcorner\,{#2}\,\lrcorner}\end{scriptsize}} +} +\newcommand{\objCodeBlock}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} +\newcommand{\objCodeOpen}{%% + \normaltext\raggedright\small\ttfamily\texbackslash + \begin{lstlisting} +} +\newcommand{\objCodeClose}{%% + \end{lstlisting} +} +\newcommand{\ocn}[1]{%% + \setlength{\parindent}{0em} + \ifx&%% #1 is empty + \hspace{-0.5ex}{\marginpar{\begin{tiny}\end{tiny}}} + \else%% #1 is nonempty + \hspace{-0.5ex}{\marginpar{\begin{tiny}\hspace{0em}\hypertarget{#1}{#1}\end{tiny}}} + \fi +} +\newcommand{\ocnhold}[1]{%% + \begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{#1}{#1}\end{tiny}}} +} +\newcommand{\objCodeBlockHold}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} +\newcommand{\objTableOpen}[1]{%% + \setlength{\LTleft}{0pt} + \setlength{\LTright}{\fill} + \begin{tiny} + \begin{longtable}{#1} +} +\newcommand{\objTableClose}{%% + \end{longtable} + \end{tiny} +} +%% \tolerance=300 +%% \clubpenalty=300 +%% \widowpenalty=300 +%% \usepackage{atbegshi} %% http://ctan.org/pkg/atbegshi %% (BUG tmp FIX deal with problem, remove first page which is blank) +%% \AtBeginDocument{\AtBeginShipoutNext{\AtBeginShipoutDiscard}} %% (BUG tmp FIX deal with problem, remove first page which is blank) +┃", + generated_by ? " " ~ name_version_and_compiler : "", + generated_by ? " (generated " ~ time_output_generated ~ ")" : "", +); + return latex_sty; + } +} +template outputLaTeXstyPaperSizeAndOrientation() { + import + std.format, + std.conv : to; + auto outputLaTeXstyPaperSizeAndOrientation(P)( + P doc_sty_info, + bool generated_by, + string name_version_and_compiler, + string time_output_generated, + ) { + string latex_sty = format(q"┃%%%% spine LaTeX output%s%s +%% - called by .tex document to set paper dimensions (size and orientation) +%% - calls spineShared.sty used/shared by all spine documents +\ProvidesPackage{./sty/%s} +\usepackage{geometry} +\geometry{ + %s, + %s, + left=%s, + right=%s, + top=%s, + bottom=%s, +} +\usepackage{./sty/spineShared}┃", + generated_by ? " " ~ name_version_and_compiler : "", + generated_by ? " (generated " ~ time_output_generated ~ ")" : "", + doc_sty_info.stylesheet, + doc_sty_info.papersize, + doc_sty_info.orient, + doc_sty_info.margin_left, + doc_sty_info.margin_right, + doc_sty_info.margin_top, + doc_sty_info.margin_bottom, +); + return latex_sty; + } +} -- cgit v1.2.3