diff options
| author | Ralph Amissah <ralph.amissah@gmail.com> | 2024-04-10 22:24:34 -0400 | 
|---|---|---|
| committer | Ralph Amissah <ralph.amissah@gmail.com> | 2024-04-10 23:08:18 -0400 | 
| commit | 90873fabd7451e1dd8c4b39303906e19bdc481f7 (patch) | |
| tree | 2dbb0e41f3e9c761645c8b37dafe979a01d38d32 /src/sisudoc/io_out/latex.d | |
| parent | 0.15.0 (diff) | |
0.16.0 sisudoc (src/sisudoc sisudoc spine)
- src/sisudoc (replaces src/doc_reform)
- sisudoc spine (used more)
Diffstat (limited to 'src/sisudoc/io_out/latex.d')
| -rw-r--r-- | src/sisudoc/io_out/latex.d | 1771 | 
1 files changed, 1771 insertions, 0 deletions
| 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; +  } +} | 
