-*- mode: org -*- #+TITLE: spine (doc_reform) output latex #+DESCRIPTION: documents - structuring, publishing in multiple formats & search #+FILETAGS: :spine:output:latex:pdf: #+AUTHOR: Ralph Amissah #+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]] #+COPYRIGHT: Copyright (C) 2015 - 2024 Ralph Amissah #+LANGUAGE: en #+STARTUP: content hideblocks hidestars noindent entitiespretty #+PROPERTY: header-args :exports code #+PROPERTY: header-args+ :noweb yes #+PROPERTY: header-args+ :results no #+PROPERTY: header-args+ :cache no #+PROPERTY: header-args+ :padline no #+PROPERTY: header-args+ :mkdirp yes #+OPTIONS: H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t - [[./doc-reform.org][doc-reform.org]] [[./][org/]] - [[./output_hub.org][output_hub]] * latex ** _module template_ :latex:pdf:module: *** latex.d module & templates #+HEADER: :tangle "../src/doc_reform/io_out/latex.d" #+HEADER: :noweb yes #+BEGIN_SRC d <> module doc_reform.io_out.latex; <> <> <> <> <> #+END_SRC *** template paperLaTeX #+NAME: Template_paper_latex #+HEADER: :noweb yes #+BEGIN_SRC d template paperLaTeX() { import std.format, std.conv : to; auto paperLaTeX() { <> return PaperType(); } } #+END_SRC *** template outputLaTeX #+NAME: Template_output_latex #+HEADER: :noweb yes #+BEGIN_SRC d template outputLaTeX() { <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> } #+END_SRC *** template outputLaTeXstyInit #+NAME: Template_latex_init #+HEADER: :noweb yes #+BEGIN_SRC d template outputLaTeXstyInit() { import doc_reform.io_out; auto paper = paperLaTeX; <> <> } #+END_SRC *** template outputLaTeXstyStatic #+NAME: Template_latex_sty_static #+HEADER: :noweb yes #+BEGIN_SRC d template outputLaTeXstyStatic() { <> string outputLaTeXstyStatic( bool generated_by, string name_version_and_compiler, string time_output_generated, ) { <> return latex_sty; } } #+END_SRC *** template outputLaTeXstyPaperSizeAndOrientation #+NAME: Template_latex_sty_paper_dimensions #+HEADER: :noweb yes #+BEGIN_SRC d template outputLaTeXstyPaperSizeAndOrientation() { <> auto outputLaTeXstyPaperSizeAndOrientation(P)( P doc_sty_info, bool generated_by, string name_version_and_compiler, string time_output_generated, ) { <> return latex_sty; } } #+END_SRC ** write latex output :latex:out: *** write latex output :latex:out: #+NAME: Function_output_write #+BEGIN_SRC d void writeOutputLaTeX(T,M)( const T latex_content, M doc_matters, string paper_size_orientation, ) { auto pth_latex = spinePathsLaTeX(doc_matters); try { { /+ debug +/ if (doc_matters.opt.action.debug_do_latex && doc_matters.opt.action.vox_gt1) { writeln(latex_content.head); writeln(latex_content.content); writeln(latex_content.tail); } } if (!exists(pth_latex.latex_path_stuff)) { (pth_latex.latex_path_stuff).mkdirRecurse; } if (doc_matters.opt.action.vox_gt0) { writeln(" ", pth_latex.latex_file_with_path(paper_size_orientation)); } { auto f = File(pth_latex.latex_file_with_path(paper_size_orientation), "w"); f.writeln(latex_content.head); f.writeln(latex_content.content); f.writeln(latex_content.tail); foreach (image; doc_matters.srcs.image_list) { string fn_src_in = doc_matters.src.image_dir_path ~ "/" ~ image; string fn_src_out_file = pth_latex.latex_path_stuff ~ "/" ~ image; if (exists(fn_src_in)) { fn_src_in.copy(fn_src_out_file); } } } if (!exists(pth_latex.latex_path_stuff ~ "/index.html")) { import doc_reform.io_out.html_snippet; mixin htmlSnippet; auto f = File(pth_latex.latex_path_stuff ~"/index.html", "w"); f.writeln(format_html_blank_page_guide_home( "../../css/html_scroll.css", (doc_matters.opt.action.webserver_url_doc_root.length > 0) ? doc_matters.opt.action.webserver_url_doc_root : doc_matters.conf_make_meta.conf.w_srv_data_root_url , "../../index.html", )); } // should be in latex init and done just once, doc_matters not passed there though if (!exists(pth_latex.base ~ "/index.html")) { import doc_reform.io_out.html_snippet; mixin htmlSnippet; auto f = File(pth_latex.base ~"/index.html", "w"); f.writeln(format_html_blank_page_guide_home( "../css/html_scroll.css", (doc_matters.opt.action.webserver_url_doc_root.length > 0) ? doc_matters.opt.action.webserver_url_doc_root : doc_matters.conf_make_meta.conf.w_srv_data_root_url, "../index.html", )); } if (!exists(pth_latex.base_sty ~ "/index.html")) { import doc_reform.io_out.html_snippet; mixin htmlSnippet; auto f = File(pth_latex.base_sty ~"/index.html", "w"); f.writeln(format_html_blank_page_guide_home( "../../css/html_scroll.css", (doc_matters.opt.action.webserver_url_doc_root.length > 0) ? doc_matters.opt.action.webserver_url_doc_root : doc_matters.conf_make_meta.conf.w_srv_data_root_url, "../../index.html", )); } } catch (ErrnoException ex) { // handle error } } #+END_SRC *** latex output hub [#A] :latex:pdf:out: #+NAME: Function_output_set #+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(); foreach (paper_size_orientation; doc_matters.conf_make_meta.conf.set_papersize) { latex.head = latex_head(doc_matters, paper_size_orientation); latex.content = latex_body(doc_abstraction, doc_matters, paper_size_orientation); latex.tail = latex_tail(doc_matters, paper_size_orientation); latex.writeOutputLaTeX(doc_matters, paper_size_orientation); } } #+END_SRC *** styles :latex:out: **** initialize #+NAME: Initialize_output_style #+BEGIN_SRC d import std.format, std.conv : to; #+END_SRC **** write latex styles output :latex:out: ***** write #+NAME: Function_output_style_write #+BEGIN_SRC d void writeOutputLaTeXstyStatic( string latex_sty, string output_dir, string filename, ) { if ((output_dir.length > 0) && isValidPath(output_dir) ) { auto pth_latex = spinePathsLaTeXsty(output_dir); try { import std.file; if (!exists(pth_latex.base_sty)) { (pth_latex.base_sty).mkdirRecurse; } { auto f = File(pth_latex.latex_document_header_sty(filename), "w"); f.writeln(latex_sty); } } catch (ErrnoException ex) { // handle error } } } #+END_SRC ***** request write (send to be written) #+NAME: Function_output_stylesheets_get_each_written #+BEGIN_SRC d void outputLaTeXstyInit()( string output_dir, bool generated_by, string name_version_and_compiler, string time_output_generated, ) { string latex_sty = outputLaTeXstyStatic!()(generated_by, name_version_and_compiler, time_output_generated); latex_sty.writeOutputLaTeXstyStatic(output_dir, "spineShared.sty"); auto sty_a4p = paper.a4.portrait; auto latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a4p, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a4p.stylesheet ~ ".sty"); auto sty_a4l = paper.a4.landscape; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a4l, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a4l.stylesheet ~ ".sty"); auto sty_b4p = paper.b4.portrait; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_b4p, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_b4p.stylesheet ~ ".sty"); auto sty_b4l = paper.b4.landscape; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_b4l, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_b4l.stylesheet ~ ".sty"); auto sty_a5p = paper.a5.portrait; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a5p, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a5p.stylesheet ~ ".sty"); auto sty_a5l = paper.a5.landscape; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_a5l, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_a5l.stylesheet ~ ".sty"); auto sty_letter_p = paper.letter.portrait; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_letter_p, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_letter_p.stylesheet ~ ".sty"); auto sty_letter_l = paper.letter.landscape; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_letter_l, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_letter_l.stylesheet ~ ".sty"); auto sty_legal_p = paper.legal.portrait; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_legal_p, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_legal_p.stylesheet ~ ".sty"); auto sty_legal_l = paper.legal.landscape; latex_papersize_and_orientation = outputLaTeXstyPaperSizeAndOrientation!()(sty_legal_l, generated_by, name_version_and_compiler, time_output_generated); latex_papersize_and_orientation.writeOutputLaTeXstyStatic(output_dir, sty_legal_l.stylesheet ~ ".sty"); } #+END_SRC **** sty: paper dimensions sty (calls static sty) #+NAME: FmtTxt_output_style_paper_dimensions_set #+BEGIN_SRC d string latex_sty = format(q"┃%%%% spine LaTeX output%s%s %% - called by .tex document to set paper dimensions (size and orientation) %% - calls spineShared.sty used/shared by all spine documents \ProvidesPackage{./sty/%s} \usepackage{geometry} \geometry{ %s, %s, left=%s, right=%s, top=%s, bottom=%s, } \usepackage{./sty/spineShared}┃", generated_by ? " " ~ name_version_and_compiler : "", generated_by ? " (generated " ~ time_output_generated ~ ")" : "", doc_sty_info.stylesheet, doc_sty_info.papersize, doc_sty_info.orient, doc_sty_info.margin_left, doc_sty_info.margin_right, doc_sty_info.margin_top, doc_sty_info.margin_bottom, ); #+END_SRC **** sty: in common fonts to try: #+BEGIN_SRC latex \usepackage[scaled]{dejavu} \renewcommand*\familydefault{\sfdefault} \usepackage{inconsolata} \usepackage[T1]{fontenc} #+END_SRC #+BEGIN_SRC latex \usepackage[scaled]{dejavu} \usepackage[scaled]{tgheros} \usepackage[scaled]{quattrocento} \usepackage[scaled]{cmbright} \usepackage[scaled]{tgadventor} \usepackage[scaled]{bookman} \usepackage[scaled]{libertine} \usepackage[scaled]{bera} \usepackage[scale=.95,type1]{arev} \usepackage[scale=.95,type1]{cabin} #+END_SRC #+NAME: FmtTxt_output_style_static_set #+BEGIN_SRC latex string latex_sty = format(q"┃%%%% spine LaTeX output%s%s %% - called by the .sty containing the paper dimensions (size and orientation) to be used %% - spineShared.sty used by all spine documents (called indirectly) \ProvidesPackage{./sty/spineShared} \usepackage{multicol} \setlength{\marginparsep}{4mm} \setlength{\marginparwidth}{8mm} \usepackage[scaled]{dejavu} \renewcommand*\familydefault{\sfdefault} \usepackage{inconsolata} \usepackage[T1]{fontenc} \usepackage{newunicodechar} %% \usepackage[utf8]{inputenc} \usepackage{alltt} \usepackage[ unicode=true, pdfusetitle, pdfsubject={}, pdfkeywords={}, %% keywords list {} {} {}, pdftoolbar=true, pdfmenubar=true, pdfwindowui=true, pdffitwindow=false, %% window fit to page when opened pdfstartview={FitH}, %% fits the width of the page to the window pdfnewwindow=true, %% links in new window pdfborder={0 0 1}, plainpages=false, %% was true bookmarks=true, bookmarksopen=false, bookmarksnumbered=false, backref=false, breaklinks=false, colorlinks=true, urlcolor=black, filecolor=black, linkcolor=black, citecolor=black, %% links_mono_or_color_set ]{hyperref} \PassOptionsToPackage{hyphens}{url}\usepackage{hyperref} \usepackage[usenames]{color} \definecolor{myblack}{rgb}{0,0,0} \definecolor{myred}{rgb}{0.75,0,0} \definecolor{mygreen}{rgb}{0,0.5,0} \definecolor{myblue}{rgb}{0,0,0.5} \definecolor{mywhite}{rgb}{1,1,1} \usepackage{textcomp} \usepackage[parfill]{parskip} \usepackage[normalem]{ulem} \usepackage{soul} \usepackage{longtable} \usepackage{graphicx} \usepackage[tc]{titlepic} \usepackage{amssymb} \usepackage{amsmath} \usepackage[cm]{sfmath} \usepackage{underscore} \usepackage{listings} \setcounter{secnumdepth}{2} \setcounter{tocdepth}{4} \usepackage{bookmark} \usepackage{microtype} \makeatletter \usepackage[multiple,ragged]{footmisc} \setlength\footnotemargin{12pt} \usepackage[para]{manyfoot} \DeclareNewFootnote{A} \makeatother \chardef\txtbullet="2022 \chardef\tilde="7E \def\asterisk{{\rm \char42} } \definecolor{Light}{gray}{.92} \definecolor{listinggray}{gray}{0.9} \definecolor{lbcolor}{rgb}{0.9,0.9,0.9} \lstset{ backgroundcolor=\color{lbcolor}, tabsize=4, rulecolor=, language=, basicstyle={\ttfamily\scriptsize}, upquote=true, columns=fixed, showstringspaces=false, extendedchars=true, breaklines=true, prebreak = \raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}}, frame=single, showtabs=false, showspaces=false, showstringspaces=false, identifierstyle=\ttfamily, keywordstyle=\color[rgb]{0,0,1}, commentstyle=\color[rgb]{0.133,0.545,0.133}, stringstyle=\color[rgb]{0.627,0.126,0.941}, } \DeclareTOCStyleEntry[numwidth+=8pt]{part}{part} \DeclareTOCStyleEntry[numwidth+=4pt]{section}{section} \DeclareTOCStyleEntry[numwidth+=3pt]{section}{paragraph} \DeclareTOCStyleEntry[numwidth+=3pt]{section}{subparagraph} \DeclareTOCStyleEntry[numwidth+=3pt]{section}{subsection} \DeclareTOCStyleEntries[indent+=4pt]{section}{section,subsection,subsubsection} \DeclareTOCStyleEntries[numwidth+=3pt]{section}{paragraph,subparagraph} \newenvironment{ParagraphIndent}[1]{%% \begin{list}{}{%% \setlength\topsep{0pt}%% \addtolength{\leftmargin}{#1} \setlength\parsep{0pt plus 1pt}%% } \item[] } {\end{list}} \newenvironment{ParagraphHang}[2]{%% \begin{list}{}{%% \setlength\topsep{0pt}%% \addtolength{\leftmargin}{#1} \itemindent=#2 \setlength\parsep{0pt plus 1pt}%% } \item[] } {\end{list}} \newenvironment{Bullet}[1]{%% \begin{list}{}{%% \setlength\topsep{0pt}%% \addtolength{\leftmargin}{#1} \itemindent=-1em \setlength\parsep{0pt plus 1pt}%% } \item[] $\txtbullet$\hspace{\enspace} } {\end{list}} \newcommand{\monosp}[1]{\normaltext\ttfamily\texbackslash#1} \newcommand{\br}{\hfill\break} \newcommand{\brl}[1]{%% \ifx&%% \hfill\break \else \vspace{#1ex} \fi } \newcommand{\brln}{\hspace*{\fill}\linebreak} \newcommand{\objBlockOpen}{%% \setlength{\parskip}{0.5ex plus0.2ex minus0.1ex}\raggedright \begin{footnotesize} } \newcommand{\objBlockClose}{%% \end{footnotesize} \setlength{\parskip}{1ex plus0.5ex minus0.2ex} } \newcommand{\objGroupOpen}{%% \setlength{\parskip}{0.5ex plus0.2ex minus0.1ex} \begin{footnotesize} } \newcommand{\objGroupClose}{%% \end{footnotesize} } \newcommand{\objPoemVerseOpen}{%% \setlength{\parskip}{0.1ex plus0.1ex minus0.1ex} \begin{footnotesize} } \newcommand{\objPoemVerseClose}{%% \end{footnotesize} \setlength{\parskip}{1ex plus0.5ex minus0.2ex} \linebreak } \newcommand{\parasep}{%% \smallskip \begin{center}*\hspace{2em}*\hspace{2em}*\end{center} \br } \newcommand{\spaces}[1]{{\hspace*{#1ex}}} \newcommand{\s}{\hspace*{1ex}} \newcommand{\hardspace}{\hspace*{1ex}} \newcommand{\-}{\hspace*{1ex}} \newcommand{\caret}{{\^{~}}} \newcommand{\pipe}{{\textbar}} \newcommand{\curlyOpen}{{} \newcommand{\curlyClose}{}} \newcommand{\lt}{{UseTextSymbol{OML}{<}}} \newcommand{\gt}{{UseTextSymbol{OML}{>}}} \newcommand{\slash}{{/}} \newcommand{\underscore}{\_} \newcommand{\exclaim}{\Verbatim{!}} \newcommand{\linktext}[2]{%% {\href{#1} {\;\ulcorner\,\textup{{#2}}\,\lrcorner}} } \newcommand{\linkurl}[2]{%% \;{\href{#1} {\;\scriptsize\ttfamily\ulcorner\,\textup{{#2}}\,\lrcorner}} } \newcommand{\link}[2]{%% {\begin{scriptsize}\color{black}\urlstyle{tt}\href{#1} {\;\ulcorner\,{#2}\,\lrcorner}\end{scriptsize}} } \newcommand{\objCodeBlock}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} \newcommand{\objCodeOpen}{%% \normaltext\raggedright\small\ttfamily\texbackslash \begin{lstlisting} } \newcommand{\objCodeClose}{%% \end{lstlisting} } \newcommand{\ocn}[1]{%% \setlength{\parindent}{0em} \ifx&%% #1 is empty \hspace{-0.5ex}{\marginpar{\begin{tiny}\end{tiny}}} \else%% #1 is nonempty \hspace{-0.5ex}{\marginpar{\begin{tiny}\hspace{0em}\hypertarget{#1}{#1}\end{tiny}}} \fi } \newcommand{\ocnhold}[1]{%% \begin{tiny}\hspace{0mm}\end{tiny}{\marginpar{\begin{tiny}\hspace{0mm}\hypertarget{#1}{#1}\end{tiny}}} } \newcommand{\objCodeBlockHold}[1]{\normaltext\raggedright\small\ttfamily\texbackslash#1} \newcommand{\objTableOpen}[1]{%% \setlength{\LTleft}{0pt} \setlength{\LTright}{\fill} \begin{tiny} \begin{longtable}{#1} } \newcommand{\objTableClose}{%% \end{longtable} \end{tiny} } %% \tolerance=300 %% \clubpenalty=300 %% \widowpenalty=300 %% \usepackage{atbegshi} %% http://ctan.org/pkg/atbegshi %% (BUG tmp FIX deal with problem, remove first page which is blank) %% \AtBeginDocument{\AtBeginShipoutNext{\AtBeginShipoutDiscard}} %% (BUG tmp FIX deal with problem, remove first page which is blank) ┃", generated_by ? " " ~ name_version_and_compiler : "", generated_by ? " (generated " ~ time_output_generated ~ ")" : "", ); #+END_SRC * stuff ** output imports #+NAME: ImportsAndMixins_imports #+BEGIN_SRC d import std.digest.sha, std.file, std.outbuffer, std.uri, std.conv : to; import doc_reform.io_out, doc_reform.io_out.rgx, doc_reform.io_out.rgx_latex; mixin spineRgxOut; static auto rgx = RgxO(); mixin spineRgxLSC; static auto rgx_sc = RgxLSC(); mixin spineLanguageCodes; auto lang = Lang(); auto paper = paperLaTeX; #+END_SRC ** shared *** paper dimensions (struct) geometry #+NAME: Struct_shared_geometry_paper_dimensions #+BEGIN_SRC d string mm(uint mmi) { string _mm = format(q"┃%smm┃", mmi.to!string); return _mm; } struct PaperType { @safe auto a4() { struct A4 { auto portrait() { struct V { string stylesheet = "spineA4portrait"; string papersize = "a4paper"; string orient = "portrait"; string fontsize = "11pt"; const uint w = 170; const uint h = 257; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 450; bool is_portrait = true; } return V(); } auto landscape() { struct H { string stylesheet = "spineA4landscape"; string papersize = "a4paper"; string orient = "landscape"; string fontsize = "11pt"; const uint w = 238; const uint h = 160; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 300; bool is_portrait = false; } return H(); } } return A4(); } @safe auto a5() { struct A5 { auto portrait() { struct V { string stylesheet = "spineA5portrait"; string papersize = "a5paper"; string orient = "portrait"; string fontsize = "11pt"; const uint w = 112; const uint h = 162; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 280; bool is_portrait = true; } return V(); } auto landscape() { struct H { string stylesheet = "spineA5landscape"; string papersize = "a5paper"; string orient = "landscape"; string fontsize = "11pt"; const uint w = 152; const uint h = 100; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 190; bool is_portrait = false; } return H(); } } return A5(); } @safe auto b4() { struct B4 { auto portrait() { struct V { string stylesheet = "spineB4portrait"; string papersize = "b4paper"; string orient = "portrait"; string fontsize = "11pt"; const uint w = 140; const uint h = 204; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 356; bool is_portrait = true; } return V(); } auto landscape() { struct H { string stylesheet = "spineB4landsape"; string papersize = "b4paper"; string orient = "landscape"; string fontsize = "11pt"; const uint w = 200; const uint h = 130; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 260; bool is_portrait = false; } return H(); } } return B4(); } @safe auto letter() { struct Letter { auto portrait() { struct V { string stylesheet = "spineLetterPortrait"; string papersize = "letterpaper"; string orient = "portrait"; string fontsize = "11pt"; const uint w = 166; const uint h = 212; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 468; bool is_portrait = true; } return V(); } auto landscape() { struct H { string stylesheet = "spineLetterLandscape"; string papersize = "letterpaper"; string orient = "landscape"; string fontsize = "11pt"; const uint w = 226; const uint h = 166; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 290; bool is_portrait = false; } return H(); } } return Letter(); } @safe auto legal() { struct Legal { auto portrait() { struct V { string stylesheet = "spineLegalPortrait"; string papersize = "legalpaper"; string orient = "portrait"; string fontsize = "11pt"; const uint w = 168; const uint h = 286; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 474; bool is_portrait = true; } return V(); } auto landscape() { struct H { string stylesheet = "spineLegalLandscape"; string papersize = "legalpaper"; string orient = "landscape"; string fontsize = "11pt"; const uint w = 296; const uint h = 166; const uint l = 30; const uint r = 20; const uint t = 30; const uint b = 30; string width = mm(w); string height = mm(h); string margin_left = mm(l); string margin_right = mm(r); string margin_top = mm(t); string margin_bottom = mm(b); uint img_px = 420; bool is_portrait = false; } return H(); } } return Legal(); } } #+END_SRC *** latex \escape special characters **** object (string text within) - “” characters not directly available for use in font - run into problems using " for quotes and modified latex header - (m => "\"") - \usepackage[autostyle, english = american]{csquotes} \MakeOuterQuote{"} - (m => "''") works alone better #+NAME: Function_shared_special_characters_to_escape_operations #+BEGIN_SRC d @safe string sp_char_ops()( string _txt, ) { string _unescape_sp_char_esc()(string _txt) { _txt = _txt .replaceAll(rgx_sc.latex_special_char_escaped, format(q"┃%s┃", "$1")) .replaceAll(rgx_sc.latex_special_char_escaped_braced, format(q"┃%s┃", "$1")); return _txt; } string _unescape_fontface_esc()(string _txt) { _txt = _txt.replaceAll(rgx_sc.latex_identify_inline_fontface, format(q"┃%s%s┃", "$1", "$2")); return _txt; } _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx_sc.latex_special_char_for_escape); _txt = replaceAll!(m => "{\\" ~ m[1] ~ "}")(_txt, rgx_sc.latex_special_char_for_escape_and_braces); _txt = replaceAll!(m => "''")(_txt, rgx.quotes_open_and_close); _txt = replaceAll!(m => "$\\cdot$")(_txt, rgx.middle_dot); _txt = replaceAll!(m => _unescape_sp_char_esc(m[0]))(_txt, rgx_sc.latex_identify_inline_link); _txt = replaceAll!(m => _unescape_fontface_esc(m[0]))(_txt, rgx_sc.latex_identify_inline_fontface); return _txt; } #+END_SRC #+NAME: Function_shared_special_characters_to_escape_object #+BEGIN_SRC d @safe string sp_char_esc(O)( string _txt, const O obj, ) { if (obj.metainfo.is_a != "code") { _txt = _txt.sp_char_ops; } return _txt; } #+END_SRC **** string text #+NAME: Function_shared_special_characters_to_escape_text #+BEGIN_SRC d @safe string sp_char_esc_txt()( string _txt, ) { _txt = _txt.sp_char_ops; return _txt; } #+END_SRC ***** line breaks #+NAME: Function_shared_marked_linebreaks_newline_to_latex #+BEGIN_SRC d @safe string marked_linebreaks_newlines()( string _txt, ) { _txt = _txt.split(rgx.br_linebreaks_newlines).join("\\br\n").strip; // _txt = replaceAll!(m => "\\br " ~ m[1])(_txt, rgx.br_linebreaks_newlines); return _txt; } #+END_SRC *** not used latex \escape special characters UNUSED #+BEGIN_SRC d @safe string sp_char_esc_()( string _txt, ) { _txt = replaceAll!(m => "\\" ~ m[1])(_txt, rgx_sc.latex_special_char); return _txt; } #+END_SRC *** inline markup **** fontface - bold, italics, underscore, strikethrough #+NAME: Function_shared_fontface #+BEGIN_SRC d @safe string fontface()( string _txt, ) { _txt = _txt .replaceAll(rgx.inline_emphasis, format(q"┃\begin{bfseries}%s\end{bfseries}┃", "$1")) .replaceAll(rgx.inline_bold, format(q"┃\begin{bfseries}%s\end{bfseries}┃", "$1")) .replaceAll(rgx.inline_italics, format(q"┃\emph{%s}┃", "$1")) .replaceAll(rgx.inline_italics, format(q"┃\uline{%s}┃", "$1")) .replaceAll(rgx.inline_superscript, format(q"┃$$^{%s}$$┃", "$1")) .replaceAll(rgx.inline_subscript, format(q"┃$$_{%s}$$┃", "$1")) .replaceAll(rgx.inline_strike, format(q"┃\sout{%s}┃", "$1")) .replaceAll(rgx.inline_insert, format(q"┃\uline{%s}┃", "$1")) .replaceAll(rgx.inline_mono, format(q"┃\begin{monosp}%s\end{monosp}┃", "$1")) .replaceAll(rgx.inline_italics, format(q"┃``%s''┃", "$1")); return _txt; } #+END_SRC **** spaces ***** leading hardspace UNUSED #+NAME: Function_shared_leading_hardspaces #+BEGIN_SRC d @safe string leading_hardspaces()( string _txt, ) { string hardspaces(string _spaces) { _spaces = _spaces .replaceAll(rgx.space, "{\\s}"); return _spaces; } _txt = replaceAll!(m => hardspaces(m[0]))(_txt, rgx.spaces_line_start); return _txt; } #+END_SRC ***** nbsp character UNUSED #+NAME: output_latex_shared_character_nbsp_to_hardspace_ #+BEGIN_SRC d @safe string nbsp_char_replace()(string _txt) { if (_txt.match(rgx.nbsp_char)) { _txt = _txt.replaceAll(rgx.nbsp_char, "{\\s}"); } return _txt; } #+END_SRC ***** nbsp character #+NAME: Function_shared_character_nbsp_to_hardspace #+BEGIN_SRC d @safe string nbsp_char()(string _txt) { if (_txt.match(rgx.nbsp_char)) { foreach (m; _txt.matchAll(rgx.nbsp_chars)) { int spaces_ = 0; foreach (n; m[0].matchAll(rgx.nbsp_char)) { spaces_ ++; } _txt = _txt.replaceFirst(rgx.nbsp_chars, "\\spaces{" ~ spaces_.to!string ~ "}"); } } return _txt; } #+END_SRC ***** keep spaces #+NAME: Function_shared_character_spaces_to_hardspace #+BEGIN_SRC d @safe string spaces_to_nbsp()(string _txt) { if (_txt.match(rgx.spaces_keep)) { foreach (m; _txt.matchAll(rgx.spaces_keep)) { int spaces_ = 0; foreach (n; m[0].matchAll(rgx.space)) { spaces_ ++; } _txt = _txt.replaceFirst(rgx.spaces_keep, "\\spaces{" ~ spaces_.to!string ~ "}"); } } return _txt; } #+END_SRC ***** remove nbsp character #+NAME: Function_shared_character_nbsp_to_space #+BEGIN_SRC d @safe 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: Function_shared_links_and_images #+BEGIN_SRC d @safe string links_and_images(O,M)( string _txt, const O obj, M doc_matters, ) { if (obj.has.inline_links) { // TODO some images do not have inline links ... image without link string _width_adjust(string _width) { if (_width.to!int > 300) { _width = "300"; } // will need to vary max with papersize & orientation return _width; } string _latex_image_path(string _image_path) { auto pth_latex = spinePathsLaTeX(doc_matters); _image_path = pth_latex.latex_path_stuff ~ "/" ~ _image_path; return _image_path; } string _if_images(string _linked_content) { if (_linked_content.match(rgx.inline_image_info)) { _linked_content = replaceAll!(m => format(q"┃\includegraphics*[width=%spt]{%s}%s┃", _width_adjust(m[2]), _latex_image_path(m[1]), " \\br\n") )(_linked_content, rgx.inline_image_info); } return _linked_content; } string _check_link(string _link) { _link = _link .replaceFirst(rgx_sc.latex_clean_internal_link, "") .replaceAll(rgx_sc.latex_special_char_for_escape_url, "\\$1"); return _link; } if (obj.metainfo.is_a != "code") { _txt = replaceAll!(m => m[1] ~ "┤" ~ to!string((obj.stow.link[m[2].to!ulong])).encode ~ "├" )(_txt, rgx.inline_link_number_only); _txt = replaceAll!(m => ((m[1] == m[2]) && (m[2].match(rgx.uri))) // url link (regular link with url) ? format(q"┃\linkurl{%s}{%s}┃", _check_link(m[1]), (_check_link(m[1])).sp_char_esc_txt) : ((m[2].match(rgx.uri)) && (m[1].match(rgx.inline_image_info))) // linked image ? format(q"┃%s\href{%s}%s{%s}┃", "\\br ", _check_link(m[2]), "\n", _if_images(m[1])) // markup for images : (m[2].match(rgx.uri)) // not linked image ? format(q"┃%s\linktext{%s}{%s}┃", "\\br ", _check_link(m[2]), m[1]) // regular link with text : format(q"┃\hyperlink{%s}{%s}┃", _check_link(m[2]), _if_images(m[1])) // internal links, like book index )(_txt, rgx.inline_link); } } return _txt; } #+END_SRC *** footnotes **** footnotes #+NAME: Function_shared_footnotes #+BEGIN_SRC d @safe string footnotes()( string _txt, ) { if (_txt.match(rgx.inline_notes_al_gen)) { string _tex_note = q"┃\hypertarget{noteref_%s}{}\footnote[%s]{%% \label{note_%s}%s}┃"; _txt = _txt.split(rgx.br_linebreaks).join("\\br ").replaceAll(rgx.inline_notes_al_regular_number_note, format(_tex_note, "$1", "$1", "$1", "$2".strip ).strip ); } return _txt; } #+END_SRC **** footnote remove #+NAME: Function_shared_footnotes_remove #+BEGIN_SRC d @safe 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: Function_shared_para #+BEGIN_SRC d @safe string para(O)( string _txt, O obj, ) { if (obj.metainfo.is_of_type == "para") { string _tex_para; _tex_para = q"┃\ocn{%s}%s┃"; _txt = format(_tex_para, obj.metainfo.object_number, _txt.footnotes ).strip; } return _txt; } #+END_SRC **** bookindex para #+NAME: Function_shared_bookindex #+BEGIN_SRC d @safe string bookindex(O)( string _txt, O obj, ) { if (obj.metainfo.is_of_type == "para" && obj.metainfo.is_a == "bookindex" ) { string _tex_para; _tex_para = q"┃%s┃"; _txt = format(_tex_para, _txt.replaceAll(rgx_sc.latex_clean_bookindex_linebreak, "\n") ~ "\n\\brln\n" ); } return _txt; } #+END_SRC *** bullets & indentation #+NAME: Function_head_bullets_and_indentation #+BEGIN_SRC d @safe string bullets_and_indentation(O)( string _txt, O obj, ) { string _tex_para; string _hang; string _indent; int _paper_margin = -10; int _indent_increment = 8; // 5; 10; if (obj.attrib.bullet) { int _bullet_space = 5; _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin + _bullet_space).to!string; _txt = format(q"┃\begin{Bullet}{%smm}%s\end{Bullet}┃", _indent, _txt.footnotes ).strip; } else if ( obj.attrib.indent_base != 0 && obj.attrib.indent_base == obj.attrib.indent_hang ) { _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin).to!string; _tex_para = q"┃\begin{ParagraphIndent}{%smm}%s \end{ParagraphIndent}┃"; _txt = format(_tex_para, _indent, _txt.footnotes ).strip; } else if ( obj.attrib.indent_base != 0 || obj.attrib.indent_hang != 0 ) { _indent = ((obj.attrib.indent_base * _indent_increment) + _paper_margin).to!string; _hang = (((obj.attrib.indent_hang - obj.attrib.indent_base) * _indent_increment)).to!string; _tex_para = q"┃\begin{ParagraphHang}{%smm}{%smm}%s \end{ParagraphHang}┃"; _txt = format(_tex_para, _indent, _hang, _txt.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n") ).strip; } return _txt; } #+END_SRC *** heading #+NAME: Function_shared_heading #+BEGIN_SRC d @safe string heading(O,M)( string _txt, O obj, M doc_matters, string paper_size_orientation, string _part = "" ) { struct latexMarks { string pg_break = "\\clearpage\n"; } latexMarks manual_breaks( latexMarks _ltx, string test_for_break_level, ) { if ((!(doc_matters.conf_make_meta.make.breaks.empty) && (matchFirst(doc_matters.conf_make_meta.make.breaks, test_for_break_level))) ) { // manually override defaults if ((matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) && (matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) ) { if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) { if (matchFirst(m.captures["breakpage"], test_for_break_level)) { _ltx.pg_break = "\\clearpage\n"; } else if (auto n = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) { if (matchFirst(n.captures["breakcolumn"], test_for_break_level)) { if ((paper_size_orientation == "a4.landscape") || (paper_size_orientation == "b4.landscape") || (paper_size_orientation == "a5.landscape") || (paper_size_orientation == "letter.landscape") || (paper_size_orientation == "legal.landscape") ) { _ltx.pg_break = "\\\\ \\columnbreak\n"; // "\\\\ \\newpage\n"; } else { // portrait _ltx.pg_break = "\\clearpage\n"; } } } } } else if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakpage)) { if (matchFirst(m.captures["breakpage"], test_for_break_level)) { _ltx.pg_break = "\\clearpage\n"; } } else if (auto m = matchFirst(doc_matters.conf_make_meta.make.breaks, rgx.make_breakcolumn)) { if (matchFirst(m.captures["breakcolumn"], test_for_break_level)) { if ((paper_size_orientation == "a4.landscape") || (paper_size_orientation == "b4.landscape") || (paper_size_orientation == "a5.landscape") || (paper_size_orientation == "letter.landscape") || (paper_size_orientation == "legal.landscape") ) { _ltx.pg_break = "\\\\ \\columnbreak\n"; // "\\\\ \\newpage\n"; } else { // portrait _ltx.pg_break = "\\clearpage\n"; } } } } else if (!(doc_matters.conf_make_meta.make.breaks.empty)) { _ltx.pg_break = ""; } return _ltx; } if (obj.metainfo.is_a == "heading") { string _tex_para; latexMarks _ltx = latexMarks(); string _pg_break; string _sect; string _post; string _title_add; string _columns = ""; switch (obj.metainfo.heading_lev_markup) { case 0: // A == TITLE _pg_break = "\\begin{document}\n"; goto default; case 1: // B == part: section heading level _pg_break = "\\clearpage\n"; goto default; case 2: // C == part: section heading level _pg_break = "\\clearpage\n"; goto default; case 3: // D == part: section heading level _pg_break = "\\clearpage\n"; goto default; case 4: // 1 == section _columns = (_part != "bookindex") ? "" : "\n\\br\n\\begin{multicols}{2}"; if (doc_matters.conf_make_meta.make.doc_type == "article") { // defaults for article _ltx.pg_break = ""; } else if (doc_matters.conf_make_meta.make.doc_type == "book") { // defaults for book _ltx.pg_break = "\\clearpage\n"; } else { _ltx.pg_break = "\\clearpage\n"; } _ltx = manual_breaks(_ltx, "1"); _pg_break = _ltx.pg_break; _sect = "section"; _post = ""; _title_add = format(q"┃ \markboth{%s}{%s}┃", doc_matters.conf_make_meta.meta.title_full, doc_matters.conf_make_meta.meta.title_full, ); goto default; case 5: // 2 == subsection _pg_break = ""; // _pg_break = "newpage"; // doubt this is necessary _sect = "subsection"; _post = " \\br\n"; _title_add = ""; goto default; case 6: // 3 == subsubsection _pg_break = ""; // _pg_break = "newpage"; // doubt this is necessary _sect = "subsubsection"; _post = " \\br\n"; _title_add = ""; goto default; case 7: // 4 == paragraph _pg_break = ""; // _pg_break = "newpage"; // doubt this is necessary _sect = "paragraph"; _post = " \\br\n"; _title_add = ""; goto default; case 8: // 5 == subparagraph _pg_break = ""; // _pg_break = "newpage"; // doubt this is necessary _sect = "subparagraph"; _post = " \\br\n"; _title_add = ""; goto default; default: if (obj.metainfo.heading_lev_markup == 0) { _tex_para = q"┃ \begin{document} \thispagestyle{empty} \title{%s%s} \author{ \textnormal{%s}} \date{\begin{tiny}%s\end{tiny}} \maketitle \addcontentsline{toc}{part}{%s} \newpage \pagestyle{fancy} \pagenumbering{alph} \setcounter{page}{1} \markboth{%s}{%s} \br\linebreak Copyright {\begin{small}{\copyright\end{small}} %s \br\linebreak %s \clearpage┃"; _txt = format(_tex_para, (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, doc_matters.conf_make_meta.meta.title_subtitle.empty ? "" : " \\\\ - \\\\ " ~ (doc_matters.conf_make_meta.meta.title_subtitle).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.creator_author).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.date_published).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.rights_copyright).sp_char_esc_txt.marked_linebreaks_newlines, (doc_matters.conf_make_meta.meta.rights_license).sp_char_esc_txt.marked_linebreaks_newlines, ); } else if (obj.metainfo.heading_lev_markup < 4) { if (!(_txt.footnotes.strip == "Endnotes")) { _tex_para = q"┃%s\part*{\ocn{%s}%s} \addcontentsline{toc}{part}{%s} \markboth{%s}┃"; _txt = format(_tex_para, _pg_break, obj.metainfo.object_number, _txt.strip.footnotes, _txt.strip.remove_footnotes, (doc_matters.conf_make_meta.meta.title_main).sp_char_esc_txt, ); } } else if (obj.metainfo.heading_lev_markup > 3) { if (obj.metainfo.heading_lev_markup == 4 && _txt.match(regex(r"^Table of Contents$"))) { _tex_para = q"┃ \pagenumbering{arabic} \setcounter{page}{1} \markboth{ }{ } \part*{\ocn{1}%s \newline %s} \clearpage \pagenumbering{roman} \setcounter{page}{1} \renewcommand{\contentsname}{} \tableofcontents \clearpage \pagenumbering{arabic} \setcounter{page}{2} \clearpage \markboth{%s}{%s} %% \null \clearpage \setcounter{page}{2}┃"; _txt = format(_tex_para, (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.creator_author).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, (doc_matters.conf_make_meta.meta.title_full).sp_char_esc_txt, ); } else if (obj.metainfo.heading_lev_markup == 4 && _part == "bookindex" && _txt.match(regex(r"^Index$")) ) { _tex_para = q"┃%s\%s*{\ocn{%s}%s} \addcontentsline{toc}{%s}{%s%s}%s%s┃"; _txt = format(_tex_para, _pg_break, _sect.strip, obj.metainfo.object_number, _txt.footnotes.strip, _sect, _txt.remove_footnotes.strip, _post, _title_add, _columns, ); } else if (obj.metainfo.dummy_heading && obj.metainfo.heading_lev_markup == 4 ) { /+ dummy headings completely omitted +/ _txt = ""; } else { _tex_para = q"┃%s\%s*{\ocn{%s}%s} \addcontentsline{toc}{%s}{%s%s}%s┃"; _txt = format(_tex_para, _pg_break, _sect.strip, obj.metainfo.object_number, _txt.footnotes.strip, _sect, _txt.remove_footnotes.strip, _post, _title_add, ); } } break; } } return _txt.strip; } #+END_SRC *** grouped text **** group - (hardspace not honored) clear hardspace marker #+NAME: Function_shared_group #+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"┃\ocn{%s}\objGroupOpen %s \objGroupClose ┃"; _txt = format(_tex_para, obj.metainfo.object_number, _txt.footnotes.split(rgx.br_line_spaced).join("\\brl{1}").strip // provides more control (more noise, not as tidy) // _txt.footnotes.split(rgx.br_line_spaced).join("") // this works using a line-space, looks tidy, keep ref. ).strip; } return _txt; } #+END_SRC **** block - (hardspace honored) \hardspace #+NAME: Function_shared_block #+BEGIN_SRC d string block(O,M)( string _txt, O obj, M doc_matters, ) { if (obj.metainfo.is_a == "block") { string _tex_para; _tex_para = q"┃\ocn{%s}\objBlockOpen %s \objBlockClose ┃"; _txt = format(_tex_para, obj.metainfo.object_number, _txt.nbsp_char.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n").strip ).strip; } return _txt; } #+END_SRC **** (poem) verse - (hardspace honored) \hardspace #+NAME: Function_shared_verse #+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"┃\ocn{%s}\objPoemVerseOpen %s \objPoemVerseClose ┃"; _txt = format(_tex_para, obj.metainfo.object_number, _txt.spaces_to_nbsp.footnotes.split(rgx.br_linebreaks_newlines).join("\\br\n").strip ).strip; } return _txt; } #+END_SRC **** codeblock - (hardspace honored) \begin{lstlisting} clear hardspace marker #+NAME: Function_shared_codeblock #+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"┃\ocn{%s}\begin{objCodeBlock}\begin{lstlisting} %s \end{lstlisting}\end{objCodeBlock} ┃"; _txt = format(_tex_para, obj.metainfo.object_number, _txt.nbsp_char_to_space ).strip; } return _txt; } #+END_SRC **** table - own set of rules ***** tablarize #+NAME: Function_shared_tablarize #+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 ~= "\\\\"; } Tuple!(string, string) t = tuple( _table, _tablenote, ); return t; } #+END_SRC ***** table #+NAME: Function_shared_table #+BEGIN_SRC d string table(O,M)( string _txt, O obj, M doc_matters, string paper_size_orientation, ) { if (obj.metainfo.is_a == "table") { auto _t = _txt.tablarize(obj); string _table = _t[0]; string _t_n = _t[1]; uint pw = 0; switch (paper_size_orientation) { case "a4.portrait": pw = (paper.a4.portrait.w - 20); break; case "a4.landscape": pw = (paper.a4.landscape.w - 20); break; case "b4.portrait": pw = (paper.b4.portrait.w - 20); break; case "b4.landscape": pw = (paper.b4.landscape.w - 20); break; case "a5.portrait": pw = (paper.a5.portrait.w - 20); break; case "a5.landscape": pw = (paper.a5.landscape.w - 20); break; case "letter.portrait": pw = (paper.letter.portrait.w - 20); break; case "letter.landscape": pw = (paper.letter.landscape.w - 20); break; case "legal.portrait": pw = (paper.legal.portrait.w - 20); break; case "legal.landscape": pw = (paper.legal.landscape.w - 20); break; default: pw = 0; break; } // auto textwidth = (pw - 24); string _colw = ""; foreach (w; obj.table.column_widths) { _colw ~= format(q"┃p{%.0fmm}┃", (w * pw / 100) // (w * (pw - 24)/ 100) // (w * textwidth / 100) ); } string _tex_para; _tex_para = q"┃\ocn{%s}\objTableOpen{%s} %s \objTableClose ┃"; _txt = format(_tex_para, obj.metainfo.object_number, _colw, _table, ).strip; } return _txt; } #+END_SRC ** latex parts *** latex head :head: **** latex head function #+NAME: MethodOpen_head #+BEGIN_SRC d string latex_head(M)( M doc_matters, string paper_size_orientation, ) { #+END_SRC **** latex head options ***** paper type dimensions ****** struct #+NAME: Struct_head_papertype #+BEGIN_SRC d struct paperTypeLatex { string a4_portrait; string a4_landscape; string b4_portrait; string b4_landscape; string a5_portrait; string a5_landscape; string us_letter_portrait; string us_letter_landscape; string us_legal_portrait; string us_legal_landscape; } auto paper_type_latex = paperTypeLatex(); #+END_SRC ****** footer #+NAME: Function_head_footer #+BEGIN_SRC d string _footer(M)(M doc_matters) { string _ft = "\\lfoot[\\textrm{\\thepage}]"; string _ft_1 = format(q"┃{\tiny \href{%s}{%s}}┃", "https://sisudoc.org", "SiSU",); string _ft_2 = format(q"┃ \cfoot{\href{%s}{%s}}┃", "https://git.sisudoc.org", "git",); if (doc_matters.conf_make_meta.make.footer.length > 0) { if (doc_matters.conf_make_meta.make.footer.length > 0) { if (doc_matters.conf_make_meta.make.footer[0].matchAll(rgx.inline_link)) { _ft ~= doc_matters.conf_make_meta.make.footer[0] .replace(rgx.inline_link, "{\\tiny \\href{$2}{$1}}"); } else { _ft ~= _ft_1; } } if (doc_matters.conf_make_meta.make.footer.length > 1) { if (doc_matters.conf_make_meta.make.footer[1].matchAll(rgx.inline_link)) { _ft ~= doc_matters.conf_make_meta.make.footer[1] .replace(rgx.inline_link, "\n\\cfoot{\\href{$2}{$1}}"); } else { _ft ~= _ft_2; } } } else { _ft ~= _ft_1; _ft ~= _ft_2; } return _ft; } #+END_SRC ***** paper margins ****** struct #+NAME: Struct_head_tex_papermargins #+BEGIN_SRC d struct paperMargins { string portrait; string landscape; } auto margins = paperMargins(); #+END_SRC ***** multicol ****** struct #+NAME: Struct_head_tex_columns_multi #+BEGIN_SRC d struct columnsMulti { string portrait; string landscape; } auto multicol = columnsMulti(); #+END_SRC ****** portrait #+NAME: FmtTxtOpen_head_tex_columns_multi_portrait #+BEGIN_SRC d multicol.portrait = format(q"┃ #+END_SRC #+NAME: FmtTxtSet_head_tex_columns_multi_portrait #+BEGIN_SRC latex \usepackage{multicol} #+END_SRC #+NAME: FmtTxtClose_head_tex_columns_multi_portrait #+BEGIN_SRC d ┃", ); #+END_SRC ****** landscape #+NAME: VarSet_head_tex_columns_multi_landscape #+BEGIN_SRC d multicol.landscape = ""; #+END_SRC ***** color links ****** struct #+NAME: Struct_head_tex_colorlinks #+BEGIN_SRC d struct colorLinks { string mono; string color; } auto links = colorLinks(); #+END_SRC ****** mono #+NAME: FmtTxtOpen_head_tex_colorlinks_mono #+BEGIN_SRC d links.mono = format(q"┃ #+END_SRC #+NAME: FmtTxtSet_head_tex_colorlinks_mono #+BEGIN_SRC latex colorlinks=true, urlcolor=black, filecolor=black, linkcolor=black, citecolor=black, #+END_SRC #+NAME: FmtTxtClose_head_tex_colorlinks_mono #+BEGIN_SRC d ┃", ); #+END_SRC ****** color #+NAME: FmtTxtOpen_head_tex_colorlinks_color #+BEGIN_SRC d links.color = format(q"┃ #+END_SRC #+NAME: FmtTxtSet_head_tex_colorlinks_color #+BEGIN_SRC latex colorlinks=true, urlcolor=myblue, %% \href{...}{...} external url filecolor=mygreen, %% \href{...} local file linkcolor=myred, %% \href{...} and \pageref{...} citecolor=black, #+END_SRC #+NAME: FmtTxtClose_head_tex_colorlinks_color #+BEGIN_SRC d ┃", ); #+END_SRC **** latex head open ***** dimensions & orientation ****** set #+NAME: MethodOpen_head_format_string_paper_set #+BEGIN_SRC d string set_paper(P)(P paper_set,) { string paper_type_description; #+END_SRC #+NAME: Condition_FmtTxtOpen_head_format_string_paper_set_format_portrait #+BEGIN_SRC d if (paper_set.is_portrait) { paper_type_description = format(q"┃ #+END_SRC #+NAME: FmtTxtSet_head_format_string_paper_set_format_portrait_tex #+BEGIN_SRC latex \documentclass[%s,%s,titlepage,makeidx]{scrartcl} \usepackage{%s} \usepackage[%s,%s]{babel} \usepackage[autostyle, english = american]{csquotes} %% \MakeOuterQuote{"} %% not required, using '' as quote delimiter \selectlanguage{%s} \hypersetup{ pdftitle={%s}, pdfauthor={%s}, pdfsubject={%s}, } #+END_SRC #+BEGIN_SRC latex \usepackage[%s,%s]{babel} \usepackage[autostyle, english = american]{csquotes} \MakeOuterQuote{"} \setmainlanguage{} \setotherlanguage{} \selectlanguage{%s} %% \usepackage{polyglossia} #+END_SRC #+NAME: FmtTxtSet_head_tex_set_part_section_subsection_subsubsection_paragraph_subparagraph #+BEGIN_SRC latex \usepackage{fancyhdr} \lhead[ ]{ } \chead[ \fancyplain{} \bfseries \footnotesize \leftmark ]{ \fancyplain{} \bfseries \footnotesize \rightmark } \rhead[ ]{ } %s \rfoot[\tiny \href{}{}]{\textrm{\thepage}} #+END_SRC #+NAME: FmtTxtClose_head_format_string_paper_set_format_portrait_variables #+BEGIN_SRC d ┃", paper_set.fontsize, paper_set.papersize, "./sty/" ~ paper_set.stylesheet, lang.codes[doc_matters.src.language]["xlp"], "english", lang.codes[doc_matters.src.language]["xlp"], doc_matters.conf_make_meta.meta.title_full.strip, doc_matters.conf_make_meta.meta.creator_author.strip, doc_matters.conf_make_meta.meta.classify_subject.strip, _footer(doc_matters), ); #+END_SRC #+NAME: Condition_FmtTxtOpen_head_format_string_paper_set_format_landscape #+BEGIN_SRC d } else { paper_type_description = format(q"┃ #+END_SRC #+NAME: FmtTxtSet_head_format_string_paper_set_format_landscape_tex #+BEGIN_SRC latex \documentclass[%s,%s,landscape,titlepage,twocolumn,makeidx]{scrartcl} \usepackage{%s} \usepackage[english]{babel} %% \usepackage{polyglossia} \setmainlanguage{%s} \setotherlanguage{%s} \selectlanguage{%s} \hypersetup{ pdftitle={%s}, pdfauthor={%s}, pdfsubject={%s}, } #+END_SRC #+NAME: FmtTxtClose_head_format_string_paper_set_format_landscape_variables #+BEGIN_SRC d ┃", paper_set.fontsize, paper_set.papersize, "./sty/" ~ paper_set.stylesheet, lang.codes[doc_matters.src.language]["xlp"], "english", lang.codes[doc_matters.src.language]["xlp"], doc_matters.conf_make_meta.meta.title_full.strip, doc_matters.conf_make_meta.meta.creator_author.strip, doc_matters.conf_make_meta.meta.classify_subject.strip, _footer(doc_matters), ); #+END_SRC #+NAME: MethodClose_head_format_string_paper_set_return #+BEGIN_SRC d } return paper_type_description; } #+END_SRC ***** (a4, a5, b4, letter, legal) * (portrait & landscape) #+BEGIN_SRC sh $SpineBIN/spine --verbose --latex --set-papersize="a4,letter.portrait,b4.portrait" --output="$SpineOUT" $SpinePOD/* #+END_SRC #+NAME: Switch_head_format_string_paper_set_orientation #+BEGIN_SRC d string paper_size_orientation_latex; switch (paper_size_orientation) { case "a4.portrait": paper_size_orientation_latex = set_paper(paper.a4.portrait); break; case "a4.landscape": paper_size_orientation_latex = set_paper(paper.a4.landscape); break; case "b4.portrait": paper_size_orientation_latex = set_paper(paper.b4.portrait); break; case "b4.landscape": paper_size_orientation_latex = set_paper(paper.b4.landscape); break; case "a5.portrait": paper_size_orientation_latex = set_paper(paper.a5.portrait); break; case "a5.landscape": paper_size_orientation_latex = set_paper(paper.a5.landscape); break; case "letter.portrait": paper_size_orientation_latex = set_paper(paper.letter.portrait); break; case "letter.landscape": paper_size_orientation_latex = set_paper(paper.letter.landscape); break; case "legal.portrait": paper_size_orientation_latex = set_paper(paper.legal.portrait); break; case "legal.landscape": paper_size_orientation_latex = set_paper(paper.legal.landscape); break; default: paper_size_orientation_latex = paper_type_latex.a4_portrait; } #+END_SRC ***** set color links #+NAME: ConditionalSetVar_head_format_string_paper_set_color #+BEGIN_SRC d string links_mono_or_color_set = links.mono.strip; if ( (doc_matters.opt.action.latex_color_links) || (paper_size_orientation == "a4.landscape" || "a5.landscape" || "b4.landscape" || "letter.landscape" || "legal.landscape") ){ links_mono_or_color_set = links.mono.strip; } #+END_SRC ***** format latex head, open #+NAME: FmtTxtOpen_head_format_tex_set_start_latex_head #+BEGIN_SRC d string _latex_head = format(q"┃%%%% spine LaTeX output%s%s #+END_SRC ***** description comment #+NAME: FmtTxtSet_head_tex_set_generated_by #+BEGIN_SRC latex %%%% %s %s #+END_SRC ***** paper type (a4, letter, ...; ( portrait | landscape )) - paper_type_latex.a4_portrait - paper_type_latex.a4_landscape - paper_type_latex.us_letter_portrait - paper_type_latex.us_letter_landscape #+NAME: FmtTxtSet_head_tex_set_paper_type #+BEGIN_SRC latex %s #+END_SRC ***** paper margins (portrait | landscape) - margins.portrait - margins.landscape #+NAME: FmtTxtSet_head_tex_set_orintation #+BEGIN_SRC latex %s #+END_SRC ***** latex head %%\usepackage{breakurl} **** latex head close (variables set) #+NAME: FmtTxtClose_head_a_format_string_variables #+BEGIN_SRC d ┃", doc_matters.opt.action.generated_by ? " " ~ doc_matters.generator_program.name_version_and_compiler : "", doc_matters.opt.action.generated_by ? " (generated " ~ doc_matters.generator_program.time_output_generated ~ ")" : "", doc_matters.generator_program.project_name.strip, doc_matters.generator_program.url_home.strip, paper_size_orientation_latex.strip, margins.portrait.strip, ); #+END_SRC **** latex head return #+NAME: MethodClose_head_close #+BEGIN_SRC d return _latex_head.strip; } #+END_SRC *** ↻ latex body :content:body: **** latex body function #+NAME: MethodOpen_body_function #+BEGIN_SRC d string latex_body(D,M)( const D doc_abstraction, M doc_matters, string paper_size_orientation, ) { string _latex_body = ""; bool _multicolumns = false; string _txt; #+END_SRC **** ↻ loop open #+NAME: MethodLoopOpen_body_foreach_doc_part #+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: CasePart_body_for_doc_frontmatter #+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, paper_size_orientation); goto default; case "toc": break; default: _latex_body ~= _txt ~ "\n\n"; _txt = ""; break; } break; default: break; } break; #+END_SRC ***** body #+NAME: CasePart_body_for_doc_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, paper_size_orientation); goto default; case "para": _txt = _txt.para(obj) .bullets_and_indentation(obj) .links_and_images(obj, doc_matters); goto default; default: _latex_body ~= _txt ~ "\n\n"; _txt = ""; break; } break; case "block": switch (obj.metainfo.is_a) { case "quote": goto default; // TODO case "group": /+ (hardspaces not honored) [remove any hardspace marker] +/ _txt = _txt.group(obj, doc_matters) .links_and_images(obj, doc_matters); goto default; case "block": /+ (hardspace honored) \hardspace +/ _txt = _txt.block(obj, doc_matters) .links_and_images(obj, doc_matters); goto default; case "verse": /+ (hardspace honored) \hardspace +/ _txt = _txt.verse(obj, doc_matters) .links_and_images(obj, doc_matters); goto default; case "code": /+ (hardspace honored) \begin{lstlisting} clear hardspace marker +/ _txt = _txt.codeblock(obj, doc_matters); goto default; case "table": _txt = _txt.table(obj, doc_matters, paper_size_orientation); goto default; // TODO default: _latex_body ~= _txt ~ "\n\n"; _txt = ""; break; } break; default: break; } break; #+END_SRC ***** backmatter #+NAME: CasePart_body_for_doc_backmatter #+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, paper_size_orientation, part); goto default; case "endnote": assert(part == "endnotes"); /* uncomment code to reinstate endnotes in endnote section */ // _txt = _txt.para(obj) // .bullets_and_indentation(obj) // .links_and_images(obj, doc_matters); // goto default; break; case "glossary": assert(part == "glossary"); _txt = _txt.para(obj) .bullets_and_indentation(obj) .links_and_images(obj, doc_matters); goto default; case "bibliography": assert(part == "bibliography"); _txt = _txt.para(obj) .bullets_and_indentation(obj); goto default; case "bookindex": assert(part == "bookindex"); /+ two column, special section +/ _txt = _txt.bookindex(obj) .links_and_images(obj, doc_matters); goto default; case "blurb": assert(part == "blurb"); _txt = _txt.para(obj) .bullets_and_indentation(obj) .links_and_images(obj, doc_matters); goto default; default: _latex_body ~= (part == "bookindex" && obj.metainfo.is_a != "heading") ? _txt : (_txt ~ "\n\n"); _txt = ""; break; } break; default: break; } break; #+END_SRC ***** after #+NAME: CasePart_body_for_doc_default #+BEGIN_SRC d case "comment": break; default: { /+ debug +/ if (doc_matters.opt.action.debug_do_latex && doc_matters.opt.action.vox_gt1) { writeln(__FILE__, ":", __LINE__, ": ", obj.metainfo.is_of_part); writeln(__FILE__, ":", __LINE__, ": ", obj.metainfo.is_a); writeln(__FILE__, ":", __LINE__, ": ", obj.text); } } break; } } } if (_multicolumns) { _multicolumns = false; _latex_body ~= "\n\\end{multicols}\n"; } #+END_SRC **** latex body return #+NAME: MethodClose_body_function_return #+BEGIN_SRC d return _latex_body; } #+END_SRC *** latex tail :tail: **** latex tail function #+NAME: MethodOpen_tail_function #+BEGIN_SRC d string latex_tail(M)( M doc_matters, string paper_size_orientation, ) { #+END_SRC **** latex tail starts #+NAME: FmtTxtOpen_tail_format_string #+BEGIN_SRC d string _latex_tail = format(q"┃ #+END_SRC ***** latex tail format inclusions ***** latex document end #+NAME: FmtTxtSet_tail_format_string_tex #+BEGIN_SRC latex \end{document} #+END_SRC **** latex tail format inclusions #+NAME: FmtTxtClose_tail_format_string #+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: MethodClose_tail_function_return #+BEGIN_SRC d return _latex_tail; } #+END_SRC * document header including copyright & license #+NAME: doc_header_including_copyright_and_license #+HEADER: :noweb yes #+BEGIN_SRC emacs-lisp <<./spine_version_info_and_doc_header_including_copyright_and_license.org:spine_doc_header_including_copyright_and_license()>> #+END_SRC * __END__