From d21e5b572433f39111282805435e6337f0e1b4c0 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Mon, 20 May 2019 10:20:38 -0400 Subject: 0.7.2 latex (for pdf) (initial stub) --- org/default_paths.org | 36 + org/default_regex.org | 18 + org/doc_reform.org | 20 +- org/meta_abstraction.org | 9 + org/output_hub.org | 14 +- org/output_latex.org | 1832 ++++++++++++++++++++++++++++++++ src/doc_reform/doc_reform.d | 18 +- src/doc_reform/meta/metadoc_from_src.d | 9 + src/doc_reform/output/hub.d | 8 +- src/doc_reform/output/latex.d | 1164 ++++++++++++++++++++ src/doc_reform/output/paths_output.d | 29 + src/doc_reform/output/rgx.d | 12 + util/dr_tex.rb | 70 ++ views/version.txt | 2 +- 14 files changed, 3235 insertions(+), 6 deletions(-) create mode 100644 org/output_latex.org create mode 100644 src/doc_reform/output/latex.d create mode 100755 util/dr_tex.rb diff --git a/org/default_paths.org b/org/default_paths.org index 5e4f958..859415c 100644 --- a/org/default_paths.org +++ b/org/default_paths.org @@ -926,6 +926,7 @@ import doc_reform.meta.rgx; <> <> <> +<> <> #+END_SRC @@ -1297,6 +1298,41 @@ template DocReformPathsODT() { } #+END_SRC +** _latex_ :latex: + +#+name: template_paths_latex +#+BEGIN_SRC d +template DocReformPathsLaTeX() { + mixin DocReformRgxInit; + static auto rgx = Rgx(); + auto DocReformPathsLaTeX(M)( + M doc_matters, + ) { + struct _PathsStruct { + string base_filename(string fn_src) { + return fn_src.baseName.stripExtension; + } + string base() { + auto out_pth = DocReformOutPaths!()(doc_matters.output_path, doc_matters.src.language); + string base_dir = "latex"; + return asNormalizedPath((out_pth.output_root).chainPath(base_dir)).array; + } + string latex_path_stuff() { + return asNormalizedPath(base.chainPath(base_filename(doc_matters.src.filename))).array; + } + string latex_file_with_path() { + return asNormalizedPath(base.chainPath(base_filename(doc_matters.src.filename) ~ "." ~ doc_matters.src.language ~ ".tex")).array; + } + string images() { + string image_dir = "image"; + return asNormalizedPath((base).chainPath(image_dir)).array; + } + } + return _PathsStruct(); + } +} +#+END_SRC + ** _sqlite_ :sqlite: *** discrete diff --git a/org/default_regex.org b/org/default_regex.org index e8b6b3f..2958027 100644 --- a/org/default_regex.org +++ b/org/default_regex.org @@ -415,6 +415,24 @@ static xhtml_greater_than = ctRegex!(`[>]`, "m"); / static xhtml_line_break = ctRegex!(` [\\]{2}`, "m"); //
#+END_SRC +*** latex special characters + +#+name: sp_ch_xhtml_rgx +#+BEGIN_SRC d +static latex_special_char_shortlist = ctRegex!(`([%$_#&\\])`); +static latex_special_char_curlybraces = ctRegex!(`([{}])`); +static latex_special_char = ctRegex!(`([%${}_#&\\])`); +static latex_special_char_for_escape = ctRegex!(`([%${}_#\\])`); +static latex_special_char_for_escape_and_braces = ctRegex!(`([&])`); +static latex_special_char_for_escape_url = ctRegex!(`([%])`); +static latex_special_char_escaped = ctRegex!(`\\([%${}_#\\])`); +static latex_special_char_escaped_braced = ctRegex!(`[{]\\([&])[}]`); +static latex_identify_inline_link = ctRegex!(`┥.+?┝┤\S+?├`, "mg"); +static latex_clean_internal_link = ctRegex!(`^(?:#|¤\S+?#)`, "m"); +static latex_identify_inline_fontface = ctRegex!(`\\([_#$]┨.+?┣)\\([_#$])`, "mg"); +static latex_clean_bookindex_linebreak = ctRegex!(`\s*\\\\\\\\\s*`, "m"); +#+END_SRC + * 2. ctRegex defaults shared by meta & output (generic) ** misc generic diff --git a/org/doc_reform.org b/org/doc_reform.org index ac0aa4d..12eb46a 100644 --- a/org/doc_reform.org +++ b/org/doc_reform.org @@ -27,7 +27,7 @@ struct Version { int minor; int patch; } -enum _ver = Version(0, 7, 1); +enum _ver = Version(0, 7, 2); #+END_SRC ** compilation restrictions (supported compilers) @@ -314,6 +314,7 @@ bool[string] opts = [ "html" : false, "html-seg" : false, "html-scroll" : false, + "latex" : false, "light" : false, "manifest" : false, "ocn" : true, @@ -321,6 +322,7 @@ bool[string] opts = [ "odt" : false, "parallel" : false, "parallel-subprocesses" : false, + "pdf" : false, "quiet" : false, "pod" : false, "serial" : false, @@ -367,6 +369,7 @@ auto helpInfo = getopt(args, "html", "--html process html output", &opts["html"], "html-seg", "--html-seg process html output", &opts["html-seg"], "html-scroll", "--html-seg process html output", &opts["html-scroll"], + "latex", "--latex output for pdfs", &opts["latex"], "light", "--light default light theme", &opts["light"], "manifest", "--manifest process manifest output", &opts["manifest"], "ocn", "--ocn object cite numbers (default)", &opts["ocn"], @@ -375,6 +378,7 @@ auto helpInfo = getopt(args, "parallel", "--parallel parallelisation", &opts["parallel"], "parallel-subprocesses", "--parallel-subprocesses nested parallelisation", &opts["parallel-subprocesses"], "quiet|q", "--quiet output to terminal", &opts["quiet"], + "pdf", "--pdf latex output for pdfs", &opts["pdf"], "pod", "--pod doc reform pod source content bundled", &opts["pod"], "serial", "--serial serial processing", &opts["serial"], "source", "--source markup source text content", &opts["source"], @@ -417,7 +421,7 @@ if (helpInfo.helpWanted) { #+NAME: doc_reform_args #+BEGIN_SRC d -enum outTask { pod, source, sqlite, sqlite_multi, odt, epub, html_scroll, html_seg, html_stuff } +enum outTask { pod, source, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff } struct OptActions { bool assertions() { return opts["assertions"]; @@ -469,6 +473,12 @@ struct OptActions { { _is = true; } else { _is = false; } return _is; } + bool latex() { + bool _is; + if ( opts["latex"] || opts["pdf"]) + { _is = true; } else { _is = false; } + return _is; + } bool odt() { bool _is; if ( opts["odf"] || opts["odt"]) @@ -591,6 +601,7 @@ struct OptActions { || html || epub || odt + || latex || manifest || pod || source @@ -629,6 +640,9 @@ struct OptActions { if (odt) { schedule ~= outTask.odt; } + if (latex) { + schedule ~= outTask.latex; + } return schedule.sort().uniq; } bool abstraction() { @@ -640,6 +654,7 @@ struct OptActions { || html || epub || odt + || latex || manifest || sqlite_discrete || sqlite_delete @@ -653,6 +668,7 @@ struct OptActions { || html || epub || odt + || latex || sqlite_discrete || sqlite_update ) { _is = true; } else { _is = false; } diff --git a/org/meta_abstraction.org b/org/meta_abstraction.org index 4192d3b..317be72 100644 --- a/org/meta_abstraction.org +++ b/org/meta_abstraction.org @@ -2916,30 +2916,36 @@ string[][string] document_section_keys_sequenced = [ "scroll": ["head", "toc", "body",], "seg": ["head", "toc", "body",], "sql": ["head", "body",], + "latex": ["head", "toc", "body",] ]; if (document_the["endnotes"].length > 1) { document_section_keys_sequenced["scroll"] ~= "endnotes"; document_section_keys_sequenced["seg"] ~= "endnotes"; + document_section_keys_sequenced["latex"] ~= "endnotes"; } if (document_the["glossary"].length > 1) { document_section_keys_sequenced["scroll"] ~= "glossary"; document_section_keys_sequenced["seg"] ~= "glossary"; document_section_keys_sequenced["sql"] ~= "glossary"; + document_section_keys_sequenced["latex"] ~= "glossary"; } if (document_the["bibliography"].length > 1) { document_section_keys_sequenced["scroll"] ~= "bibliography"; document_section_keys_sequenced["seg"] ~= "bibliography"; document_section_keys_sequenced["sql"] ~= "bibliography"; + document_section_keys_sequenced["latex"] ~= "bibliography"; } if (document_the["bookindex"].length > 1) { document_section_keys_sequenced["scroll"] ~= "bookindex"; document_section_keys_sequenced["seg"] ~= "bookindex"; document_section_keys_sequenced["sql"] ~= "bookindex"; + document_section_keys_sequenced["latex"] ~= "bookindex"; } if (document_the["blurb"].length > 1) { document_section_keys_sequenced["scroll"] ~= "blurb"; document_section_keys_sequenced["seg"] ~= "blurb"; document_section_keys_sequenced["sql"] ~= "blurb"; + document_section_keys_sequenced["latex"] ~= "blurb"; } if ((opt_action.html) || (opt_action.html_scroll) @@ -7540,6 +7546,9 @@ template docSectKeysSeq() { string[] sql() { return document_section_keys_sequenced["sql"]; } + string[] latex() { + return document_section_keys_sequenced["latex"]; + } } return doc_sect_keys_seq(); } diff --git a/org/output_hub.org b/org/output_hub.org index bd56940..d974516 100644 --- a/org/output_hub.org +++ b/org/output_hub.org @@ -33,7 +33,7 @@ template outputHub() { mixin Msg; auto msg = Msg!()(doc_matters); static auto rgx = Rgx(); - enum outTask { pod, source, sqlite, sqlite_multi, odt, epub, html_scroll, html_seg, html_stuff } + enum outTask { pod, source, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff } void Scheduled(D,I)(int sched, D doc_abstraction, I doc_matters) { auto msg = Msg!()(doc_matters); <> @@ -138,6 +138,18 @@ if (sched == outTask.html_stuff) { } #+END_SRC +**** latex / pdf :latex:pdf: + +#+name: output_scheduled_task +#+BEGIN_SRC d +if (sched == outTask.latex) { + msg.v("latex processing... (available for downstream processing & pdf output"); + import doc_reform.output.latex; + outputLaTeX!()(doc_abstraction, doc_matters); + msg.vv("latex done"); +} +#+END_SRC + **** odf / odt :odf:odt: #+name: output_scheduled_task diff --git a/org/output_latex.org b/org/output_latex.org new file mode 100644 index 0000000..be0e653 --- /dev/null +++ b/org/output_latex.org @@ -0,0 +1,1832 @@ +#+TITLE: doc_reform output latex +#+DESCRIPTION: documents - structuring, publishing in multiple formats & search +#+FILETAGS: :doc_reform:output:latex:pdf: +#+AUTHOR: Ralph Amissah +#+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]] +#+COPYRIGHT: Copyright (C) 2015 - 2019 Ralph Amissah +#+LANGUAGE: en +#+STARTUP: indent content hideblocks hidestars +#+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t +#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc +#+OPTIONS: author:nil email:nil creator:nil timestamp:nil +#+PROPERTY: header-args :results silent :padline no :exports code :cache no :noweb yes +#+EXPORT_SELECT_TAGS: export + +- [[./doc_reform.org][doc_reform]] [[./][org/]] +- [[./output_hub.org][output_hub]] + +* latex +** module template :latex:pdf:module: + +#+BEGIN_SRC d :tangle "../src/doc_reform/output/latex.d" :noweb yes +module doc_reform.output.latex; +template outputLaTeX() { + <> + mixin InternalMarkup; // watch + mixin DocReformOutputRgxInit; + auto rgx = Rgx(); + <> +<> + <> + <> +<> + <> + <> +<> + <> + <> + <> + <> +<> + <> + <> +} +#+END_SRC + +** write latex output :latex:out: + +#+name: output_latex +#+BEGIN_SRC d +void writeOutputLaTeX(T,M)( + const T latex_content, + M doc_matters, +) { + auto pth_latex = DocReformPathsLaTeX(doc_matters); + try { + { /+ debug +/ + if (doc_matters.opt.action.debug_do + && doc_matters.opt.action.verbose) { + 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; + } + writeln(pth_latex.latex_file_with_path); + auto f = File(pth_latex.latex_file_with_path, "w"); + f.writeln(latex_content.head); + f.writeln(latex_content.content); + f.writeln(latex_content.tail); + foreach (image; doc_matters.srcs.image_list) { + auto fn_src_in = doc_matters.src.image_dir_path ~ "/" ~ image; + auto fn_src_out_file = pth_latex.latex_path_stuff ~ "/" ~ image; + if (exists(fn_src_in)) { + fn_src_in.copy(fn_src_out_file); + } + } + } catch (ErrnoException ex) { + // handle error + } +} +#+END_SRC + +** latex output hub [#A] :latex:pdf:out: + +#+name: output_latex +#+BEGIN_SRC d +void outputLaTeX(D,M)( + const D doc_abstraction, + M doc_matters, +) { + struct LaTeX { + string head; + string content; + string tail; + } + auto latex = LaTeX(); + latex.head = latex_head(doc_matters); + latex.content = latex_body(doc_abstraction, doc_matters); + latex.tail = latex_tail(doc_matters); + latex.writeOutputLaTeX(doc_matters); +} +#+END_SRC + +* stuff +** output imports + +#+name: output_latex_imports +#+BEGIN_SRC d +import doc_reform.output; +import + std.digest.sha, + std.file, + std.outbuffer, + std.uri, + std.conv : to; +#+END_SRC + +** shared +*** paper dimensions (struct) + +#+name: output_latex_shared +#+BEGIN_SRC d + auto paper() { + struct PaperType { + auto a4() { + struct A4 { + auto portrait() { + struct V { + uint w = 160; + uint h = 228; + uint img_px = 450; + } + return V(); + } + auto landscape() { + struct H { + uint w = 238; + uint h = 160; + uint img_px = 300; + } + return H(); + } + } + return A4(); + } + auto a5() { + struct A5 { + auto portrait() { + struct V { + uint w = 112; + uint h = 162; + uint img_px = 280; + } + return V(); + } + auto landscape() { + struct H { + uint w = 152; + uint h = 100; + uint img_px = 190; + } + return H(); + } + } + return A5(); + } + auto b4() { + struct B4 { + auto portrait() { + struct V { + uint w = 140; + uint h = 204; + uint img_px = 356; + } + return V(); + } + auto landscape() { + struct H { + uint w = 200; + uint h = 130; + uint img_px = 260; + } + return H(); + } + } + return B4(); + } + auto letter() { + struct Letter { + auto portrait() { + struct V { + uint w = 166; + uint h = 212; + uint img_px = 468; + } + return V(); + } + auto landscape() { + struct H { + uint w = 226; + uint h = 166; + uint img_px = 290; + } + return H(); + } + } + return Letter(); + } + auto legal() { + struct Legal { + auto portrait() { + struct V { + uint w = 168; + uint h = 286; + uint img_px = 474; + } + return V(); + } + auto landscape() { + struct H { + uint w = 296; + uint h = 166; + uint img_px = 420; + } + return H(); + } + } + return Legal(); + } + } + return PaperType(); + } +#+END_SRC + +*** latex \escape special characters +**** general + +#+name: output_latex_shared +#+BEGIN_SRC d +string sp_char_esc(O)( + string _txt, + const O obj, +) { + string _unescape_sp_char_esc()(string _txt) { + _txt = _txt + .replaceAll(rgx.latex_special_char_escaped, + format(q"┃%s┃", "$1")) + .replaceAll(rgx.latex_special_char_escaped_braced, + format(q"┃%s┃", "$1")); + return _txt; + } + string _unescape_fontface_esc()(string _txt) { + _txt = _txt.replaceAll(rgx.latex_identify_inline_fontface, + format(q"┃%s%s┃", "$1", "$2")); + return _txt; + } + if (obj.metainfo.is_a != "code") { + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx.latex_special_char_for_escape); + _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx.latex_special_char_for_escape_and_braces); + _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx.latex_identify_inline_link); + _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx.latex_identify_inline_fontface); + } + return _txt; +} +#+END_SRC + +#+name: output_latex_shared +#+BEGIN_SRC d +string sp_char_esc_txt()( + string _txt, +) { + string _unescape_sp_char_esc()(string _txt) { + _txt = _txt + .replaceAll(rgx.latex_special_char_escaped, + format(q"┃%s┃", "$1")) + .replaceAll(rgx.latex_special_char_escaped_braced, + format(q"┃%s┃", "$1")); + return _txt; + } + string _unescape_fontface_esc()(string _txt) { + _txt = _txt.replaceAll(rgx.latex_identify_inline_fontface, + format(q"┃%s%s┃", "$1", "$2")); + return _txt; + } + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx.latex_special_char_for_escape); + _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx.latex_special_char_for_escape_and_braces); + _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx.latex_identify_inline_link); + _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx.latex_identify_inline_fontface); + return _txt; +} +#+END_SRC + +*** not used latex \escape special characters + +#+BEGIN_SRC d +string sp_char_esc()( + string _txt, +) { + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx.latex_special_char); + return _txt; +} +#+END_SRC + +*** inline markup +**** fontface + +- bold, italics, underscore, strikethrough + +#+name: output_latex_shared +#+BEGIN_SRC d +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"┃$$^{\textrm{%s}}$$┃", "$1")) + .replaceAll(rgx.inline_subscript, format(q"┃$$_{\textrm{%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; +} +#+END_SRC + +**** spaces +***** leading hardspace + +#+name: output_latex_shared +#+BEGIN_SRC d +string leading_hardspaces()( + string _txt, +) { + string hardspaces(string _spaces) { + _spaces = _spaces + .replaceAll(rgx.space, "\\hardspace "); + return _spaces; + } + _txt = replaceAll!(m => hardspaces(m[0]))(_txt, rgx.spaces_line_start); + return _txt; +} +#+END_SRC + +***** nbsp character + +#+name: output_latex_shared +#+BEGIN_SRC d +string nbsp_char()(string _txt) { + if (_txt.match(rgx.nbsp_char)) { + _txt = _txt.replaceAll(rgx.nbsp_char, "\\hardspace "); + } + return _txt; +} +#+END_SRC + +***** remove nbsp character + +#+name: output_latex_shared +#+BEGIN_SRC d +string nbsp_char_to_space()(string _txt) { + if (_txt.match(rgx.nbsp_char)) { + _txt = _txt.replaceAll(rgx.nbsp_char, " "); + } + return _txt; +} +#+END_SRC + +**** links and images +***** links / urls + +#+name: output_latex_shared +#+BEGIN_SRC d +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 = DocReformPathsLaTeX(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]), " \\\\\n") + )(_linked_content, rgx.inline_image_info); + } + return _linked_content; + } + string _check_link(string _link) { + _link = _link + .replaceFirst(rgx.latex_clean_internal_link, "") + .replaceAll(rgx.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))) + ? format(q"┃\begin{scriptsize}\lefthalfcap\url{%s}\righthalfcup\end{scriptsize}┃", _check_link(m[1])) + : (m[2].match(rgx.uri)) // ERROR + ? format(q"┃%s\href{%s}%s{%s}┃", "\\\\\n", _check_link(m[2]), "\n", _if_images(m[1])) + : format(q"┃\hyperlink{%s}{%s}┃", _check_link(m[2]), _if_images(m[1])) + )(_txt, rgx.inline_link); + } + } + return _txt; +} +#+END_SRC + +*** footnotes +**** footnotes + +#+name: output_latex_shared +#+BEGIN_SRC d +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.replaceAll(rgx.inline_notes_al_regular_number_note, + format(_tex_note, + "$1", "$1", "$1", + "$2".strip + ).strip + ); + } + return _txt; +} +#+END_SRC + +**** footnote remove + +#+name: output_latex_shared +#+BEGIN_SRC d +string remove_footnotes()( + string _txt, +) { + if (_txt.match(rgx.inline_notes_al_gen)) { + _txt = replaceAll!(m => "")(_txt, rgx.inline_notes_al_gen); + } + return _txt; +} +#+END_SRC + +*** para +**** para + +#+name: output_latex_shared +#+BEGIN_SRC d +string para(O)( + string _txt, + O obj, +) { + if (obj.metainfo.is_of_type == "para") { + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.footnotes + ).strip; + } + return _txt; +} +#+END_SRC + +**** bookindex para + +#+name: output_latex_shared +#+BEGIN_SRC d +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.latex_clean_bookindex_linebreak, "\n") ~ "\n\\\\\n" + ); + } + return _txt; +} +#+END_SRC + +*** bullets & indentation + +#+name: output_latex_head +#+BEGIN_SRC d +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}$\txtbullet$\hspace{\enspace}%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; + _txt = format(q"┃\begin{ParagraphHang}{%smm}{%smm}%s \end{ParagraphHang}┃", + _indent, _hang, + _txt.footnotes + ).strip; + } + return _txt; +} +#+END_SRC + +*** heading + +#+name: output_latex_shared_0 +#+BEGIN_SRC d + string heading(O,M)( + string _txt, + O obj, + M doc_matters, + string _part = "" + ) { + if (obj.metainfo.is_a == "heading") { + string _tex_para; + 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\\\\\n\\begin{multicols}{2}"; + _pg_break = "\\clearpage\n"; + _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 = " \\\n"; + _title_add = ""; + goto default; + case 6: // 3 == subsubsection + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "subsubsection"; + _post = " \\\n"; + _title_add = ""; + goto default; + default: + if (obj.metainfo.heading_lev_markup == 0) { + _tex_para = q"┃\begin{document} +\title{%s} +\author{ \textnormal{%s}} +\date{\begin{tiny}%s\end{tiny}} +\pagenumbering{roman}\maketitle +\pagestyle{fancy} +\newpage +\markboth{%s}{%s} +\\\\[3]\ \linebreak Copyright {\begin{small}{\copyright\end{small}} %s \\ +%s +\pagestyle{fancy} +\clearpage┃"; + _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.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_full).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.rights_copyright).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.rights_license).sp_char_esc_txt, + ); + } else if (obj.metainfo.heading_lev_markup < 4) { + _tex_para = q"┃%s\part*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{part}{%s} +\markboth{%s}┃"; + _txt = format(_tex_para, + _pg_break, + obj.metainfo.object_number, + 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{none} +\setcounter{page}{1} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +\part*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{1}{1}\end{tiny}}}%s \newline %s} + +\clearpage +\markboth{%s}{%s} +\pagenumbering{gobble} +\renewcommand{\contentsname}{} +\tableofcontents +\markboth{%s}{%s} + +\clearpage +\pagenumbering{arabic} +\setcounter{page}{1} +\markboth{%s}{%s} +%% \null +\clearpage +\setcounter{page}{1}┃"; + _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_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.title_full).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*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{%s}{%s%s}%s%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + 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*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{%s}{%s%s}%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.footnotes.strip, + _sect, + _txt.remove_footnotes.strip, + _post, + _title_add, + ); + } + } + break; + } + } + return _txt.strip; + } +#+END_SRC + +*** grouped text +**** group + +- (hardspace not honored) clear hardspace marker + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +string group(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "group") { + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} +\begin{footnotesize} +%s +\end{footnotesize} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.footnotes.strip + ).strip; + } + return _txt; +} +#+END_SRC + +**** block + +- (hardspace honored) \hardspace + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +string block(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "block") { + // _txt = _txt.nbsp_char; + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} +\begin{footnotesize} +%s +\end{footnotesize} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +┃"; // \hardspace + /+ try both: +/ + _txt = _txt.split(rgx.br_newlines_linebreaks).join("\n\n"); // _txt = _txt.split(rgx.br_newlines_linebreaks).join(" \\\n"); + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.nbsp_char.footnotes.strip + ).strip; + } + return _txt; +} +#+END_SRC + +**** verse + +- (hardspace honored) \hardspace + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +string verse(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "verse") { + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.1ex plus0.1ex minus0.1ex} +\begin{footnotesize} + +%s + +\end{footnotesize} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +\linebreak +┃"; // \hardspace + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.nbsp_char.footnotes.split("\n").join("\n\n").strip + ).strip; + } + return _txt; +} +#+END_SRC + +**** codeblock + +- (hardspace honored) \begin{lstlisting} clear hardspace marker + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +string codeblock(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "code") { + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex}\begin{Codeblock} +\begin{lstlisting} +%s +\end{lstlisting} +\end{Codeblock} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.nbsp_char_to_space + ).strip; + } + return _txt; +} +#+END_SRC + +**** table + +- own set of rules + +***** tablarize + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +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 ~= "\\\\"; + } + auto t = tuple( + _table, + _tablenote, + ); + return t; +} +#+END_SRC + +***** table + +#+name: output_latex_shared_0 +#+BEGIN_SRC d +string table(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "table") { + auto _t = _txt.tablarize(obj); + string _table = _t[0]; + string _t_n = _t[1]; + string papertype = "a4"; + uint pw = 0; + switch (papertype) { + case "a4": pw = (paper.a4.portrait.w - 20); break; + case "a5": pw = (paper.a5.portrait.w - 20); break; + case "b4": pw = (paper.b4.portrait.w - 20); break; + case "letter": pw = (paper.letter.portrait.w - 20); break; + case "legal": pw = (paper.legal.portrait.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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}} +\setlength{\LTleft}{0pt} +\setlength{\LTright}{\fill} +\begin{tiny} +\begin{longtable}{%s} +%s +\end{longtable} +\end{tiny} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _colw, + _table, + ).strip; + } + return _txt; +} +#+END_SRC + +** latex parts +*** latex head :head: +**** latex head function + +#+name: output_latex_head +#+BEGIN_SRC d +string latex_head(M)( + M doc_matters, +) { +#+END_SRC + +**** latex head options +***** paper type dimensions +****** struct + +#+name: output_latex_head +#+BEGIN_SRC d + struct paperType { + string a4_portrait; + string a4_landscape; + string us_letter_portrait; + string us_letter_landscape; + } + auto paper = paperType(); +#+END_SRC + +****** a4, portrait + +#+name: output_latex_head_1 +#+BEGIN_SRC d + paper.a4_portrait = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\documentclass[12pt,a4paper,titlepage]{scrartcl} +\setlength{\textheight}{228mm} \setlength{\textwidth}{160mm} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** a4, landscape + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + paper.a4_landscape = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\documentclass[11pt,a4paper,landscape,titlepage,twocolumn]{scrartcl} +\setlength{\textheight}{160mm} \setlength{\textwidth}{238mm} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** us letter, portrait + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + paper.us_letter_portrait = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\documentclass[12pt,letterpaper,titlepage]{scrartcl} +\setlength{\textheight}{212mm} \setlength{\textwidth}{166mm} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** us letter, landscape + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + paper.us_letter_landscape = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\documentclass[11pt,letterpaper,landscape,titlepage,twocolumn]{scrartcl} +\setlength{\textheight}{166mm} \setlength{\textwidth}{226mm} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +***** paper margins +****** struct + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + struct paperMargins { + string portrait; + string landscape; + } + auto margins = paperMargins(); +#+END_SRC + +****** portrait + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + margins.portrait = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\setlength{\oddsidemargin}{0mm} \setlength{\evensidemargin}{0mm} +\setlength{\topmargin}{-12pt} \setlength{\headheight}{12pt} +\setlength{\headsep}{35pt} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** landscape + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + margins.landscape = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\setlength{\oddsidemargin}{6mm} \setlength{\evensidemargin}{6mm} +\setlength{\topmargin}{-12mm} \setlength{\headheight}{12pt} +\setlength{\headsep}{20pt} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +***** multicol +****** struct + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + struct columnsMulti { + string portrait; + string landscape; + } + auto multicol = columnsMulti(); +#+END_SRC + +****** portrait + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + multicol.portrait = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\usepackage{multicol} +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** landscape + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + multicol.landscape = ""; +#+END_SRC + +***** color links +****** struct + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + struct colorLinks { + string mono; + string color; + } + auto links = colorLinks(); +#+END_SRC + +****** mono + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + links.mono = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\usepackage[xetex, + colorlinks=true, + urlcolor=myblack, + filecolor=myblack, + linkcolor=myblack, +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +****** color + +#+name: output_latex_head_1_tex +#+BEGIN_SRC d + links.color = format(q"┃ +#+END_SRC + +#+name: output_latex_head_1_tex +#+BEGIN_SRC latex +\usepackage[xetex, + colorlinks=true, + urlcolor=myblue, %% \href{...}{...} external url + filecolor=mygreen, %% \href{...} local file + linkcolor=myred, %% \href{...} and \pageref{...} +#+END_SRC + +#+name: output_latex_head_1_close +#+BEGIN_SRC d +┃", + ); +#+END_SRC + +**** latex head starts + +#+name: output_latex_head_0 +#+BEGIN_SRC d + string _latex_head = format(q"┃%%%% DocReform LaTeX output +#+END_SRC + +***** description comment + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +%%%% Generated by: %s +%%%% D version: ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux-gnu] +%%%% LaTeX output +%%%% Last Generated on: +%%%% SiSU http://www.jus.uio.no/sisu +#+END_SRC + +***** paper type (a4, letter, ...; ( portrait | landscape )) + +- paper.a4_portrait +- paper.a4_landscape +- paper.us_letter_portrait +- paper.us_letter_landscape + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +%s +#+END_SRC + +***** paper margins (portrait | landscape) + +- margins.portrait +- margins.landscape + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +%s +#+END_SRC + +***** margin shared + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\setlength{\marginparsep}{4mm} +\setlength{\marginparwidth}{8mm} +#+END_SRC + +***** multicol (portrait | landscape) + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +%s +#+END_SRC + +***** language & font + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage{polyglossia, ucs, fontspec, xltxtra, xunicode} +\setmainlanguage{english} +\setotherlanguage{} +\setmainfont{Liberation Sans} +\setmonofont[Scale=0.85]{Liberation Mono} +#+END_SRC + +%% \setsansfont{Liberation Sans} +%% \setromanfont{Liberation Serif} + +***** latex head + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage{alltt} +\usepackage{thumbpdf} +#+END_SRC + +***** color links: no = mono | yes = color + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +%s +#+END_SRC + +***** metadata + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex + pdftitle={%s}, + pdfauthor={%s}, + pdfsubject={%s}, + pdfkeywords={}, + pageanchor=true, + plainpages=true, + pdfpagelabels=true, + pagebackref, + bookmarks=true, + bookmarksopen=true, + pdfmenubar=true, + pdfpagemode=UseOutline, + pdffitwindow=true, + pdfwindowui=true, + plainpages=false, + pdfstartview=FitH +] +{hyperref} +#+END_SRC + +%% pdfusetitle=true, +%% pdfpagelayout=SinglePage, +%% pdfpagelayout=TwoColumnRight, +%% pdfpagelayout=TwoColumnLeft, +%% pdfstartpage=3, + +%%%% trace lost characters +%% \tracinglostchars = 1 +%% \tracingonline = 1 + +***** define colors + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\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} +#+END_SRC + +***** latex head + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage{url} +\urlstyle{sf} +#+END_SRC + +%%\usepackage{breakurl} + +***** latex head + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage{textcomp} +\usepackage[parfill]{parskip} +\usepackage[normalem]{ulem} +\usepackage{soul} +\usepackage{longtable} +\usepackage[tc]{titlepic} +\usepackage{graphicx} +\makeatletter +\parindent0pt +\usepackage{amssymb} +\usepackage{listings} +\usepackage{color} +\usepackage{textcomp} +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{4} +\makeatletter +#+END_SRC + +***** indent, bullet, list + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage[multiple,ragged]{footmisc} +\setlength\footnotemargin{12pt} +\usepackage[para]{manyfoot} +\DeclareNewFootnote{A} +\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[] +} +{\end{list}} +#+END_SRC + +%%\DeclareNewFootnote[para]{A} + +***** part, section, subsection, paragraph, subparagraph + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\usepackage{fancyhdr} +\lhead{} +\renewcommand{\part}{\@startsection + {part}{1}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\section}{\@startsection + {section}{2}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\subsection}{\@startsection + {subsection}{3}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\subsubsection}{\@startsection + {subsubsection}{4}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\bfseries\raggedright}} +\renewcommand{\paragraph}{\@startsection + {paragraph}{5}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\itshape\raggedright}} +\renewcommand{\subparagraph}{\@startsection + {subparagraph}%%{6}%%{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\itshape\raggedright}} +#+END_SRC + +%% \makeatother + +***** latex head misc. including defined commands + +#+name: output_latex_head_0_tex +#+BEGIN_SRC latex +\selectlanguage{english} +\lhead[ ]{ } +\chead[ \fancyplain{} \bfseries \footnotesize \leftmark ]{ \fancyplain{} \bfseries \footnotesize \rightmark } +\rhead[ ]{ } +\lfoot[\textrm{\thepage}]{\tiny \href{http://sisudoc.org}{SiSU}} +\cfoot{\href{http://git.sisudoc.org}{git}} +\rfoot[\tiny \href{}{}]{\textrm{\thepage}} +\tolerance=300 +\clubpenalty=300 +\widowpenalty=300 +\makeatother +\makeatother +\chardef\txtbullet="2022 +\chardef\tilde="7E +\def\asterisk{{\rm \char42} } +\definecolor{Light}{gray}{.92} +\newcommand{\Codeblock}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} +\newcommand{\monosp}[1]{\normaltext\ttfamily\texbackslash#1} +\newcommand{\parasep}{\\ \begin{center}*\hspace{2em}*\hspace{2em}*\end{center} \\} +\newcommand{\hardspace}{{~}} +\newcommand{\caret}{{\^{~}}} +\newcommand{\pipe}{{\textbar}} +\newcommand{\curlyopen}{{} +\newcommand{\curlyclose}{}} +\newcommand{\lt}{{UseTextSymbol{OML}{<}}} +\newcommand{\gt}{{UseTextSymbol{OML}{>}}} +\newcommand{\slash}{{/}} +\newcommand{\underscore}{\_} +\newcommand{\exclaim}{\Verbatim{!}} +\definecolor{listinggray}{gray}{0.9} +\definecolor{lbcolor}{rgb}{0.9,0.9,0.9} +\lstset{ + backgroundcolor=\color{lbcolor}, + tabsize=4, + rulecolor=, + language=, + basicstyle=\scriptsize, + upquote=true, + aboveskip={1.5\baselineskip}, + 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}, +} +#+END_SRC + +%%\chardef\asterisk="2A +%%\newcommand{\hardspace}{\hspace{.5em}} + +**** latex head format inclusions + +#+name: output_latex_head_0_close +#+BEGIN_SRC d +┃", + doc_matters.opt.action.debug_do ? "" : doc_matters.generator_program.name_and_version.strip, + paper.a4_portrait.strip, + margins.portrait.strip, + multicol.portrait.strip, + links.mono.strip, // links.color.strip, + 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, +); +#+END_SRC + +**** latex head return + +#+name: output_latex_head_close +#+BEGIN_SRC d + return _latex_head.strip; +} +#+END_SRC + +*** ↻ latex body :content:body: +**** latex body function + +#+name: output_latex_body +#+BEGIN_SRC d +string latex_body(D,M)( + const D doc_abstraction, + M doc_matters, +) { + string _latex_body = ""; + bool _multicolumns = false; + string _txt; +#+END_SRC + +**** ↻ loop open + +#+name: output_latex_body +#+BEGIN_SRC d + foreach (part; doc_matters.has.keys_seq.latex) { + foreach (obj; doc_abstraction[part]) { + switch (obj.metainfo.is_of_part) { +#+END_SRC + +**** ↻ within loop +***** frontmatter + +#+name: output_latex_body +#+BEGIN_SRC d + 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); + goto default; + case "toc": + break; + default: + _latex_body ~= _txt ~ "\n\n"; + _txt = ""; + break; + } + break; + default: break; + } + break; +#+END_SRC + +***** body + +#+name: output_latex_body +#+BEGIN_SRC d + 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); + 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); + goto default; // TODO + default: + _latex_body ~= _txt ~ "\n\n"; + _txt = ""; + break; + } + break; + default: break; + } + break; +#+END_SRC + +***** backmatter + +#+name: output_latex_body +#+BEGIN_SRC d + 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, part); + goto default; + case "endnote": assert(part == "endnotes"); + _txt = _txt.para(obj) + .bullets_and_indentation(obj) + .links_and_images(obj, doc_matters); + goto default; + 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; +#+END_SRC + +***** after + +#+name: output_latex_body +#+BEGIN_SRC d + case "comment": + break; + default: + { /+ debug +/ + if (doc_matters.opt.action.debug_do + && doc_matters.opt.action.verbose) { + 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"; + } +#+END_SRC + +**** latex body return + +#+name: output_latex_body +#+BEGIN_SRC d + return _latex_body; +} +#+END_SRC + +*** latex tail :tail: +**** latex tail function + +#+name: output_latex_tail +#+BEGIN_SRC d +string latex_tail(M)( + M doc_matters, +) { +#+END_SRC + +**** latex tail starts + +#+name: output_latex_tail +#+BEGIN_SRC d + string _latex_tail = format(q"┃ +#+END_SRC + +***** latex tail format inclusions + + +***** latex document end + +#+name: output_latex_tail_tex +#+BEGIN_SRC latex + +\end{document} +#+END_SRC + +**** latex tail format inclusions + +#+name: output_latex_tail_close +#+BEGIN_SRC d +┃", + // doc_matters.conf_make_meta.meta.title_full, + // doc_matters.conf_make_meta.meta.creator_author, +); +#+END_SRC + +**** latex tail return + +#+name: output_latex_tail_close +#+BEGIN_SRC d + return _latex_tail; +} +#+END_SRC + +* latex system command helper script +** latex command, ruby script + +#+BEGIN_SRC ruby :tangle "../util/dr_tex.rb" :tangle-mode (identity #o755) :shebang #!/usr/bin/env ruby +require 'fileutils' +pwd = Dir.pwd +argv,texfiles_with_path,flags=[],[],[] +lngs = %{(am|bg|bn|br|ca|cs|cy|da|de|el|en|eo|es|et|eu|fi|fr|ga|gl|he|hi|hr|hy|ia|is|it|ja|ko|la|lo|lt|lv|ml|mr|nl|no|nn|oc|pl|pt|pt_BR|ro|ru|sa|se|sk|sl|sq|sr|sv|ta|te|th|tk|tr|uk|ur|vi|zh)} +Regexp.new(lngs, Regexp::IGNORECASE) +argv=$* +argv.sort.each{|y| (y =~/^--\S+$/i) ? (flags << y) : (texfiles_with_path << y) } +if flags.length==0 \ +|| flags.inspect =~/"--help"/ + cmd=(/([^\/]+)$/).match($0)[1] + puts < 0 + texfiles_with_path.each do |texfile_with_path| + if texfile_with_path =~/.+\.tex/ + #puts texfile_with_path + if FileTest.file?(texfile_with_path) + file_basename_with_path = texfile_with_path.sub(/\.tex$/,'') + file_basename = file_basename_with_path.sub(/.*?([^\/]+)$/,'\1') + _out_path = out_path + if file_basename =~ /\.#{lngs}$/ + lng = file_basename.match(/\.#{lngs}$/)[1] + puts file_basename + puts lng + puts _out_path + unless _out_path.match(/\/#{lng}\/pdf$/) + _out_path = "#{out_path}/#{lng}/pdf" + FileUtils::mkdir_p(_out_path) + end + end + texpdf_cmd = %{xetex -interaction=batchmode -fmt=xelatex -papersize=#{paper_size} #{texfile_with_path}\n} + puts texpdf_cmd + 2.times { |i| system(texpdf_cmd) } + if (FileTest.file?(%{#{pwd}/#{file_basename}.pdf})) && (FileTest.directory?(_out_path)) + FileUtils::Verbose::mv(%{#{pwd}/#{file_basename}.pdf}, %{#{_out_path}/#{file_basename}.pdf}) + puts (%{#{_out_path}/#{file_basename}.pdf}) + else + puts "issue with pdf file or output directory" + puts "pdf file: #{pwd}/#{file_basename}.pdf}" + puts "output dir: #{_out_path}/" + end + suffix = ['log', 'out', 'toc', 'aux'] + suffix.each { |s| FileUtils::rm_f(%{#{pwd}/#{file_basename}.#{s}})} + end + end + end +end +Dir.chdir(pwd) +__END__ +#+END_SRC diff --git a/src/doc_reform/doc_reform.d b/src/doc_reform/doc_reform.d index 25ab2cc..06866c2 100755 --- a/src/doc_reform/doc_reform.d +++ b/src/doc_reform/doc_reform.d @@ -122,6 +122,7 @@ void main(string[] args) { "html" : false, "html-seg" : false, "html-scroll" : false, + "latex" : false, "light" : false, "manifest" : false, "ocn" : true, @@ -129,6 +130,7 @@ void main(string[] args) { "odt" : false, "parallel" : false, "parallel-subprocesses" : false, + "pdf" : false, "quiet" : false, "pod" : false, "serial" : false, @@ -175,6 +177,7 @@ void main(string[] args) { "html", "--html process html output", &opts["html"], "html-seg", "--html-seg process html output", &opts["html-seg"], "html-scroll", "--html-seg process html output", &opts["html-scroll"], + "latex", "--latex output for pdfs", &opts["latex"], "light", "--light default light theme", &opts["light"], "manifest", "--manifest process manifest output", &opts["manifest"], "ocn", "--ocn object cite numbers (default)", &opts["ocn"], @@ -183,6 +186,7 @@ void main(string[] args) { "parallel", "--parallel parallelisation", &opts["parallel"], "parallel-subprocesses", "--parallel-subprocesses nested parallelisation", &opts["parallel-subprocesses"], "quiet|q", "--quiet output to terminal", &opts["quiet"], + "pdf", "--pdf latex output for pdfs", &opts["pdf"], "pod", "--pod doc reform pod source content bundled", &opts["pod"], "serial", "--serial serial processing", &opts["serial"], "source", "--source markup source text content", &opts["source"], @@ -218,7 +222,7 @@ void main(string[] args) { if (helpInfo.helpWanted) { defaultGetoptPrinter("Some information about the program.", helpInfo.options); } - enum outTask { pod, source, sqlite, sqlite_multi, odt, epub, html_scroll, html_seg, html_stuff } + enum outTask { pod, source, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff } struct OptActions { bool assertions() { return opts["assertions"]; @@ -270,6 +274,12 @@ void main(string[] args) { { _is = true; } else { _is = false; } return _is; } + bool latex() { + bool _is; + if ( opts["latex"] || opts["pdf"]) + { _is = true; } else { _is = false; } + return _is; + } bool odt() { bool _is; if ( opts["odf"] || opts["odt"]) @@ -392,6 +402,7 @@ void main(string[] args) { || html || epub || odt + || latex || manifest || pod || source @@ -430,6 +441,9 @@ void main(string[] args) { if (odt) { schedule ~= outTask.odt; } + if (latex) { + schedule ~= outTask.latex; + } return schedule.sort().uniq; } bool abstraction() { @@ -441,6 +455,7 @@ void main(string[] args) { || html || epub || odt + || latex || manifest || sqlite_discrete || sqlite_delete @@ -454,6 +469,7 @@ void main(string[] args) { || html || epub || odt + || latex || sqlite_discrete || sqlite_update ) { _is = true; } else { _is = false; } diff --git a/src/doc_reform/meta/metadoc_from_src.d b/src/doc_reform/meta/metadoc_from_src.d index 4e0120f..bd8a635 100644 --- a/src/doc_reform/meta/metadoc_from_src.d +++ b/src/doc_reform/meta/metadoc_from_src.d @@ -2254,30 +2254,36 @@ template DocReformDocAbstraction() { "scroll": ["head", "toc", "body",], "seg": ["head", "toc", "body",], "sql": ["head", "body",], + "latex": ["head", "toc", "body",] ]; if (document_the["endnotes"].length > 1) { document_section_keys_sequenced["scroll"] ~= "endnotes"; document_section_keys_sequenced["seg"] ~= "endnotes"; + document_section_keys_sequenced["latex"] ~= "endnotes"; } if (document_the["glossary"].length > 1) { document_section_keys_sequenced["scroll"] ~= "glossary"; document_section_keys_sequenced["seg"] ~= "glossary"; document_section_keys_sequenced["sql"] ~= "glossary"; + document_section_keys_sequenced["latex"] ~= "glossary"; } if (document_the["bibliography"].length > 1) { document_section_keys_sequenced["scroll"] ~= "bibliography"; document_section_keys_sequenced["seg"] ~= "bibliography"; document_section_keys_sequenced["sql"] ~= "bibliography"; + document_section_keys_sequenced["latex"] ~= "bibliography"; } if (document_the["bookindex"].length > 1) { document_section_keys_sequenced["scroll"] ~= "bookindex"; document_section_keys_sequenced["seg"] ~= "bookindex"; document_section_keys_sequenced["sql"] ~= "bookindex"; + document_section_keys_sequenced["latex"] ~= "bookindex"; } if (document_the["blurb"].length > 1) { document_section_keys_sequenced["scroll"] ~= "blurb"; document_section_keys_sequenced["seg"] ~= "blurb"; document_section_keys_sequenced["sql"] ~= "blurb"; + document_section_keys_sequenced["latex"] ~= "blurb"; } if ((opt_action.html) || (opt_action.html_scroll) @@ -6089,6 +6095,9 @@ template docSectKeysSeq() { string[] sql() { return document_section_keys_sequenced["sql"]; } + string[] latex() { + return document_section_keys_sequenced["latex"]; + } } return doc_sect_keys_seq(); } diff --git a/src/doc_reform/output/hub.d b/src/doc_reform/output/hub.d index b840811..8f16528 100644 --- a/src/doc_reform/output/hub.d +++ b/src/doc_reform/output/hub.d @@ -15,7 +15,7 @@ template outputHub() { mixin Msg; auto msg = Msg!()(doc_matters); static auto rgx = Rgx(); - enum outTask { pod, source, sqlite, sqlite_multi, odt, epub, html_scroll, html_seg, html_stuff } + enum outTask { pod, source, sqlite, sqlite_multi, latex, odt, epub, html_scroll, html_seg, html_stuff } void Scheduled(D,I)(int sched, D doc_abstraction, I doc_matters) { auto msg = Msg!()(doc_matters); if (sched == outTask.pod) { @@ -48,6 +48,12 @@ template outputHub() { outputHTML!().images_cp(doc_matters); msg.vv("html css & images done"); } + if (sched == outTask.latex) { + msg.v("latex processing... (available for downstream processing & pdf output"); + import doc_reform.output.latex; + outputLaTeX!()(doc_abstraction, doc_matters); + msg.vv("latex done"); + } if (sched == outTask.odt) { msg.v("odf:odt processing... "); import doc_reform.output.odt; diff --git a/src/doc_reform/output/latex.d b/src/doc_reform/output/latex.d new file mode 100644 index 0000000..586e9fb --- /dev/null +++ b/src/doc_reform/output/latex.d @@ -0,0 +1,1164 @@ +module doc_reform.output.latex; +template outputLaTeX() { + import doc_reform.output; + import + std.digest.sha, + std.file, + std.outbuffer, + std.uri, + std.conv : to; + mixin InternalMarkup; // watch + mixin DocReformOutputRgxInit; + auto rgx = Rgx(); + auto paper() { + struct PaperType { + auto a4() { + struct A4 { + auto portrait() { + struct V { + uint w = 160; + uint h = 228; + uint img_px = 450; + } + return V(); + } + auto landscape() { + struct H { + uint w = 238; + uint h = 160; + uint img_px = 300; + } + return H(); + } + } + return A4(); + } + auto a5() { + struct A5 { + auto portrait() { + struct V { + uint w = 112; + uint h = 162; + uint img_px = 280; + } + return V(); + } + auto landscape() { + struct H { + uint w = 152; + uint h = 100; + uint img_px = 190; + } + return H(); + } + } + return A5(); + } + auto b4() { + struct B4 { + auto portrait() { + struct V { + uint w = 140; + uint h = 204; + uint img_px = 356; + } + return V(); + } + auto landscape() { + struct H { + uint w = 200; + uint h = 130; + uint img_px = 260; + } + return H(); + } + } + return B4(); + } + auto letter() { + struct Letter { + auto portrait() { + struct V { + uint w = 166; + uint h = 212; + uint img_px = 468; + } + return V(); + } + auto landscape() { + struct H { + uint w = 226; + uint h = 166; + uint img_px = 290; + } + return H(); + } + } + return Letter(); + } + auto legal() { + struct Legal { + auto portrait() { + struct V { + uint w = 168; + uint h = 286; + uint img_px = 474; + } + return V(); + } + auto landscape() { + struct H { + uint w = 296; + uint h = 166; + uint img_px = 420; + } + return H(); + } + } + return Legal(); + } + } + return PaperType(); + } + string sp_char_esc(O)( + string _txt, + const O obj, + ) { + string _unescape_sp_char_esc()(string _txt) { + _txt = _txt + .replaceAll(rgx.latex_special_char_escaped, + format(q"┃%s┃", "$1")) + .replaceAll(rgx.latex_special_char_escaped_braced, + format(q"┃%s┃", "$1")); + return _txt; + } + string _unescape_fontface_esc()(string _txt) { + _txt = _txt.replaceAll(rgx.latex_identify_inline_fontface, + format(q"┃%s%s┃", "$1", "$2")); + return _txt; + } + if (obj.metainfo.is_a != "code") { + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx.latex_special_char_for_escape); + _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx.latex_special_char_for_escape_and_braces); + _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx.latex_identify_inline_link); + _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx.latex_identify_inline_fontface); + } + return _txt; + } + string sp_char_esc_txt()( + string _txt, + ) { + string _unescape_sp_char_esc()(string _txt) { + _txt = _txt + .replaceAll(rgx.latex_special_char_escaped, + format(q"┃%s┃", "$1")) + .replaceAll(rgx.latex_special_char_escaped_braced, + format(q"┃%s┃", "$1")); + return _txt; + } + string _unescape_fontface_esc()(string _txt) { + _txt = _txt.replaceAll(rgx.latex_identify_inline_fontface, + format(q"┃%s%s┃", "$1", "$2")); + return _txt; + } + _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx.latex_special_char_for_escape); + _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx.latex_special_char_for_escape_and_braces); + _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx.latex_identify_inline_link); + _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx.latex_identify_inline_fontface); + 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"┃$$^{\textrm{%s}}$$┃", "$1")) + .replaceAll(rgx.inline_subscript, format(q"┃$$_{\textrm{%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, "\\hardspace "); + 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)) { + _txt = _txt.replaceAll(rgx.nbsp_char, "\\hardspace "); + } + 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 = DocReformPathsLaTeX(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]), " \\\\\n") + )(_linked_content, rgx.inline_image_info); + } + return _linked_content; + } + string _check_link(string _link) { + _link = _link + .replaceFirst(rgx.latex_clean_internal_link, "") + .replaceAll(rgx.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))) + ? format(q"┃\begin{scriptsize}\lefthalfcap\url{%s}\righthalfcup\end{scriptsize}┃", _check_link(m[1])) + : (m[2].match(rgx.uri)) // ERROR + ? format(q"┃%s\href{%s}%s{%s}┃", "\\\\\n", _check_link(m[2]), "\n", _if_images(m[1])) + : format(q"┃\hyperlink{%s}{%s}┃", _check_link(m[2]), _if_images(m[1])) + )(_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.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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + 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.latex_clean_bookindex_linebreak, "\n") ~ "\n\\\\\n" + ); + } + return _txt; + } + string heading(O,M)( + string _txt, + O obj, + M doc_matters, + string _part = "" + ) { + if (obj.metainfo.is_a == "heading") { + string _tex_para; + 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\\\\\n\\begin{multicols}{2}"; + _pg_break = "\\clearpage\n"; + _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 = " \\\n"; + _title_add = ""; + goto default; + case 6: // 3 == subsubsection + _pg_break = ""; + // _pg_break = "newpage"; // doubt this is necessary + _sect = "subsubsection"; + _post = " \\\n"; + _title_add = ""; + goto default; + default: + if (obj.metainfo.heading_lev_markup == 0) { + _tex_para = q"┃\begin{document} +\title{%s} +\author{ \textnormal{%s}} +\date{\begin{tiny}%s\end{tiny}} +\pagenumbering{roman}\maketitle +\pagestyle{fancy} +\newpage +\markboth{%s}{%s} +\\\\[3]\ \linebreak Copyright {\begin{small}{\copyright\end{small}} %s \\ +%s +\pagestyle{fancy} +\clearpage┃"; + _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.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_full).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.rights_copyright).sp_char_esc_txt, + (doc_matters.conf_make_meta.meta.rights_license).sp_char_esc_txt, + ); + } else if (obj.metainfo.heading_lev_markup < 4) { + _tex_para = q"┃%s\part*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{part}{%s} +\markboth{%s}┃"; + _txt = format(_tex_para, + _pg_break, + obj.metainfo.object_number, + 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{none} +\setcounter{page}{1} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +\part*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{1}{1}\end{tiny}}}%s \newline %s} + +\clearpage +\markboth{%s}{%s} +\pagenumbering{gobble} +\renewcommand{\contentsname}{} +\tableofcontents +\markboth{%s}{%s} + +\clearpage +\pagenumbering{arabic} +\setcounter{page}{1} +\markboth{%s}{%s} +%% \null +\clearpage +\setcounter{page}{1}┃"; + _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_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.title_full).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*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{%s}{%s%s}%s%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + 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*{\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}%s} +\addcontentsline{toc}{%s}{%s%s}%s┃"; + _txt = format(_tex_para, + _pg_break, + _sect.strip, + obj.metainfo.object_number, + 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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} +\begin{footnotesize} +%s +\end{footnotesize} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.footnotes.strip + ).strip; + } + return _txt; +} +string block(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "block") { + // _txt = _txt.nbsp_char; + string _tex_para; + _tex_para = q"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} +\begin{footnotesize} +%s +\end{footnotesize} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +┃"; // \hardspace + /+ try both: +/ + _txt = _txt.split(rgx.br_newlines_linebreaks).join("\n\n"); // _txt = _txt.split(rgx.br_newlines_linebreaks).join(" \\\n"); + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.nbsp_char.footnotes.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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.1ex plus0.1ex minus0.1ex} +\begin{footnotesize} + +%s + +\end{footnotesize} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +\linebreak +┃"; // \hardspace + _txt = format(_tex_para, + obj.metainfo.object_number, + obj.metainfo.object_number, + _txt.nbsp_char.footnotes.split("\n").join("\n\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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}}\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex}\begin{Codeblock} +\begin{lstlisting} +%s +\end{lstlisting} +\end{Codeblock} +\setlength{\parskip}{1ex plus0.5ex minus0.2ex} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + 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 ~= "\\\\"; + } + auto t = tuple( + _table, + _tablenote, + ); + return t; +} +string table(O,M)( + string _txt, + O obj, + M doc_matters, +) { + if (obj.metainfo.is_a == "table") { + auto _t = _txt.tablarize(obj); + string _table = _t[0]; + string _t_n = _t[1]; + string papertype = "a4"; + uint pw = 0; + switch (papertype) { + case "a4": pw = (paper.a4.portrait.w - 20); break; + case "a5": pw = (paper.a5.portrait.w - 20); break; + case "b4": pw = (paper.b4.portrait.w - 20); break; + case "letter": pw = (paper.letter.portrait.w - 20); break; + case "legal": pw = (paper.legal.portrait.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"┃\begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{%s}{%s}\end{tiny}}} +\setlength{\LTleft}{0pt} +\setlength{\LTright}{\fill} +\begin{tiny} +\begin{longtable}{%s} +%s +\end{longtable} +\end{tiny} +┃"; + _txt = format(_tex_para, + obj.metainfo.object_number, + 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}$\txtbullet$\hspace{\enspace}%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; + _txt = format(q"┃\begin{ParagraphHang}{%smm}{%smm}%s \end{ParagraphHang}┃", + _indent, _hang, + _txt.footnotes + ).strip; + } + return _txt; + } + string latex_head(M)( + M doc_matters, + ) { + struct paperType { + string a4_portrait; + string a4_landscape; + string us_letter_portrait; + string us_letter_landscape; + } + auto paper = paperType(); + paper.a4_portrait = format(q"┃ +\documentclass[12pt,a4paper,titlepage]{scrartcl} +\setlength{\textheight}{228mm} \setlength{\textwidth}{160mm} +┃", + ); + paper.a4_landscape = format(q"┃ +\documentclass[11pt,a4paper,landscape,titlepage,twocolumn]{scrartcl} +\setlength{\textheight}{160mm} \setlength{\textwidth}{238mm} +┃", + ); + paper.us_letter_portrait = format(q"┃ +\documentclass[12pt,letterpaper,titlepage]{scrartcl} +\setlength{\textheight}{212mm} \setlength{\textwidth}{166mm} +┃", + ); + paper.us_letter_landscape = format(q"┃ +\documentclass[11pt,letterpaper,landscape,titlepage,twocolumn]{scrartcl} +\setlength{\textheight}{166mm} \setlength{\textwidth}{226mm} +┃", + ); + struct paperMargins { + string portrait; + string landscape; + } + auto margins = paperMargins(); + margins.portrait = format(q"┃ +\setlength{\oddsidemargin}{0mm} \setlength{\evensidemargin}{0mm} +\setlength{\topmargin}{-12pt} \setlength{\headheight}{12pt} +\setlength{\headsep}{35pt} +┃", + ); + margins.landscape = format(q"┃ +\setlength{\oddsidemargin}{6mm} \setlength{\evensidemargin}{6mm} +\setlength{\topmargin}{-12mm} \setlength{\headheight}{12pt} +\setlength{\headsep}{20pt} +┃", + ); + struct columnsMulti { + string portrait; + string landscape; + } + auto multicol = columnsMulti(); + multicol.portrait = format(q"┃ +\usepackage{multicol} +┃", + ); + multicol.landscape = ""; + struct colorLinks { + string mono; + string color; + } + auto links = colorLinks(); + links.mono = format(q"┃ +\usepackage[xetex, + colorlinks=true, + urlcolor=myblack, + filecolor=myblack, + linkcolor=myblack, +┃", + ); + links.color = format(q"┃ +\usepackage[xetex, + colorlinks=true, + urlcolor=myblue, %% \href{...}{...} external url + filecolor=mygreen, %% \href{...} local file + linkcolor=myred, %% \href{...} and \pageref{...} + ┃", + ); + string _latex_head = format(q"┃%%%% DocReform LaTeX output +%%%% Generated by: %s +%%%% D version: ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux-gnu] +%%%% LaTeX output +%%%% Last Generated on: +%%%% SiSU http://www.jus.uio.no/sisu +%s +%s +\setlength{\marginparsep}{4mm} +\setlength{\marginparwidth}{8mm} +%s +\usepackage{polyglossia, ucs, fontspec, xltxtra, xunicode} +\setmainlanguage{english} +\setotherlanguage{} +\setmainfont{Liberation Sans} +\setmonofont[Scale=0.85]{Liberation Mono} +\usepackage{alltt} +\usepackage{thumbpdf} +%s + pdftitle={%s}, + pdfauthor={%s}, + pdfsubject={%s}, + pdfkeywords={}, + pageanchor=true, + plainpages=true, + pdfpagelabels=true, + pagebackref, + bookmarks=true, + bookmarksopen=true, + pdfmenubar=true, + pdfpagemode=UseOutline, + pdffitwindow=true, + pdfwindowui=true, + plainpages=false, + pdfstartview=FitH +] +{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{url} +\urlstyle{sf} +\usepackage{textcomp} +\usepackage[parfill]{parskip} +\usepackage[normalem]{ulem} +\usepackage{soul} +\usepackage{longtable} +\usepackage[tc]{titlepic} +\usepackage{graphicx} +\makeatletter +\parindent0pt +\usepackage{amssymb} +\usepackage{listings} +\usepackage{color} +\usepackage{textcomp} +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{4} +\makeatletter +\usepackage[multiple,ragged]{footmisc} +\setlength\footnotemargin{12pt} +\usepackage[para]{manyfoot} +\DeclareNewFootnote{A} +\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[] +} +{\end{list}} +\usepackage{fancyhdr} +\lhead{} +\renewcommand{\part}{\@startsection + {part}{1}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\section}{\@startsection + {section}{2}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\subsection}{\@startsection + {subsection}{3}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\bfseries\large\upshape\raggedright}} +\renewcommand{\subsubsection}{\@startsection + {subsubsection}{4}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\bfseries\raggedright}} +\renewcommand{\paragraph}{\@startsection + {paragraph}{5}{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\itshape\raggedright}} +\renewcommand{\subparagraph}{\@startsection + {subparagraph}%%{6}%%{-2mm}%% + {-\baselineskip}{0.5\baselineskip}%% + {\normalfont\normalsize\itshape\raggedright}} +\selectlanguage{english} +\lhead[ ]{ } +\chead[ \fancyplain{} \bfseries \footnotesize \leftmark ]{ \fancyplain{} \bfseries \footnotesize \rightmark } +\rhead[ ]{ } +\lfoot[\textrm{\thepage}]{\tiny \href{http://sisudoc.org}{SiSU}} +\cfoot{\href{http://git.sisudoc.org}{git}} +\rfoot[\tiny \href{}{}]{\textrm{\thepage}} +\tolerance=300 +\clubpenalty=300 +\widowpenalty=300 +\makeatother +\makeatother +\chardef\txtbullet="2022 +\chardef\tilde="7E +\def\asterisk{{\rm \char42} } +\definecolor{Light}{gray}{.92} +\newcommand{\Codeblock}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} +\newcommand{\monosp}[1]{\normaltext\ttfamily\texbackslash#1} +\newcommand{\parasep}{\\ \begin{center}*\hspace{2em}*\hspace{2em}*\end{center} \\} +\newcommand{\hardspace}{{~}} +\newcommand{\caret}{{\^{~}}} +\newcommand{\pipe}{{\textbar}} +\newcommand{\curlyopen}{{} +\newcommand{\curlyclose}{}} +\newcommand{\lt}{{UseTextSymbol{OML}{<}}} +\newcommand{\gt}{{UseTextSymbol{OML}{>}}} +\newcommand{\slash}{{/}} +\newcommand{\underscore}{\_} +\newcommand{\exclaim}{\Verbatim{!}} +\definecolor{listinggray}{gray}{0.9} +\definecolor{lbcolor}{rgb}{0.9,0.9,0.9} +\lstset{ + backgroundcolor=\color{lbcolor}, + tabsize=4, + rulecolor=, + language=, + basicstyle=\scriptsize, + upquote=true, + aboveskip={1.5\baselineskip}, + 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}, +} + ┃", + doc_matters.opt.action.debug_do ? "" : doc_matters.generator_program.name_and_version.strip, + paper.a4_portrait.strip, + margins.portrait.strip, + multicol.portrait.strip, + links.mono.strip, // links.color.strip, + 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, + ); + return _latex_head.strip; + } + string latex_body(D,M)( + const D doc_abstraction, + M doc_matters, + ) { + 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); + 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); + 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); + 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, part); + goto default; + case "endnote": assert(part == "endnotes"); + _txt = _txt.para(obj) + .bullets_and_indentation(obj) + .links_and_images(obj, doc_matters); + goto default; + 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 + && doc_matters.opt.action.verbose) { + 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 _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, + ) { + auto pth_latex = DocReformPathsLaTeX(doc_matters); + try { + { /+ debug +/ + if (doc_matters.opt.action.debug_do + && doc_matters.opt.action.verbose) { + 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; + } + writeln(pth_latex.latex_file_with_path); + auto f = File(pth_latex.latex_file_with_path, "w"); + f.writeln(latex_content.head); + f.writeln(latex_content.content); + f.writeln(latex_content.tail); + foreach (image; doc_matters.srcs.image_list) { + auto fn_src_in = doc_matters.src.image_dir_path ~ "/" ~ image; + auto fn_src_out_file = pth_latex.latex_path_stuff ~ "/" ~ image; + if (exists(fn_src_in)) { + fn_src_in.copy(fn_src_out_file); + } + } + } 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(); + latex.head = latex_head(doc_matters); + latex.content = latex_body(doc_abstraction, doc_matters); + latex.tail = latex_tail(doc_matters); + latex.writeOutputLaTeX(doc_matters); + } +} diff --git a/src/doc_reform/output/paths_output.d b/src/doc_reform/output/paths_output.d index 615a666..305aa17 100644 --- a/src/doc_reform/output/paths_output.d +++ b/src/doc_reform/output/paths_output.d @@ -331,6 +331,35 @@ template DocReformPathsODT() { return _PathsStruct(); } } +template DocReformPathsLaTeX() { + mixin DocReformRgxInit; + static auto rgx = Rgx(); + auto DocReformPathsLaTeX(M)( + M doc_matters, + ) { + struct _PathsStruct { + string base_filename(string fn_src) { + return fn_src.baseName.stripExtension; + } + string base() { + auto out_pth = DocReformOutPaths!()(doc_matters.output_path, doc_matters.src.language); + string base_dir = "latex"; + return asNormalizedPath((out_pth.output_root).chainPath(base_dir)).array; + } + string latex_path_stuff() { + return asNormalizedPath(base.chainPath(base_filename(doc_matters.src.filename))).array; + } + string latex_file_with_path() { + return asNormalizedPath(base.chainPath(base_filename(doc_matters.src.filename) ~ "." ~ doc_matters.src.language ~ ".tex")).array; + } + string images() { + string image_dir = "image"; + return asNormalizedPath((base).chainPath(image_dir)).array; + } + } + return _PathsStruct(); + } +} template DocReformPathsSQLiteDiscrete() { mixin DocReformRgxInit; static auto rgx = Rgx(); diff --git a/src/doc_reform/output/rgx.d b/src/doc_reform/output/rgx.d index c9e9516..5ab71f9 100644 --- a/src/doc_reform/output/rgx.d +++ b/src/doc_reform/output/rgx.d @@ -132,5 +132,17 @@ static template DocReformOutputRgxInit() { static xhtml_less_than = ctRegex!(`[<]`, "m"); // < static xhtml_greater_than = ctRegex!(`[>]`, "m"); // > static xhtml_line_break = ctRegex!(` [\\]{2}`, "m"); //
+ static latex_special_char_shortlist = ctRegex!(`([%$_#&\\])`); + static latex_special_char_curlybraces = ctRegex!(`([{}])`); + static latex_special_char = ctRegex!(`([%${}_#&\\])`); + static latex_special_char_for_escape = ctRegex!(`([%${}_#\\])`); + static latex_special_char_for_escape_and_braces = ctRegex!(`([&])`); + static latex_special_char_for_escape_url = ctRegex!(`([%])`); + static latex_special_char_escaped = ctRegex!(`\\([%${}_#\\])`); + static latex_special_char_escaped_braced = ctRegex!(`[{]\\([&])[}]`); + static latex_identify_inline_link = ctRegex!(`┥.+?┝┤\S+?├`, "mg"); + static latex_clean_internal_link = ctRegex!(`^(?:#|¤\S+?#)`, "m"); + static latex_identify_inline_fontface = ctRegex!(`\\([_#$]┨.+?┣)\\([_#$])`, "mg"); + static latex_clean_bookindex_linebreak = ctRegex!(`\s*\\\\\\\\\s*`, "m"); } } diff --git a/util/dr_tex.rb b/util/dr_tex.rb new file mode 100755 index 0000000..a73f07b --- /dev/null +++ b/util/dr_tex.rb @@ -0,0 +1,70 @@ +#!/usr/bin/env ruby +require 'fileutils' +pwd = Dir.pwd +argv,texfiles_with_path,flags=[],[],[] +lngs = %{(am|bg|bn|br|ca|cs|cy|da|de|el|en|eo|es|et|eu|fi|fr|ga|gl|he|hi|hr|hy|ia|is|it|ja|ko|la|lo|lt|lv|ml|mr|nl|no|nn|oc|pl|pt|pt_BR|ro|ru|sa|se|sk|sl|sq|sr|sv|ta|te|th|tk|tr|uk|ur|vi|zh)} +Regexp.new(lngs, Regexp::IGNORECASE) +argv=$* +argv.sort.each{|y| (y =~/^--\S+$/i) ? (flags << y) : (texfiles_with_path << y) } +if flags.length==0 \ +|| flags.inspect =~/"--help"/ + cmd=(/([^\/]+)$/).match($0)[1] + puts < 0 + texfiles_with_path.each do |texfile_with_path| + if texfile_with_path =~/.+\.tex/ + #puts texfile_with_path + if FileTest.file?(texfile_with_path) + file_basename_with_path = texfile_with_path.sub(/\.tex$/,'') + file_basename = file_basename_with_path.sub(/.*?([^\/]+)$/,'\1') + _out_path = out_path + if file_basename =~ /\.#{lngs}$/ + lng = file_basename.match(/\.#{lngs}$/)[1] + puts file_basename + puts lng + puts _out_path + unless _out_path.match(/\/#{lng}\/pdf$/) + _out_path = "#{out_path}/#{lng}/pdf" + FileUtils::mkdir_p(_out_path) + end + end + texpdf_cmd = %{xetex -interaction=batchmode -fmt=xelatex -papersize=#{paper_size} #{texfile_with_path}\n} + puts texpdf_cmd + 2.times { |i| system(texpdf_cmd) } + if (FileTest.file?(%{#{pwd}/#{file_basename}.pdf})) && (FileTest.directory?(_out_path)) + FileUtils::Verbose::mv(%{#{pwd}/#{file_basename}.pdf}, %{#{_out_path}/#{file_basename}.pdf}) + puts (%{#{_out_path}/#{file_basename}.pdf}) + else + puts "issue with pdf file or output directory" + puts "pdf file: #{pwd}/#{file_basename}.pdf}" + puts "output dir: #{_out_path}/" + end + suffix = ['log', 'out', 'toc', 'aux'] + suffix.each { |s| FileUtils::rm_f(%{#{pwd}/#{file_basename}.#{s}})} + end + end + end +end +Dir.chdir(pwd) +__END__ diff --git a/views/version.txt b/views/version.txt index 9a7e61e..c1a5679 100644 --- a/views/version.txt +++ b/views/version.txt @@ -4,7 +4,7 @@ struct Version { int minor; int patch; } -enum _ver = Version(0, 7, 1); +enum _ver = Version(0, 7, 2); version (Posix) { version (DigitalMars) { } else version (LDC) { -- cgit v1.2.3