From 410a49d5dbc31b199c4352132e8d1ec71d2336bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20N=C3=BCtzi?= Date: Sat, 23 Apr 2022 23:12:33 +0200 Subject: [PATCH] feat: Add custom rulers and PDF include and optional table midrules (#29) Features: - md: Add rulers, e.g. `[Name:]{.hrule-fill thickness=0.5pt width=10cm}`. - md: Add PDF include syntax, e.g. `![Pandoc User's Guide](files/PandocUsersGuide.pdf){.includepdf pages=5- style="width:100%;height:20cm;max-width:100%"}`. - md: Custom table conversion includes some option to add horizontal rules. Bugfixes: - build various old setups. - html: duplicated ids in navigation and TOC. - latex: Do not load `lmodern` in `xelatex`. - docker: Add `poppler` utils to the Docker containers. --- .vscode/settings.json | 24 --- .vscode/tasks.json | 16 ++ build.gradle.kts | 2 +- build/Content.html | 174 +++++++++--------- build/Content.pdf | Bin 131 -> 131 bytes build/output-tex/input.tex | 87 +++++++-- chapters/KonvexeProbleme.md | 2 +- chapters/MarkdownSamples.md | 28 ++- chapters/TableSamples.md | 2 +- chapters/tables-tex/TableExample.tex | 17 +- chapters/tables/TableExample.html | 138 +++++++------- files/PandocUsersGuide.pdf | Bin 0 -> 131 bytes includes/convert-tables.json | 3 +- tools/.style.yapf | 2 +- tools/convert/css/main.css | 74 ++++---- tools/convert/css/src/main.less | 6 +- tools/convert/css/src/rulers.less | 8 + tools/convert/defaults/pandoc-filters.yaml | 10 +- tools/convert/defaults/pandoc-general.yaml | 4 +- tools/convert/filters/create-rulers.lua | 85 +++++++++ .../{setAbstract.lua => set-abstract.lua} | 0 ...transformEmoji.lua => transform-emoji.lua} | 0 ...ansformImages.lua => transform-images.lua} | 0 ...transformImages.py => transform-images.py} | 31 ++-- tools/convert/includes/GeneralMacros.sty | 33 ++++ tools/convert/includes/SideNav.js | 22 ++- tools/convert/includes/Template.html | 4 +- tools/convert/includes/Template.tex | 4 +- tools/convert/includes/TemplateSidebar.html | 10 +- tools/convert/includes/Title.html | 4 +- tools/convert/scripts/convert-tables.py | 103 ++++++----- tools/docker/setup/setup-build-tools.sh | 16 +- 32 files changed, 584 insertions(+), 325 deletions(-) create mode 100644 files/PandocUsersGuide.pdf create mode 100644 tools/convert/css/src/rulers.less create mode 100755 tools/convert/filters/create-rulers.lua rename tools/convert/filters/{setAbstract.lua => set-abstract.lua} (100%) rename tools/convert/filters/{transformEmoji.lua => transform-emoji.lua} (100%) rename tools/convert/filters/{transformImages.lua => transform-images.lua} (100%) rename tools/convert/filters/{transformImages.py => transform-images.py} (88%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5520477..06a2f50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -44,30 +44,6 @@ "**/CVS": true }, "files.trimTrailingWhitespace": false, - "latex-workshop.latex.autoBuild.run": "never", - "latex-workshop.latex.recipes": [ - { - "name": "latexmk 🔃", - "tools": [ - "latexmk" - ] - } - ], - "latex-workshop.latex.tools": [ - { - "args": [ - "-r", - "../tools/.latexmkrc", - "-xelatex", - "-cd-", - "%DOC%" - ], - "command": "latexmk", - "cwd": "", - "env": {}, - "name": "latexmk" - } - ], "prettier.configPath": "tools/.prettierrc", "python.defaultInterpreterPath": "${workspaceFolder}/.venv", "python.formatting.provider": "yapf", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a5cb02e..c90326b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -50,6 +50,22 @@ // "group": "converter" // } // }, + { + "label": "đŸ› ïž Build with latexmk", + "type": "shell", + "command": "latexmk", + "args": [ + "-xelatex", + "-r", + "tools/.latexmkrc", + "-gg", + "-outdir=build/output-tex", + "build/output-tex/input.tex"], + "problemMatcher": [], + "presentation": { + "group": "converter" + }, + }, { "label": "📄 View HTML", "type": "shell", diff --git a/build.gradle.kts b/build.gradle.kts index f2a1b49..ef5120c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -261,7 +261,7 @@ abstract class PandocTask @Inject constructor() : Exec() { failIfWarning.convention(true) verbose.convention(false) additionalArgs.convention(arrayOf()) - markdownFiles.convention(project.fileTree("${project.rootDir}/chapters/"){include("**/*.md", "**/*.html")}) + markdownFiles.convention(project.fileTree("${project.rootDir}/chapters/"){include("**/*.md", "**/*.html", "**/*.tex")}) assetFiles.convention(project.fileTree("${project.rootDir}/files/"){ include("**/*") }) literatureFiles.convention(project.fileTree("${project.rootDir}/literature/"){ include("**/*") }) convertFiles.convention(project.fileTree("${settings.dataDir}"){ include("**/*") }) diff --git a/build/Content.html b/build/Content.html index 4c7b871..311de06 100644 --- a/build/Content.html +++ b/build/Content.html @@ -166,16 +166,28 @@ sidnav.style.width = `${expandWidth}px`; if (m.offsetLeft - expandWidth < 0) { - m.style.marginLeft = `${expandWidth + 40}px` + m.style.marginLeft = `${expandWidth + 40}px`; } - - document.getElementById("nav-content-inline").style.display = "none"; + + document.getElementById("nav-content").style.display = "none"; + + toc = document.getElementById("TOC"); + // Append to sidebar. + toc.parentNode.removeChild(toc); + document.getElementById("side-nav-content").append(toc); } function closeSideNav() { document.getElementById("side-nav").style.width = "0"; document.getElementById("main-markdown").style.marginLeft = null; - document.getElementById("nav-content-inline").style.display = "initial"; + + navContent = document.getElementById("nav-content"); + navContent.style.display = "initial"; + + toc = document.getElementById("TOC"); + // Append to inline. + toc.parentNode.removeChild(toc); + document.getElementById("nav-content").append(toc); } var EXPAND_ALL = "⊞"; @@ -258,73 +270,14 @@ ⊞ × -

Technical Documents

Demonstrating the Power of Markdown -with Pandoc

+with Pandoc

Authors: Gabriel NĂŒtzi, The Community

@@ -345,7 +298,7 @@

Demonstrating the Power of Markdown gradle and of course pandoc.

- - \ No newline at end of file + diff --git a/build/Content.pdf b/build/Content.pdf index 09967b1e445d2fc3a9b4c5d127b9a0bb6340968c..a02a239cb44020dec55a9f95fc802e16e78465c6 100644 GIT binary patch delta 84 zcmV~$!4ZHU3{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.3000}}@{}} \caption{Table by included \texttt{.html} file.}\tabularnewline \toprule() -Fruits +\textbf{Fruits asd} & -Vegetables +\textbf{Vegetables} & -Constraints +\textbf{Constraints} & -Properties +\textbf{Properties} \\ \midrule() \endhead -\textbf{First} & +Pre & Zuccini & ripe & long \\ \midrule + +First & \begin{enumerate} \tightlist \item @@ -952,8 +998,9 @@ \subsection{\texorpdfstring{\LaTeX~Table}{~Table}}\label{table}} \item[Definition 2] \(x^2\) is a squared variable \end{description} - & \\ -\textbf{Second} & + & \\ \midrule + +Second & \begin{itemize} \tightlist \item @@ -1074,4 +1121,4 @@ \chapter*{References}\label{references}} \end{CSLReferences} -\end{document} \ No newline at end of file +\end{document} diff --git a/chapters/KonvexeProbleme.md b/chapters/KonvexeProbleme.md index 28f4efd..843caef 100644 --- a/chapters/KonvexeProbleme.md +++ b/chapters/KonvexeProbleme.md @@ -137,4 +137,4 @@ Mit der Beziehung zwischen **proximalem Punkt** und **Normalkegel** $\eqref{eq:p `\begin{align} -\frac{df}{d\vvec{x}}(\vvec{x}^*) \in \ncone{C}(\vvec{x}^*) \quad \Leftrightarrow \quad \vvec{x}^* = \prox{C}(\vvec{x}^* - \frac{df}{d\vvec{x}}(\vvec{x}^*)), \end{align}`{=latex} -welche man iterative lösen kann, was zum **Gradienten-Projektionsverfahren** fĂŒhrt (Gradient Projection Algorithm). \ No newline at end of file +welche man iterative lösen kann, was zum **Gradienten-Projektionsverfahren** fĂŒhrt (Gradient Projection Algorithm). diff --git a/chapters/MarkdownSamples.md b/chapters/MarkdownSamples.md index 61a0fc8..f4c3eae 100644 --- a/chapters/MarkdownSamples.md +++ b/chapters/MarkdownSamples.md @@ -93,4 +93,30 @@ protected: InputSockets m_inputs; //!< The input sockets. OutputSockets m_outputs; //!< The output sockets. }; -``` \ No newline at end of file +``` + +# PDF Include Sample + +You can also include PDFs directly by: +Selecting pages works only in `latex` output. + +![Pandoc User's Guide](files/PandocUsersGuide.pdf){.includepdf pages=5- style="width:100%;height:20cm;max-width:100%"} + +# Questionaire Sample + +## Personal {.unnumbered .unlisted} + +- [Name:]{.hrule-fill thickness=0.5pt width=10cm} +- [Email:]{.hrule-fill thickness=0.5pt width=10cm} + +## How hard is Markdown? {.unnumbered .unlisted} + +- [ ] easy +- [ ] medium hard +- [ ] ridiculuous hard + +## Which features would you like to have which Markdown does currently not support? {.unnumbered .unlisted} + +[]{.hrule-fill thickness=0.5pt width=100% .linebreak} \ +[]{.hrule-fill thickness=0.5pt width=100% .linebreak} \ +[]{.hrule-fill thickness=0.5pt width=50% .linebreak} \ diff --git a/chapters/TableSamples.md b/chapters/TableSamples.md index 77798cb..12029e3 100644 --- a/chapters/TableSamples.md +++ b/chapters/TableSamples.md @@ -16,7 +16,7 @@ tables/TableExample.html :::{include-if-format=latex;json;native} ## \LaTeX\ Table - Included latex file as raw `latex`. -- Converted from `.html` by `convert-tables.py` and `table.json`. +- Converted from `.html` by `convert-tables.py` and `convert-tables.json`. - Latex citations do work inside. ```{.include format=latex raw=true include-if-format=latex;json;native .relative-to-current} diff --git a/chapters/tables-tex/TableExample.tex b/chapters/tables-tex/TableExample.tex index e78e8db..e7bed5e 100644 --- a/chapters/tables-tex/TableExample.tex +++ b/chapters/tables-tex/TableExample.tex @@ -5,17 +5,19 @@ >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.3000}}@{}} \caption{Table by included \texttt{.html} file.}\tabularnewline \toprule() -Fruits +\textbf{Fruits asd} & -Vegetables +\textbf{Vegetables} & -Constraints +\textbf{Constraints} & -Properties +\textbf{Properties} \\ \midrule() \endhead -\textbf{First} & +Pre & Zuccini & ripe & long \\ \midrule + +First & \begin{enumerate} \tightlist \item @@ -31,8 +33,9 @@ \item[Definition 2] \(x^2\) is a squared variable \end{description} - & \\ -\textbf{Second} & + & \\ \midrule + +Second & \begin{itemize} \tightlist \item diff --git a/chapters/tables/TableExample.html b/chapters/tables/TableExample.html index 720af6b..052f8f0 100644 --- a/chapters/tables/TableExample.html +++ b/chapters/tables/TableExample.html @@ -1,72 +1,80 @@ - + - - - - - - - - - - - - - - - - - - - - - - -
Table by included .html file. + Table by included + .html + file. +
- Fruits - - Vegetables - - Constraints - - Properties -
- First - -
    -
  1. Lorem ipsum.
  2. -
  3. Aliquam tinc.
  4. -
-
-
    -
    -
    Definition 1
    -
    $\int_0^1{x^2} := \frac{1}{3}$
    -
    Definition 2
    -
    $x^2$ is a squared variable
    -
    -
-
- Second - -
    -
  • Lorem ipsum.
  • -
  • Mauris eu.
  • -
-
-
    -
  1. Lorem sit.
  2. -
  3. Dapibus.
  4. -
-
-
    -
  1. Aliquam risus.
  2. -
  3. Auctor neque.
  4. -
-
\ No newline at end of file + + + Fruits asd + Vegetables + Constraints + Properties + + + + + + Pre + + + Zuccini + + + ripe + + long + + + + First + + +
    +
  1. Lorem ipsum.
  2. +
  3. Aliquam tinc.
  4. +
+ + +
    +
    +
    Definition 1
    +
    $\int_0^1{x^2} := \frac{1}{3}$
    +
    Definition 2
    +
    $x^2$ is a squared variable
    +
    +
+ + + + + + Second + + +
    +
  • Lorem ipsum.
  • +
  • Mauris eu.
  • +
+ + +
    +
  1. Lorem sit.
  2. +
  3. Dapibus.
  4. +
+ + +
    +
  1. Aliquam risus.
  2. +
  3. Auctor neque.
  4. +
+ + + + diff --git a/files/PandocUsersGuide.pdf b/files/PandocUsersGuide.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4f289dab7b950b466cf00af573c7d7e61c2672e8 GIT binary patch literal 131 zcmWN?K@!3s3;@78uiyig1OlP`O@ScHsC1o*nY`gVgD=0M+Iugkl9U!j-D0tYJ0lmjkOC%OY>?70?667Q?F #TOC { +html #main #side-nav-content > #TOC { font-size: 14.4pt; line-height: 14.4pt; padding-left: 3ex; padding-right: 2ex; padding-bottom: 3em; } -html #main #nav-content > #TOC h1, -html #main #nav-content > #TOC h2, -html #main #nav-content > #TOC h3, -html #main #nav-content > #TOC h4, -html #main #nav-content > #TOC h5, -html #main #nav-content > #TOC h6 { +html #main #side-nav-content > #TOC h1, +html #main #side-nav-content > #TOC h2, +html #main #side-nav-content > #TOC h3, +html #main #side-nav-content > #TOC h4, +html #main #side-nav-content > #TOC h5, +html #main #side-nav-content > #TOC h6 { color: #00acd1; font-family: 'Museo Sans', "Fira Sans", "Helvetica", sans-serif; font-weight: bold; } -html #main #nav-content > #TOC ul li ul li a { +html #main #side-nav-content > #TOC ul li ul li a { font-size: 12.96pt; } -html #main #nav-content > #TOC ul li ul li ul li a { +html #main #side-nav-content > #TOC ul li ul li ul li a { font-size: 11.52pt; } -html #main #nav-content > #TOC ul { +html #main #side-nav-content > #TOC ul { padding-inline-start: 2ex; list-style-type: none; } -html #main #nav-content > #TOC li { +html #main #side-nav-content > #TOC li { color: #00acd1; } -html #main #nav-content > #TOC a { +html #main #side-nav-content > #TOC a { color: #00acd1; padding-top: 0.5ex; padding-bottom: 0.5ex; display: block; transition: 0.3s; } -html #main #nav-content > #TOC ul li { +html #main #side-nav-content > #TOC ul li { list-style-type: none; position: relative; } -html #main #nav-content > #TOC ul li ul { +html #main #side-nav-content > #TOC ul li ul { display: none; padding-left: 15px; } -html #main #nav-content > #TOC ul li.open > ul { +html #main #side-nav-content > #TOC ul li.open > ul { display: block; } -html #main #nav-content > #TOC ul li a { +html #main #side-nav-content > #TOC ul li a { text-decoration: none; } -html #main #nav-content > #TOC ul li:before { +html #main #side-nav-content > #TOC ul li:before { /* the expand/collapse symbols before each item */ display: block; position: absolute; @@ -340,10 +340,10 @@ html #main #nav-content > #TOC ul li:before { font-size: 18pt; font-weight: bold; } -html #main #nav-content > #TOC ul li.open:before { +html #main #side-nav-content > #TOC ul li.open:before { content: "â–Ÿ"; } -html #main #nav-content > #TOC ul li.leaf:before { +html #main #side-nav-content > #TOC ul li.leaf:before { content: ""; } html #main-markdown { @@ -351,34 +351,34 @@ html #main-markdown { margin: auto; /* base style */ } -html #main-markdown #nav-content-inline > #TOC { +html #main-markdown #nav-content > #TOC { font-size: 12pt; line-height: 12pt; } -html #main-markdown #nav-content-inline > #TOC h1, -html #main-markdown #nav-content-inline > #TOC h2, -html #main-markdown #nav-content-inline > #TOC h3, -html #main-markdown #nav-content-inline > #TOC h4, -html #main-markdown #nav-content-inline > #TOC h5, -html #main-markdown #nav-content-inline > #TOC h6 { +html #main-markdown #nav-content > #TOC h1, +html #main-markdown #nav-content > #TOC h2, +html #main-markdown #nav-content > #TOC h3, +html #main-markdown #nav-content > #TOC h4, +html #main-markdown #nav-content > #TOC h5, +html #main-markdown #nav-content > #TOC h6 { color: #00acd1; font-family: 'Museo Sans', "Fira Sans", "Helvetica", sans-serif; font-weight: bold; } -html #main-markdown #nav-content-inline > #TOC ul li ul li a { +html #main-markdown #nav-content > #TOC ul li ul li a { font-size: 10.8pt; } -html #main-markdown #nav-content-inline > #TOC ul li ul li ul li a { +html #main-markdown #nav-content > #TOC ul li ul li ul li a { font-size: 9.6pt; } -html #main-markdown #nav-content-inline > #TOC ul { +html #main-markdown #nav-content > #TOC ul { padding-inline-start: 2ex; list-style-type: none; } -html #main-markdown #nav-content-inline > #TOC li { +html #main-markdown #nav-content > #TOC li { color: #00acd1; } -html #main-markdown #nav-content-inline > #TOC a { +html #main-markdown #nav-content > #TOC a { color: #00acd1; padding-top: 0.5ex; padding-bottom: 0.5ex; @@ -834,6 +834,12 @@ html #main-markdown td :last-child { html #main-markdown tr:hover { background-color: #f5f5f5; } +html #main-markdown span.hrule-fill { + display: inline-block; + width: 100%; + border-bottom-style: solid; + border-bottom-width: 1pt; +} html #main-markdown #refs { text-align: left; } @@ -1329,6 +1335,12 @@ html #main-markdown-numbered td :last-child { html #main-markdown-numbered tr:hover { background-color: #f5f5f5; } +html #main-markdown-numbered span.hrule-fill { + display: inline-block; + width: 100%; + border-bottom-style: solid; + border-bottom-width: 1pt; +} html #main-markdown-numbered #refs { text-align: left; } diff --git a/tools/convert/css/src/main.less b/tools/convert/css/src/main.less index dd0a7f9..e60102b 100644 --- a/tools/convert/css/src/main.less +++ b/tools/convert/css/src/main.less @@ -15,6 +15,7 @@ @import "numbered-headings.less"; @import "quotes.less"; @import "references.less"; +@import "rulers.less"; @import "scrollbar.less"; @import "sidenav.less"; @import "table.less"; @@ -52,6 +53,7 @@ .define-quotes(); .define-blockquote(); .define-tables(); + .define-rulers(); .define-references(); // custom styles applied @@ -72,7 +74,7 @@ html { .define-links(); - #nav-content > #TOC { + #side-nav-content > #TOC { .define-toc-style(@main-heading-color, 1.2*@main-font-size); .define-collapsable-list(18pt, @topShift:2.5pt); padding-left: 3ex; @@ -85,7 +87,7 @@ html { max-width: 21cm - 2 * 1.5cm; margin: auto; - #nav-content-inline > #TOC { + #nav-content > #TOC { .define-toc-style(@main-heading-color, @main-font-size); } diff --git a/tools/convert/css/src/rulers.less b/tools/convert/css/src/rulers.less new file mode 100644 index 0000000..5a0592a --- /dev/null +++ b/tools/convert/css/src/rulers.less @@ -0,0 +1,8 @@ +.define-rulers() { + span.hrule-fill { + display: inline-block; + width: 100%; + border-bottom-style: solid; + border-bottom-width: 1pt; + } +} diff --git a/tools/convert/defaults/pandoc-filters.yaml b/tools/convert/defaults/pandoc-filters.yaml index 3e43eb1..84583e7 100644 --- a/tools/convert/defaults/pandoc-filters.yaml +++ b/tools/convert/defaults/pandoc-filters.yaml @@ -10,13 +10,15 @@ filters: # - tee.py - pandoc-crossref # - tee.py - - transformImages.py - # - tee.py - - transformEmoji.lua + - transform-images.py # - tee.py + - transform-emoji.lua + # tee.py + - create-rulers.lua + # tee.py - citeproc # - tee.py - - setAbstract.lua + - set-abstract.lua # - tee.py # Quote replacement is not needed. # - pandoc-quotes.lua diff --git a/tools/convert/defaults/pandoc-general.yaml b/tools/convert/defaults/pandoc-general.yaml index b0f521c..8981222 100644 --- a/tools/convert/defaults/pandoc-general.yaml +++ b/tools/convert/defaults/pandoc-general.yaml @@ -1,8 +1,8 @@ -from: markdown+markdown_in_html_blocks+link_attributes+inline_code_attributes+raw_attribute+backtick_code_blocks+fenced_code_attributes+tex_math_dollars+fenced_divs+inline_code_attributes+table_captions+footnotes+bracketed_spans +from: &format markdown+markdown_in_html_blocks+link_attributes+inline_code_attributes+raw_attribute+backtick_code_blocks+fenced_code_attributes+tex_math_dollars+fenced_divs+inline_code_attributes+table_captions+footnotes+bracketed_spans+superscript+subscript+strikeout+escaped_line_breaks # These custom variables all go into the AST! metadata: - include-format: markdown+markdown_in_html_blocks+link_attributes+inline_code_attributes+raw_attribute+backtick_code_blocks+fenced_code_attributes+tex_math_dollars+fenced_divs+inline_code_attributes+footnotes+table_captions+bracketed_spans + include-format: *format include-auto: true include-table-dir: "tables" include-fail-if-read-error: true diff --git a/tools/convert/filters/create-rulers.lua b/tools/convert/filters/create-rulers.lua new file mode 100755 index 0000000..1fcfc24 --- /dev/null +++ b/tools/convert/filters/create-rulers.lua @@ -0,0 +1,85 @@ +--- Pandoc filter for replacing the rule elements: +--- - `[]{.ruler-empty-line}` (an empty span with class attribute `.ruler-empty-line`) +--- with the corresponding rule element in HTML and Latex. + +local List = require 'pandoc.List' + +function create_latex_rule(element) + width = element.attributes["width"] + thickness = element.attributes["thickness"] + height = element.attributes["height"] + + cmd = "\\xhrulefill" + + args = "" + if width ~= nil then + if width:match("%d*%%") then + _, _, percentage = string.find(width, "^(%d*)") + width = string.format("%0.4f", tonumber(percentage)/100.0) .. "\\textwidth" + end + + args = args .. string.format(",fill=%s", width) + end + + if thickness ~= nil then + args = args .. string.format(",thickness=%s", thickness) + end + + if height ~= nil then + if height:match("%d*%%") then + _, _, percentage = string.find(height, "^(%d*)") + width = string.format("%0.4f", tonumber(percentage)/100.0) .. "\\baselineskip" + end + args = args .. string.format(",height=%s", height) + end + + if args ~= "" then + cmd = cmd .. "[" .. args .. "]" + end + + -- Set the test infront of the line. + elements = pandoc.List() + if element.content ~= nil then + elements = elements .. element.content + end + elements = elements .. {pandoc.RawInline("latex", cmd)} + + return elements +end + +function create_html_rule(element) + width = element.attributes["width"] + thickness = element.attributes["thickness"] + height = element.attributes["height"] + + attr = "" + if width ~= nil then + attr = attr .. string.format("width:%s;", width) + end + + if thickness ~= nil then + attr = attr .. string.format("border-bottom-width:%s", thickness) + end + + if height ~= nil then + attr = attr .. string.format("vertical-align:%s", height) + end + + return pandoc.Span(element.content, { class = "hrule-fill" , style = attr } ) +end + +function add_rulers(element) + if element.classes:includes("hrule-fill") then + if FORMAT:match("html*") then + return create_html_rule(element) + elseif FORMAT:match("latex") then + return create_latex_rule(element) + end + end + + return element +end + +return { + {Span = add_rulers} +} diff --git a/tools/convert/filters/setAbstract.lua b/tools/convert/filters/set-abstract.lua similarity index 100% rename from tools/convert/filters/setAbstract.lua rename to tools/convert/filters/set-abstract.lua diff --git a/tools/convert/filters/transformEmoji.lua b/tools/convert/filters/transform-emoji.lua similarity index 100% rename from tools/convert/filters/transformEmoji.lua rename to tools/convert/filters/transform-emoji.lua diff --git a/tools/convert/filters/transformImages.lua b/tools/convert/filters/transform-images.lua similarity index 100% rename from tools/convert/filters/transformImages.lua rename to tools/convert/filters/transform-images.lua diff --git a/tools/convert/filters/transformImages.py b/tools/convert/filters/transform-images.py similarity index 88% rename from tools/convert/filters/transformImages.py rename to tools/convert/filters/transform-images.py index bb77496..ad68e82 100755 --- a/tools/convert/filters/transformImages.py +++ b/tools/convert/filters/transform-images.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python +# -*- coding: utf-8 -*- """ Pandoc filter to convert image includes to latex commands: - `\imageWithCaption` or `\svgWithCaption` (for `.svg` extensions) @@ -25,7 +26,7 @@ def latexblock(code): return RawInline(code, format="tex") -def includeImage( +def include_image( attributes, baseCommand, url, @@ -42,7 +43,7 @@ def includeImage( ] -def getPdfPages(url): +def get_pdf_pages(url): pages = None try: cmd = None @@ -63,7 +64,7 @@ def getPdfPages(url): return pages if pages else None -def includePDF( +def include_pdf( attributes, baseCommand, url, @@ -77,7 +78,7 @@ def includePDF( try: if not pages: - pageEnd = getPdfPages(url) + pageEnd = get_pdf_pages(url) else: if "-" in pages: p = pages.split("-") @@ -87,7 +88,7 @@ def includePDF( if p[1]: pageEnd = int(p[1]) else: - pageEnd = getPdfPages(url) + pageEnd = get_pdf_pages(url) else: pageEnd = int(p) except ValueError: @@ -120,7 +121,7 @@ def includePDF( ] -def transformImgToLatex(image: Image): +def transform_img_to_latex(image: Image): url = image.url label = image.identifier @@ -138,26 +139,26 @@ def transformImgToLatex(image: Image): if "includepdf" in image.classes: baseCommand = r"includePDF" - blockBuilder = includePDF + blockBuilder = include_pdf else: baseCommand = r"imageWithCaption" if os.path.splitext(url)[1] == ".svg": baseCommand = r"svgWithCaption" - blockBuilder = includeImage + blockBuilder = include_image # Parse witdh/height - def toScaling(size: Union[str, None], proportionalTo: str): + def to_scaling(size: Union[str, None], proportionalTo: str): if size and "%" in size: s = float(size.strip().replace("%", "")) / 100.0 return "{0}{1}".format(s, proportionalTo) else: return size - width = toScaling( + width = to_scaling( image.attributes.get("width", None), proportionalTo=r"\textwidth", ) - height = toScaling( + height = to_scaling( image.attributes.get("height", None), proportionalTo=r"\textwidth", ) @@ -179,14 +180,14 @@ def toScaling(size: Union[str, None], proportionalTo: str): ) -def transformImages(elem: Element, doc: Doc): +def transform_images(elem: Element, doc: Doc): if doc.format == "latex": if isinstance(elem, Image): - return transformImgToLatex(elem) + return transform_img_to_latex(elem) def main(doc: Doc = None): - return run_filter(transformImages, doc=doc) + return run_filter(transform_images, doc=doc) if __name__ == "__main__": diff --git a/tools/convert/includes/GeneralMacros.sty b/tools/convert/includes/GeneralMacros.sty index fc5fe30..a3ebcc9 100644 --- a/tools/convert/includes/GeneralMacros.sty +++ b/tools/convert/includes/GeneralMacros.sty @@ -37,3 +37,36 @@ \clearpage% } } + +% Ruler commands +% https://tex.stackexchange.com/a/309705/7083 +% \xhrulefill[height=-2pt,thickness=1pt,fill=3cm] +\ExplSyntaxOn +\NewDocumentCommand{\xhrulefill}{O{}} + { + \group_begin: + \severin_xhrulefill:n { #1 } + \group_end: + } + +\keys_define:nn { severin/xhrulefill } + { + height .dim_set:N = \l_severin_xhrule_height_dim, + thickness .dim_set:N = \l_severin_xhrule_thickness_dim, + fill .skip_set:N = \l_severin_xhrule_fill_skip, + height .initial:n = 0pt, + thickness .initial:n = 0.4pt, + fill .initial:n = 0pt plus 1fill, + } + +\cs_new_protected:Nn \severin_xhrulefill:n + { + \keys_set:nn { severin/xhrulefill } { #1 } + \leavevmode + \leaders\hrule + height \dim_eval:n { \l_severin_xhrule_thickness_dim + \l_severin_xhrule_height_dim } + depth \dim_eval:n { -\l_severin_xhrule_height_dim } + \skip_horizontal:N \l_severin_xhrule_fill_skip + \kern 0pt +} +\ExplSyntaxOff diff --git a/tools/convert/includes/SideNav.js b/tools/convert/includes/SideNav.js index b4cda10..8a61fb8 100644 --- a/tools/convert/includes/SideNav.js +++ b/tools/convert/includes/SideNav.js @@ -6,16 +6,28 @@ sidnav.style.width = `${expandWidth}px`; if (m.offsetLeft - expandWidth < 0) { - m.style.marginLeft = `${expandWidth + 40}px` + m.style.marginLeft = `${expandWidth + 40}px`; } - - document.getElementById("nav-content-inline").style.display = "none"; + + document.getElementById("nav-content").style.display = "none"; + + toc = document.getElementById("TOC"); + // Append to sidebar. + toc.parentNode.removeChild(toc); + document.getElementById("side-nav-content").append(toc); } function closeSideNav() { document.getElementById("side-nav").style.width = "0"; document.getElementById("main-markdown").style.marginLeft = null; - document.getElementById("nav-content-inline").style.display = "initial"; + + navContent = document.getElementById("nav-content"); + navContent.style.display = "initial"; + + toc = document.getElementById("TOC"); + // Append to inline. + toc.parentNode.removeChild(toc); + document.getElementById("nav-content").append(toc); } var EXPAND_ALL = "⊞"; @@ -79,4 +91,4 @@ } window.addEventListener('load', onLoad); - \ No newline at end of file + diff --git a/tools/convert/includes/Template.html b/tools/convert/includes/Template.html index 7bc3dbd..cf1ca49 100644 --- a/tools/convert/includes/Template.html +++ b/tools/convert/includes/Template.html @@ -52,7 +52,7 @@
$endif$ $if(toc)$ - diff --git a/tools/convert/includes/Title.html b/tools/convert/includes/Title.html index ea28adb..ce4a878 100644 --- a/tools/convert/includes/Title.html +++ b/tools/convert/includes/Title.html @@ -2,7 +2,7 @@

$title$

$if(subtitle)$ -

$subtitle$

+

$subtitle$

$endif$

Authors: $for(author)$$author$$sep$, $endfor$ @@ -21,4 +21,4 @@

$subtitle$

- \ No newline at end of file + diff --git a/tools/convert/scripts/convert-tables.py b/tools/convert/scripts/convert-tables.py index 711f709..5e509fe 100755 --- a/tools/convert/scripts/convert-tables.py +++ b/tools/convert/scripts/convert-tables.py @@ -11,21 +11,22 @@ from concurrent.futures import ProcessPoolExecutor -def loadPandocDefault(dataDir: str): +def load_pandoc_default(dataDir: str): # Settings general defaults - pandocGeneralDefaults = os.path.join(dataDir, "defaults/pandoc-general.yaml") + pandocGeneralDefaults = os.path.join(dataDir, + "defaults/pandoc-general.yaml") with open(pandocGeneralDefaults, "r") as f: return yaml.load(f, Loader=yaml.FullLoader) -def setEnvironment(dataDir: str): +def set_environment(dataDir: str): # Setting important env. variables filters = os.path.join(dataDir, "filters") s = os.environ.get("PYTHONPATH") os.environ["PYTHONPATH"] = "{0}:{1}".format(filters, s if s else "") -def replaceColumnType(match): +def replace_column_type(match): columns = "" for c in match.group(2): columns += "S" + c @@ -46,14 +47,14 @@ def replaceColumnType(match): } -def getStretchRegexes(spacing): +def get_stretch_regexes(spacing): return [( # Set spacing for in between tabularnewline re.compile(r"\\tabularnewline"), r"\\tabularnewline\\addlinespace[{0}]".format(spacing), )] -def getFormat(file, pandocDefaults): +def get_format(file, pandocDefaults): ext = os.path.splitext(file)[1] if ext == ".html": @@ -66,7 +67,7 @@ def getFormat(file, pandocDefaults): raise ValueError("Wrong format {0}".format(ext)) -def getExtension(format): +def get_extension(format): if "html" in format: return ".html" @@ -78,7 +79,7 @@ def getExtension(format): raise ValueError("Wrong format {0}".format(format)) -def setLatexSpacing(output, spacing): +def set_latex_spacing(output, spacing): startTag = "\\endhead" endTag = "\\bottomrule" @@ -88,13 +89,16 @@ def setLatexSpacing(output, spacing): print("Found cell body between '{0}-{1}'".format(start, end)) substring = output[start:end] - for reg, repl in getStretchRegexes(spacing): + for reg, repl in get_stretch_regexes(spacing): substring = reg.sub(repl, substring) return output[0:start] + substring + output[end:] -def getColumnSizes(output, scaleToOne=False, scaleToFullMargin=0, columnRatios=None): +def get_column_sizes(output, + scaleToOne=False, + scaleToFullMargin=0, + columnRatios=None): endTag = "\\endhead" end = output.find(endTag) @@ -136,8 +140,8 @@ def getColumnSizes(output, scaleToOne=False, scaleToFullMargin=0, columnRatios=N return widths, formats -def setColumnFormat(output, widths, formats): - +def set_column_format(output, widths, formats): + # Remove all minipages reg = re.compile(r"\\end\{minipage\}") output = reg.sub(r"", output) @@ -146,41 +150,55 @@ def setColumnFormat(output, widths, formats): return reg.sub(r"", output) -def deleteEmptyLines(output): +def delete_empty_lines(output): reg = re.compile(r"^\s*\n", re.MULTILINE) return reg.sub("", output) -def postProcessLatexTables(config, output): +def add_mid_rules(match): + s = match.group(0) + count = s.count(r"\\") + return s.replace(r"\\", r"\\ \midrule" + "\n", count - 1) + + +def post_process_latex_tables(config, output): print("Post-process latex tables ...") - r = re.compile(r"\\begin\{longtable\}.*?\\end\{longtable\}", re.DOTALL) + rTable = re.compile(r"\\begin\{longtable\}.*?\\end\{longtable\}", re.DOTALL) + rLines = re.compile(r"\\endhead.*?\\bottomrule", re.DOTALL) def postProcessLatexTable(match): table = match.group(0) # Count column sized - widths, formats = getColumnSizes(table, config.get("scaleColumnsToFull", False), - config.get("scaleColumnsToFullMargin", 0.0), - config.get("columnRatios", None)) + widths, formats = get_column_sizes( + table, config.get("scaleColumnsToFull", False), + config.get("scaleColumnsToFullMargin", 0.0), + config.get("columnRatios", None)) - table = setColumnFormat(table, widths, formats) + table = set_column_format(table, widths, formats) # Stretch cell rows in latex output spacing = config.get("rowSpacing") if spacing: print("Apply spacing ...") - table = setLatexSpacing(table, spacing) + table = set_latex_spacing(table, spacing) - return deleteEmptyLines(table) + table = delete_empty_lines(table) - return r.sub(postProcessLatexTable, output) + if config.get("addMidRules", False): + table = rLines.sub(add_mid_rules, table) + + return table + + return rTable.sub(postProcessLatexTable, output) def convertTable(file, config, rootDir, dataDir, pandocDefaults): - fromFormat = config["from"] if "from" in config else getFormat(file, pandocDefaults) + fromFormat = config["from"] if "from" in config else get_format( + file, pandocDefaults) toFormat = config["to"] - toExt = getExtension(toFormat) + toExt = get_extension(toFormat) # Make output file baseName, ext = os.path.splitext(os.path.split(file)[1]) @@ -189,7 +207,8 @@ def convertTable(file, config, rootDir, dataDir, pandocDefaults): # Run pandoc print("--------------------------------------------------------------") - print("Converting '{0}' -> '{1}' [{2} -> {3}]".format(file, outFile, fromFormat, toFormat)) + print("Converting '{0}' -> '{1}' [{2} -> {3}]".format( + file, outFile, fromFormat, toFormat)) output = subprocess.check_output([ "pandoc", @@ -205,7 +224,8 @@ def convertTable(file, config, rootDir, dataDir, pandocDefaults): "-t", toFormat, file, - ], encoding="utf-8") + ], + encoding="utf-8") # Pre save... with open(outFile, "w") as o: @@ -219,13 +239,13 @@ def convertTable(file, config, rootDir, dataDir, pandocDefaults): output = reg.sub(repl, output) if toFormat == "latex": - output = postProcessLatexTables(config, output) + output = post_process_latex_tables(config, output) with open(outFile, "w") as o: o.write(output) -def convertTables(config, rootDir, dataDir, pandocDefaults): +def convert_tables(config, rootDir, dataDir, pandocDefaults): globs = config["globs"] if isinstance(globs, str): @@ -246,30 +266,29 @@ def convertTables(config, rootDir, dataDir, pandocDefaults): def run(configs, rootDir, dataDir, parallel=False): - setEnvironment(dataDir) - pandocDefaults = loadPandocDefault(dataDir) + set_environment(dataDir) + pandocDefaults = load_pandoc_default(dataDir) if parallel: with ProcessPoolExecutor() as executor: - executor.map(lambda x: convertTables(x, rootDir, dataDir, pandocDefaults), configs) + for r in executor.map( + lambda x: convert_tables(x, rootDir, dataDir, pandocDefaults + ), configs): + pass else: for c in configs: - convertTables(c, rootDir, dataDir, pandocDefaults) + convert_tables(c, rootDir, dataDir, pandocDefaults) if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument( - '--data-dir', - required=True, - help="Pandoc data directory." - ) - parser.add_argument( - '--root-dir', - required=True, - help="The repository with the source." - ) + parser.add_argument('--data-dir', + required=True, + help="Pandoc data directory.") + parser.add_argument('--root-dir', + required=True, + help="The repository with the source.") parser.add_argument( '--config', required=True, diff --git a/tools/docker/setup/setup-build-tools.sh b/tools/docker/setup/setup-build-tools.sh index 5f078af..85bc27d 100755 --- a/tools/docker/setup/setup-build-tools.sh +++ b/tools/docker/setup/setup-build-tools.sh @@ -140,7 +140,7 @@ function installLatexPackages() { function installFonts() { sudo apk add --no-cache fontconfig || die "Could not install fontconfig." - + sudo apk add --no-cache ttf-dejavu || die "Could not install Deja Vue font." local dir=$(mktemp -d) @@ -160,7 +160,7 @@ function installFonts() { curl -L https://github.com/google/fonts/archive/main.tar.gz -o gf.tar.gz && tar -xf gf.tar.gz && sudo mkdir -p /usr/share/fonts/truetype/google-fonts && - find "fonts-main" -name "*.ttf" -exec sudo install -m644 {} /usr/share/fonts/truetype/google-fonts/ \; || return 1 + find "fonts-main" -name "*.ttf" -exec sudo install -m644 {} /usr/share/fonts/truetype/google-fonts/ \; || return 1 ) || die "Could not install google fonts." rm -rf "$dir" && @@ -170,15 +170,22 @@ function installFonts() { function installInkscape() { if haveHomebrew; then - brew install inkscape || die "Failed to install inkscape" + brew install inkscape || die "Failed to install 'inkscape'" elif [ "$os" = "ubuntu" ] || [ "$os" = "alpine" ]; then - sudo apk add inkscape || die "Failed to install inkscape" + sudo apk add inkscape || die "Failed to install 'inkscape'" else die "Operating system '$os' not supported." fi } +function installPdfTools() { + printInfo " -> Installing pdf tools ..." + installPackages "$os" \ + --ubuntu poppler-utils \ + --alpine poppler-utils || + die "Failed to install 'poppler-utils'" +} os="$1" # osRelease="$2" @@ -194,3 +201,4 @@ installJDK installNode installInkscape # installParallel +installPdfTools