texlive[64870] Master: luaoptions (30oct22)

commits+karl at tug.org commits+karl at tug.org
Sun Oct 30 21:46:46 CET 2022


Revision: 64870
          http://tug.org/svn/texlive?view=revision&revision=64870
Author:   karl
Date:     2022-10-30 21:46:45 +0100 (Sun, 30 Oct 2022)
Log Message:
-----------
luaoptions (30oct22)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/libexec/ctan2tds
    trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/Contributors.md
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/LICENSE
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/README.md
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/latexmkrc
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.tex
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsbase.cls
    trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsmanual.cls
    trunk/Master/texmf-dist/tex/lualatex/luaoptions/
    trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions-lib.lua
    trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.lua
    trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.sty
    trunk/Master/tlpkg/tlpsrc/luaoptions.tlpsrc

Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/Contributors.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/Contributors.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/Contributors.md	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,6 @@
+## Authors
+
+Luaoptions is developped by:
+
+- [Fr. Jacques Peron](mailto:cataclop at hotmail.com); [@jperon](https://github.com/jperon)
+- [Urs Liska](mailto:git at ursliska.de); [@uliska](https://github.com/uliska), [@openlilylib](https://github.com/openlilylib)


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/Contributors.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/LICENSE
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/LICENSE	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/LICENSE	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015--2022 the lualatex-tools Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/README.md	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,15 @@
+Main author: [Fr. Jacques Peron](mailto:cataclop at hotmail.com)\nThis material is subject to the MIT license.\n
+# `luaoptions`
+Option handling for LuaLaTeX packages
+
+This package has been extracted from
+[`lyluatex`](https://github.com/jperon/lyluatex) where it was originally
+developed as supporting functionality. However, as it turned out it is useful
+as a building block for LuaLaTeX packages in general, and the development of
+[`luaformatters`](https://github.com/lualatex-tools/luaformatters) made it
+clear that the option handling code had to be moved to a standalone package.
+
+Initially there is no extensive documentation available since the package wasn't
+originally intended to be exposed to third-party packages or even end-users;
+the best sources of documentation are `lyluatex` and `luaformatters` codes,
+and the docstrings of `luaoptions.lua` and `luaoptions-lib.lua`.


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/latexmkrc
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/latexmkrc	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/latexmkrc	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,2 @@
+$pdf_mode="1";
+$pdflatex="lualatex --shell-escape %O %S";

Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf	2022-10-30 20:43:48 UTC (rev 64869)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf	2022-10-30 20:46:45 UTC (rev 64870)

Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.tex
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.tex	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,188 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+%
+\documentclass[
+]{luaoptionsmanual}
+\usepackage{amsmath,amssymb}
+\usepackage[]{libertine}
+\usepackage{iftex}
+\ifPDFTeX
+  \usepackage[T1]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+  \usepackage{unicode-math}
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+\fi
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+  pdfauthor={Fr.~Jacques Peron; Urs Liska},
+  hidelinks,
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+\usepackage{color}
+\usepackage{fancyvrb}
+\newcommand{\VerbBar}{|}
+\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
+\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
+% Add ',fontsize=\small' for more characters per line
+\newenvironment{Shaded}{}{}
+\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
+\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}}
+\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\BuiltInTok}[1]{\textcolor[rgb]{0.00,0.50,0.00}{#1}}
+\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}}
+\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
+\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
+\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}}
+\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}}
+\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
+\newcommand{\ExtensionTok}[1]{#1}
+\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
+\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}}
+\newcommand{\ImportTok}[1]{\textcolor[rgb]{0.00,0.50,0.00}{\textbf{#1}}}
+\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
+\newcommand{\NormalTok}[1]{#1}
+\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}}
+\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}}
+\newcommand{\RegionMarkerTok}[1]{#1}
+\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
+\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
+\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
+\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+\ifLuaTeX
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+
+\title{\texttt{luaoptions}}
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+\subtitle{0.8}
+\author{Fr.~Jacques Peron \and Urs Liska}
+\date{\luaoptionsmanualdate}
+
+\begin{document}
+\maketitle
+
+\thispagestyle{empty}
+\enlargethispage*{3\baselineskip}
+
+\hypertarget{introduction}{%
+\section{Introduction}\label{introduction}}
+
+\texttt{luaoptions} is a LuaLaTeX package providing extensive support
+for handling \emph{options}, on package level and locally. It is hosted
+at \url{https://github.com/lualatex-tools/luaoptions} and maintained by
+Jacques Peron
+(\href{mailto:cataclop at hotmail.com}{\nolinkurl{cataclop at hotmail.com}})
+and Urs Liska
+(\href{mailto:git at ursliska.de}{\nolinkurl{git at ursliska.de}}). The
+package was originally developed as part of the \texttt{lyluatex}
+package\footnote{\url{https://github.com/jperon/lyluatex}} but has now
+been extracted as a standalone package because we realized it can be a
+useful tool for arbitrary LuaLaTeX packages having to deal with
+\emph{options} -- both \emph{package options} and \emph{optional macro
+arguments}. A \texttt{lyluatex} installation should not be a dependency
+for packages that want to make use of option handling but are not
+interested in music engraving \dots
+
+\texttt{luaoptions} allows the declaration of sets of options, along
+with defaults, expected/allowed values and limited type checking. These
+options can be enforced as package options, changed at any point during
+a document, or overwritten locally by optional macro arguments. It is
+also possible to instantiate an \texttt{Options} object as an
+independent Lua object, without linking it to a package.
+\texttt{luaoptions} can be used to enforce and prepopulate options, or
+it can be used to simply handle the parsing of optional
+\texttt{key=value} arguments into proper Lua tables.
+
+The main use of \texttt{luaoptions} is to define package options as
+follows:
+
+\begin{Shaded}
+\begin{Highlighting}[]
+\FunctionTok{\textbackslash{}RequirePackage}\NormalTok{\{luaoptions\}}
+\FunctionTok{\textbackslash{}directlua}\NormalTok{\{}
+\NormalTok{  local \_opt = lua\_options}
+\NormalTok{  lua\_options.register(\textquotesingle{}myoptions\textquotesingle{}, \{}
+\NormalTok{    [\textquotesingle{}option\textquotesingle{}] = \{\textquotesingle{}default value\textquotesingle{}, \textquotesingle{}other value\textquotesingle{}, \textquotesingle{}\textquotesingle{}\},}
+\NormalTok{    [\textquotesingle{}otheroption\textquotesingle{}] = \{\textquotesingle{}default\textquotesingle{}, validator\},}
+\NormalTok{    [\textquotesingle{}yetanotheroptions\textquotesingle{}] = \{\},}
+\NormalTok{  \})}
+\NormalTok{\}}
+\end{Highlighting}
+\end{Shaded}
+
+\texttt{validator} is a function that returns \texttt{true} when the
+defined option is valid, \texttt{false} otherwise. \texttt{luaoptions}
+itself contains predefined such functions.
+
+After that, defined options are available in a lua table, which can be
+used by the mean of the \texttt{client} command:
+
+\begin{Shaded}
+\begin{Highlighting}[]
+\KeywordTok{local}\NormalTok{ myopts }\OperatorTok{=}\NormalTok{ lua\_options}\OperatorTok{.}\NormalTok{client}\OperatorTok{(}\StringTok{\textquotesingle{}myoptions\textquotesingle{}}\OperatorTok{)}
+\NormalTok{tex}\OperatorTok{.}\NormalTok{sprint}\OperatorTok{(}\NormalTok{myopts}\OperatorTok{.}\NormalTok{option}\OperatorTok{)}
+\end{Highlighting}
+\end{Shaded}
+
+This initial release does \emph{not} include documentation beyond this
+short introduction; please refer to the docstrings in
+\texttt{luaoptions.lua} and \texttt{luaoptions-lib.lua} for more
+information.
+
+For the time being it is possible to look into how some of our own
+packages make use of \texttt{luaoptions}:
+
+\begin{itemize}
+\tightlist
+\item
+  \url{https://github.com/jperon/lyluatex/blob/master/lyluatextools.sty}
+\item
+  \url{https://github.com/jperon/lyluatex/blob/master/lyluatex.lua}
+\item
+  \url{https://github.com/lualatex-tools/luaformatters/blob/master/luaformatters.sty}
+\item
+  \url{https://github.com/lualatex-tools/luaformatters/blob/master/luaformatters.lua}
+\item
+  \url{https://github.com/lualatex-tools/luaformatters/blob/master/submodules/luaformatters-formatter.lua}
+\end{itemize}
+
+\end{document}


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptions.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsbase.cls
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsbase.cls	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsbase.cls	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,37 @@
+%Luaoptions LaTeX class.
+%
+% Copyright (C) 2015-2022 the lualatex-tools Project
+% License: MIT
+% This file is part of lualatex-tools.
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{luaoptionsbase}[2022/10/30 v0.8]  %%LUAOPTIONS_DATE LUAOPTIONS_VERSION
+
+\LoadClass[DIV=11]{scrartcl}
+\RequirePackage{blindtext}
+\RequirePackage{libertine}
+\RequirePackage{listings}
+\RequirePackage{minted}
+\RequirePackage{pgffor}
+\RequirePackage{fancyvrb}
+\RequirePackage[colorlinks=true]{hyperref}
+
+
+% Common formatting elements for manual and examples
+\usepackage{xcolor}
+\newcommand{\highlight}[1]{\textcolor{blue}{#1}}
+\newcommand{\cmd}[1]{\highlight{\texttt{\textbackslash #1}}}
+\newcommand{\option}[1]{\highlight{\texttt{#1}}}
+\newcommand{\lyMargin}[1]{%
+
+\medskip
+\hspace*{-1em}%
+\noindent%
+\highlight{#1}
+\nopagebreak
+}
+
+\newcommand{\lyOption}[2]{\lyMargin{\texttt{#1} {\small \emph{(#2)}}\index{#1}}}
+\newcommand{\lyCmd}[1]{%
+\lyMargin{\texttt{\textbackslash #1}\index{\textbackslash #1}}}
+\newcommand{\lyIssue}[1]{\lyMargin{\textbf{\textcolor{red}{#1}}}}


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsbase.cls
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsmanual.cls
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsmanual.cls	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsmanual.cls	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,41 @@
+%Luaoptions LaTeX class for the manual.
+%
+% Copyright (C) 2015-2022 the lualatex-tools Project
+% License: MIT
+% This file is part of luaoptions.
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{luaoptionsmanual}[2022/10/30 v0.8]  %%LUAOPTIONS_DATE LUAOPTIONS_VERSION
+
+\LoadClass{luaoptionsbase}
+
+\RequirePackage{fontspec}
+\RequirePackage{microtype}
+\RequirePackage{libertine}
+\setmonofont[Scale=MatchLowercase,StylisticSet=1]{InconsolataN}
+\defaultfontfeatures{
+	Ligatures=TeX,
+	Scale=MatchLowercase,
+	Numbers=Proportional,
+	Numbers=OldStyle
+}
+\frenchspacing
+
+\RequirePackage{makeidx}
+\makeindex
+
+\newcommand{\linkexample}[2]{
+    \addcontentsline{toc}{subsection}{#2}
+    \hypertarget{#1}{}
+}
+
+
+\newcommand{\luaoptionsmanualdate}{
+	\directlua{
+		local PC = string.char(37)
+		local date_fmt = PC..'Y-'..PC..'m-'..PC..'d'
+		local p = io.popen('git log -n1 --date=short --format='..PC..'"ad"', 'r')
+		tex.sprint(p and p:read('*a'):sub(1,-2) or os.date(date_fmt))
+		if p then p:close() end
+	}
+}


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luaoptions/luaoptionsmanual.cls
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions-lib.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions-lib.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions-lib.lua	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,240 @@
+-- luacheck: ignore ly log self luatexbase internalversion font fonts tex token kpse status
+local err, warn, info, log = luatexbase.provides_module({
+    name               = "luaoptions-lib",
+    version            = '0.8',  --LUAOPTIONS_VERSION
+    date               = "2022/10/30",  --LUAOPTIONS_DATE
+    description        = "Module luaoptions-lib.",
+    author             = "The lualatex-tools Project",
+    copyright          = "2015-2022 - the lualatex-tools Project",
+    license            = "MIT",
+})
+
+local lib = {}
+lib.TEX_UNITS = {'bp', 'cc', 'cm', 'dd', 'in', 'mm', 'pc', 'pt', 'sp', 'em',
+'ex'}
+
+-------------------------
+-- General tool functions
+
+function lib.basename(str)
+--[[
+  Given the full path to a file, return only the file name (without path).
+  If there is no slash, return the full name.
+--]]
+    return str:gsub(".*/(.*)", "%1") or str
+end
+
+
+function lib.contains(table_var, value)
+--[[
+  Returns the key if the given table contains the given value, or nil.
+  A value of 'false' (string) is considered equal to false (Boolean).
+--]]
+    for k, v in pairs(table_var) do
+        if v == value then return k
+        elseif v == 'false' and value == false then return k
+        end
+    end
+end
+
+
+function lib.contains_key(table_var, key)
+-- Returs true if the given key is present in the table, nil otherwise.
+    for k in pairs(table_var) do
+        if k == key then return true end
+    end
+end
+
+
+function lib.convert_unit(value)
+--[[
+  Convert a LaTeX unit, if possible.
+  TODO: Understand what this *really* does, what is accepted and returned.
+--]]
+    if not value then return 0
+    elseif value == '' then return false
+    elseif value:match('\\') then
+        local n, u = value:match('^%d*%.?%d*'), value:match('%a+')
+        if n == '' then n = 1 end
+        return tonumber(n) * tex.dimen[u] / tex.sp("1pt")
+    else return ('%f'):format(tonumber(value) or tex.sp(value) / tex.sp("1pt"))
+    end
+end
+
+
+function lib.current_font_size()
+--[[
+    Convenience function to return the font size of the current font
+--]]
+    return lib.fontinfo(font.current()).size
+end
+
+
+function lib.dirname(str)
+--[[
+  Given the full path to a file, return only the path (without file name),
+  including the last slash. If there is no slash, return an empty string.
+--]]
+    return str:gsub("(.*/).*", "%1") or ''
+end
+
+
+local fontdata = fonts.hashes.identifiers
+function lib.fontinfo(id)
+--[[
+  Return a LuaTeX font object based on the given ID
+--]]
+    return fontdata[id] or font.getfont(id)
+end
+
+
+function lib.max(a, b)
+    a, b = tonumber(a), tonumber(b)
+    if a > b then return a else return b end
+end
+
+
+function lib.min(a, b)
+    a, b = tonumber(a), tonumber(b)
+    if a < b then return a else return b end
+end
+
+
+function lib.mkdirs(str)
+    local path
+    if str:sub(1, 1) == '/' then path = '' else path = '.' end
+    for dir in str:gmatch('([^%/]+)') do
+        path = path .. '/' .. dir
+        lfs.mkdir(path)
+    end
+end
+
+
+function lib.orderedkeys(t)
+    local orderedIndex = {}
+    for k in pairs(t) do table.insert(orderedIndex, k) end
+    table.sort(orderedIndex)
+    return orderedIndex
+end
+
+
+function lib.orderedpairs(t)
+    local key
+    local i = 0
+    local orderedIndex = lib.orderedkeys(t)
+    return function ()
+            i = i + 1
+            key = orderedIndex[i]
+            if key then return key, t[key] end
+        end
+end
+
+
+function lib.print_table(t, indent)
+-- Recursively print a table, avoiding recursion loops
+    indent = indent or '  '
+    local visited = {}
+    local skips = 0
+
+    local function _print_table(_t, _ind)
+        local keys = lib.orderedkeys(_t)
+        local display_keys = {}
+        local length = 0
+        for key, _ in pairs(_t) do
+            length = lib.max(length, #tostring(key))
+        end
+        for key, _ in pairs(_t) do
+            display_key = tostring(key)
+            display_keys[key] = display_key .. string.rep(
+                ' ', length - #display_key)
+        end
+        for k, v in lib.orderedpairs(_t) do
+            if type(v) == 'table' then
+                if visited[v] then
+                    skips = skips + 1
+                else
+                    visited[v] = true
+                    print(_ind..display_keys[k], v)
+                    if #_ind > 40 then err("k") end
+                    _print_table(v, _ind..indent)
+                end
+            else
+                if v == '' then v = '(empty string)' end
+                print(_ind..display_keys[k], v)
+            end
+        end
+    end
+
+    print()
+    visited[t] = true
+    print("Print table:", t)
+    _print_table(t, indent)
+    print()
+    if skips > 0 then
+        print(string.format('%s recursive tables skipped', skips))
+    end
+    print("============")
+    print()
+end
+
+function lib.readlinematching(s, f)
+    if f then
+        local result = ''
+        while result and not result:find(s) do result = f:read() end
+        f:close()
+        return result
+    end
+end
+
+
+function lib.splitext(str, ext)
+--[[
+    If 'ext' is supplied return str stripped of the given extension,
+    otherwise return the base and extension (if any)
+--]]
+    return ext and (str:match('(.*)%.'..ext..'$') or str)
+        or (str:match('(.*)%.(%w*)$') or str)
+end
+
+
+------------------------------------
+-- Engine, version, TeX distribution
+
+local function _loaded(ext)
+--[[
+    Returns a function that checks whether a class or a package is loaded
+    https://tex.stackexchange.com/questions/501635/
+--]]
+    local fmt = "ver@%s." .. ext
+    return function(name)
+        local macro = token.get_macro(fmt:format(name))
+        return macro ~= nil
+    end
+end
+
+-- Lua implementations of \@ifpackageloaded and \@ifclassloaded
+lib.class_loaded = _loaded('cls')
+lib.package_loaded = _loaded('sty')
+
+local tex_engine = {}
+setmetatable(tex_engine, tex_engine)
+
+function tex_engine:__call()
+--[[
+    Defines the properties extracted from the first line of jobname.log.
+--]]
+    local f = io.open(tex.jobname..'.log')
+    if not f then return end
+    self.engine, self.engine_version, self.dist, self.dist_version, self.format, self.format_version =
+        f:read():match(
+            'This is ([^,]*), Version ([^%(]*) %(([^%)]*) ([^%)]*)%)%s+%(format=([^%)]*) ([^)]*)%)'
+        )
+    f:close()
+    return self
+end
+
+function tex_engine:__index(k) return rawget(self(), k) end
+
+
+lib.tex_engine = tex_engine
+return lib


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions-lib.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.lua	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,329 @@
+-- luacheck: ignore ly warn info log self luatexbase internalversion font fonts tex token kpse status
+local err, warn, info, log = luatexbase.provides_module({
+    name               = "luaoptions",
+    version            = '0.8',  --LUAOPTIONS_VERSION
+    date               = "2022/10/30",  --LUAOPTIONS_DATE
+    description        = "Module luaoptions.",
+    author             = "The lualatex-tools Project",
+    copyright          = "2015-2022 - the lualatex-tools Project",
+    license            = "MIT",
+})
+
+--[[
+    This module provides functionality to handle package options and make them
+    configurable in a fine-grained fashion as
+    - package options
+    - local options (for individual instances of commands/environments)
+    - changed “from here on” within a document.
+
+-- ]]
+
+local lib = require(kpse.find_file("luaoptions-lib.lua") or "luaoptions-lib.lua")
+local optlib = {}  -- namespace for the returned table
+local Opts = {options = {}}  -- Options class
+Opts.__index = function (self, k) return self.options[k] or rawget(Opts, k) end
+setmetatable(Opts, Opts)
+local clients = {}
+
+function Opts:new(declarations)
+--[[
+    Declare an options object along with default and accepted values.
+    To *some* extent also provide type checking.
+    - declarations: a definition table stored in the calling module (see below)
+    Each entry in the 'declarations' table represents one package option, with each
+    value being an array (table with integer indexes instead of keys). For
+    details please refer to the manual.
+--]]
+    local o = setmetatable(
+        {
+            declarations = declarations,
+            options = {}
+        },
+        self
+    )
+    for k, v in pairs(declarations) do
+        o.options[k] = v[1] or ''
+    end
+    return o
+end
+
+function Opts:check_local_options(opts, ignore_declarations)
+--[[
+    Parse the given options (options passed to a command/environment),
+    sanitize them against the global package options and return a table
+    with the local options that should then supersede the global options.
+    If ignore_declaration is given any non-false value the sanitization
+    step is skipped (i.e. local options are only parsed and duplicates
+    rejected).
+--]]
+    local options = {}
+    local next_opt = opts:gmatch('([^,]+)')  -- iterator over options
+    for opt in next_opt do
+        local k, v = opt:match('([^=]+)=?(.*)')
+        if k then
+            if v and v:sub(1, 1) == '{' then  -- handle keys with {multiple, values}
+                while select(2, v:gsub('{', '')) ~= select(2, v:gsub('}', '')) do v = v..','..next_opt() end
+                v = v:sub(2, -2)  -- remove { }
+            end
+            if not ignore_declarations then
+                k, v = self:sanitize_option(k:gsub('^%s', ''), v:gsub('^%s', ''))
+            end
+            if k then
+                if options[k] then err('Option %s is set two times for the same score.', k)
+                else options[k] = v
+                end
+            end
+        end
+    end
+    return options
+end
+
+function Opts:has_option(name)
+--[[
+    Returns true if the given option is declared
+--]]
+    return self.declarations[name] ~= nil
+end
+
+function Opts:is_neg(k)
+--[[
+    Type check for a 'negative' option. This is an existing option
+    name prefixed with 'no' (e.g. 'noalign')
+--]]
+    local _, i = k:find('^no')
+    return i and lib.contains_key(self.declarations, k:sub(i + 1))
+end
+
+function Opts:sanitize_option(k, v)
+--[[
+    Check and (if necessary) adjust the value of a given option.
+    Reject undefined options
+    Check 'negative' options
+    Handle boolean options (empty strings or 'false'), set them to real booleans
+--]]
+    local declarations = self.declarations
+    if k == '' or k == 'noarg' then return end
+    if not lib.contains_key(declarations, k) then err('Unknown option: '..k) end
+    -- aliases
+    if declarations[k] and declarations[k][2] == optlib.is_alias then
+        if declarations[k][1] == v then return
+        else k = declarations[k] end
+    end
+    -- boolean
+    if v == 'false' then v = false end
+    -- negation (for example, noindent is the negation of indent)
+    if self:is_neg(k) then
+        if v ~= nil and v ~= 'default' then
+            k = k:gsub('^no(.*)', '%1')
+            v = not v
+        else return
+        end
+    end
+    return k, v
+end
+
+function Opts:set_option(k, v)
+--[[
+    Set an option for the given prefix to be in effect from this point on.
+    Raises an error if the option is not declared or does not meet the
+    declared expectations. (TODO: The latter has to be integrated by extracting
+    optlib.validate_option from optlib.validate_options and call it in
+    sanitize_option).
+--]]
+    k, v = self:sanitize_option(k, v)
+    if k then
+        self.options[k] = v
+        self:validate_option(k)
+    end
+end
+
+function Opts:use_option(key)
+--[[
+    Call an option and write its value to the TeX space.
+    This is a shorthand for accessing options from the TeX side
+    (rather than having to write tex.print(XX_opts.some_options))
+--]]
+    local option = self.options[key]
+    if option then
+        tex.print(option:explode('\n'))
+    else
+        err(string.format("Trying to access non-existent option %s", key))
+    end
+end
+
+function Opts:validate_option(key, options_obj)
+--[[
+    Validate an (already sanitized) option against its expected values.
+    With options_obj a local options table can be provided,
+    otherwise the global options stored in OPTIONS are checked.
+--]]
+    local package_opts = self.declarations
+    local options = options_obj or self.options
+    local unexpected
+    if options[key] == 'default' then
+        -- Replace 'default' with an actual value
+        options[key] = package_opts[key][1]
+        unexpected = options[key] == nil
+    end
+    if not lib.contains(package_opts[key], options[key]) and package_opts[key][2] then
+        -- option value is not in the array of accepted values
+        if type(package_opts[key][2]) == 'function' then package_opts[key][2](key, options[key])
+        else unexpected = true
+        end
+    end
+    if unexpected then
+        err([[
+    Unexpected value "%s" for option %s:
+    authorized values are "%s"
+    ]],
+            options[key], key, table.concat(package_opts[key], ', ')
+        )
+    end
+end
+
+function Opts:validate_options(options_obj)
+--[[
+    Validate the given set of options against the option declaration
+    table for the given prefix.
+    With options_obj a local options table can be provided,
+    otherwise the global options stored in OPTIONS are checked.
+--]]
+    for k, _ in lib.orderedpairs(self.declarations) do
+        self:validate_option(k, options_obj)
+    end
+end
+
+
+function optlib.is_alias()
+--[[
+    This function doesn't do anything, but if an option is defined
+    as an alias, its second parameter will be this function, so the
+    test declarations[k][2] == optlib.is_alias in Opts:sanitize_options
+    will return true.
+--]]
+end
+
+
+function optlib.is_dim(k, v)
+--[[
+    Type checking for options that accept a LaTeX dimension.
+    This can be
+    - a number (integer or float)
+    - a number with unit
+    - a (multiplied) TeX length
+    (see error message in code for examples)
+--]]
+    if v == '' or v == false or tonumber(v) then return true end
+    local n, sl, u = v:match('^%d*%.?%d*'), v:match('\\'), v:match('%a+')
+    -- a value of number - backslash - length is a dimension
+    -- invalid input will be prevented in by the LaTeX parser already
+    if n and sl and u then return true end
+    if n and lib.contains(lib.TEX_UNITS, u) then return true end
+    err([[
+Unexpected value "%s" for dimension %s:
+should be either a number (for example "12"),
+a number with unit, without space ("12pt"),
+or a (multiplied) TeX length (".8\linewidth")
+]],
+        v, k
+    )
+end
+
+
+function optlib.is_neg(k, _)
+--[[
+    Type check for a 'negative' option. At this stage,
+    we only check that it begins with 'no'.
+--]]
+    return k:find('^no')
+end
+
+
+function optlib.is_num(_, v)
+--[[
+    Type check for number options
+--]]
+    return v == '' or tonumber(v)
+end
+
+
+function optlib.is_str(_, v)
+--[[
+    Type check for string options
+--]]
+    return type(v) == 'string'
+end
+
+
+function optlib.merge_options(base_opt, super_opt)
+--[[
+    Merge two tables.
+    Create a new table as a copy of base_opt, then merge with
+    super_opt. Entries in super_opt supersede (i.e. overwrite)
+    colliding entries in base_opt.
+--]]
+    local result = {}
+    for k, v in pairs(base_opt) do result[k] = v end
+    for k, v in pairs(super_opt) do result[k] = v end
+    return result
+end
+
+function optlib.register(client_name, declarations)
+--[[
+    Register a client as package options.
+    - Create a new Opts object,
+    - initialize it,
+    - store it in a global variable <client_name>_opts,
+    - write the code to handle the package options.
+--]]
+    local o = Opts:new(declarations)
+    local exopt = ''
+    for k, v in pairs(declarations) do
+        tex.sprint(string.format([[
+\DeclareOptionX{%s}{\setluaoption{%s}{%s}{#1}}%%
+]],
+            k, client_name, k
+        ))
+        exopt = exopt..k..'='..(v[1] or '')..','
+    end
+    clients[client_name] = o
+    tex.sprint([[\ExecuteOptionsX{]]..exopt..[[}%%]], [[\ProcessOptionsX]])
+end
+
+function optlib.client(name)
+--[[
+    Return the FormattersTable instance registered with the given client name.
+    Return 'nil' if no client is found.
+--]]
+    return clients[name]
+end
+
+function optlib.get_option(client_name, k)
+--[[
+    Get an option's value from a registered client.
+    Raises an error if the client hasn't been registered.
+--]]
+    local client = optlib.client(client_name)
+    return client.options[k]
+end
+
+function optlib.set_option(client_name, k, v)
+--[[
+    Set an option.
+    Look up a registered client and set an option.
+    Produces an error if the client hasn't been registered.
+--]]
+    local client = optlib.client(client_name)
+    client:set_option(k, v)
+end
+
+function optlib.use_option(client_name, k)
+--[[
+    Look up an option and write it to LaTex.
+--]]
+    local client = optlib.client(client_name)
+    client:use_option(k)
+end
+
+optlib.Opts = Opts
+return optlib


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.sty	2022-10-30 20:46:45 UTC (rev 64870)
@@ -0,0 +1,36 @@
+% luaoptions support package.
+%
+% Copyright (C) 2015-2022 the lualatex-tools Project
+% License: MIT
+% This file is part of luaoptions.
+
+\NeedsTeXFormat{LaTeX2e}%
+\ProvidesPackage{luaoptions}[2022/10/30 v0.8]
+
+% Dependencies
+\RequirePackage{luatexbase}
+\RequirePackage{luaotfload}
+\RequirePackage{xkeyval}
+
+\directlua{
+  lua_options = require(kpse.find_file("luaoptions.lua") or "luaoptions.lua")
+}
+
+% Set an option in a registered client
+\newcommand{\setluaoption}[3]{%
+  \directlua{
+    lua_options.set_option(
+      '\luatexluaescapestring{#1}',
+      '\luatexluaescapestring{#2}',
+      '\luatexluaescapestring{#3}')
+  }
+}
+
+% Use an option and directly write it to LaTeX
+\newcommand{\useluaoption}[2]{%
+  \directlua{
+    lua_options.use_option(
+      '\luatexluaescapestring{#1}',
+      '\luatexluaescapestring{#2}')
+  }%
+}


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luaoptions/luaoptions.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2022-10-30 20:43:48 UTC (rev 64869)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2022-10-30 20:46:45 UTC (rev 64870)
@@ -510,7 +510,8 @@
     luaimageembed luaindex luainputenc luaintro luakeys
     lualatex-doc lualatex-doc-de
     lualatex-math lualatex-truncate lualibs luamathalign
-    luamesh luamplib luaotfload luapackageloader luaprogtable luapstricks
+    luamesh luamplib luaoptions luaotfload
+    luapackageloader luaprogtable luapstricks
     luaquotes luarandom
     luasseq luatex85 luatexbase luatexja luatexko luatextra
     luatodonotes luatruthtable luavlna luaxml

Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds	2022-10-30 20:43:48 UTC (rev 64869)
+++ trunk/Master/tlpkg/libexec/ctan2tds	2022-10-30 20:46:45 UTC (rev 64870)
@@ -2168,6 +2168,7 @@
  'lualatex-math', '\.sty',      # not phst-doc.cls
  'luamathalign','luam.*\.lua|\.sty',	# not build.lua
  'luamesh',	'\.sty',        # not lltxdoc.cls
+ 'luaoptions',	'(\.sty|\.lua)$',	# not .cls
  'luapackageloader', '\.lua|' . $standardtex,
  'luaprogtable','\.lua|' . $standardtex,
  'luapstricks',	'\.lua|' . $standardtex,

Modified: trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2022-10-30 20:43:48 UTC (rev 64869)
+++ trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2022-10-30 20:46:45 UTC (rev 64870)
@@ -50,6 +50,7 @@
 depend lualibs
 depend luamathalign
 depend luamplib
+depend luaoptions
 depend luaotfload
 depend luapackageloader
 depend luaprogtable

Added: trunk/Master/tlpkg/tlpsrc/luaoptions.tlpsrc
===================================================================


More information about the tex-live-commits mailing list.