aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2019-05-20 10:20:38 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2019-10-17 19:07:20 -0400
commitd21e5b572433f39111282805435e6337f0e1b4c0 (patch)
tree7a604e949edeef496ef79870f98aa4b722136d34
parent0.7.1 odt (initial stub) (diff)
0.7.2 latex (for pdf) (initial stub)doc-reform_v0.7.2
-rw-r--r--org/default_paths.org36
-rw-r--r--org/default_regex.org18
-rw-r--r--org/doc_reform.org20
-rw-r--r--org/meta_abstraction.org9
-rw-r--r--org/output_hub.org14
-rw-r--r--org/output_latex.org1832
-rwxr-xr-xsrc/doc_reform/doc_reform.d18
-rw-r--r--src/doc_reform/meta/metadoc_from_src.d9
-rw-r--r--src/doc_reform/output/hub.d8
-rw-r--r--src/doc_reform/output/latex.d1164
-rw-r--r--src/doc_reform/output/paths_output.d29
-rw-r--r--src/doc_reform/output/rgx.d12
-rwxr-xr-xutil/dr_tex.rb70
-rw-r--r--views/version.txt2
14 files changed, 3235 insertions, 6 deletions
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;
<<template_paths_html>>
<<template_paths_epub>>
<<template_paths_odf>>
+<<template_paths_latex>>
<<template_paths_sqlite>>
#+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"); // <br />
#+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);
<<output_scheduled_task>>
@@ -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() {
+ <<output_latex_imports>>
+ mixin InternalMarkup; // watch
+ mixin DocReformOutputRgxInit;
+ auto rgx = Rgx();
+ <<output_latex_shared>>
+<<output_latex_shared_0>>
+ <<output_latex_head>>
+ <<output_latex_head_1>>
+<<output_latex_head_1_tex>>
+ <<output_latex_head_1_close>>
+ <<output_latex_head_0>>
+<<output_latex_head_0_tex>>
+ <<output_latex_head_0_close>>
+ <<output_latex_head_close>>
+ <<output_latex_body>>
+ <<output_latex_tail>>
+<<output_latex_tail_tex>>
+ <<output_latex_tail_close>>
+ <<output_latex>>
+}
+#+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 <<WOK
+#{cmd} --help
+#{cmd} --out=[output path]
+#{cmd} --paper-size=a5 --out=~/test
+WOK
+end
+paper_size = (flags.inspect.match(/"--paper-size=(a4|a5|b5|letter|legal)"/)) ? $1 : "a4"
+out_path = Dir.pwd
+if (flags.inspect.match(/"--out=\S+"/))
+ out_path = flags.inspect.match(/"--out=(\S+)"/)[1]
+ unless (FileTest.directory?(out_path))
+ puts "Creating output directory: --out=#{out_path}"
+ FileUtils::mkdir_p(out_path)
+ unless (FileTest.directory?(out_path))
+ puts "FAILS unable to create directory: #{out_path}"
+ exit
+ end
+ end
+end
+if texfiles_with_path.length == 0
+ texfiles_with_path=Dir.glob('*.tex')
+end
+if texfiles_with_path.length > 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"); // &lt;
static xhtml_greater_than = ctRegex!(`[>]`, "m"); // &gt;
static xhtml_line_break = ctRegex!(` [\\]{2}`, "m"); // <br />
+ 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 <<WOK
+#{cmd} --help
+#{cmd} --out=[output path]
+#{cmd} --paper-size=a5 --out=~/test
+WOK
+end
+paper_size = (flags.inspect.match(/"--paper-size=(a4|a5|b5|letter|legal)"/)) ? $1 : "a4"
+out_path = Dir.pwd
+if (flags.inspect.match(/"--out=\S+"/))
+ out_path = flags.inspect.match(/"--out=(\S+)"/)[1]
+ unless (FileTest.directory?(out_path))
+ puts "Creating output directory: --out=#{out_path}"
+ FileUtils::mkdir_p(out_path)
+ unless (FileTest.directory?(out_path))
+ puts "FAILS unable to create directory: #{out_path}"
+ exit
+ end
+ end
+end
+if texfiles_with_path.length == 0
+ texfiles_with_path=Dir.glob('*.tex')
+end
+if texfiles_with_path.length > 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) {