@joaodotwork/md-2-pdf 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,6 +20,9 @@ Most markdown-to-pdf converters struggle with diagrams or produce poorly formatt
20
20
  - Interactive, blue clickable links.
21
21
  - Automatic widow/orphan protection (keeps headers with content).
22
22
  - Wide tables wrap to fit the page — pipe tables with short separator dashes (`|---|---|`) get equal column widths and wrapping cells instead of overflowing.
23
+ - Long inline code (filenames, identifiers) wraps cleanly inside narrow table cells, breaking at `-`, `_`, `.`, and `/` instead of colliding with the next column.
24
+ - Code blocks wrap soft-overflow lines instead of running off the page (via `fvextra` `breaklines`), with a `↪` continuation marker.
25
+ - Unicode-safe monospace font (DejaVu Sans Mono) — box-drawing characters (`│ └── ├──`) and other non-ASCII glyphs render correctly in code blocks.
23
26
  - Customizable margins and geometry.
24
27
  - **Multi-Engine Support:** Automatically detects and uses the best available PDF engine (`xelatex`, `pdflatex`, `weasyprint`, or `wkhtmltopdf`).
25
28
  - **Batch Processing:** Convert single files or entire directories with one command.
@@ -0,0 +1,40 @@
1
+ -- Make long inline code spans (`like-this-filename.json`, `vngrd_woodcut_v3`)
2
+ -- wrappable inside narrow table cells.
3
+ --
4
+ -- Pandoc emits inline code as \texttt{...}, which has no break opportunities
5
+ -- inside the word (no spaces, hyphenchar disabled). Long identifiers then
6
+ -- overflow their column. We insert a zero-width \allowbreak after each
7
+ -- hyphen / underscore / dot / slash, so TeX can break the line there if it
8
+ -- needs to. The visible character stays put.
9
+
10
+ local break_after = { ['-'] = true, ['_'] = true, ['.'] = true, ['/'] = true }
11
+
12
+ local function latex_escape(c)
13
+ if c == '\\' then return '\\textbackslash{}'
14
+ elseif c == '{' then return '\\{'
15
+ elseif c == '}' then return '\\}'
16
+ elseif c == '$' then return '\\$'
17
+ elseif c == '&' then return '\\&'
18
+ elseif c == '%' then return '\\%'
19
+ elseif c == '#' then return '\\#'
20
+ elseif c == '_' then return '\\_'
21
+ elseif c == '^' then return '\\textasciicircum{}'
22
+ elseif c == '~' then return '\\textasciitilde{}'
23
+ else return c
24
+ end
25
+ end
26
+
27
+ function Code(elem)
28
+ if FORMAT ~= 'latex' and FORMAT ~= 'pdf' then return nil end
29
+ local text = elem.text
30
+ if not text:find('[-_./]') then return nil end
31
+ local out = {}
32
+ for i = 1, #text do
33
+ local c = text:sub(i, i)
34
+ out[#out + 1] = latex_escape(c)
35
+ if break_after[c] then
36
+ out[#out + 1] = '\\allowbreak{}'
37
+ end
38
+ end
39
+ return pandoc.RawInline('latex', '\\texttt{' .. table.concat(out) .. '}')
40
+ end
package/md_to_pdf.py CHANGED
@@ -170,6 +170,7 @@ def convert_markdown_to_pdf(
170
170
  # Locate bundled Lua filters
171
171
  script_dir = Path(__file__).resolve().parent
172
172
  table_fit_filter = script_dir / 'filters' / 'table-fit.lua'
173
+ code_break_filter = script_dir / 'filters' / 'code-break.lua'
173
174
 
174
175
  # Convert to PDF using pandoc
175
176
  cmd = [
@@ -179,6 +180,7 @@ def convert_markdown_to_pdf(
179
180
  '--from=gfm',
180
181
  f'--pdf-engine={pdf_engine}',
181
182
  f'--lua-filter={table_fit_filter}',
183
+ f'--lua-filter={code_break_filter}',
182
184
  '-V', 'geometry:top=0.75in',
183
185
  '-V', 'geometry:bottom=1in',
184
186
  '-V', 'geometry:left=0.75in',
@@ -189,8 +191,19 @@ def convert_markdown_to_pdf(
189
191
  '-V', 'colorlinks=true',
190
192
  '-V', 'linkcolor=blue',
191
193
  '-V', 'urlcolor=blue',
192
- '-V', 'header-includes=\\renewcommand{\\rule}[2]{\\vspace{0.5em}} \\widowpenalty=10000 \\clubpenalty=10000 \\brokenpenalty=10000 \\setlength{\\emergencystretch}{3em} \\usepackage{newunicodechar} \\newunicodechar{·}{\\textperiodcentered\\allowbreak} \\newunicodechar{•}{\\textbullet\\allowbreak}'
194
+ '-V', 'header-includes=\\renewcommand{\\rule}[2]{\\vspace{0.5em}} \\widowpenalty=10000 \\clubpenalty=10000 \\brokenpenalty=10000 \\setlength{\\emergencystretch}{3em} \\usepackage{newunicodechar} \\newunicodechar{·}{\\textperiodcentered\\allowbreak} \\newunicodechar{•}{\\textbullet\\allowbreak} \\usepackage{fvextra} \\DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaklines,commandchars=\\\\\\{\\}} \\DefineVerbatimEnvironment{verbatim}{Verbatim}{breaklines}'
193
195
  ]
196
+
197
+ # Use a Unicode-rich monospace font when the engine supports it (fontspec).
198
+ # DejaVu Sans Mono ships with TeX Live and covers box-drawing characters
199
+ # (│ └── ├──), so ASCII-art trees in code blocks render correctly. Pass the
200
+ # font as a .ttf filename so fontspec resolves it via kpsewhich, which
201
+ # works regardless of fontconfig setup or TeX Live install path.
202
+ if pdf_engine in ('xelatex', 'lualatex'):
203
+ cmd.extend([
204
+ '-V', 'monofont=DejaVuSansMono.ttf',
205
+ '-V', 'monofontoptions=BoldFont=DejaVuSansMono-Bold.ttf, ItalicFont=DejaVuSansMono-Oblique.ttf, BoldItalicFont=DejaVuSansMono-BoldOblique.ttf',
206
+ ])
194
207
 
195
208
  try:
196
209
  subprocess.run(cmd, check=True, capture_output=True)
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@joaodotwork/md-2-pdf",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Convert markdown files to PDF with mermaid diagram support",
5
5
  "main": "index.js",
6
6
  "bin": {
7
- "md-2-pdf": "./bin/index.js"
7
+ "md-2-pdf": "bin/index.js"
8
8
  },
9
9
  "scripts": {
10
10
  "test": "echo \"Error: no test specified\" && exit 1"