summaryrefslogtreecommitdiff
path: root/macros/luatex/generic
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic')
-rw-r--r--macros/luatex/generic/luamplib/NEWS9
-rw-r--r--macros/luatex/generic/luamplib/luamplib.dtx58
-rw-r--r--macros/luatex/generic/luamplib/luamplib.pdfbin153451 -> 153704 bytes
-rw-r--r--macros/luatex/generic/minim-mp/README14
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.doc43
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.lua37
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.pdfbin120017 -> 120799 bytes
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.sty32
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.tex1
-rw-r--r--macros/luatex/generic/minim-pdf/README31
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.doc165
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.lua103
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.pdfbin126824 -> 145084 bytes
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.tex80
-rw-r--r--macros/luatex/generic/minim/README6
-rw-r--r--macros/luatex/generic/minim/minim-doc.sty36
-rw-r--r--macros/luatex/generic/minim/minim-pdfresources.lua2
-rw-r--r--macros/luatex/generic/minim/minim.doc13
-rw-r--r--macros/luatex/generic/minim/minim.pdfbin365466 -> 383422 bytes
-rw-r--r--macros/luatex/generic/penlightplus/penlightplus.lua120
-rw-r--r--macros/luatex/generic/penlightplus/penlightplus.pdfbin66585 -> 80983 bytes
-rw-r--r--macros/luatex/generic/penlightplus/penlightplus.sty80
-rw-r--r--macros/luatex/generic/penlightplus/penlightplus.tex164
23 files changed, 732 insertions, 262 deletions
diff --git a/macros/luatex/generic/luamplib/NEWS b/macros/luatex/generic/luamplib/NEWS
index d56d4df857..3e91c9cc67 100644
--- a/macros/luatex/generic/luamplib/NEWS
+++ b/macros/luatex/generic/luamplib/NEWS
@@ -1,5 +1,14 @@
History of the luamplib package
+2024/03/01 2.26.0
+ * when \mplibcachedir{<dir>} is not set, default cache directory will
+ be in the following order:
+ $TEXMFVAR/luamplib_cache
+ $TEXMF_OUTPUT_DIRECTORY/luamplib_cache
+ ./luamplib_cache
+ $TEXMFOUTPUT/luamplib_cache
+ .
+
2024/01/25 2.25.3
* protect "..." even if textextlabel is disabled (revert part of v2.25.0)
diff --git a/macros/luatex/generic/luamplib/luamplib.dtx b/macros/luatex/generic/luamplib/luamplib.dtx
index 3b6aad6e35..8bdbf884e4 100644
--- a/macros/luatex/generic/luamplib/luamplib.dtx
+++ b/macros/luatex/generic/luamplib/luamplib.dtx
@@ -85,7 +85,7 @@ See source file '\inFileName' for licencing and contact information.
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{luamplib.drv}%
- [2024/01/25 v2.25.3 Interface for using the mplib library]%
+ [2024/03/01 v2.26.0 Interface for using the mplib library]%
\documentclass{ltxdoc}
\usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace}
\usepackage[x11names]{xcolor}
@@ -153,7 +153,7 @@ See source file '\inFileName' for licencing and contact information.
% \author{Hans Hagen, Taco Hoekwater, Elie Roux, Philipp Gesang and Kim Dohyun\\
% Maintainer: LuaLaTeX Maintainers ---
% Support: \email{lualatex-dev@tug.org}}
-% \date{2024/01/25 v2.25.3}
+% \date{2024/03/01 v2.26.0}
%
% \maketitle
%
@@ -328,8 +328,13 @@ See source file '\inFileName' for licencing and contact information.
% |$TEXMFMAIN/metapost/context/base| are already registered by default.
%
% By default, cache files will be stored in |$TEXMFVAR/luamplib_cache| or,
-% if it's not available, in the same directory as where pdf/dvi output file
-% is saved. This however can be changed by the command
+% if it's not available (mostly not writable),
+% in the directory where output files are saved:
+% to be specific, |$TEXMF_OUTPUT_DIRECTORY/luamplib_cache|,
+% |./luamplib_cache|, |$TEXMFOUTPUT/luamplib_cache|, and |.| in this order.
+% (|$TEXMF_OUTPUT_DIRECTORY| is normally the value of |--output-directory|
+% command-line option.)
+% This behavior however can be changed by the command
% |\mplibcachedir{<directory path>}|, where tilde (|~|) is interpreted
% as the user's home directory (on a windows machine as well).
% As backslashes (|\|) should be escaped by users, it would be easier to use
@@ -446,8 +451,8 @@ See source file '\inFileName' for licencing and contact information.
luatexbase.provides_module {
name = "luamplib",
- version = "2.25.3",
- date = "2024/01/25",
+ version = "2.26.0",
+ date = "2024/03/01",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -528,7 +533,7 @@ local is_writable = file.is_writable or function(name)
end
end
end
-local mk_full_path = lfs.mkdirs or function(path)
+local mk_full_path = lfs.mkdirp or lfs.mkdirs or function(path)
local full = ""
for sub in path:gmatch("(/*[^\\/]+)") do
full = full .. sub
@@ -549,31 +554,24 @@ local currenttime = os.time()
local outputdir
if lfstouch then
- local texmfvar = kpse.expand_var('$TEXMFVAR')
- if texmfvar and texmfvar ~= "" and texmfvar ~= '$TEXMFVAR' then
- for _,dir in next, texmfvar:explode(os.type == "windows" and ";" or ":") do
- if not lfsisdir(dir) then
- mk_full_path(dir)
- end
- if is_writable(dir) then
- local cached = format("%s/luamplib_cache",dir)
- lfsmkdir(cached)
- outputdir = cached
- break
+ for i,v in ipairs{'TEXMFVAR','TEXMF_OUTPUT_DIRECTORY','.','TEXMFOUTPUT'} do
+ local var = i == 3 and v or kpse.var_value(v)
+ if var and var ~= "" then
+ for _,vv in next, var:explode(os.type == "unix" and ":" or ";") do
+ local dir = format("%s/%s",vv,"luamplib_cache")
+ if not lfsisdir(dir) then
+ mk_full_path(dir)
+ end
+ if is_writable(dir) then
+ outputdir = dir
+ break
+ end
end
+ if outputdir then break end
end
end
end
-if not outputdir then
- outputdir = "."
- for _,v in ipairs(arg) do
- local t = v:match("%-output%-directory=(.+)")
- if t then
- outputdir = t
- break
- end
- end
-end
+outputdir = outputdir or '.'
function luamplib.getcachedir(dir)
dir = dir:gsub("##","#")
@@ -610,7 +608,7 @@ local noneedtoreplace = {
["mp-grph.mpiv"] = true, ["mp-idea.mpiv"] = true, ["mp-luas.mpiv"] = true,
["mp-mlib.mpiv"] = true, ["mp-node.mpiv"] = true, ["mp-page.mpiv"] = true,
["mp-shap.mpiv"] = true, ["mp-step.mpiv"] = true, ["mp-text.mpiv"] = true,
- ["mp-tool.mpiv"] = true,
+ ["mp-tool.mpiv"] = true, ["mp-cont.mpiv"] = true,
}
luamplib.noneedtoreplace = noneedtoreplace
@@ -2061,7 +2059,7 @@ luamplib.colorconverter = colorconverter
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/01/25 v2.25.3 mplib package for LuaTeX]
+ [2024/03/01 v2.26.0 mplib package for LuaTeX]
\ifx\newluafunction\@undefined
\input ltluatex
\fi
diff --git a/macros/luatex/generic/luamplib/luamplib.pdf b/macros/luatex/generic/luamplib/luamplib.pdf
index e46210d999..506ec49715 100644
--- a/macros/luatex/generic/luamplib/luamplib.pdf
+++ b/macros/luatex/generic/luamplib/luamplib.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-mp/README b/macros/luatex/generic/minim-mp/README
index 6c10eeabb2..372e9626e1 100644
--- a/macros/luatex/generic/minim-mp/README
+++ b/macros/luatex/generic/minim-mp/README
@@ -1,4 +1,4 @@
-Version: 2024/1.4
+Version: 2024/1.5
SUMMARY
@@ -19,6 +19,18 @@ In order to obtain the typeset manual of this package, simply say:
HISTORY
+2025/1.5 (in development)
+
+ New features:
+
+ * Add a luamplib compatibility mode to the latex package.
+ * Make default format and math mode configurable.
+
+ Bug fixes:
+
+ * Make metafun not crash immediately.
+ * Comments (% characters) are now handled by metapost, not tex.
+
2024/1.4 (5/1/2024)
* Support the extended graphics state (extgstate)
diff --git a/macros/luatex/generic/minim-mp/minim-mp.doc b/macros/luatex/generic/minim-mp/minim-mp.doc
index 9429544d8e..0cd4ff574e 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.doc
+++ b/macros/luatex/generic/minim-mp/minim-mp.doc
@@ -8,8 +8,8 @@
\else \startmetadata
author {Esger Renkema}
title {minim-mp}
- date {2024-01-05}
- version {2024/1.4}
+ date {2024-02-25}
+ version {2024/1.5}
keywords {LuaTeX; Plain TeX; MetaPost; mplib}
stopmetadata
\maketitle \fi
@@ -29,8 +29,8 @@ a persistent metapost instance. This will also give you more control over image
extraction. See below under „Metapost instances”. The ⟦options⟧ will also be
explained there (for simple cases, you will not need them).
-The logging of the metapost run will be included in the regular log file. If an
-error occurs, the logging will also be shown on the terminal.
+The logs of the metapost run will be included in the regular log file. If an
+error occurs, the log of the last snippet will also be shown on the terminal.
\section As a stand-alone Metapost compiler % 1
@@ -49,16 +49,26 @@ and ⟦\end{document}⟧ will be inserted automatically if omitted.
\section LaTeX compatibility % 1
-An experimental latex package is included in ⟦minim-mp.sty⟧. It accepts no
-options, as it really is a rather thin wrapper around the plain tex package.
-It does, however, provide a proper ⟦*metapost⟧ latex environment as an
+An experimental latex package is included in ⟦minim-mp.sty⟧. It really is
+a rather thin wrapper around the plain tex package,
+but does provide a proper ⟦*metapost⟧ latex environment as an
alternative to ⟦\directmetapost⟧.
-
-The ⟦metapost⟧ environment has no persistent backing instance.
-You can create a similar environment ⟦envname⟧ that does with
+The ⟦metapost⟧ environment has no persistent backing instance,
+but you can create a similar environment ⟦envname⟧ that does with
⟦*\newmetapostenvironment [options] {envname}⟧.
If your demands are even more complex, you should fall back to the plain tex
-commands described below.
+commands described in the next section.
+
+As in luamplib, you can use ⟦*\mpcolor {name}⟧ to insert the proper colour
+values; this macro is only available inside the above environments.
+
+When the package is loaded with the option ⟦luamplib⟧, minim-mp will try and
+act as a drop-in replacement for luamplib. The effort made is not very great
+though, but it will define an ⟦mplibcode⟧ environment, as well as the
+⟦\mplibcodeinherit⟧, ⟦\mplibshowlog⟧, ⟦\mplibsetformat⟧ and
+⟦\mplibnumbersystem⟧ switches.
+Please do note that this is not the recommended way of using minim-mp, which
+remains the interface documented in the next section.
\section Metapost instances % 1
@@ -73,7 +83,7 @@ These are the options you can use:
Option&Default&Description\cr
⟦jobname⟧&⟦':metapost:'⟧&Used in error messages.\cr
⟦format⟧&⟦'plain.mp'⟧&Format to initialise the instance with.\cr
-⟦math⟧&⟦'scaled'⟧&One of ⟦scaled⟧, ⟦decimal⟧ or ⟦double⟧.\cr
+⟦mathmode⟧&⟦'scaled'⟧&One of ⟦scaled⟧, ⟦decimal⟧ or ⟦double⟧.\cr
⟦seed⟧&⟦nil⟧&Random seed for this instance.\cr
⟦catcodes⟧&⟦0⟧&Catcode table for ⟦btex ... etex⟧.\cr
⟦env⟧&copy of ⟦_G⟧&Lua environment; see below.\cr
@@ -103,7 +113,7 @@ tex can parse as a number.
Say ⟦*\remainingmpimages \id⟧ for the number of images not yet retrieved.
Finally, as a shorthand, ⟦*\runmetapostimage \id { code }⟧ will add
-⟦beginfig ... endfig⟧ to your ⟦code⟧ and write the resulting image immediately
+⟦beginfig ... endfig;⟧ to your ⟦code⟧ and write the resulting image immediately
to the current list.
@@ -364,7 +374,7 @@ A transparency group is a special kind of XForm, and these can be created from
withing metapost: ⟦<id> =⟧ ⟦*saveboxresource (<attributes>) <picture>⟧ returns
a number identifying the resource and can be fed attributes in the same way as
⟦setgstate⟧. XForms defined through metapost are available to other metapost
-instances, but not to tex, though the macro painting them, ⟦*boxresource <id>⟧,
+instances but not to tex, though the macro painting them, ⟦*boxresource <id>⟧,
also accepts identifiers of tex-defined box resources. There remains a subtle
difference, however: metapost-defined box resources are placed at their
original origin.
@@ -429,6 +439,11 @@ Each metapost instance is a table containing the following entries:
⟦catcodes⟧&Number of the catcode table used with ⟦btex ... etex⟧.\cr
⟦env⟧&The lua environment for ⟦runscript⟧.\cr}
+Default values for the format and number system are available in the
+⟦M.default_format⟧ and ⟦M.default_mathmode⟧ variables,
+while ⟦M.on_line⟧ controls whether the logs are always printed to the
+terminal.
+
\section Debugging % 1
diff --git a/macros/luatex/generic/minim-mp/minim-mp.lua b/macros/luatex/generic/minim-mp/minim-mp.lua
index 9069ab7147..fba6573239 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.lua
+++ b/macros/luatex/generic/minim-mp/minim-mp.lua
@@ -228,7 +228,7 @@ end
local function parse_lua_table(name, str)
local f, msg = load('return '..str, name, 't')
if msg then return alloc.err(msg) end
- t = f()
+ local t = f()
if not t or type(t) ~= 'table' then
return alloc.err('%s attributes must be given as lua table', name)
end
@@ -772,9 +772,9 @@ local function get_boxresource_center (id)
end
end
-E.set_boxresource_dimensions = set_boxresource_dimensions
-E.get_boxresource_dimensions = get_boxresource_dimensions
-E.get_boxresource_center = get_boxresource_center
+E.set_boxresource_dimensions = set_boxresource_dimensions
+E.get_boxresource_dimensions = get_boxresource_dimensions
+E.get_boxresource_center = get_boxresource_center
local function save_as_boxresource(pic)
-- attributes
@@ -1248,6 +1248,21 @@ function E.quote_for_lua(s)
return E.quote(mkluastring(s))
end
+-- These are here so that luametafun does not bug out immediately. Please note
+-- that using metafun is not otherwise supported or recommended.
+local cct_maketext = alloc.registernumber('minim:mp:catcodes:maketext')
+E.catcodes = { numbers =
+ { inicatcodes = cct_maketext , texcatcodes = cct_maketext
+ , luacatcodes = cct_maketext , notcatcodes = cct_maketext
+ , vrbcatcodes = cct_maketext , prtcatcodes = cct_maketext
+ , ctxcatcodes = cct_maketext , txtcatcodes = cct_maketext
+} }
+E.mp = mp or { } -- all seem nonessential
+E.mp.mf_path_reset = E.mp.mf_path_reset or function() end
+E.mp.mf_finish_saving_data = E.mp.mf_finish_saving_data or function() end
+E.mp.report = E.mp.report or function() end
+
+
-- 2 typesetting with tex
-- The result of the maketext function is fed back into metapost; on that side,
@@ -1330,7 +1345,6 @@ function M.make_glyph(glyphname, fnt)
alloc.err('Font not found: %s (id %s)', fnt, fontid)
return { }, 10
end
- local fontname = thefont.psname
local gid = luaotfload.aux.gid_of_name(fontid, glyphname)
if not gid then
alloc.err('Font %s has no glyph named %s', thefont.psname, glyphname)
@@ -1393,6 +1407,9 @@ M.get_contours = E.get_contours
-- 2 opening, running and and closing instances
+M.default_format = 'plain.mp'
+M.default_mathmode = 'scaled'
+
local function apply_default_instance_opts(t)
return
{ ini_version = true
@@ -1401,7 +1418,7 @@ local function apply_default_instance_opts(t)
, find_file = new_file_finder()
--, script_error = ...
, job_name = t.jobname
- , math_mode = t.math or 'scaled'
+ , math_mode = t.mathmode or t.math or M.default_mathmode
, random_seed = t.seed or nil
-- , file_line_error_style
, make_text = maketext
@@ -1440,14 +1457,18 @@ function M.run (nr, code)
save_image_list(self, picts)
end
-M.init_code = { 'let dump=endinput;', 'input INIT;', 'input minim-mp.mp;', 'input minim.mp;' }
+M.init_code = { 'let dump=endinput;'
+ , 'boolean mplib; mplib:=true;'
+ , 'input INIT;'
+ , 'input minim-mp.mp;'
+ , 'input minim.mp;' }
local maketext_catcodes = alloc.registernumber('minim:mp:catcodes:maketext')
function M.open (t)
local nr = #instances + 1
t.jobname = t.jobname or ':metapost:'
-- creating instance options
- local init = string.gsub(table.concat(M.init_code, ''), 'INIT', t.format or 'plain.mp')
+ local init = string.gsub(table.concat(M.init_code, ''), 'INIT', t.format or M.default_format)
local opts = apply_default_instance_opts(t)
local instance = mplib.new(opts)
-- adding the instance
diff --git a/macros/luatex/generic/minim-mp/minim-mp.pdf b/macros/luatex/generic/minim-mp/minim-mp.pdf
index 9ea6a51612..eae0cd360e 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.pdf
+++ b/macros/luatex/generic/minim-mp/minim-mp.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-mp/minim-mp.sty b/macros/luatex/generic/minim-mp/minim-mp.sty
index 250e86668e..6240c80b9a 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.sty
+++ b/macros/luatex/generic/minim-mp/minim-mp.sty
@@ -29,7 +29,7 @@
\newmetapostinstance[#1]\mnm@tmp
\expandafter\let\csname #2@instance\endcsname\mnm@tmp
\newenvironment{#2}{%
- \begingroup \catcode`\#=12
+ \begingroup \catcode`\#=12 \catcode`\%=12
\let\mpcolor = \minimpcolor
\csname:#2:\endcsname}
{\csname end:#2:\endcsname \endgroup}%
@@ -50,3 +50,33 @@
\newtoks\mpcolorspectoks \newtoks\mpcolorruntoks \newtoks\mpcolorvaltoks
\mpcolorruntoks{\expandafter\extractcolorspec\the\mpcolorspectoks\mptmpcolor
\expandafter\mpcolorvaltoks\expandafter\@gobble\mptmpcolor}
+
+% as a rather fragile drop-in replacement for luamplib
+\DeclareOption{luamplib}{%
+ \def\mplibtextextlabel#1{} % always enabled
+ \def\mplibshowlog#1{\directlua{
+ require 'minim-mp'.on_line = %
+ \ifcsname minimp@switch@#1\endcsname
+ true \else false \fi }}
+ \newmetapostenvironment[jobname='\jobname']{@mplibcode}
+ \def\mplibcodeinherit#1{%
+ \ifcsname minimp@switch@#1\endcsname
+ \let\mplibcode=\@mplibcode
+ \let\endmplibcode=\@mplibcode
+ \else
+ \let\mplibcode=\metapost
+ \let\endmplibcode=\endmetapost
+ \fi}
+ \mplibcodeinherit{disable}
+ \def\mplibsetformat#1{\directlua{
+ require 'minim-mp'.default_format = '#1.mp' }}
+ \def\mplibnumbersystem#1{\directlua{
+ require 'minim-mp'.default_math = '#1' }}
+} \ProcessOptions*
+
+\let\minimp@switch@@enable=\relax
+\let\minimp@switch@@enabled=\relax
+\let\minimp@switch@@true=\relax
+\let\minimp@switch@@yes=\relax
+
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.tex b/macros/luatex/generic/minim-mp/minim-mp.tex
index 6d95334677..7b8cef6c6b 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.tex
+++ b/macros/luatex/generic/minim-mp/minim-mp.tex
@@ -16,6 +16,7 @@
\newcatcodetable \minim:mp:catcodes:mpcode
{\catcodetable\minim:initcatcodes
\catcode`\{=1 \catcode`\}=2 \catcode9=10
+ \catcode`\#=12 \catcode`\%=12 \catcode`\~=12
\savecatcodetable\csname minim:mp:catcodes:mpcode\endcsname}
\directlua { require('minim-mp') }
diff --git a/macros/luatex/generic/minim-pdf/README b/macros/luatex/generic/minim-pdf/README
index 0626208f2f..c449a9a2c4 100644
--- a/macros/luatex/generic/minim-pdf/README
+++ b/macros/luatex/generic/minim-pdf/README
@@ -1,4 +1,4 @@
-Version: 2024/1.4
+Version: 2024/1.5
SUMMARY
@@ -27,26 +27,39 @@ In order to obtain the typeset manual of this package, simply say:
HISTORY
+2024/1.5 (in development)
+
+ New features:
+
+ * Add \autotagplainoutput and \sectionstructure.
+ * Allow bookmarks that are not associated to structure elements.
+ * The characters ~#% need no longer be escaped in a \hyperlink url.
+
+ Bug fixes:
+
+ * When writing the document structure is disabled, emit a warning instead
+ of an error for incompatible structure types.
+
2024/1.4 (5/1/2024)
Breaking changes:
- * Table cells and headers now connect automatically in \automarktable
+ * Table cells and headers now connect automatically in \automarktable.
New features:
- * Add support for pdf/ua
- * Re-write \hyperlink, adding many options
- * Add ref and title options to structure elements
- * New helper macros for footnotes
- * Add \withpdfresource
+ * Add support for pdf/ua.
+ * Re-write \hyperlink, adding many options.
+ * Add ref and title options to structure elements.
+ * New helper macros for footnotes.
+ * Add \withpdfresource.
2023/1.3 (20/10/2023)
New features:
- * Add \markcolumnspan and \markrowspan
- * Add \markcolumnhead and \markrowhead
+ * Add \markcolumnspan and \markrowspan.
+ * Add \markcolumnhead and \markrowhead.
2023/1.2 (3/3/2023)
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.doc b/macros/luatex/generic/minim-pdf/minim-pdf.doc
index 111d8c1423..3dc0349aca 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.doc
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.doc
@@ -14,8 +14,8 @@ all other features of the package are described here.
\else \startmetadata
author {Esger Renkema}
title {minim-pdf}
- date {2024-01-05}
- version {2024/1.4}
+ date {2024-02-25}
+ version {2024/1.5}
keywords {LuaTeX; Plain TeX; PDF/A; Tagged PDF; accessibility; a11y;
hypertext; bookmarks; document outline; associated files}
stopmetadata
@@ -40,9 +40,16 @@ Hyperlinks can be made with
With the ⟦name⟧ action, a named destination must be used (see below), while the
⟦user⟧ action will be passed directly to the back-end (as with the pdftex
primitive).
+After the ⟦url⟧ action, the characters \Uchar`\~, \# and \% need not be escaped.
+(Of course, this does nothing for already-tokenised text; be aware of this when
+you wrap ⟦\hyperlink⟧ into another macro.)
+Any spaces after the ⟦<action>⟧ will be ignored.
+
The ⟦*\hyperlinkstyle⟧ token list can be used so set common (pdf) link
attributes; it defaults to ⟦/Border [0 0 0]⟧. The contents of the optional
⟦attr⟧ parameter will be appended to these.
+The ⟦alt⟧ options sets the ⟦/Contents⟧ key that is required by PDF/UA (where it
+has the purpose of an alt text).
A named destination can be created with ⟦*\nameddestination {...}⟧ (also in
horizontal mode, unlike the backend primitive) and if you cannot think of
@@ -53,18 +60,24 @@ generated name.
\section Bookmarks % 1
-Bookmarks (also known as outlines) can be added with ⟦*\outline [open|closed]
-[dest {name}] {title}⟧.
+Bookmarks (also known as outlines) can be added with
+⟦*\outline [level n] [open|closed] [dest {name}] {title}⟧.
Add ⟦open⟧ or ⟦closed⟧ to have the bookmark appear initially open or closed
-(default), and
+(the default), and
say ⟦dest {name}⟧ for having it refer to a specific named destination
(otherwise, a new one will be created where the ⟦\outline⟧ command appears).
-A bookmark is automatically associated with the current structure element and
-the hierarchy of structure elements determines the nesting of bookmarks.
-Therefore, if you want nested bookmarks, you \emph{must} precede the ⟦\outline⟧
-command with a declaration of the current structure element, even if you have
-otherwise disabled tagging. See the next chapter on how to do this.
+In the absence of the ⟦level⟧ option, the bookmark is automatically associated
+with the current structure element and the hierarchy of structure elements
+determines the nesting of bookmarks. This works even if you have otherwise
+disabled tagging and is the recommended way of generating outlines.
+(You can find all relevant macros in next chapter under ‘Document structure’
+and ‘Structure element aliases’.)
+
+As a fallback, outlines specified with the ⟦level n⟧ option will be inserted at
+the end of the current outline list at the specified level (${\tt n}≥1$ and
+need not be contiguous). Both methods can be intertwined, but please use the
+document structure if you can.
\section Page labels % 1
@@ -201,6 +214,46 @@ For a more general introduction to and discussion of tagged pdf, please read
the (excellent) manual of latex’s tagpdf package.
+\section Quick-start guide % 1
+
+The minimal setup for producing tagged pdf from plain tex documents is
+something like the following:
+
+⟦% first update all fonts to TrueType (ttf) or OpenType (otf)
+\input luaotfload.sty
+% ... font redefinitions omitted ...
+\input minim-mp
+\pdfalevel 2a % declare pdf/a conformance, enable tagging
+\autotagplainoutput % update the output routine
+% create section markers and counters
+\sectionstructure { subsection, section, chapter }⟧
+
+You can then update your sectioning macros to look like this:
+
+⟦\def\section#1\par{%
+ % space above
+ \bigskip \goodbreak
+ % structure and outline (this is the new part)
+ \marksection \outline open {#1}
+ % section header
+ \noindent {\bf \the\chapternr.\the\sectionnr. #1}
+ % space below
+ \smallskip \noindent}⟧
+
+Other macros you might have for laying out structural elements, such as tables
+or lists, should of course also be updated. The rest of this chapter describes
+the tools you can use.
+
+Please be advised that producing tagged pdf will likely forever remain
+a fragile and error-prone process.
+You should always validate the resulting pdf.
+An easy-to-use and free validator is \hyperlink alt {The veraPDF website.}
+url {https://verapdf.org/home}veraPDF\endlink.
+For inspecting the document structure, you can use the ⟦pdfinfo⟧ utility that
+comes with the \hyperlink alt {The Poppler website.}
+url {https://poppler.freedesktop.org/}Poppler\endlink\ pdf library.
+
+
\section Purpose, limitations and pitfalls % 1
The main purpose of this package is semi-automatically marking up the
@@ -213,7 +266,7 @@ Furthermore, while the macros in this package are sophisticated enough that
tagging can be done without any manual intervantion, it is quite possible and
rather easy to generate the wrong document structure, or even cause syntax
errors in the resulting pdf code.
-You should always check the result in an external application.
+You should always inspect and validate the result.
This is the full list of limitations, pitfalls and shortcomings:
\startlist
@@ -223,15 +276,13 @@ can mark out-of-order content explicitly if you know what you are doing; see
below).
\item2. The contents of ⟦\localleftbox⟧ and ⟦\localrightbox⟧ must be marked
manually, probably as artifact.
-\item3. You must mark page header, page footer and footnote rule yourself; no
-default is set.
-\item4. There currently is no way of marking xforms or other pdf objects as
+\item3. There currently is no way of marking xforms or other pdf objects as
content items of themselves.
-\item5. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
+\item4. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
should not contain tagging commands.
-\item6. Likewise, you should be careful with box reuse: it might work, but you
+\item5. Likewise, you should be careful with box reuse: it might work, but you
should check.
-\item7. This package currently only supports pdf~1.7 tagging and is not yet
+\item6. This package currently only supports pdf~1.7 tagging and is not yet
ready for use with pdf~2.0.
\stoplist
@@ -279,7 +330,7 @@ Use of ⟦ActualText⟧, ⟦Alt⟧ or ⟦Lang⟧ attribute on MCIs, while allowe
pdf standard, is not supported by this package. You should set these on the
structure element instead.
-The begining and ending of a content item can be forced with
+The beginning and ending of a content item can be forced with
⟦*\startcontentitem⟧ and ⟦*\stopcontentitem⟧, while ⟦*\ensurecontentitem⟧ will
only open a new content item if you are currently outside any.
If you need some part to be a single content item, you can use
@@ -336,17 +387,10 @@ All these helpful features can be disabled by setting
will have to be closed by an explicit closing tag, as in xml.
In this case, ⟦\stopelement⟧ and ⟦\ensurestopelement⟧ will be equivalent.
-By default, ⟦P⟧ structure elements are inserted automatically at the start of
-every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
-argument empty will prevent marking the next paragraph.
-Keep in mind that the reassignment is local: if a paragraph marked with
-⟦\nextpartag⟧ starts inside a group, it will not reset.
-Auto-marking paragraphs can be (locally) disabled or enabled by saying
-⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
-
You can query the place in the document structure of any point with
⟦*\showdocumentstructure⟧.
+
\section Structure element aliases % 1
New structure element tags can be created with
@@ -360,6 +404,33 @@ Any aliases you declare will be written to the pdf’s ⟦RoleMap⟧ only if the
have actually been used.
+\section Automatic tagging of paragraphs % 1
+
+By default, ⟦P⟧ structure elements are inserted automatically at the start of
+every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
+argument empty will prevent marking the next paragraph.
+Keep in mind that the (internal) reassignment is local: if a paragraph marked
+with ⟦\nextpartag⟧ starts inside a group, it will not reset.
+Hence, to avoid surprises, you should have ⟦\nextpartag⟧ and the start of your
+paragraph at the same grouping level.
+
+Useful structure elements for ⟦\nextpartag⟧ include ⟦H⟧ for headings and ⟦LI⟧
+for list items. Since minim-pdf produces strongly-structured documents, the
+tags ⟦H1⟧, ⟦H2⟧, ⟦H3⟧ etc. should not be used.
+
+Please also note that if you add ⟦\hbox⟧es directly to a vertical list
+(this includes ⟦\line⟧, ⟦\centerline⟧ and the like),
+the ⟦\everypar⟧ token list is not inserted and no new paragraph structure element
+will be opened.
+The contents of the ⟦\hbox⟧ will be added to the current structure element, and
+this may result in an invalid structure hierarchy (and an error messsage
+reading ‘Structure type mismatch’).
+You can make your intentions clear by inserting ⟦\startelement{P}⟧ at the
+appropriate place (see above).
+
+Auto-marking paragraphs can be (locally) disabled or enabled by saying
+⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
+
\section Manipulating the logical order % 1
With the process outlined above, the logical order of structure elements has to
@@ -504,7 +575,7 @@ list item. Of course, this only works with two-column tables.
Cells spanning multiple cells or rows can be marked with
⟦*\markcolumnspan {width}⟧ and ⟦*\markrowspan {height}⟧; these statements may not
occur before ⟦\marktablecell⟧. Note that while ⟦\markcolumnspan⟧ properly
-increases the (internal) column number, ⟦\markcolumnrow⟧ does nothing of the
+increases the (internal) column number, ⟦\markrowspan⟧ does nothing of the
sort (and indeed, no general logic can be given in the latter case). Always proceed
with caution when using cells spanning multiple rows, and inspect the resulting
structure carefully.
@@ -529,6 +600,46 @@ For tagging (foot)notes, ⟦*\marknoteref{*}⟧ and ⟦*\marknotelbl{*}⟧, when
around the footnote markers, will insert the proper ⟦Ref⟧, ⟦Note⟧ and ⟦Lbl⟧
tags.
+Helper macros for tagging sections can be setup quickly with
+⟦*\sectionstructure { <section list> }⟧. The ⟦<section list>⟧ should be an
+increasing comma-separated list of section types, e.g.
+⟦{subsection, section, chapter}⟧. This will first reserve the ⟦\count⟧
+registers ⟦\subsectionnr⟧ etc, then create the structure aliases ⟦/Subsection⟧
+etc. and finally define the helper macros ⟦\marksubsection⟧ etc, which will do
+the following:
+\startlist
+\item 1. Call ⟦\ensurestopelement⟧ on all lower section types.
+\item 2. Set all lower section number counts to zero.
+\item 3. Increase the current section type number by one.
+\item 4. Call ⟦\startelement⟧ for the current section type.
+\item 5. Set the ⟦\nextpartag⟧ to ⟦H⟧.
+\stoplist
+The proper place for these helper macros is just before the section heading;
+inbetween those two may come an ⟦\outline⟧ statement (see the previous
+chapter). You can set the ⟦title⟧ option to the internal ⟦\startelement⟧
+statement with an optional argument (e.g.
+⟦\marksection [Section \the\sectionnr]⟧).
+
+\section Tagging the output routine % 1
+
+The command ⟦*\autotagplainoutput⟧ will try and update plain tex’s output routine
+to produce tagged page artifacts and footnotes.
+It redefines ⟦\makeheadline⟧, ⟦\makefootline⟧,
+⟦\footnoterule⟧, ⟦\footnote⟧ and ⟦\vfootnote⟧.
+Headline and footline will not be marked as artifacts if their contents equal
+⟦\hfil⟧; the footnote macros are edited to include the ⟦\marknoteref⟧ and
+⟦\marknotelbl⟧ macros described above.
+Note that the ⟦\topinsert⟧, ⟦\midinsert⟧ and ⟦\pageinsert⟧ macros are left
+untouched; you will have to mark those explicitly.
+
+You can make some changes to the affected macros before calling
+⟦\autotagplainoutput⟧, as it tries to be smart about it.
+Though the redefinitions involve a full expansion,
+most conditionals and common typesetting instructions (⟦\line⟧, ⟦\quad⟧,
+⟦\strut⟧ etc.) are safe-to-use and will not be expanded.
+If you include custom macros of your own, however, it is wise to have those
+⟦\protected⟧.
+
% 
\endmanual
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.lua b/macros/luatex/generic/minim-pdf/minim-pdf.lua
index 875fd89659..101a548e4b 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.lua
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.lua
@@ -229,7 +229,13 @@ local function determine_parent_node(current, se)
end
end
if not c then
- alloc.err('Structure type mismatch: %s in %s', se.struct, current.struct)
+ if tagging_enabled() then
+ alloc.err('Structure type mismatch: %s in %s',
+ pdf_name(se.struct), pdf_name(current.struct))
+ else
+ alloc.msg('Warning (minim-pdf): Structure type mismatch (%s in %s)',
+ pdf_name(se.struct), pdf_name(current.struct))
+ end
end
return c or current
end
@@ -820,6 +826,13 @@ alloc.luadef('lastdestinationname', function() tex.sprint(last_dest_name()) end)
-- provide the arguments to \pdfextension startlink
local link_types = { }
+local function make_link_attr(s)
+ local attr = { 'attr {\\csname minim:linkattr\\endcsname' }
+ if s.attr then table.insert(attr, s.attr) end
+ if s.alt or s.contents then insert_formatted(attr, '/Contents %s', pdf_string(s.alt or s.contents)) end
+ table.insert(attr, '}')
+ return attr
+end
alloc.luadef('hyper:makelink', function()
local s = options_scanner()
:argument('alt'):argument('contents') -- same thing
@@ -832,18 +845,32 @@ alloc.luadef('hyper:makelink', function()
userf = link_types.first
end
local user = userf()
- attr = { 'attr {\\csname minim:linkattr\\endcsname' }
- if s.attr then table.insert(attr, s.attr) end
- if s.alt or s.contents then insert_formatted(attr, '/Contents %s', pdf_string(s.alt or s.contents)) end
- insert_formatted(attr, '} user {%s}', user)
+ local attr = make_link_attr(s)
tex.sprint(table.concat(attr, ' '))
+ tex.sprint('user {')
+ tex.write(user)
+ tex.sprint('}\\ignorespaces')
end)
+local function scan_escaped_argument(chars_to_escape)
+ local stored = { }
+ for char in string.utfvalues(chars_to_escape) do
+ stored[char] = tex.getcatcode(char)
+ tex.setcatcode(char, 12)
+ end
+ local res = token.scan_argument()
+ for char, code in pairs(stored) do
+ tex.setcatcode(char, code)
+ end
+ return res
+end
+
function link_types.dest()
return string.format('/Subtype/Link /A <</S/GoTo /D %s>>', pdf_string(token.scan_argument()))
end
function link_types.url()
- return string.format('/Subtype/Link /A <</S/URI /URI %s>>', pdf_string(token.scan_argument()))
+ local url = scan_escaped_argument ('~#$%^&_')
+ return string.format('/Subtype/Link /A <</S/URI /URI %s>>', pdf_string(url))
end
function link_types.user() return token.scan_argument() end
@@ -855,7 +882,7 @@ function link_types.last() return '/Subtype/Link /A <</S/Named /N/LastPage>>' en
-- 1 bookmarks (outlines)
-- start with a dummy top-level bookmark
-local bookmarks = { { count = 0 } }
+local bookmarks = { { count = 0, level = 0 } }
structure[1].bookmark = bookmarks[1]
local function write_bookmarks()
@@ -870,13 +897,13 @@ local function write_bookmarks()
' <</Type /Outlines /First %s 0 R /Last %s 0 R /Count %s >> ',
bookmarks[2].outline_obj, bookmarks[1].last.outline_obj, #bookmarks - 1))
-- write bookmark objects
- for i=2, #bookmarks do
+ for i=2, #bookmarks do -- skip the root (i=1)
local bm, res = bookmarks[i], { }
insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest %s', pdf_string(bm.title),
bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, pdf_string(bm.dest))
if bm.next then insert_formatted(res, '/Next %s 0 R', bm.next.outline_obj) end
if bm.prev then insert_formatted(res, '/Prev %s 0 R', bm.prev.outline_obj) end
- if bm.struct and bm.struct.objnum then
+ if bm.struct and bm.struct.objnum then -- false if no structures are written out
insert_formatted(res, '/SE %s 0 R', bm.struct.objnum)
end
if bm.count > 0 then
@@ -888,37 +915,51 @@ local function write_bookmarks()
end
function M.add_bookmark(bm)
- local se = current_structure_element()
- bm.parent, bm.count = false, 0
- bm.dest = bm.dest or write_new_dest()
- se.bookmark, bm.struct = bm, se
- -- find and update the parent bookmarks
- local p = se.parent
- while p do
- local pbm = p.bookmark
- if pbm then
- if not bm.parent then
- if pbm.last then pbm.last.next = bm end
- bm.parent, bm.prev = pbm, pbm.last
- pbm.first, pbm.last = pbm.first or bm, bm
+ local pbm
+ if bm.level then
+ for i = #bookmarks, 1, -1 do
+ pbm = bookmarks[i]
+ if pbm.level < bm.level then
+ break
end
- -- update the count until the first closed bookmark
- pbm.count = pbm.count + 1
- p = pbm.open and pbm.parent
- else
- p = p.parent
end
+ else
+ local se = current_structure_element()
+ if se.bookmark then
+ return alloc.err('Structure element %s already has a bookmark', pdf_name(se.struct))
+ end
+ se.bookmark, bm.struct = bm, se
+ -- derive parent from strucrure
+ pbm = se.parent
+ while not pbm.bookmark do
+ pbm = pbm.parent
+ end
+ pbm = pbm.bookmark
end
+ -- initial values; links to other bookmarks
+ bm.parent, bm.count = false, 0
+ bm.dest = bm.dest or write_new_dest()
+ if pbm.last then pbm.last.next = bm end
+ bm.parent, bm.prev = pbm, pbm.last
+ pbm.first, pbm.last = pbm.first or bm, bm
+ bm.level = bm.level or (pbm.level + 1)
+ -- update the count until the first closed bookmarks
+ repeat
+ pbm.count = pbm.count + 1
+ pbm = pbm.open and pbm.parent
+ until not pbm
+ -- append to the list
table.insert(bookmarks, bm)
end
alloc.luadef('outline', function()
- local s = options_scanner()
+ local bm = options_scanner()
:keyword('open', 'closed')
:string('dest')
+ :int('level')
:scan()
- s.title = token.scan_string()
- M.add_bookmark(s)
+ bm.title = token.scan_string()
+ M.add_bookmark(bm)
end, 'protected')
@@ -987,7 +1028,7 @@ alloc.luadef('embedfile', function()
t.name = t.file or alloc.err('No name specified for embedded file stream')
end
t.name = pdf_string(t.name or '(unnamed)')
- local fs, ef = M.embed_file(t, t.global)
+ local fs, _ = M.embed_file(t, t.global)
-- where to attach?
if t.global then
table.insert(attached_files, { name = t.name, objnum = fs } )
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.pdf b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
index 2b2ea69c42..2056601eec 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.pdf
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.tex b/macros/luatex/generic/minim-pdf/minim-pdf.tex
index 8a5f738063..d5300fd58f 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.tex
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.tex
@@ -323,6 +323,84 @@
\markelement{Lbl}{{\stopformulatagging#1}}}
\def\tagging:ensurestopNote{\ensurestopelement{Note}}
+% \sectionstructure { subsection, section, chapter }
+\def\sectionstructure{%
+ \newtoks\tag:sect:resets \tag:sect:resets{}%
+ \splitcommalist\tag:sect:a}
+\def\tag:sect:a#1{\expandafter\tag:sect:b
+ \expandafter{\Uchar\uccode`#1}{#1}}
+\def\tag:sect:b#1#2{% Section section
+ \addstructuretype Sect #1\relax
+ \expandafter\newcount\csname #2nr\endcsname
+ \expandafter\edef\csname mark#2\endcsname{%
+ \noexpand\withoptions[]%
+ \expandafter\noexpand\csname #2:domark\endcsname}%
+ \expandafter\edef\csname #2:domark\endcsname[##1]{%
+ \unexpanded{\ifhmode\errhelp{You should place section markers
+ in the vertical list, before the header.}\errmessage
+ {Section marker in horizontal list}\fi}%
+ \global\advance\expandafter\noexpand
+ \csname #2nr\endcsname1
+ \noexpand\the\expandafter\noexpand
+ \csname #2:resets\endcsname
+ \startelement\noexpand\ifx=##1=\noexpand\else
+ title{##1}\noexpand\fi{#1}%
+ \nextpartag{H}\ignorespaces}%
+ \expandafter\newtoks\csname #2:resets\endcsname
+ \csname #2:resets\endcsname \tag:sect:resets
+ \etoksapp\tag:sect:resets{%
+ \noexpand\ensurestopelement{#1}%
+ \global\expandafter\noexpand\csname#2nr\endcsname0 }}
+
+% tagging the plain output routine
+\begingroup\catcode`\@=11
+\gdef\autotagplainoutput{%
+ \let \vfootnot = \tag:vfootnote
+ \begingroup
+ % these should not be expanded
+ \tag:mkrelax
+ \ifhmode \ifvmode \ifnum \ifdim \ifodd \ifeven
+ \ifcondition \unless \else \fi \next \tmp
+ \strut \strutbox \footstrut
+ \the \number \empty \folio
+ \line \leftline \rightline \centerline
+ \nointerlineskip \offinterlineskip
+ \textindent \narrower \hang \llap \rlap
+ \enspace \thinspace \hidewidth
+ \quad \qquad \enskip
+ \@sf \fo@t \footins
+ \tag:mkrelax
+ % redefine head- and footlines
+ \def\footline{\taggedfootline}%
+ \def\headline{\taggedheadline}%
+ \xdef\makeheadline{\makeheadline}%
+ \xdef\makefootline{\makefootline}%
+ \xdef\footnoterule{\markartifact{Layout}\footnoterule}
+ % redefine vfootnote
+ \def\textindent##1{\noexpand\nextpartag{}%
+ \noexpand\marknotelbl{\noexpand\textindent{##1}}%
+ \noexpand\startelement{P}}%
+ \xdef\vfootnote##1{\vfootnote{##1}}%
+ % redefine footnote
+ \let\vfootnote=\relax \let\textindent=\relax
+ \def\fi##1\@sf{\noexpand\fi\noexpand\marknoteref{##1}\@sf}
+ \xdef\footnote##1{\footnote{##1}}%
+ \endgroup}
+\endgroup
+\def\tag:mkrelax#1{\ifx\tag:mkrelax#1\tag:else
+ \let#1=\relax\expandafter\tag:mkrelax\tag:fi}
+\let\tag:else=\else \let\tag:fi=\fi
+\newtoks \taggedheadline \newtoks \taggedfootline
+\taggedheadline{\tagtoks:nonempty{Pagination /Subtype/Header}\headline}
+\taggedfootline{\tagtoks:nonempty{Pagination /Subtype/Footer}\footline}
+\def\tagtoks:nonempty#1#2{%
+ \edef\tagtoks:tmp{\the#2}%
+ \ifx\tagtoks:tmp\tagtoks:hfil
+ \the#2\else
+ \markartifact{#1}{\the#2}\fi}
+\def\tagtoks:hfil{\hfil}
+
+
% 1 tagging formulas
% \autotagformulas
@@ -408,7 +486,7 @@
% \hyperlink <args> ... \endlink
% args: alt {...} attr {...} <type>
% type: dest {name} | url {url} | next | prev | first | last
-\protected\def\endlink{\pdfextension endlink\stopelement{Link}\relax}
+\protected\def\endlink{\pdfextension endlink\ensurestopelement{Link}\relax}
\protected\def\startlink{\startelement{Link}\pdfextension startlink}
\protected\def\hyperlink{\quitvmode\startlink\hyper:makelink}
diff --git a/macros/luatex/generic/minim/README b/macros/luatex/generic/minim/README
index 4aa90c7cd8..a61e0f74ec 100644
--- a/macros/luatex/generic/minim/README
+++ b/macros/luatex/generic/minim/README
@@ -1,4 +1,4 @@
-Version: 2024/1.4
+Version: 2024/1.5
SUMMARY
@@ -31,6 +31,10 @@ the packages mentioned above.
HISTORY
+2024/1.4 (25/2/2024)
+
+ No changes.
+
2024/1.4 (5/1/2024)
* Documented the pdf resource management module
diff --git a/macros/luatex/generic/minim/minim-doc.sty b/macros/luatex/generic/minim/minim-doc.sty
index 93d807f16a..6f662dced6 100644
--- a/macros/luatex/generic/minim/minim-doc.sty
+++ b/macros/luatex/generic/minim/minim-doc.sty
@@ -42,7 +42,7 @@
\font\tenrm {Latin Modern Roman:script=latn;protrusion=default;} at 10pt
\font\tenbf {Latin Modern Roman/B:script=latn;} at 10pt
\font\tenit {Latin Modern Roman/I:script=latn;} at 10pt
-\font\tentt {Latin Modern Mono:script=latn;+smcp;} at 10pt
+\font\tentt {Latin Modern Mono:script=latn;} at 10pt
\font\title {Latin Modern Roman/B:script=latn;} at 12pt
\font\Title {Latin Modern Roman/B:script=latn;} at 16pt
@@ -122,25 +122,8 @@ endfig;}
% 1 document structure
-% page artifacts
-\edef\tmp{\markartifact{Pagination /Subtype/Footer}{\the\footline}}
-\footline\expandafter{\tmp}
-
-% footnotes
-\edef\footnoterule{\markartifact{Layout}\footnoterule}
-\catcode`\@=11
-\def\footnote#1{\let\@sf\empty % parameter #2 (the text) is read later
- \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
- \marknoteref{#1}\@sf\vfootnote{#1}}
-\def\vfootnote#1{%
- \insert\footins\bgroup
- \interlinepenalty\interfootnotelinepenalty
- \splittopskip\ht\strutbox % top baseline for broken footnotes
- \splitmaxdepth\dp\strutbox \floatingpenalty\@MM
- \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
- \nextpartag{}\marknotelbl{#1}\enspace\startelement{P}%
- \footstrut\futurelet\next\fo@t}
-\catcode`\@=12
+\autotagplainoutput
+\def\textindent#1{\noindent#1\enspace\ignorespaces}
% \startlist \item x. ... \stoplist
\def\listskip{\vskip 3pt plus 2pt\vskip-\parskip}
@@ -151,31 +134,26 @@ endfig;}
\hbox to 2em{\hss\startelement{Lbl}#1.~~}%
\startelement{LBody}\ignorespaces}
+\sectionstructure{section, chapter}
+
% \chapter Title \par
-\addstructuretype Sect Chapter
\protected\def\chapter#1 \par{%
\vfil\break
- \ensurestopelement{Section}%
- \global\advance\chapterno1 \global\sectionno0
- \startelement title{Chapter \the\chapterno}{Chapter}%
+ \markchapter[Chapter \the\chapternr]%
\outline open {#1}%
\addtotoc{\chapter{#1}{\lastdestinationname}}%
\nextpartag{H}\quitvmode
\red{\Title#1\hfill\copy\notehead}\bigskip\nobreak}
-\newcount \chapterno
% \section Title \par
-\addstructuretype Sect Section
\protected\def\section#1 \par{%
\bigskip\penalty-50\relax
- \global\advance\sectionno1
- \startelement title{Section \the\chapterno.\the\sectionno}{Section}%
+ \marksection[Section \the\chapternr.\the\sectionnr]%
\outline closed {#1}%
\addtotoc{\section{#1}{\lastdestinationname}}%
\nextpartag{H}\quitvmode
\red{\title#1}%
\par\nobreak}
-\newcount \sectionno
% table of contents
\newtoks\toc \newif\iftoc \toctrue
diff --git a/macros/luatex/generic/minim/minim-pdfresources.lua b/macros/luatex/generic/minim/minim-pdfresources.lua
index 468da03b48..66d168f4ec 100644
--- a/macros/luatex/generic/minim/minim-pdfresources.lua
+++ b/macros/luatex/generic/minim/minim-pdfresources.lua
@@ -121,7 +121,7 @@ local removal_regex = {
local function update_page_resources(shippingout)
if M.self_destruct then return end
local resources = shippingout and pdf.getpageresources() or pdf.getxformresources() or ''
- for kind, used in pairs(page_resources) do
+ for kind, _ in pairs(page_resources) do
resources = string.gsub(resources, removal_regex[kind], '')
local entry = make_resource_entry(kind)
if entry then
diff --git a/macros/luatex/generic/minim/minim.doc b/macros/luatex/generic/minim/minim.doc
index e975718b1e..ef35a8ea4e 100644
--- a/macros/luatex/generic/minim/minim.doc
+++ b/macros/luatex/generic/minim/minim.doc
@@ -4,8 +4,8 @@
\startmetadata
author {Esger Renkema}
title {minim}
- date {2024-01-05}
- version {2024/1.4}
+ date {2024-02-25}
+ version {2024/1.5}
keywords {LuaTeX; Plain TeX; MetaPost; PDF/A; Tagged PDF; accessibility; a11y;
Unicode mathematics; XMP; metadata; hypertext; bookmarks}
stopmetadata
@@ -39,11 +39,8 @@ For building your own format files, you can re-use the file \red{minim.ini}:
if you define ⟦\fmtname⟧ before inputting this file, no ⟦\dump⟧ will be
performed.
-
-\bigskip
-
-\tocfalse \section Contents \par \bigskip
-\begingroup \parskip1pt
+\tocfalse \section Contents \par
+\smallskip \begingroup \parskip1pt
\protected\def\chapter#1#2#3{%
\stopelement{TOC}\smallskip
\nextpartag{}\red{\tenbf\marktocentry{#2}{}{\strut#1}{\hfill~}{#3}}%
@@ -60,11 +57,9 @@ performed.
One central design goal of minim is to be as unobtrusive as possible: you
should be able to safely ignore any function you do not want to use.
Please get in touch if you find this not the case.
-
Particular care has been taken to be compatible with \red{ltluatex}. All
overlapping functions should produce the same results and ltluatex can be
loaded either before or after minim.
-Earlier incompatibilities with \red{pgf} have been resolved.
\licencesection
diff --git a/macros/luatex/generic/minim/minim.pdf b/macros/luatex/generic/minim/minim.pdf
index 3848cf5103..e632089dfa 100644
--- a/macros/luatex/generic/minim/minim.pdf
+++ b/macros/luatex/generic/minim/minim.pdf
Binary files differ
diff --git a/macros/luatex/generic/penlightplus/penlightplus.lua b/macros/luatex/generic/penlightplus/penlightplus.lua
index 6aa1331fdd..a831c6721d 100644
--- a/macros/luatex/generic/penlightplus/penlightplus.lua
+++ b/macros/luatex/generic/penlightplus/penlightplus.lua
@@ -1,6 +1,6 @@
--% Kale Ewasiuk (kalekje@gmail.com)
---% 2023-12-08
---% Copyright (C) 2021-2023 Kale Ewasiuk
+--% 2024-02-29
+--% Copyright (C) 2021-2024 Kale Ewasiuk
--%
--% Permission is hereby granted, free of charge, to any person obtaining a copy
--% of this software and associated documentation files (the "Software"), to deal
@@ -143,8 +143,9 @@ function penlight.tex.wrth(s1, s2) -- helpful printing, makes it easy to debug,
end
wrt2('\n^^^^^\n')
end
+penlight.wrth = penlight.tex.wrth
+penlight.tex.help_wrt = penlight.tex.wrth
penlight.help_wrt = penlight.tex.wrth
-penlight.wrth = penlight.help_wrt
function penlight.tex.prt_array2d(t)
for _, r in ipairs(t) do
@@ -456,22 +457,18 @@ function str_mt.__index.subpar(s, r)
end
-function str_mt.__index.fmt(s, t, fmt) -- format a $1 string with an array or table and formats
- -- formats can be a luakeys string, or a table
- fmt = fmt or {}
- if type(fmt) == 'string' then
- fmt = penlight.tablex.strinds(penlight.luakeys.parse(fmt, {naked_as_value=true}))
- end
+function str_mt.__index.fmt(s, t, fmt) -- format a $1 and $k string with an array or table and formats
+ -- formats can be a luakeys string, or a table and are applied to table before string is formatted
if type(t) ~= 'table' then t = {t} end
t = penlight.tablex.strinds(t)
- for k, f in pairs(fmt) do -- apply formats
- t[k] = string.format('%'..f, t[tostring(k)])
- end
+ t = penlight.tablex.fmt(t, fmt, true)
return s % t
end
-
-
+function str_mt.__index.parsekv(s, t) -- parsekv string
+ if type(t) ~= 'table' then t = penlight.luakeys.parse(t) end
+ return penlight.luakeys.parse(s, t)
+end
-- -- -- -- function stuff
@@ -532,6 +529,37 @@ function penlight.tablex.strinds(t) -- convert indices that are numbers to strin
end
+function penlight.tablex.listcontains(t, v)
+ return penlight.tablex.find(t, v) ~= nil
+end
+
+
+-- format contents of a table
+function penlight.tablex.fmt(t, fmt, strinds)
+ if fmt == nil then
+ return t
+ end
+ strinds = strinds or false -- if your fmt table should use string indexes
+ if type(fmt) == 'string' then
+ if not fmt:find('=') then -- if no = assume format all same
+ for k, v in pairs(t) do -- apply same format to all
+ if tonumber(v) ~= nil then -- only apply to numeric values
+ t[k] = string.format("%"..fmt, v)
+ end
+ end
+ return t
+ else
+ fmt = fmt:parsekv('naked_as_value') -- make fmt a table from keyval str
+ end
+ end
+ if strinds then fmt = penlight.tablex.strinds(fmt) end -- convert int inds to str inds
+ for k, f in pairs(fmt) do -- apply formatting to table
+ t[k] = string.format("%"..f, tostring(t[k]))
+ end
+ return t
+end
+
+
function penlight.tablex.map_slice(func, T, j1, j2)
if type(j1) == 'string' then
return penlight.array2d.map_slice(func, {T}, ','..j1)[1]
@@ -556,24 +584,25 @@ function penlight.tablex.filterstr(t, exp, case)
end
end
-
+--todo add doc
function penlight.utils.filterfiles(...)
-- f1 is a series of filtering patterns, or condition
-- f2 is a series of filtering patters, or condition
-- (f1_a or f2_...) and (f2 .. ) must match
local args = table.pack(...)
- -- todo -- check where boolean is for recursive or not, set starting argument
+ -- dir, recursive[bool], filt1, filt2 etc...
+ -- OR recursive[bool], filt1, filt2, etc..
+ -- OR filt1, filt2, filt3, etc..
-- this could allow one to omit dir
- -- todo if no boolean at all, assume dir = '.' and r = false
- -- if boolean given, assume dir = '.'
+ -- if boolean given ar arg 1, assume dir = '.'
local nstart = 3
- local r = args[2]
- local dir = args[1]
+ local r = args[2] -- recursive
+ local dir = args[1] -- start dir
if type(args[1]) == 'boolean' then
dir = '.'
r = args[1]
nstart = 2
- elseif type(args[2]) ~= 'boolean' then
+ elseif type(args[2]) ~= 'boolean' then -- if boolean given ar arg 1, assume dir = '.'
dir = '.'
r = false
nstart = 1
@@ -591,7 +620,6 @@ end
-
-- -- -- -- -- -- -- -- functions below extend the array2d module
@@ -808,6 +836,18 @@ function penlight.tex.split2items(s, d)
end
+function penlight.toggle_luaexpr(expr)
+ if expr then
+ tex.sprint('\\toggletrue{luaexpr}')
+ else
+ tex.sprint('\\togglefalse{luaexpr}')
+ end
+end
+
+
+
+
+
penlight.tbls = {}
penlight.rec_tbl = ''
@@ -820,6 +860,11 @@ function penlight.get_tbl_name(s)
return s
end
+function penlight.get_tbl(s)
+ s = penlight.get_tbl_name(s)
+ return penlight.tbls[s]
+end
+
function penlight.get_tbl_index(s)
local tbl = ''
local key = ''
@@ -830,6 +875,7 @@ function penlight.get_tbl_index(s)
elseif s:find('/') then
local tt = s:split('/')
tbl = tt[1]
+ if tbl == '' then tbl = penlight.rec_tbl end
key = tonumber(tonumber(tt[2]))
if key < 0 then key = #penlight.tbls[tbl]+1+key end
else
@@ -837,6 +883,7 @@ function penlight.get_tbl_index(s)
key = tonumber(s) or s
if type(key) == 'number' and key < 0 then key = #penlight.tbls[tbl]+1+key end
end
+ if tbl == '' then tbl = penlight.rec_tbl end
if penlight.tbls[tbl] == nil or penlight.tbls[tbl][key] == nil then
penlight.tex.pkgerror('penlightplus', 'Invalid index of tbl using: "'..s..'"')
end
@@ -881,10 +928,26 @@ function penlight.check_recent_tbl_undefault()
end
end
+function penlight.def_tbl(ind, def, g)
+ local _tbl, _key = penlight.get_tbl_index(ind)
+ if def == '' then def = 'dtbl'.._tbl.._key end
+ token.set_macro(def, tostring(penlight.tbls[_tbl][_key]), g)
+end
+
+function penlight.def_tbl_all(ind, def)
+ local _tbl = penlight.get_tbl_name(ind)
+ if def == '' then def = 'dtbl'.._tbl end
+ for k, v in pairs(penlight.tbls[_tbl]) do
+ token.set_macro(def..k, tostring(v))
+ end
+end
+
-- TODO TODO TODO get error working xy def, and referene which table for key-vals
penlight.tbl_xysep = '%s+' -- spaces separate x-y coordinates
-function penlight.def_tbl_coords(str, def)
- -- todo could definitely make this flexible for a table...
+function penlight.def_tbl_coords(ind, def)
+ local tbl, key = penlight.get_tbl_index(ind)
+ local str = penlight.tbls[tbl][key]
+ if def == '' then def = 'dtbl'..tbl..key end
local x, y = str:strip():splitv(penlight.tbl_xysep)
if (not penlight.hasval(x)) or (not penlight.hasval(y)) then
penlight.tex.pkgerror('penlightplus', 'def_tbl_coords function could not parse coordiantes given as "'..str..'" ensure two numbers separated by space are given!', '', true)
@@ -894,7 +957,14 @@ function penlight.def_tbl_coords(str, def)
end
---
+
+
+
+
+
+
+
+-- global setting type stuff
function penlight.make_tex_global()
for k,v in pairs(penlight.tex) do -- make tex functions global
diff --git a/macros/luatex/generic/penlightplus/penlightplus.pdf b/macros/luatex/generic/penlightplus/penlightplus.pdf
index 17d95268eb..8f4fcb9717 100644
--- a/macros/luatex/generic/penlightplus/penlightplus.pdf
+++ b/macros/luatex/generic/penlightplus/penlightplus.pdf
Binary files differ
diff --git a/macros/luatex/generic/penlightplus/penlightplus.sty b/macros/luatex/generic/penlightplus/penlightplus.sty
index f5ffc0f176..ee7ff3ad11 100644
--- a/macros/luatex/generic/penlightplus/penlightplus.sty
+++ b/macros/luatex/generic/penlightplus/penlightplus.sty
@@ -1,6 +1,6 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2023-12-08
-% Copyright (C) 2021-2023 Kale Ewasiuk
+% 2024-02-29
+% Copyright (C) 2021-2024 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.
-\ProvidesPackage{penlightplus}[2023-12-08]
+\ProvidesPackage{penlightplus}[2024-02-29]
\RequirePackage{luacode}
\RequirePackage{luakeys}
@@ -84,22 +84,16 @@
\newtoggle{luaexpr}\togglefalse{luaexpr}
\begin{luacode*}
- function toggle_luaexpr(expr)
- if expr then
- tex.sprint('\\toggletrue{luaexpr}')
- else
- tex.sprint('\\togglefalse{luaexpr}')
- end
- end
+
\end{luacode*}
-\NewDocumentCommand{\ifluax}{m m O{}}{%
- \luadirect{toggle_luaexpr(#1)}%
+\NewDocumentCommand{\ifluax}{m m O{}}{% if lua expression is true do {m} if not [o]
+ \luadirect{penlight.toggle_luaexpr(#1)}%
\iftoggle{luaexpr}{#2}{#3}%
\togglefalse{luaexpr}% safety set to false
}
-\NewDocumentCommand{\ifluaxv}{m m O{}}{\ifluax{penlight.hasval(#1)}{#2}[#3]}
+\NewDocumentCommand{\ifluaxv}{m m O{}}{\ifluax{penlight.hasval(#1)}{#2}[#3]}% if lua expression is truthy do {m} else [o]
@@ -116,6 +110,10 @@
penlight.rec_tbl = \luastring{#1}
}}
+\NewDocumentCommand{\tblfrkvCD}{m +m O{}}{\tblfrkv{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}}
+%% tbl from key-vals, then check defaults, then define all keys using default format
+\NewDocumentCommand{\tblfrkvNCD}{m +m O{}}{\tblfrkvN{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}}
+
\NewDocumentCommand{\tblfrkvN}{m +m O{}}{\luadirect{%
penlight.rec_tbl_opts = penlight.luakeys.parse(\luastring{#3})
penlight.tbls[\luastring{#1}] = penlight.luakeys.parse(string.subpar(\luastringN{#2}), penlight.rec_tbl_opts)
@@ -124,9 +122,38 @@
\NewDocumentCommand{\tblfrcsv}{m +m O{}}{\tblfrkv{#1}{#2}[naked_as_value=true,#3]}
+\NewDocumentCommand{\tblfrcsvN}{m +m O{}}{\tblfrkvN{#1}{#2}[naked_as_value=true,#3]}
+
\NewDocumentCommand{\tblkvundefcheck}{}{\luadirect{penlight.check_recent_tbl_undefault()}}% check defaults list and throw error if foreign keys were used
+
+
+\NewDocumentCommand{\tblapp}{m m}{\luadirect{% append to a table (ie using integer index) with a value (second arg) # todo option for string or number
+ __tbl__ = penlight.get_tbl_name(\luastring{#1})
+ table.insert(penlight.tbls[__tbl__], \luastring{#2})
+}}
+
+\NewDocumentCommand{\tblcon}{m m}{\luadirect{% concatenate to a table (ie using integer index) with a list of comma separated values (second arg) #
+ __tbl__ = penlight.get_tbl_name(\luastring{#1})
+ for k, v in ipairs(penlight.luakeys.parse(string.subpar(\luastring{#2}), {naked_as_value=true})) do
+ table.insert(penlight.tbls[__tbl__], v)
+ end
+}}
+
+\NewDocumentCommand{\tbladd}{m m m}{\luadirect{% add a kv pair to a table
+ __tbl__ = penlight.get_tbl_name(\luastring{#1})
+ penlight.tbls[__tbl__][\luastring{#2}] = \luastring{#3}
+}}
+
+\NewDocumentCommand{\tbladdN}{m m m}{\luadirect{% add a kv pair to a table
+ __tbl__ = penlight.get_tbl_name(\luastring{#1})
+ penlight.tbls[__tbl__][\luastring{#2}] = \luastringN{#3}
+}}
+
+
+
+
\NewDocumentCommand{\tblchg}{ m }{\luadirect{% change recent table
penlight.rec_tbl = \luastring{#1}
}}
@@ -140,36 +167,21 @@
penlight.set_tbl_item(\luastring{#1}, \luastring{#2})
}}
-% todo if no definition is provided, assume <tblname><key>
-\NewDocumentCommand{\tbldef}{ m m }{\luadirect{% define a {table key}{def}
- local _tbl, _key = penlight.get_tbl_index(\luastring{#1})
- local _tbl_def_ = \luastring{#2}
- if _tbl_def_ == '' then _tbl_def_ = 'dtbl'.._tbl.._key end
- token.set_macro(_tbl_def_, tostring(penlight.tbls[_tbl][_key]))
-}}
-\NewDocumentCommand{\tbldefall}{ m m }{\luadirect{% define all {table} keys to {table} \table<key1>
- % todo maybe change tbldef {def} to [def] and make same as table name
- local _tbl = penlight.get_tbl_name(\luastring{#1})
- local _tbl_def_ = \luastring{#2}
- if _tbl_def_ == '' then _tbl_def_ = 'dtbl'.._tbl end
- for k, v in pairs(penlight.tbls[_tbl]) do
- token.set_macro(_tbl_def_..k, tostring(v))
- end
-}}
+\NewDocumentCommand{\tbldef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2})}}
+% define a table, use * to make global definition
+\NewDocumentCommand{\tblgdef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2}, 'global')}}
-\NewDocumentCommand{\tblgdef}{ m m }{\luadirect{% define a table, use * to make global definition
- token.set_macro(\luastring{#2}, tostring(penlight.get_tbl_item(\luastring{#1})), 'global')
-}}
-
-\NewDocumentCommand{\tbldefxy}{ m m }{\luadirect{penlight.def_tbl_coords(penlight.get_tbl_item(\luastring{#1}), \luastring{#2})}}% define #2x and #2y from a space delimited x-y pair
+\NewDocumentCommand{\tbldefall}{ m m }{\luadirect{penlight.def_tbl_all(\luastring{#1}, \luastring{#2})}}
+\NewDocumentCommand{\tbldefxy}{ m m }{\luadirect{penlight.def_tbl_coords(\luastring{#1}, \luastring{#2})}}% define #2x and #2y from a space delimited x-y pair
\NewDocumentCommand{\tblif}{m m O{}}{\ifluax{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]}
\NewDocumentCommand{\tblifv}{m m O{}}{\ifluaxv{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]}
+\NewDocumentCommand{\tblprt}{m}{\luadirect{penlight.wrth(penlight.get_tbl(\luastring{#1}),'penlightplus table: '..\luastring{#1})}}
% legacy code, delete this
\let\kvtblundefcheck\tblkvundefcheck
diff --git a/macros/luatex/generic/penlightplus/penlightplus.tex b/macros/luatex/generic/penlightplus/penlightplus.tex
index 988a51bb2a..53488619bf 100644
--- a/macros/luatex/generic/penlightplus/penlightplus.tex
+++ b/macros/luatex/generic/penlightplus/penlightplus.tex
@@ -1,6 +1,6 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2023-12-08
-% Copyright (C) 2021-2023 Kale Ewasiuk
+% 2024-02-29
+% Copyright (C) 2021-2024 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
@@ -35,11 +35,11 @@
\setlength\ResultBoxRule{0mm}
\lstset{
language=[LaTeX]TeX,
- basicstyle=\ttfamily\small,
- commentstyle=\ttfamily\small\color{gray},
+ basicstyle=\ttfamily\footnotesize,
+ commentstyle=\ttfamily\footnotesize\color{gray},
frame=none,
numbers=left,
- numberstyle=\ttfamily\small\color{gray},
+ numberstyle=\ttfamily\footnotesize\color{gray},
prebreak=\raisebox{0ex}[0ex][0ex]{\color{gray}\ensuremath{\hookleftarrow}},
extendedchars=true,
breaklines=true,
@@ -53,7 +53,7 @@
\date{\today}
-\RequirePackage{penlightplus}
+\RequirePackage[pl,globals]{penlightplus}
\title{penlightplus}
\subtitle{Additions to the Penlight Lua Libraries}
@@ -97,14 +97,28 @@ The gloals flags below are taken care of in the package options:\\
\cmd{__PL_NO_HYPERREF__} a flag used to change the behaviour of a function, depending on if you don't use the hyperref package\\
\cmd{__PDFmetadata__} a table used to store PDF meta-data
+
+\subsubsection*{global extras}
+If the package option \cmd{globals} is used, many additional globals are set for easier scripting.
+\cmd{pl.hasval}, \cmd{pl.COMP}, \cmd{pl.utils.kpairs}, \cmd{pl.utils.npairs} become globals.
+\cmd{pl.tablex} is aliased as \cmd{pl.tbx and tbx} (which also includes all native Lua table functions), and
+\cmd{pl.array2d} is aliased as \cmd{pl.a2d and a2d}.
+
+If you want global \cmd{pl.tex} funcs and vars, call \cmd{pl.make_tex_global()}\\
+
+
\subsubsection*{penlight additions}
Some functionality is added to penlight and Lua.
\llcmd{pl.hasval(x)} Python-like boolean testing\\
\llcmd{COMP'xyz'()} Python-like comprehensions:\\\url{https://lunarmodules.github.io/Penlight/libraries/pl.comprehension.html}\\
+
+\cmd{clone_function(f)} returns a cloned function\\
+\cmd{operator.strgt(a,b)} compares strings a greater than b (useful for sorting)\\
+\cmd{operator.strlt(a,b)} compares strings a less than b (useful for sorting)\\
+
\llcmd{math.mod(n,d)}, \cmd{math.mod2(n)} math modulous\\
-\\
\llcmd{string.}\cmd{upfirst(s)} uppercase first letter\\
\llcmd{string.}\cmd{delspace(s)} delete all spaces\\
@@ -123,6 +137,16 @@ Some functionality is added to penlight and Lua.
a few improvements. \cmd{t} can be an array (reference items like \cmd{\$1} in the string),
and \cmd{fmt} can be a table of formats (keys correspond to those in \cmd{t}), or a string that
is processed by luakeys.\\
+\llcmd{string.}\cmd{parsekv(s, opts)} parse a string using \cmd{penlight.luakeys}. A string or table can be used for opts.
+
+\llcmd{tablex.}\cmd{fmt(t, f)} format a table with table or key-value string f\\
+\llcmd{tablex.}\cmd{strinds(t)} convert integer indexes to string indices (1 -> '1')\\
+\llcmd{tablex.}\cmd{filterstr(t,e,case)} keep only values in table t that contain expression e, case insensitive by default.\\
+\llcmd{tablex.}\cmd{mapslice(f,t,i1,i2)} map a function to elements between i1 and i2\\
+\llcmd{tablex.}\cmd{listcontains(t,v)} checks if a value is in a array-style list \\
+
+
+
\llcmd{pl.}\cmd{char(n)} return letter corresponding to 1=a, 2=b, etc.\\
\llcmd{pl.}\cmd{Char(n)} return letter corresponding to 1=A, 2=B, etc.\\
@@ -156,17 +180,13 @@ to a package warning saying \cmd{'cs' was declared and used in document, but nev
is true, it will overwrite an existing command (using \cmd{defcmd}), otherwise, it will throw error like \cmd{newcmd}.\\
\llcmd{get_ref_info(l)}accesses the \cmd{\r@label} and returns a table\\
+\subsubsection*{Recording latex input}
+\cmd{penlight.tex.startrecording()} start recording input buffer without printing to latex\\
+\cmd{penlight.tex.stoprecording()} stop recording input buffer\\
+\cmd{penlight.tex.readbuf()} internal-use function that interprets the buffer. This will ignore an environment ending (eg. \cmd{end{envir}})\\\\
+\cmd{penlight.tex.recordedbuf} the string variable where the recorded buffer is stored\\
-\subsubsection*{global extras}
-If the package option \cmd{globals} is used, many additional globals are set for easier scripting.
-\cmd{pl.hasval}, \cmd{pl.COMP}, \cmd{pl.utils.kpairs}, \cmd{pl.utils.npairs} become globals.
-\cmd{pl.tablex} is aliased as \cmd{pl.tbx and tbx} (which also includes all native Lua table functions), and
-\cmd{pl.array2d} is aliased as \cmd{pl.a2d and a2d}.
-
-If you want global \cmd{pl.tex} funcs and vars, call \cmd{pl.make_tex_global()}
-\\
-
\subsection*{Macro helpers}
@@ -224,17 +244,27 @@ no, once, twice, or full expansion. For example, we can control the expansion of
\cmd{\tblchg{t}} changes the 'recent' table\\
\cmd{\tblfrkv{t}{key-val string}[luakeys opts]} new table from key-vals using \cmd{luakeys} \\
\cmd{\tblfrkvN{t}{key-val string}[luakeys opts]} does not expand key-val string \cmd{luakeys} \\
- \cmd{\tblfrcsv} a shorthand \cmd{\tblfrkv{t}{csv}[naked_as_value=true,opts]}, a good way to convert a comma-separated list to an array\\
+\cmd{\tblfrkvCD{t}{key-val string}[luakeys opts]} define tbl from key-val,
+check if any were not defined as defaults (see below), and then push all to definitions\\
+\cmd{\tblkvundefcheck} will throw an error if you use define a table from key-values
+and use a key that was not specified in the luakeys parse options via \cmd{opts.defaults} or \cmd{opts.defs}.
+ \cmd{\tblfrcsv{t}{csv}} a shorthand \cmd{\tblfrkv{t}{csv}[naked_as_value=true,opts]}, a good way to convert a comma-separated list to an array\\
+ \cmd{\tblfrcsvN{t}{csv}} same as above, but the csv is not expanded.
\cmd{\tblset{i}{v}} sets a value of the table/index \cmd{i} to \cmd{v}\\
-\cmd{\tblget{i}} gets the value and \cmd{tex.sprint()}'s it\\
+\cmd{\tblget{i}} gets the value and \cmd{tex.sprint()}s it\\
+\cmd{\tbladd{i}{v}} add a new value to a table using index method\\
+\cmd{\tbladdN{i}{v}} above, but don't expand the value argument\\
+\cmd{\tblcon{t}{csv}} concatenate an array-style csv\\
+\cmd{\tblapp{t}{v}} append a value (integer-wise) to a table\\
\cmd{\tbldef{i}{d}} pushes the value to macro \cmd{d}\\
-\cmd{\tbldefall{t}{d}} define all item in table \cmd{t} (use recent if blank) with format \cmd{d<key>}, if \cmd{d} is blank, commands are defined as \cmd{tbl<t><k>} \\
-\cmd{\tblgdef{i}{d}} pushes the value to a global\\
+\cmd{\tbldefall{t}{d}} define all item in table \cmd{t} (use recent if blank) with format \cmd{d<key>} where d is your prefix. If d is blank, keys will be defined as \cmd{\dtbl<t><k>}
+\cmd{\tblgdef{i}{d}} pushes the defined value to a global\\
\cmd{\tbldefxy{i}{d}} splits the value of item by spaces creates two definitions \cmd{\dx} and \cmd{\dy}. Useful for pasing tikz coordinates like \cmd{xy=0 5}\\
+For definiting tables, if \cmd{d} is blank, commands are defined as \cmd{dtbl<t><k>}\\
\cmd{\iftbl{i}{tr}[fa]} runs code \cmd{ta} if the item is true else \cmd{fr}\\
\cmd{\iftblv{i}{tr}[fa]} runs code \cmd{ta} if the item is truthy else \cmd{fr}\\
-\cmd{\tblkvundefcheck} will throw an error if you use define a table from key-values
-and use a key that was not specified in the luakeys parse options via \cmd{opts.defaults} or \cmd{opts.defs}.
+
+\cmd{\tblprt{t}} print the table in console
There are 3 ways to use the index (placeholder \cmd{{i}} above).
\cmd{t.key} where \cmd{t} is the table name and \cmd{key} is a string key,
@@ -248,6 +278,7 @@ or simply use \cmd{ind} without the table name, where the assumed table is the l
\tblset{a}{tRuE!!}
\tblget{a}\\
\tblget{my.x}\\
+\tblget{.x}\\
\tblif{n}{tr}[fa]\\
\tblifv{n}{TR}[FA]\\
\tblif{my.y}{Tr}[Fa]\\
@@ -263,14 +294,21 @@ or simply use \cmd{ind} without the table name, where the assumed table is the l
\tblset{my.a}{12 36}
\tbldefxy{my.a}{coord} (\coordx,\coordy)
+\tbldefxy{my.a}{} (\dtblmyax,\dtblmyay)
+\tbldefxy{a}{} (\dtblmyax,\dtblmyay)
\tblfrcsv{me}{a,b,"c,see",d,e}
\tblget{me/1},\tblget{2}\\
\tblget{3}\\
-\tblset{me/4}{D}\tblget{me/4}\\
+\tblset{me/4}{D}\tblget{me/4}\tblget{/4}\\
\tblset{5}{E}\tblget{5}\\
\tblget{-2},\tblget{me/-1}\\
+\tblget{/-3}\\
%% \tblget{k} % would throw error
+
+\tblfrkvCD{M}{a=A,b=B,d=D}[defaults={a,b,c,d}]
+\dtblMa \dtblMb \dtblMc \dtblMd
+
\end{LTXexample}
@@ -287,6 +325,38 @@ Note: for this versions: all latex tbl commands are now prefixed with \cmd{tbl},
Old-style commands eg. \cmd{gettbl} will be kept as aliases for a few more releases then removed.
+\subsubsection*{A practical tbl example}
+
+\begin{LTXexample}
+\begin{luacode*}
+ function prt_pyth()
+ t = pl.tbls.pyth
+ if not t.a then
+ pl.tex.pkgerror('must pass a= to \\pyth')
+ elseif not t.b then
+ t.b = (tonumber(t.c)^2 -
+ tonumber(t.a)^2)^0.5
+ elseif not t.c then
+ t.c = (tonumber(t.a)^2 +
+ tonumber(t.b)^2)^0.5
+ end
+ local t = pl.tbx.fmt(t,'.'..t.d..'f') -- format table according to d decimals
+ s = 'Right-angle sides a=$a and b=$b form a hypotenuse of c=$c'
+ pl.tex.prt(s:fmt(t))
+ end
+\end{luacode*}
+\NewDocumentCommand{\pyth}{m}{%
+ \tblfrkv{pyth}{#1}[defaults={a=false,b=false,c=false,d=0,e=extras}]
+ \luadirect{prt_pyth()}%
+}
+
+\pyth{a=3,c=5}\\
+\pyth{a=3.2,b=4.2,d=2}\\
+C: \tblget{c}
+
+\end{LTXexample}
+
+
\subsection*{Splitting strings}
Splitting text (or a cmd) into oxford comma format via:
\cmd{\splittocomma[expansion level]{text}{text to split on}}:
@@ -314,9 +384,20 @@ You can do a similar string split but to \cmd{\item} instead of commas with \cmd
+\subsubsection*{PDF meta data (for pdfx package)}
+\cmd{\writePDFmetadatakv*{m}} Take a key-value string (eg. \cmd{title=whatever, author=me}) and writes to the \cmd{jobname.xmpdata} file, to be used by pdfx. \cmd{*} will first clear the data\\
+\cmd{\writePDFmetadata} runs the lua function \cmd{penlight.tex.writePDFmetadata()},
+which pushes the lua variable \cmd{__PDFmetadata__} (a table) to the xmpdata file.
+
+
+%\pyth{} % erro
+%\begin{luacode*}
+% pl.tex.wrth(('a,b,c=3'):parsekv('!naked_as_value'), 'dumy')
+%\end{luacode*}
+
% \tblfrkv{tbl_def}{kale=cool,paul=gay,craig=fun}
% \tblfrkv{tbl}{kale,paul=gay} %[naked_as_value=true]
%
@@ -338,24 +419,25 @@ You can do a similar string split but to \cmd{\item} instead of commas with \cmd
%
% \THINg[color=blue,size=tiny]{Kale}
%
-%\begin{luacode*}
-%penlight.wrth(('$1'):fmt(5.5,'.8f','XYZ'))
-%function prttol()
-% penlight.tbls.tol[3] = penlight.tbls.tol[3] or 3
-% penlight.tbls.tol[4] = penlight.tbls.tol[1]*(1.0-penlight.tbls.tol[3]/100.0) + 0.0
-% penlight.tbls.tol[5] = penlight.tbls.tol[1]*(1.0+penlight.tbls.tol[3]/100.0) + 0.0
-% penlight.tbls.tol['k'] = 'fuckboi'
-% penlight.wrth(('$k $1\\$2 (\\pmpct{$3} tolerance, $4\\ndash$5\\$2)'):fmt(penlight.tbls.tol, '4=.1f, 5=.1f'), 'XYZ')
-%end
-%\end{luacode*}
-%\NewDocumentCommand{\prttol}{ m }{% {50.0,kV,3} % 50\us (\pmpct{20} tolerance, 40=--60\us)
-%\tblfrcsv{tol}{#1}\luadirect{prttol()}}
-%
-%\prttol{50,kV,3.21}
-%
-%\begin{luacode*}
-%--pl.wrth(('2.23'):gnum())
-%\end{luacode*}
+\begin{luacode*}
+function prttol()
+ local dec = penlight.tbls.tol[4] or 1
+ penlight.wrth(dec,'??')
+ penlight.tbls.tol[3] = penlight.tbls.tol[3] or 3
+ penlight.tbls.tol[4] = penlight.tbls.tol[1]*(1.0-penlight.tbls.tol[3]/100.0) + 0.0
+ penlight.tbls.tol[5] = penlight.tbls.tol[1]*(1.0+penlight.tbls.tol[3]/100.0) + 0.0
+ --penlight.tbls.tol['k'] = 'fuckboi'
+ --ttt = pl.tbx.fmt(penlight.tbls.tol, '.3f')
+ penlight.wrth(('$1\\$2 (\\pmpct{$3} tolerance, $4\\ndash$5\\$2)'):fmt(penlight.tbls.tol, '4=.'..dec..'f, 5=.'..dec..'f'), 'XYZ')
+end
+\end{luacode*}
+\NewDocumentCommand{\prttol}{ m }{\tblfrcsv{tol}{#1}\luadirect{prttol()}}% {50.0,kV,3,P} % 50\us (\pmpct{20} tolerance, 40=--60\us), P is optional and precision of the range (number of decimals)
+
+\prttol{50,kV,3}
+
+\begin{luacode*}
+ pl.wrth(pl.filterfiles('.',true,'.*%.tex'), 'FF')
+\end{luacode*}
\end{document} \ No newline at end of file