summaryrefslogtreecommitdiff
path: root/Master/texmf-dist
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2023-10-10 20:24:53 +0000
committerKarl Berry <karl@freefriends.org>2023-10-10 20:24:53 +0000
commitf9ef02225e8e2c547c2e884aaa50cbe21a604045 (patch)
tree47961285574c0ecd8a7b2b2141ae4d3a6d06f71d /Master/texmf-dist
parent60edacb591380fc24ec38250489e8999f91b566f (diff)
non-decimal-units (10oct23)
git-svn-id: svn://tug.org/texlive/trunk@68504 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r--Master/texmf-dist/doc/latex/non-decimal-units/README.md4
-rw-r--r--Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.pdfbin163176 -> 155980 bytes
-rw-r--r--Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.preamble.sty106
-rw-r--r--Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.tex598
-rw-r--r--Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.british.tex41
-rw-r--r--Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.danish.tex222
-rw-r--r--Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.german.tex32
-rw-r--r--Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.sty1340
8 files changed, 1317 insertions, 1026 deletions
diff --git a/Master/texmf-dist/doc/latex/non-decimal-units/README.md b/Master/texmf-dist/doc/latex/non-decimal-units/README.md
index fb4f75a2c00..e5e9eb728c9 100644
--- a/Master/texmf-dist/doc/latex/non-decimal-units/README.md
+++ b/Master/texmf-dist/doc/latex/non-decimal-units/README.md
@@ -5,9 +5,9 @@ Macros for displaying and manipulating historical non-decimal units.
See [non-decimal-units.pdf](docs/non-decimal-units.pdf) for the documentation.
-Contents last updated 2023-09-27.
+Contents last updated 2023-10-10.
-<!-- Package available via CTAN at https://www.ctan.org/pkg/non-decimal-units -->
+Package available via CTAN at https://www.ctan.org/pkg/non-decimal-units
License: CC-BY-SA 4.0
Author: Mikkel Eide Eriksen <mikkel.eriksen@gmail.com>
diff --git a/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.pdf b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.pdf
index 60e5b7acd83..19b21b0375b 100644
--- a/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.pdf
+++ b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.preamble.sty b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.preamble.sty
new file mode 100644
index 00000000000..977d02cbf5c
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.preamble.sty
@@ -0,0 +1,106 @@
+\usepackage{makeidx}
+\makeindex
+
+\usepackage{needspace}
+
+\usepackage{csquotes}
+\usepackage[english]{babel}
+\usepackage[
+ backend=biber,
+ urldate=long,
+ date=long,
+]{biblatex}
+\addbibresource{non-decimal-units.bib}
+
+\usepackage{enumitem}
+\usepackage[
+ hidelinks,
+]{hyperref}
+
+\usepackage{tcolorbox}
+\tcbuselibrary{documentation}
+\tcbuselibrary{minted}
+\tcbuselibrary{breakable}
+
+\definecolor{DarkDefinition}{rgb}{0.392,0.392,0.942}
+
+\tcbset{
+ listing engine=minted,
+ color definition=DarkDefinition,
+ floatplacement=h,
+ index colorize=true,
+ doc head={
+ interior style={
+ fill,
+ color=blue!10,
+ },
+ boxsep=2pt,
+ after skip=0pt,
+ nobeforeafter,
+ },
+ doc raster={
+ raster after skip=0pt,
+ },
+ before doc body={
+ \begin{tcolorbox}[
+ colback=blue!5,
+ colframe=blue!5,
+ arc=0pt,
+ outer arc=0pt,
+ before skip=0pt,
+ nobeforeafter,
+ ]
+ },
+ after doc body={\end{tcolorbox}},
+}
+
+\AtBeginEnvironment{tcb@manual@entry}{%
+ \needspace{4\baselineskip}%
+}
+
+\newtcbinputlisting{\unitlisting}[2]{%
+ listing file = {../latex/non-decimal-units.#1.tex},
+ title = Listing of units loaded with the \docAuxKey{#1} option,
+ listing only,
+ breakable,
+ minted options={fontsize=\small},
+ docexample,
+}
+
+\setlist[description]{
+ leftmargin=5em,
+ rightmargin=\leftmargin,
+ itemindent=\labelwidth,
+ align=right,
+ font=\docAuxKey,
+ noitemsep,
+}
+
+\usepackage{fnpct}
+
+\usepackage{tabularray}
+\UseTblrLibrary{booktabs}
+
+\usepackage{cleveref}
+
+\RequirePackage[autolanguage]{numprint}
+
+\usepackage[
+ danish,
+]{non-decimal-units}
+
+\RequirePackage{fontspec}
+\newfontfamily\mufifont{Palemonas MUFI}
+
+\RequirePackage[
+ MUFI,
+ fonts={
+ MUFI=\mufifont,
+ },
+]{unicode-alphabets}
+
+\nduKeys{%
+ units/mark/symbol=\mufi{markflour},
+ units/skilling/symbol=\mufi{schillgerm},
+ units/penning/symbol=\mufi{20B0},
+} \ No newline at end of file
diff --git a/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.tex b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.tex
index d5490aa0215..866efed85a2 100644
--- a/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.tex
+++ b/Master/texmf-dist/doc/latex/non-decimal-units/non-decimal-units.tex
@@ -1,15 +1,19 @@
% !TEX TS-program = LuaLaTeX-shell-escape
-\documentclass{article}
+\documentclass[
+ a4paper,
+ margin=4cm
+]{article}
\usepackage{non-decimal-units.preamble}
\title{Non-Decimal Units for \LaTeX}
\author{Mikkel Eide Eriksen\\\href{mailto:mikkel.eriksen@gmail.com}{\texttt{mikkel.eriksen@gmail.com}}}
-\nduset{
+\nduKeys{
set aligned for environment=tabular,
- aliases/danish rigsdaler,
- restrict segment depth=2,
+ tabularray column type=U,
+ unit depth=skilling,
+ unit separator={~},
}
\begin{document}
@@ -18,7 +22,7 @@
\section{Preface} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-Many historical unit systems were non-decimal. For example, the Danish rigsdaler\footnote{\url{https://en.wikipedia.org/wiki/Danish_rigsdaler}} --- where 1 \nduName{danish rigsdaler}{0} consists of \nduFactor{danish rigsdaler}{1}~\nduName{danish rigsdaler}{1}, each again consisting of \nduFactor{danish rigsdaler}{2}~\nduName{danish rigsdaler}{2} for a total of 96 \nduName{danish rigsdaler}{2} per \nduName{danish rigsdaler}{0} --- was used from 1625 to 1875, when currency was decimalised to the current system of 1 krone = 100 øre.
+Many historical unit systems were non-decimal. For example, the Danish rigsdaler\footnote{\url{https://en.wikipedia.org/wiki/Danish_rigsdaler}} --- where 1 rigsdaler consists of 16~mark, each again consisting of 16~skilling for a total of 96 skilling per rigsdaler --- was used from 1625 to 1875, when currency was decimalised to the current system of 1 krone = 100 øre.
% https://en.wikipedia.org/wiki/Non-decimal_currency
@@ -30,7 +34,7 @@ This package enables creation and configuration of such units to facilitate thei
In order to do this, values are divided into \emph{segments}, which are separated by decimal points: for example, the historical Danish monetary value \nduValue{danish rigsdaler}{1.2.3} is entered as \texttt{1.2.3}, which the code then formats appropriately.
-Issues can be reported at \url{https://github.com/mikkelee/latex-units/issues} but keep in mind I am not very experienced with \LaTeX ;)
+Issues can be reported at \url{https://github.com/mikkelee/latex-units/issues}.
\clearpage
\section{Configuration} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -45,16 +49,16 @@ Where \meta{options} may contain one or more of the following unit systems. See
\begin{description}
\item[british] Currencies
-\item[danish] Currencies and areas
+\item[danish] Currencies, areas, and weights
\item[german] Currencies
\end{description}
-Alternately, one may configure new units via \refCom{nduNewUnit}.
+Alternately, one may configure new units via \refCom{nduNewBaseUnit} and \refCom{nduNewUnitGroup}.
\end{docCommand}
\begin{docCommand}
- {nduset}
+ {nduKeys}
{\marg{options}}
Can be used to set options globally (in the preamble) or locally (in a group). See further documentation for possible keys/values.
@@ -70,18 +74,18 @@ The central macro is \docAuxCommand*{nduValue}. It formats values for display an
\begin{docCommand}
{nduValue}
- {\marg{unit name}\oarg{options}\marg{value}}
+ {\marg{unit group}\oarg{options}\marg{value}}
-Formats \meta{value} according to the setup configured for the \meta{unit name}, as well as any provided \meta{options}. The number of decimal points and the values between them determine how many and which segments are displayed.
+Formats \meta{value} according to the setup configured for the \meta{unit group}, as well as any provided \meta{options}.
-Empty segments are skipped, unless the \refKey{replace nil with} key is set.
+If no special configuration is made, the number of decimal points and the values between them determine how many and which units are displayed. For example, empty values are skipped unless the \refKey{replace nil with} key is set.
\begin{dispExample*}{
title=Example usage: \docAuxCommand*{nduValue} macro
}
\nduValue{danish rigsdaler}{1.2.3}\\
-\nduValue{danish rigsdaler}{1..}\\
-\nduValue{danish rigsdaler}{.2.}\\
+\nduValue{danish rigsdaler}{1}\\
+\nduValue{danish rigsdaler}{.2}\\
\nduValue{danish rigsdaler}{..3}\\
\end{dispExample*}
\end{docCommand}
@@ -90,38 +94,56 @@ Empty segments are skipped, unless the \refKey{replace nil with} key is set.
\subsubsection{Options}
\begin{docKeys}[
- doc name = show,
+ doc name = display,
]{
{
- doc parameter = {=values},
+ doc parameter = {=values only},
},
{
- doc parameter = {=values and symbols},
- doc description = initially \texttt{values and symbols},
+ doc parameter = {=formatted},
+ doc description = initially \texttt{formatted},
},
{
- doc parameter = {=symbols},
+ doc parameter = {=symbols only},
+ },
+ {
+ doc parameter = {=numprint},
},
}
-Changes which information is included in the expansion.
+ Changes which information is included in the expansion.
-Because only those segments with a value will be included, \docAuxKey*{show}=\docValue*{symbols} can be used to list the segment units (though if only one or two is needed, it may be preferable to use \refCom{nduSymbol}).
+ Because only present values will be included, \docAuxKey*{display}=\docValue*{symbols only} can be used to list the segment units (though it may be preferable to use \refCom{nduHeader} or \refCom{nduSymbol}).
\begin{dispExample}
\nduValue{danish hartkorn}
- [show=symbols]
+ [display=symbols only]
{0.0.0.0.0}
\nduValue{danish hartkorn}
- [show=symbols]
+ [display=values only]
{0.0...}
\end{dispExample}
+
+ Finally, it is possible to use the \href{https://ctan.org/pkg/numprint}{numprint} package to format numbers, especially useful for larger values. Note that this may be counter to the formatting of some units (eg. British pounds), in which case one may prefer the \docAuxKey{use numprint} key instead.
+
+\begin{dispExample}
+\nduValue{danish rigsdaler}
+ [display=numprint]
+ {1000}
+\end{dispExample}
\end{docKeys}
-See also \cref{units:new} for further discussion on possible options.
+\begin{docKey}
+ {format}
+ {=\marg{...}}
+ {initially \docAuxCommand*{VALUE}\docAuxCommand*{nobreakspace}\docAuxCommand*{SYMBOL}}
+
+ Sets how a given base unit should be formatted for display.
+
+ The placeholders \docAuxCommand*{VALUE} and \docAuxCommand*{SYMBOL} will be substituted when the value is typeset.
+\end{docKey}
-\clearpage
\begin{docKeys}
[]
{
@@ -140,156 +162,117 @@ The key \docAuxKey*{replace nil with} replaces nil (empty) segments with a custo
The key \docAuxKey*{treat zero as nil} replaces 0 with nothing, which in turn means that setting both will replace both zero and nil with the custom string.
-These keys also apply in non-tabular contexts, but are probably most useful here.
-
-\begin{dispExample*}{
- title=Example usage: \docAuxKey*{replace nil with} key
-}
-\begingroup
-\nduset{
- treat zero as nil,
- replace nil with=---,
-}
-\begin{tabular}{r r}
- \toprule
- & \nduHeader{danish rigsdaler} \\
- \midrule
- a & \nduValue{danish rigsdaler}{1.2.3} \\
- b & \nduValue{danish rigsdaler}{100.0.0} \\
- c & \nduValue{danish rigsdaler}{.1.} \\
- \bottomrule
-\end{tabular}
-\endgroup
-\end{dispExample*}
\end{docKeys}
+\begin{docKey}
+ {unit depth}
+ {=\meta{unit name}}
+ {initially no restriction}
+
+ When calculating or displaying a value, only the segments up to and including \meta{unit name} will be considered.
+
+ In this document, the depth has been globally set to \texttt{skilling}, but older historical sub-units can be included by locally setting the depth to eg. \texttt{hvid} (or indeed not restricting it globally).
+
+ If the \meta{unit name} is not present in the current unit group, it has no effect.
+
+\begin{dispExample}
+\nduValue{danish rigsdaler}
+ [unit depth=skilling]
+ {1.2.3.4.5}
-\clearpage
-\subsection{Tabular Data} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-In order to align values in a tabular context, the \docAuxKey*{aligned} key causes \docAuxCommand{nduValue} to wrap each segment in a cell of equal width, using \docAuxCommand*{makebox}.
-
-Additionally, the \docAuxCommand*{nduHeader} macro provides a convenient header showing the unit symbols.
-
-All segments will be included in the headers and cells, whether they contain a value or not. If no value is provided for the segment, and no nil replacement is specified with the \refKey{replace nil with} key, the cell will be empty.
-
-\begin{docCommand}
- {nduHeader}
- {\marg{unit name}\oarg{options}}
- Formats the unit symbols in boxes suitable for a header. See \cpageref{units:new} for configuration of symbols.
-\end{docCommand}
-
-\clearpage
-\subsubsection{Options}
-
-\begin{docKeys}
- []
- {
- {
- doc name = aligned,
- doc description = {initially not set},
- },
- {
- doc name = set aligned for environment,
- doc description = {initially set for \texttt{tabular}},
- },
- }
+\nduValue{danish rigsdaler}
+ [unit depth=penning]
+ {1.2.3.4.5}
+\end{dispExample}
+\end{docKey}
- Setting \docAuxKey*{aligned} will format the presently displayed header in aligned boxes, desirable in tabular contexts.
+\begin{docKey}
+ {unit separator}
+ {=\meta{...}}
+ {initially \docAuxCommand*{nobreakspace}}
+
+ When displaying a value, this string will be inserted between each segment.
- Additionally, the \docAuxKey*{set aligned for environment} key can be set to an environment name, causing \docAuxKey*{aligned} to automatically be set aligned for those enviroments, using \docAuxCommand*{AtBeginEnvironment}. It can be set multiple times, once for each required environment.
+\begin{dispExample}
+\nduValue{danish hartkorn}[
+ display=values only,
+ unit separator=.
+ ]
+ {1.2.3.4}
-\begin{dispExample*}{
- title=Example usage: \docAuxCommand*{nduHeader} and \docAuxCommand*{nduValue} macros with \docAuxKey*{aligned} key.
-}
-\begingroup
-\begin{tabular}{r r}
- \toprule
- & \nduHeader{danish rigsdaler} \\
- \midrule
- a & \nduValue{danish rigsdaler}{1.2.3} \\
- b & \nduValue{danish rigsdaler}{100..} \\
- c & \nduValue{danish rigsdaler}{.1.} \\
- \bottomrule
-\end{tabular}
-\endgroup
-\end{dispExample*}
+\nduValue{danish rigsdaler}
+ [unit separator={---}]
+ {1.2.3}
+\end{dispExample}
-\end{docKeys}
+\end{docKey}
\begin{docKey}
- {cell width}
- {=\meta{length}}
- {initially \texttt{5em}}
-
-Changes the width of each segment.
+ {use numprint}
+ {}
+ {not set initially}
+
+ When displaying a value, use the \href{https://ctan.org/pkg/numprint}{numprint} package, including when using the \docAuxKey{format} key. You can of course also configure the numprint settings, either in a group or locally.
-\begin{dispExample*}{
- title=Example usage: \docAuxKey*{cell width} key
-}
+\begin{dispExample}
\begingroup
-\nduset{
- cell width=3em,
-}
-\begin{tabular}{r r}
- \toprule
- & \nduHeader{danish rigsdaler} \\
- \midrule
- a & \nduValue{danish rigsdaler}{1.2.3} \\
- b & \nduValue{danish rigsdaler}{100..} \\
- c & \nduValue{danish rigsdaler}{.1.} \\
- \bottomrule
-\end{tabular}
+\selectlanguage{ngerman}
+\nduValue{danish rigsdaler}
+ [use numprint]
+ {1000.0}
\endgroup
-\end{dispExample*}
+\end{dispExample}
+
\end{docKey}
\clearpage
-\subsection{Arithmetical Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Basic arithmetic functions can be used to build a result for display. Internally, this is done by converting the value to a representation, which is the total number of the smallest usable unit, eg. \nduValue{danish rigsdaler}{1.2.3} is 131 \nduName{danish rigsdaler}{2}.
+\section{Arithmetical Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-Results can be gathered in two ways, either manually via the \docAuxCommand*{nduMath} macro, or automatically via the \docAuxKey{add to variable} and \docAuxKey{subtract from variable} keys, the latter being especially suitable in tabular contexts.
-
-\begin{docCommands}[]{
- {
- doc name = nduMath,
- doc parameter = \marg{unit name}\oarg{options}\marg{variable}\marg{operator}\marg{value}
- },
- {
- doc name = nduResult,
- doc parameter = \marg{unit name}\oarg{options}\marg{variable}
- }
-}
+Basic arithmetic functions can be used to build a result for display. This is done by converting the value to an internal representation and storing it in a global variable. The first time a variable is used, it is assumed that the value is 0.
-The first arguments of \docAuxCommand*{nduMath} are identical to those of the \refCom{nduValue} macro. In addition, it has \meta{variable} and \meta{operator} (one of \texttt{+ - * /}) arguments. The first time a variable is used, it is assumed that the value is 0. The given value is then converted to its internal representation and stored in the variable. The command does not expand to any output.
+Results can be gathered in two ways, either manually via the \docAuxCommand*{nduMath} macro, or automatically via the \docAuxKey{add to variable} and \docAuxKey{subtract from variable} keys, the latter two being especially suitable in tabular contexts.
-Note that mixing units in the same variable is not currently supported, and will likely give incorrect results.
+\begin{docCommand}
+ {nduMath}
+ {\marg{unit name}\oarg{options}\marg{variable}\marg{operator}\marg{value}}
-The \docAuxCommand*{nduResult} macro takes a stored \meta{variable} and formats it for display in the same way as \refCom{nduValue}.
+ The first arguments of \docAuxCommand*{nduMath} are identical to those of the \refCom{nduValue} macro. In addition, it has \meta{variable} and \meta{operator} (one of \texttt{+ - * /}) arguments. The command does not expand to any output.
-Both may be further configured via the \meta{options} in the same way as the other macros.
+ Note that mixing unit groups in the same variable is not currently supported, and will likely give incorrect results.
\begin{dispExample*}{
- title=Example usage: \docAuxCommand*{nduMath} and \docAuxCommand*{nduResult} macros
+ title=Example usage: \docAuxCommand*{nduMath} macro
}
\nduMath{danish rigsdaler}{example 1}{+}{0.0.10}
\nduMath{danish rigsdaler}{example 1}{+}{..8}
\nduMath{danish rigsdaler}{example 1}{+}{0.2}
\nduMath{danish rigsdaler}{example 1}{+}{0.5.1}
-\nduResult{danish rigsdaler}{example 1} % = 1.2.3
+% there is no output, the result 1.2.3
+% will be seen in the following example.
\end{dispExample*}
+\end{docCommand}
+
+\begin{docCommand}
+ {nduResult}
+ {\marg{unit name}\oarg{options}\marg{variable}}
+
+ The \docAuxCommand*{nduResult} macro takes a stored \meta{variable} and formats it via \meta{options} for display in the same way as \refCom{nduValue}.
+
\begin{dispExample*}{
title=Example usage: \docAuxCommand*{nduResult} macro
}
-\nduHeader{danish rigsdaler}\\
-\nduResult{danish rigsdaler}[aligned]{example 1}
+\nduResult{danish rigsdaler}{example 1} % = 1.2.3
+
+And let's add an additional 15 skilling:
+\nduMath{danish rigsdaler}{example 1}{+}{0.0.15}
+\nduResult{danish rigsdaler}{example 1} % = 1.3.2
\end{dispExample*}
-\end{docCommands}
+
+\end{docCommand}
\clearpage
-\subsubsection{Options}
+\subsection{Options for Arithmetical Operations}
\begin{docKeys}
[
@@ -304,14 +287,13 @@ Both may be further configured via the \meta{options} in the same way as the oth
},
}
-Setting either of these keys will cause all uses of \docAuxCommand*{nduValue} in the current group to be added to or subtracted from the variable with the given name.
+Setting either of these keys will cause all uses of \docAuxCommand*{nduValue} in the current group to be added to or subtracted from the variable with the given name. It can of course also be set on individual invocations of the command.
\begin{dispExample*}{
title=Example usage: \docAuxKey*{add to variable} key
}
\begingroup
-\nduset{
- cell width=3em,
+\nduKeys{
replace nil with=---,
add to variable=example 2
}
@@ -321,22 +303,12 @@ Setting either of these keys will cause all uses of \docAuxCommand*{nduValue} in
\midrule
a & \nduValue{danish rigsdaler}{1.2.3} \\
b & \nduValue{danish rigsdaler}{100.1.} \\
- \bottomrule
+ \midrule
total & \nduResult{danish rigsdaler}{example 2} \\ % = 101.3.3
+ \bottomrule
\end{tabular}
\endgroup
\end{dispExample*}
-
-Results are global and remain accessible outside the group:
-\begin{dispExample}
-\nduResult{danish rigsdaler}{example 2}
-\end{dispExample}
-
-Adding an additional 15 \nduName{danish rigsdaler}{2} to the existing result gives:
-\begin{dispExample}
-\nduMath{danish rigsdaler}{example 2}{+}{0.0.15}
-\nduResult{danish rigsdaler}{example 2} % = 101.4.2
-\end{dispExample}
\end{docKeys}
\begin{docKey}
@@ -349,38 +321,151 @@ Reformats an amount, which is useful for quick conversions.
\begin{dispExample*}{
title=Example usage: \docAuxKey*{normalize} key
}
-100 \nduName{danish rigsdaler}{2} equal
+100 skilling equal
\nduValue{danish rigsdaler}[normalize]{..100} % 1.0.4
\end{dispExample*}
\end{docKey}
+\clearpage
+\section{Tabular Data} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\section{Accessing Information About Units} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+There are a couple of ways to display values in tabular context, centered around explicitly or implicitly setting the \docAuxKey{aligned} key, which causes \docAuxCommand{nduValue} to wrap each segment in a cell of configurable width.
+
+Additionally, all segments will be included in headers and cells, whether they contain a value or not (provided \docAuxKey{unit depth} allows it). If no value is provided for the segment, and no nil replacement is specified with the \refKey{replace nil with} key, the cell will be empty.
\begin{docCommand}
- {nduName}
- {\marg{unit name}\marg{segment}}
- Expands to the name of the the given segment of the unit.
-
- Set by \refKey{segment:name}.
+ {nduHeader}
+ {\marg{unit name}\oarg{options}}
+ Convenient header showing the unit symbols. See \cpageref{units:new} for configuration of symbols.
\end{docCommand}
+\subsection{Options for Tabular Data}
+
+\begin{docKey}
+ {aligned}
+ {}
+ {initially not set}
+
+Causes each value to be wrapped in right-aligned cells of configurable width.
+\end{docKey}
+
+\begin{docKey}
+ {cell widths}
+ {=\meta{length}}
+ {initially \texttt{3em}}
+
+Changes the width of each cell. One may supply a bracketed comma-separated list of widths. If the list is shorter than the number of base units in the group, the last width will be repeated. See page \pageref{example:table:widths} for example.
+\end{docKey}
+
+\begin{docKeys}
+ []
+ {
+ {
+ doc name = set aligned for environment,
+ doc parameter = {=\meta{name}},
+ doc description = {initially not set},
+ },
+ {
+ doc name = tabularray column type,
+ doc parameter = {=\meta{letter}},
+ doc description = {initially not set},
+ },
+ }
+
+ The \docAuxKey{set aligned for environment} key can be set to an environment name, causing \docAuxKey*{aligned} to automatically be set for those enviroments, using \docAuxCommand*{AtBeginEnvironment}. It can be set multiple times, once for each required environment. See page \pageref{example:table:environment} for example.
+
+ The \docAuxKey{tabularray column type} key can be used to create a column type, which automatically wraps the column contents in \docAuxCommand{nduValue}. The column type takes two arguments, a unit group and a set of key values for further configuration. Additionally, the special values \texttt{HEADER}, \texttt{RESULT}, and \texttt{SKIP} will respectively use \docAuxCommand{nduHeader}, \docAuxCommand{nduResult}, and skip the cell. See page \pageref{example:table:tabularray} for example\footnote{Thanks to Yukai Chou for help with \href{https://github.com/lvjr/tabularray}{tabularray} integration.}.
+
+\end{docKeys}
+
+\begin{dispExample*}{
+ title=Example of tabular data using \docAuxKey{set aligned for environment},
+ label=example:table:environment
+}
+\begingroup
+\nduKeys{
+% has been set in this document's preamble:
+% set aligned for environment=tabular,
+ treat zero as nil,
+ replace nil with=---,
+}
+\begin{tabular}{r r}
+ \toprule
+ & \nduHeader{danish rigsdaler} \\
+ \midrule
+ a & \nduValue{danish rigsdaler}{1.2.3} \\
+ b & \nduValue{danish rigsdaler}{100.0.0} \\
+ c & \nduValue{danish rigsdaler}{.1.} \\
+ \bottomrule
+\end{tabular}
+\endgroup
+\end{dispExample*}
+
+\begin{dispExample*}{
+ title=Example usage: \docAuxKey*{cell widths} key,
+ label=example:table:widths
+}
+\begingroup
+\nduKeys{
+ cell widths={5em, 1.5em},
+}
+\begin{tabular}{r r}
+ \toprule
+ & \nduHeader{danish rigsdaler} \\
+ \midrule
+ a & \nduValue{danish rigsdaler}{1.2.3} \\
+ b & \nduValue{danish rigsdaler}{100..} \\
+ c & \nduValue{danish rigsdaler}{.1.} \\
+ \bottomrule
+\end{tabular}
+\endgroup
+\end{dispExample*}
+
+\begin{dispExample*}{
+ title=Example of tabular data using \docAuxKey{tabularray column type},
+ label=example:table:tabularray
+}
+\begingroup
+% has been set in this document's preamble:
+% tabularray column type=U
+\begin{tblr}{
+ r
+ U{danish rigsdaler}{add to variable=table result 1}|
+ U{danish rigsdaler}{add to variable=table result 2}
+}
+ \toprule
+ & HEADER & HEADER\\
+ \midrule
+ a & 1.2.3 & ..15 \\
+ b & 100.0.0 & ..10 \\
+ c & .1. & ..2 \\
+ \midrule
+ total & RESULT & RESULT \\
+ \bottomrule
+\end{tblr}
+\endgroup
+\end{dispExample*}
+
+\clearpage
+\section{Accessing Information About Units} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
\begin{docCommand}
{nduSymbol}
- {\marg{unit name}\marg{segment}}
- Expands to the symbol of the the given segment of the unit.
+ {\marg{unit name}}
+ Expands to the symbol of the given base unit.
- Set by \refKey{segment:symbol}.
+ Set by \refKey{units:symbol}.
\end{docCommand}
\begin{docCommand}
{nduFactor}
- {\marg{unit name}\marg{segment}}
- Expands to the conversion factor of the the given segment of the unit, ie. how many of the underlying segment the given segment consists of.
+ {\marg{unit name}\marg{unit name}}
+ Expands to the conversion between two base units.
+ Set by \refKey{units:factor}.
\begin{dispExample}
-That is, 1 \nduName{danish rigsdaler}{0} consists of
-\nduFactor{danish rigsdaler}{1} \nduName{danish rigsdaler}{1}.
+That is, 1 \nduSymbol{rigsdaler} consists of
+\nduFactor{rigsdaler}{skilling} \nduSymbol{skilling}.
\end{dispExample}
\end{docCommand}
@@ -391,156 +476,66 @@ That is, 1 \nduName{danish rigsdaler}{0} consists of
If the included units are not suitable, more can be created. Pull requests are also welcome at \url{https://github.com/mikkelee/latex-units}.
\begin{docCommand}
- {nduNewUnit}
+ {nduNewBaseUnit}
{\marg{unit name}\marg{key/value pairs}}
-Units can have up to 7 segments, numbered \meta{0-6}. The left-most segment, that is, the \emph{top} or \emph{root} segment, is numbered \texttt{0}.
-
-The numeral part of the below key paths \docAuxKey*{segment 0/} can be any integer up to \texttt{6}, ie. \docAuxKey*{segment 6/}. The internal number of segments is determined by how many name keys are created.
-
-See below for available settings.
+Creates a new base unit. It must contain at least a \docAuxKey{symbol}, but a \docAuxKey{factor} is also required for the math functions (see below).
\end{docCommand}
\begin{docCommand}
- {nduNewMacro}
- {\marg{unit name}\oarg{key/value pairs}\marg{control sequence}}
+ {nduNewUnitGroup}
+ {\marg{unit name}\oarg{key/value pairs}\marg{ordered base units}\oarg{control sequence}}
- It is possible to create shortcut macros for commonly used \meta{unit name}s with optional overriding options.
+ In order for the math functions to work, every base unit in the group must have a conversion path to the right-most base unit, eg. if a unit group consists of base units \texttt{A, B, C}, there must be defined factors for \texttt{B\rightarrow C} and either \texttt{A\rightarrow C} or \texttt{A\rightarrow B}; if only the latter is configured, an attempt to calculate and cache it will be made internally.
- These macros take the same arguments as the full \refCom{nduValue} macro, except without the first argument (ie. the name of the unit).
+ It is possible to create shortcut macros for commonly used unit groups with optional overriding options. These macros take the same arguments as the full \refCom{nduValue} macro, except without the first argument (ie. the name of the unit).
+
+ Including several sub units may make the math results awkward, as the algorithm is greedy.
\begin{dispExample}
-\nduNewMacro{rigsdaler.mark.skilling}
- [unit groups/rigsdaler.mark.skilling/segment 0/symbol={R\textsuperscript{dl}}]
- {myRdl}
-\myRdl{1.2.3}
+\nduNewUnitGroup{my sletdaler}
+ [units/sletdaler/symbol={Sletd.}]
+ {sletdaler, ort, skilling}
+ [\mySldl]
+\mySldl{1.2.3}
\end{dispExample}
\end{docCommand}
-%\begin{docCommand}
-% {nduCommonSymbols}
-% {\marg{key/value pairs}}
-%
-% It is possible to configure commonly used symbols using the form \texttt{\meta{name}=\meta{symbol}}. These will be used as fallbacks if no specific symbol is configured for a segment via \refKey{segment:symbol}.
-%
-%\end{docCommand}
-%
-%\begin{docCommand}
-% {nduCommonFactors}
-% {\marg{key/value pairs}}
-%
-% Not currently implemented.
-%
-%\end{docCommand}
-
\clearpage
-\subsubsection{Options}
-
-\begin{docKey}
- {segment separator}
- {=\meta{...}}
- {initially \texttt{\~{}}}
-
- When displaying a value, this string will be inserted between each segment.
-
-\begin{dispExample}
-\nduValue{danish hartkorn}[
- show=values,
- segment separator=.
- ]
- {1.2.3.4}
-
-\nduValue{danish rigsdaler}
- [segment separator={---}]
- {1.2.3}
-\end{dispExample}
-
-\end{docKey}
-
-\begin{docKey}
- {restrict segment depth}
- {=\meta{integer}}
- {initially no restriction}
-
- When calculating or displaying a value, only the segments up to and including \meta{integer} will be considered.
-
- In this document, the depth has been globally set to \texttt{2} for \docAuxKey*{danish rigsdaler}, but the older historical sub-unit \nduName{danish rigsdaler}{3} can be included by locally setting the depth to \texttt{3} (or indeed not restricting it globally).
-
-\begin{dispExample}
-\nduValue{danish rigsdaler}
- [restrict segment depth=3]
- {1.2.3.4}
-\end{dispExample}
-\end{docKey}
-
-\begin{docKey}
- []
- [doc label=segment:name]
- {segment \meta{n}/name}
- {=\meta{name}}
- {no default, initially undefined}
-
- Gives the proper name of the segment's unit. Used internally to determine how many segments the unit contains.
-
- Can be accessed with by \refCom{nduName}.
-\end{docKey}
+\subsection{Options For Base Units}
\begin{docKey}
[]
- [doc label=segment:symbol]
- {segment \meta{n}/symbol}
+ [doc label=units:symbol]
+ {units/\meta{unit name}/symbol}
{=\meta{symbol}}
- {no default, initially undefined}
+ {}
- Configures a symbol displaying the unit. This is used in \docAuxCommand{nduHeader} and is also available via \docAuxCommand{nduSym} when defining the \refKey{segment:display} (see below).
-
- If none is configured, an attempt to look up a common symbol by its name is made. These can be configured with \refCom{nduCommonSymbols}.
+ Configures a symbol displaying the unit. This is used in \docAuxCommand{nduValue}, \docAuxCommand{nduHeader}, and is also available via \docAuxCommand*{SYMBOL} when defining the \refKey{units:format} (see also \refKey{}).
\end{docKey}
-\begin{docKeys}
- [
- doc parameter = {=\meta{...}},
- ]
- {
- {
- doc name = {segment \meta{n}/prefix},
- doc label = segment:prefix,
- doc description = {initially set to \texttt{\{\}}},
- },
- {
- doc name = {segment \meta{n}/suffix},
- doc label = segment:suffix,
- doc description = {initially set to \texttt{\{~\docAuxCommand*{nduSym}\}}},
- },
- }
-
- When displaying a value, segments will be wrapped between the \meta{prefix} and \meta{suffix}.
-
- The macro \docAuxCommand{nduSym} is available here to show the symbol configured for the segment.
-\end{docKeys}
-
\begin{docKey}
[]
- [doc label=segment:display]
- {segment \meta{n}/display}
- {=\marg{prefix}\marg{suffix}}
+ [doc label=units:format]
+ {units/\meta{unit name}/format}
+ {=\marg{...}}
{}
- Sets both \refKey{segment:prefix} and \refKey{segment:suffix} at the same time.
+ Sets how a given base unit should be formatted for display. If none is given, the general top-level \docAuxKey{format} key is used.
\end{docKey}
\begin{docKey}
[]
- [doc label=segment:factor]
- {segment \meta{n}/factor}
- {=\meta{integer}}
- {no default, initially undefined}
+ [doc label=units:factor]
+ {units/\meta{unit name}/factor}
+ {=\meta{integer} \meta{unit name}}
+ {}
- The conversion factor of a segment is how many of the underlying segment the given segment consists of.
+ The conversion factor of a unit is how many of an underlying unit the given unit consists of. This can be specified multiple times.
- This is used in the math macros, in order to calculate the correct segment values.
+ This is used by the math macros and keys to calculate the sums and products.
Can be accessed via \refCom{nduFactor}.
\end{docKey}
@@ -549,39 +544,22 @@ These keys can of course also be set temporarily in \refCom{nduValue}
\begin{dispExample}
\nduValue{danish rigsdaler}
- [segment 1/symbol=Mk.]
+ [units/mark/symbol=Mk.]
{.9.}
\nduValue{danish rigsdaler}
- [segment 0/display={}{~Rigsdaler og}]
+ [units/rigsdaler/format={\VALUE~Rigsdaler og}]
{1.2.3}
\nduValue{danish rigsdaler}[
- segment separator={---},
- segment 0/display={(}{)},
- segment 1/display={[}{]},
- segment 2/display={\{}{\}},
+ unit separator={---},
+ units/rigsdaler/format={(\VALUE)},
+ units/mark/format={[\VALUE]},
+ units/skilling/format={\{\VALUE\}},
]
{1.2.3}
\end{dispExample}
-\begin{docKey}
- {create macro named}
- {=\meta{control sequence}}
- {no default, initially empty}
-
- Units may provide a default shortcut macro, for example the \docValue*{danish rigsdaler} unit configures \docAuxCommand*{rdl}.
-
- This is done via \refCom{nduNewMacro} which describes the arguments of the resulting macros.
-
-\begin{dispExample*}{
- sidebyside,
- righthand width=1.75cm,
-}
-\rdl{2.3.}
-\end{dispExample*}
-\end{docKey}
-
\clearpage
\section{Included Units} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.british.tex b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.british.tex
index 28c849f641d..968742b8f99 100644
--- a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.british.tex
+++ b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.british.tex
@@ -2,26 +2,27 @@
% https://en.wikipedia.org/wiki/£sd
-\nduBaseUnits{%
- pound sterling={%
- symbol=£,
- display={\nduSym}{},
- },
- shilling={%
- symbol=s,
- factor=20 per pound sterling,
- display={}{\nduSym},
- },
- penny={%
- symbol=d,
- factor=12 per shilling,
- display={}{\nduSym},
- },
+\nduNewBaseUnit { pound~sterling } {
+ symbol = { £ } ,
+ factor = { 20~shilling } ,
+ format = { \SYMBOL\VALUE } ,
}
-\nduAliases{%
- british pound sterling lsd={%
- units=pound sterling.shilling.penny,
- segment separator={. },
- },
+\nduNewBaseUnit { shilling } {
+ symbol = { s } ,
+ factor = { 12~penny } ,
+ format = { \VALUE\SYMBOL } ,
+}
+
+\nduNewBaseUnit { penny } {
+ symbol = { d } ,
+ format = { \VALUE\SYMBOL } ,
+}
+
+\nduNewUnitGroup { british~pound~sterling~lsd } [
+ unit~separator = {.~} ,
+] {
+ pound~sterling ,
+ shilling ,
+ penny
}
diff --git a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.danish.tex b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.danish.tex
index 0ac75c3587c..a57fd8d4023 100644
--- a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.danish.tex
+++ b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.danish.tex
@@ -1,122 +1,128 @@
%%% CURRENCY %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\nduBaseUnits{%
- rigsbankdaler={%
- symbol=Rbd.,
- },
- rigsdaler={%
- symbol=Rdl.,
- },
- sletdaler={%
- symbol=Sldl.,
- },
- speciedaler={%
- symbol=Spdl.,
- },
- ort={symbol=Ort,factor=4 per rigsdaler},
- mark={%
- symbol=Mk.,
- factor=6 per rigsdaler,
- factor=4 per sletdaler,
- },
- skilling={%
- symbol=Sk.,
- factor=16 per mark,
- factor=24 per ort,
- factor=84 per speciedaler,
- factor=96 per rigsbankdaler,
- },
- hvid={%
- symbol=Hvid,
- factor=3 per skilling,
- },
- penning={%
- symbol=Pg.,
- factor=4 per hvid,
- factor=12 per skilling,
- },
-}
-
-\nduAliases{%
- danish rigsbankdaler={%
- units=rigsbankdaler.skilling,
- macro={rbd}{%
- normalize,
- treat zero as nil
- },
- },
- danish rigsdaler={%
- units=rigsdaler.mark.skilling.penning,
- macro={rdl}{%
- normalize,
- treat zero as nil
- },
- },
- danish sletdaler={%
- units=sletdaler.mark.skilling.penning,
- macro={sldl}{%
- normalize,
- treat zero as nil
- },
- },
+\nduNewBaseUnit { rigsdaler } {
+ symbol = { Rdl. } ,
+ factor = { 6~mark } ,
}
+\nduNewBaseUnit { rigsbankdaler } {
+ symbol = { Rbdl. } ,
+ symbol = { 96~skilling } ,
+}
+
+\nduNewBaseUnit { rigsdaler specie } {
+ symbol = { Rds. } ,
+ symbol = { 192~skilling } ,
+}
+
+\nduNewBaseUnit { speciedaler } {
+ symbol = { Spdl. } ,
+ factor = { 84~skilling } ,
+}
+
+\nduNewBaseUnit { sletdaler } {
+ symbol = { Sldl. } ,
+ factor = { 4~mark } ,
+}
+
+\nduNewBaseUnit { ort } {
+ symbol = { O. } ,
+ factor = { 24~skilling } ,
+}
+
+\nduNewBaseUnit { mark } {
+ symbol = { Mk. } ,
+ factor = { 16~skilling } ,
+}
+
+\nduNewBaseUnit { skilling } {
+ symbol = { Sk. } ,
+ factor = { 3~hvid } ,
+}
+
+\nduNewBaseUnit { hvid } {
+ symbol = { Hv. } ,
+ factor = { 4~penning } ,
+}
+
+\nduNewBaseUnit { penning } {
+ symbol = { P. } ,
+}
+
+\nduNewUnitGroup { danish~rigsdaler } {
+ rigsdaler ,
+ mark ,
+ skilling ,
+ hvid ,
+ penning
+}[\rdl]
+
+\nduNewUnitGroup { danish~sletdaler } {
+ sletdaler ,
+ mark ,
+ skilling ,
+ hvid ,
+ penning
+}[\sldl]
+
+\nduNewUnitGroup { danish~rigsbankdaler } {
+ rigsbankdaler ,
+ skilling
+}[\rbdl]
+
+\nduNewUnitGroup { danish~speciedaler } {
+ speciedaler ,
+ skilling
+}[\spdl]
%%%% AREA %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\nduBaseUnits{%
- tønde={%
- symbol=Td.,
- },
- skæppe={%
- symbol=Skp.,
- factor=8 per tønde,
- },
- fjerdingkar={%
- symbol=Fjk.,
- factor=4 per skæppe,
- },
- album={%
- symbol=Alb.,
- factor=3 per fjerdingkar,
- },
- penning/factor=4 per album, % penning symbols defined under currency
-}
-
-\nduAliases{%
- danish hartkorn={%
- units=tønde.skæppe.fjerdingkar.album.penning,
- macro={hartkorn}{%
- normalize,
- treat zero as nil
- },
- },
+\nduNewBaseUnit { tønde } {
+ symbol = { Td. } ,
+ factor = { 8~skæppe } ,
+}
+
+\nduNewBaseUnit { skæppe } {
+ symbol = { Sk. } ,
+ factor = { 4~fjerdingkar } ,
+}
+
+\nduNewBaseUnit { fjerdingkar } {
+ symbol = { Fj. } ,
+ factor = { 3~album } ,
+}
+
+\nduNewBaseUnit { album } {
+ symbol = { Alb. } ,
+ factor = { 4~penning } ,
}
+\nduNewUnitGroup { danish~hartkorn } {
+ tønde,
+ skæppe,
+ fjerdingkar,
+ album,
+ penning
+}[\hartkorn]
%%%% WEIGHT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\nduBaseUnits{%
- skippund={%
- symbol=Spd.,
- },
- lispund={%
- symbol=Lpd.,
- factor=20 per skippund,
- },
- skaalpund={%
- symbol=Pd.,
- factor=16 per lispund,
- },
-}
-
-\nduAliases{%
- danish pund={%
- units=skippund.lispund.skaalpund,
- macro={pund}{%
- normalize,
- treat zero as nil
- },
- },
+\nduNewBaseUnit { skippund } {
+ symbol = { Spd. } ,
+ factor = { 20~lispund } ,
+}
+
+\nduNewBaseUnit { lispund } {
+ symbol = { Lpd. } ,
+ factor = { 16~skålpund } ,
+}
+
+\nduNewBaseUnit { skålpund } {
+ symbol = { Pd. } ,
}
+\nduNewUnitGroup { danish~pund } {
+ skippund,
+ lispund,
+ skålpund
+}
diff --git a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.german.tex b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.german.tex
index 912ee0d4280..cde4d7e8737 100644
--- a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.german.tex
+++ b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.german.tex
@@ -1,21 +1,21 @@
%%% CURRENCY %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\nduBaseUnits{%
- reichsthaler={%
- symbol=Rthl., % \mufi{reichtalold}
- },
- groschen={%
- symbol=Gr., % \mufi{grosch}
- factor=30 per reichsthaler,
- },
- pfennig={%
- symbol=Pf., % \mufi{20B0}
- factor=12 per groschen,
- },
+\nduNewBaseUnit { reichsthaler } {
+ symbol = { Rthl. } ,
+ factor = { 30~groschen } ,
}
-\nduAliases{%
- german reichsthaler={%
- units=reichsthaler.groschen.pfennig,
- },
+\nduNewBaseUnit { groschen } {
+ symbol = { Gr. } ,
+ factor = { 12~pfennig } ,
}
+
+\nduNewBaseUnit { pfennig } {
+ symbol = { Pf. } ,
+}
+
+\nduNewUnitGroup { german~reichsthaler } {
+ reichsthaler ,
+ groschen ,
+ pfennig
+} \ No newline at end of file
diff --git a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.sty b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.sty
index 0444991aee4..5358a0acdb7 100644
--- a/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.sty
+++ b/Master/texmf-dist/tex/latex/non-decimal-units/non-decimal-units.sty
@@ -1,598 +1,798 @@
-\ProvidesPackage{non-decimal-units}[2023/09/27 Macros for displaying and manipulating historical non-decimal units]
+\RequirePackage{expl3}
+\ProvidesExplPackage{non-decimal-units}{2023/10/10}{1.0}{Macros for displaying and manipulating historical non-decimal units}
% License: CC-BY-SA 4.0
% Author: Mikkel Eide Eriksen <mikkel.eriksen@gmail.com>
-\RequirePackage{pgfkeys}
-\RequirePackage{pgfopts}
-\RequirePackage{bigintcalc}
-
-\RequirePackage{etoolbox}
-\RequirePackage{ifthen}
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\pgfkeys{/handlers/.store in cs/.code=\pgfkeysalso{%
- \pgfkeyscurrentpath/.code=\csdef{#1}{##1}}%
-}
-
-\def\nduset{\pgfqkeys{/ndu}}
-
-\newif\ifndushowvalues
-\newif\ifndushowaffixes
-\newif\ifndutreatzeroasnil
-\newif\ifndualigned
-\ndushowvaluestrue
-\ndushowaffixestrue
-\newif\ifndunormalize
-
-\newcounter{autorepr}
-
-\gdef\ndu@nextdelim{}%
-\gdef\ndu@delim{}%
-
-\nduset{%
- base units/.is family,
- base units/.unknown/.code={%
- \expandafter\nduBuildBaseUnitKeys\expandafter{\pgfkeyscurrentname}{#1}%
- },
- unit groups/.is family,
- unit groups/.unknown/.code={%
- \expandafter\nduBuildUnitGroupKeys\expandafter{\pgfkeyscurrentname}%
- },
- aliases/.is family,
- aliases/.unknown/.code={%
- \expandafter\nduBuildAliasKeys\expandafter{\pgfkeyscurrentname}{#1}%
- },
- show/.is choice,
- show/values/.code={\ndushowvaluestrue\ndushowaffixesfalse},
- show/values and symbols/.code={\ndushowvaluestrue\ndushowaffixestrue},
- show/symbols/.code={\ndushowvaluesfalse\ndushowaffixestrue},
- show=values and symbols,
- cell width/.initial=5em,
- add to variable/.code={%
- \csdef{ndu@current@variable}{#1}%
- \csdef{ndu@current@operator}{+}%
- },
- subtract from variable/.code={%
- \csdef{ndu@current@variable}{#1}%
- \csdef{ndu@current@operator}{-}%
- },
- replace nil with/.store in cs=ndu@nil@replacement,
- treat zero as nil/.is if=ndutreatzeroasnil,
- treat zero as nil=false,
- normalize/.is if=ndunormalize,
- normalize=false,
- segment separator/.initial={~},
- aligned/.is if=ndualigned,
- aligned=false,
- set aligned for environment/.code={%
- \AtBeginEnvironment{#1}{\nduset{aligned}}%
- },
-}
-
-\newcommand\nduBuildBaseUnitKeys[2]{%
- \nduset{%
- base units/#1/.is family,base units/#1,
- symbol/.initial={#1},
- factor/.style args={##1 per ##2}{%
- /ndu/base units/##2/factors/#1/.initial=##1,
- },
- prefix/.initial={},
- suffix/.initial={~\nduSym},
- display/.style 2 args={%
- prefix={##1},
- suffix={##2},
- },
- #2,
- }%
-}
-
-\newcommand\nduBaseUnits[1]{%
- \nduset{%
- base units,#1,
- }%
-}
-
-\newcommand\nduBuildUnitGroupKeys[1]{% called by .unknown handler
- \nduset{%
- unit groups/#1/.search also={/ndu},
- unit groups/#1/.is family,unit groups/#1,
- segment separator/.link=/ndu/segment separator,
- segment depth/.initial=-1,
- update segment depth/.code={%
- \ifnum##1>\pgfkeysvalueof{/ndu/unit groups/#1/segment depth}%
- \nduset{%
- unit groups/#1/segment depth=##1,
- }%
- \fi%
- },
- restrict segment depth/.link=/ndu/unit groups/#1/segment depth,
- }%
- \nduBuildSegments{#1}{#1}%
-}
-
-\newcommand\nduUnitGroups[1]{%
- \nduset{%
- unit groups,#1,
- }%
-}
-
-\newcommand\nduBuildAliasKeys[2]{% called by .unknown handler
- \nduset{%
- aliases/#1/.is family,aliases/#1,
- units/.code={%
- % create unit group and set search path
- \pgfkeys{%
- /ndu/unit groups/##1,
- /ndu/aliases/#1/.search also={/ndu/unit groups/##1},
- /ndu/aliases/#1/unit group/.initial=##1,
- }%
- },
- macro/.code 2 args={%
- \nduNewMacro{#1}[##2]{##1}%
- },
- #2,
- }%
-}
-
-\newcommand\nduAliases[1]{%
- \nduset{%
- aliases,#1,
- }%
-}
-
-\NewDocumentCommand\nduBuildSegments{ m > { \SplitArgument { 6 } { . } } m }{%
- \nduBuildSegments@internal{#1}#2%
-}
-
-\newcommand\nduBuildSegments@internal[8]{%
- \nduNewUnit@segment{#1}{0}{#2}{#1}%
- \nduNewUnit@segment{#1}{1}{#3}{#2}%
- \nduNewUnit@segment{#1}{2}{#4}{#3}%
- \nduNewUnit@segment{#1}{3}{#5}{#4}%
- \nduNewUnit@segment{#1}{4}{#6}{#5}%
- \nduNewUnit@segment{#1}{5}{#7}{#6}%
- \nduNewUnit@segment{#1}{6}{#8}{#7}%
-}
-
-\newcommand\nduNewUnit@segment[4]{%
- \IfValueT{#3}{%
- \nduset{
- unit groups/#1/segment #2/.is family,unit groups/#1/segment #2,
- name/.initial=#3,
- symbol/.link=/ndu/base units/#3/symbol,
- prefix/.link=/ndu/base units/#3/prefix,
- suffix/.link=/ndu/base units/#3/suffix,
- display/.style 2 args={%
- segment #2/prefix={##1}, % why is the segment needed here ???
- segment #2/suffix={##2},
- },
- factor/.link=/ndu/base units/#4/factors/#3,
- }%
- \nduset{%
- unit groups/#1/update segment depth=#2,
- }%
- }%
-}
-
-\NewDocumentCommand\nduNewMacro{ m O{} m }{%
- \expandafter\NewDocumentCommand\csname#3\endcsname { O{} m } {%
- \begingroup%
- \nduset{unit groups/#1,#2}%
- \nduValue{#1}[##1]{##2}%
- \endgroup%
- }%
+% Key setup
+%
+
+\keys_define:nn { non-decimal-units }
+{
+ % nil/zero
+ replace~nil~with .tl_set:N = \l_ndu_replace_nil_with_tl ,
+ treat~zero~as~nil .bool_set:N = \l_ndu_treat_zero_as_nil_bool ,
+ treat~zero~as~nil .default:n = true ,
+
+ % formatting
+ unit~separator .tl_set:N = \l_ndu_unit_separator_tl ,
+ unit~separator .default:n = { \nobreakspace } ,
+ default~format .tl_set:N = \l_ndu_default_format_tl ,
+ default~format .default:n = { \VALUE\nobreakspace\SYMBOL } ,
+ display .choice: ,
+ display .choices:nn =
+ { values~only, symbols~only, formatted, numprint }
+ { \tl_set_eq:NN \l_ndu_display_choice_tl \l_keys_choice_tl } ,
+ display .default:n = { formatted } ,
+ unit~depth .tl_set:N = \l_ndu_unit_depth_tl ,
+ use~numprint .bool_set:N = \l_ndu_use_numprint_bool ,
+ use~numprint .default:n = true ,
+
+ % tabular alignment
+ aligned .bool_set:N = \l_ndu_aligned_bool ,
+ aligned .default:n = true ,
+ cell~widths .code:n = {
+ \seq_set_from_clist:Nn \l_ndu_cell_widths_seq {#1}
+ } ,
+ cell~widths .default:n = 3em ,
+
+ % math
+ normalize .bool_set:N = \l_ndu_normalize_bool ,
+ normalize .default:n = true ,
+ current~variable .tl_set:N = \l_ndu_current_variable_tl ,
+ current~operator .tl_set:N = \l_ndu_current_operator_tl ,
+ add~to~variable .meta:n = {
+ current~variable = {#1} ,
+ current~operator = {+}
+ } ,
+ subtract~from~variable .meta:n = {
+ current~variable = {#1} ,
+ current~operator = {-}
+ } ,
+
+ % environments
+ set~aligned~for~environment .code = {
+ \AtBeginEnvironment{#1}{\nduKeys{aligned}}
+ } ,
+}
+
+\NewDocumentCommand { \nduKeys } { m } {
+ \keys_set:nn { non-decimal-units } { #1 }
+}
+
+% set some defaults
+\keys_set:nn { non-decimal-units } {
+ unit~separator,
+ default~format,
+ display,
+ cell~widths,
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Errors
+%
-\newcommand\nduName[2]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/name}{%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/name}%
- }{%
- \PackageError{non-decimal-units}{No name defined for "\nduAliasOrGroup{#1}" segment #2}{}%
- \nduNameMissing%
- }%
-}
-
-\newcommand\nduSymbol[2]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/symbol}{%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/symbol}%
- }{%
- \PackageError{non-decimal-units}{No symbol defined for "\nduAliasOrGroup{#1}" segment #2 (\nduName{#1}{#2})}{}%
- \nduSymbolMissing%
- }%
-}
-
-\newcommand\nduPrefix[2]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/prefix}{%
- \gdef\nduSym{\nduSymbol{\nduAliasOrGroup{#1}}{#2}}%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/prefix}%
- }{%
- \PackageError{non-decimal-units}{No prefix defined for "\nduAliasOrGroup{#1}" segment #2 (\nduName{#1}{#2})}{}%
- \nduPrefixMissing%
- }%
-}
-
-\newcommand\nduSuffix[2]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/suffix}{%
- \gdef\nduSym{\nduSymbol{\nduAliasOrGroup{#1}}{#2}}%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/suffix}%
- }{%
- \PackageError{non-decimal-units}{No suffix defined for "\nduAliasOrGroup{#1}" segment #2 (\nduName{#1}{#2})}{}%
- \nduSuffixMissing%
- }%
-}
-
-\newcommand\nduFactor[2]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/factor}{%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment #2/factor}%
- }{%
- % Having a PackageError here breaks bigintcalc.
- \nduFactorMissing@#1@#2%
- }%
-}
-
-\newcommand\ifnduFactorDefined[4]{%
- \pgfkeysifdefined{/ndu/base units/\nduName{#1}{\the\numexpr#2-1\relax}/factors/\nduName{#1}{#2}}{%
- #3%
- }{%
- #4%
- }%
-}
-
-\newcommand\nduNamedFactor[2]{%
- \pgfkeysifdefined{/ndu/base units/\nduAliasOrGroup{#1}/factors/#2}{%
- \pgfkeysvalueof{/ndu/base units/\nduAliasOrGroup{#1}/factors/#2}%
- }{%
- % Having a PackageError here breaks bigintcalc.
- \nduFactorMissing@#1@#2%
- }%
-}
-
-\newcommand\nduSegmentDepth[1]{%
- \pgfkeysifdefined{/ndu/unit groups/\nduAliasOrGroup{#1}/restrict segment depth}{%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/restrict segment depth}%
- }{%
- \pgfkeysvalueof{/ndu/unit groups/\nduAliasOrGroup{#1}/segment depth}%
- }%
-}
-
-\newcommand\nduAliasOrGroup[1]{%
- \pgfkeysifdefined{/ndu/aliases/#1/unit group}{%
- \pgfkeysvalueof{/ndu/aliases/#1/unit group}%
- }{%
- #1%
- }%
-}
+\msg_new:nnnn
+{ non-decimal-units } { missing-base-unit }
+{ No ~ base ~ unit ~ exists ~ named ~ #1 }
+{ You ~ will ~ need ~ to ~ add ~ it ~ with ~ nduNewBaseUnit. }
+%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\msg_new:nnnn
+{ non-decimal-units } { missing-unit-group }
+{ No ~ unit ~ group ~ exists ~ named ~ #1 }
+{ You ~ will ~ need ~ to ~ add ~ it ~ with ~ nduNewUnitGroup. }
-\newcommand\ndu@if@depth@at@least[3]{%
- \ifnum#2>\nduSegmentDepth{#1}%
- \relax%
- \else%
- #3%
- \fi%
-}
-
-\newcommand\ndu@nil@helper[4]{%
- \IfValueTF{#1}{%
- \ifblank{#1}{%
- \ifcsvoid{ndu@nil@replacement}{}{#2\ndu@nil@replacement{}#4}%
- }{%
- \ifndutreatzeroasnil%
- \expandafter\ifnum#1=0
- \ifcsvoid{ndu@nil@replacement}{}{#2\csuse{ndu@nil@replacement}#4}%
- \else%
- #2#3#4%
- \fi%
- \else%
- #2#3#4%
- \fi%
- }%
- }{%
- \ifcsvoid{ndu@nil@replacement}{}{#2\csuse{ndu@nil@replacement}#4}%
- }%
-}
+\msg_new:nnnn
+{ non-decimal-units } { missing-factor }
+{ No ~ conversion ~ factor ~ exists ~ between ~ #1 ~ and ~ #2 }
+{ You ~ will ~ need ~ to ~ add ~ it ~ when ~ creating ~ the ~ base ~ unit ~ or ~ via ~ nduKeys. }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\NewDocumentCommand\nduValue{ m O{} m }{%
- \nduValue@unitgroup{\nduAliasOrGroup{#1}}[#2]{#3}%
-}
-
-\NewDocumentCommand\nduValue@unitgroup{ m O{} m }{%
- % #1 = unit group
- % #2 = options
- % #3 = values joined by .
- \nduset{unit groups/#1}%
- \begingroup%
- \nduset{unit groups/#1,#2}%
- \ifndualigned%
- \nduAlignedValue@entry{#1}{#3}%
- \else%
- \nduFormatValue@entry{#1}{#3}%
- \fi%
- \endgroup%
- \ifcsvoid{ndu@current@variable}{}{%
- \nduMath{#1}{\ndu@current@variable}{\ndu@current@operator}{#3}%
- }%
+% Unit setup
+%
+
+\NewDocumentCommand { \nduNewBaseUnit } { m m } {
+ \prop_clear_new:c { l_ndu_factors_#1_prop }
+ \keys_define:nn { non-decimal-units / units / #1 } {
+ factor .code = {
+ \regex_extract_once:nnN { (\d+)\ (\D+) } { ##1 } \l_tmpa_seq
+ \prop_put:cxx { l_ndu_factors_#1_prop } { \seq_item:Nn \l_tmpa_seq 3 } { \seq_item:Nn \l_tmpa_seq 2 }
+ } ,
+ symbol .tl_set:c = { l_ndu_symbol_#1_tl } ,
+ format .tl_set:c = { l_ndu_format_#1_tl } ,
+ }
+ \keys_set:nn { non-decimal-units / units / #1 } { #2 }
+}
+
+\NewDocumentCommand { \nduNewUnitGroup } { m o m o }
+{
+ \seq_set_from_clist:cn { l_ndu_group_#1_seq } {#3}
+
+ % set base unit to rightmost item
+ \seq_get_right:cN { l_ndu_group_#1_seq } \l_tmpa_tl
+ \tl_set_eq:cN { l_ndu_base_unit_#1_tl } \l_tmpa_tl
+
+ % store keys for unit group
+ \tl_clear_new:c { l_ndu_options_#1_tl }
+ \IfValueT {#2} {
+ \tl_set:cn { l_ndu_options_#1_tl } {#2}
+ }
+
+ % optionally create macro
+ \IfValueT {#4} {
+ \NewDocumentCommand { #4 } { O{} m } {
+ \group_begin:
+ \IfValueTF {#2} {
+ \nduValue{#1}[#2,##1]{##2}
+ }
+ {
+ \nduValue{#1}[##1]{##2}
+ }
+ \group_end:
+ }
+ }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\newcommand\nduFormatSegment[3]{%
- % #1 = unit group
- % #2 = segment
- % #3 = value
- %\csshow{nduSym}%
- \ndu@nil@helper{#3}{%
- \ndu@delim%
- \ifndushowaffixes\nduPrefix{#1}{#2}\fi%
- \edef\ndu@delim{\ndu@nextdelim}%
- }{%
- \ifndushowvalues#3\fi%
- }{%
- \ifndushowaffixes\nduSuffix{#1}{#2}\fi%
- }%
-}
-
-\newcommand\nduFormatValue@helper[3]{%
- \ndu@if@depth@at@least{#1}{#2}{%
- \nduFormatSegment{#1}{#2}{#3}%
- }%
-}
-
-\newcommand\nduFormatValue@internal[8]{%
- % #1 = unit group
- % #2-8 = values
- \edef\ndu@nextdelim{\pgfkeysvalueof{/ndu/unit groups/#1/segment separator}}%
- \edef\ndu@delim{}%
- \nduFormatValue@helper{#1}{0}{#2}%
- \nduFormatValue@helper{#1}{1}{#3}%
- \nduFormatValue@helper{#1}{2}{#4}%
- \nduFormatValue@helper{#1}{3}{#5}%
- \nduFormatValue@helper{#1}{4}{#6}%
- \nduFormatValue@helper{#1}{5}{#7}%
- \nduFormatValue@helper{#1}{6}{#8}%
-}
-
-\NewDocumentCommand\nduFormatValue@entry{ m > { \SplitArgument { 6 } { . } } m }{%
- % #1 = unit group
- % #2 = values joined by .
- \ifndunormalize%
- \stepcounter{autorepr}%
- \nduConvertToRepr@internal{#1}{autorepr\arabic{autorepr}}#2%
- \nduResult{#1}{autorepr\arabic{autorepr}}%
- \else%
- \nduFormatValue@internal{#1}#2%
- \fi%
+% Conversion factor initialization and access
+%
+
+\cs_new_protected:Nn \ndu_get_factor:Nnn
+{
+ % parameters
+ % #1: output result (int)
+ % #2: from unit (tl)
+ % #3: to unit (tl)
+ \tl_if_exist:cF { l_ndu_factors_#2_prop }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-base-unit } { #2 }
+ }
+ \tl_if_exist:cF { l_ndu_factors_#3_prop }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-base-unit } { #3 }
+ }
+ \str_if_eq:nnTF {#2} {#3}
+ {
+ \int_set:Nn #1 { 1 }
+ }
+ {
+ \prop_if_in:cnTF { l_ndu_factors_#2_prop } { #3 }
+ {
+ \prop_get:cnN { l_ndu_factors_#2_prop } { #3 } \l_tmpa_tl
+ \int_set:Nn #1 { \l_tmpa_tl }
+ }{
+ \int_zero_new:N \l__ndu_factor_product_int
+ \prop_map_inline:cn { l_ndu_factors_#2_prop } {
+ \str_if_eq:nnF {#3} {##1}
+ {
+ \int_zero_new:N \l__ndu_sub_factor_int
+ \ndu_get_factor:Nnn \l__ndu_sub_factor_int { ##1 } { #3 }
+ \int_set:Nn \l__ndu_factor_product_int { ##2 * \l__ndu_sub_factor_int }
+ \int_set:Nn #1 { \l__ndu_factor_product_int }
+ \prop_put:cnx { l_ndu_factors_#2_prop } { #3 } { \int_use:N \l__ndu_factor_product_int }
+ }
+ }
+ }
+ }
+}
+\cs_generate_variant:Nn \ndu_get_factor:Nnn {
+ NnV,
+ NVV
+}
+
+% ndu_super_factors (call from nduNewUnitGroup)
+
+\NewDocumentCommand \nduFactor { m m } {
+ \ndu_get_factor:Nnn \l_tmpa_int { #1 } { #2 }
+ \int_use:N \l_tmpa_int
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\newcommand*{\ndu@minwidthbox}[2]{%
- \makebox[{\ifdim#1<\width\width\else#1\fi}][r]{%
- #2%
- }%
-}
-
-\newcommand\nduAlignedHeader@helper[2]{%
- \ndu@if@depth@at@least{#1}{#2}{\ndu@minwidthbox{\pgfkeysvalueof{/ndu/cell width}}{%
- \nduSymbol{#1}{#2}%
- }}%
+% Converting from/to representation
+%
+
+\cs_new_protected:Nn \ndu_repr_to_seq:NNNNN
+{
+ % parameters
+ % #1: output result (seq)
+ % #2: unit group (seq)
+ % #3: base unit (tl)
+ % #4: value (int)
+ % #5: unit (tl)
+ \seq_clear:N #1
+
+ \int_zero_new:N \l__ndu_remainder_int
+
+ % initial value * base factor
+ \ndu_get_factor:NVV \l_tmpa_int { #5 } { #3 }
+ \int_set:Nn \l__ndu_remainder_int { #4 * \l_tmpa_int }
+
+ % for unit in units:
+ \seq_map_inline:Nn #2
+ {
+ \int_zero_new:N \l__ndu_factor_int
+ \int_zero_new:N \l__ndu_sum_int
+
+ \ndu_get_factor:NnV \l__ndu_factor_int { ##1 } { #3 }
+
+ % while (remainder >= factor_to_base):
+ \int_while_do:nn {\l__ndu_remainder_int >= \l__ndu_factor_int} {
+ % remainder -= factor_to_base
+ \int_sub:Nn \l__ndu_remainder_int \l__ndu_factor_int
+ % result[i] += 1
+ \int_incr:N \l__ndu_sum_int
+ }
+ \seq_put_right:Nx #1 {\int_use:N \l__ndu_sum_int}
+
+ % stop when we hit the desired unit depth
+ \str_if_eq:NNT {##1} {#5} {
+ \seq_map_break:
+ }
+ }
+}
+\cs_generate_variant:Nn \ndu_repr_to_seq:NNNNN {
+ NccNc,
+ Ncccc
+}
+
+\cs_new_protected:Nn \ndu_repr_to_seq:NnN
+{
+ % parameters
+ % #1: output result (int)
+ % #2: unit group name (tl)
+ % #3: value (int)
+ \ndu_repr_to_seq:NccNc
+ #1
+ { l_ndu_group_#2_seq }
+ { l_ndu_base_unit_#2_tl }
+ #3
+ { l_ndu_base_unit_#2_tl }
+
+}
+\cs_generate_variant:Nn \ndu_repr_to_seq:NnN {
+ Nnc
+}
+
+
+\cs_new_protected:Nn \ndu_seq_to_repr:NNNN
+{
+ % parameters
+ % #1: output result (int)
+ % #2: unit group (seq)
+ % #3: base unit (tl)
+ % #4: input (seq)
+ \int_zero:N #1
+
+ \seq_map_indexed_inline:Nn #2
+ {
+ \tl_set:Nx \l__ndu_value_tl { \seq_item:Nn #4 {##1} }
+ \tl_if_blank:VF \l__ndu_value_tl {
+ \ndu_get_factor:NnV \l_tmpa_int { ##2 } { #3 }
+ \int_add:Nn #1 { \l__ndu_value_tl * \l_tmpa_int }
+ }
+ }
+}
+\cs_generate_variant:Nn \ndu_seq_to_repr:NNNN {
+ NccN
+}
+
+\cs_new_protected:Nn \ndu_seq_to_repr:NnN
+{
+ % parameters
+ % #1: output result (seq)
+ % #2: unit group name (tl)
+ % #3: values (seq)
+ \ndu_seq_to_repr:NccN
+ #1
+ { l_ndu_group_#2_seq }
+ { l_ndu_base_unit_#2_tl }
+ #3
+}
+\cs_generate_variant:Nn \ndu_seq_to_repr:NnN {
+ Nnc
}
-\newcommand\nduAlignedValue@helper[3]{%
- \ndu@if@depth@at@least{#1}{#2}{\ndu@minwidthbox{\pgfkeysvalueof{/ndu/cell width}}{\nduFormatSegment{#1}{#2}{#3}}}%
-}
-
-\newcommand\nduAlignedValue@internal[8]{%
- % #1 = unit group
- % #2-8 = values
- \nduAlignedValue@helper{#1}{0}{#2}%
- \nduAlignedValue@helper{#1}{1}{#3}%
- \nduAlignedValue@helper{#1}{2}{#4}%
- \nduAlignedValue@helper{#1}{3}{#5}%
- \nduAlignedValue@helper{#1}{4}{#6}%
- \nduAlignedValue@helper{#1}{5}{#7}%
- \nduAlignedValue@helper{#1}{6}{#8}%
-}
-
-\NewDocumentCommand\nduHeader{ m O{} }{%
- \nduHeader@unitgroup{\nduAliasOrGroup{#1}}[#2]%
-}
-
-\NewDocumentCommand\nduHeader@unitgroup{ m O{} }{%
- \nduset{unit groups/#1}%
- \begingroup%
- \nduset{unit groups/#1,#2}%
- \nduAlignedHeader@helper{#1}{0}%
- \nduAlignedHeader@helper{#1}{1}%
- \nduAlignedHeader@helper{#1}{2}%
- \nduAlignedHeader@helper{#1}{3}%
- \nduAlignedHeader@helper{#1}{4}%
- \nduAlignedHeader@helper{#1}{5}%
- \nduAlignedHeader@helper{#1}{6}%
- \endgroup%
-}
-
-\NewDocumentCommand\nduAlignedValue@entry{ m > { \SplitArgument { 6 } { . } } m }{%
- % #1 = unit group
- % #2 = values joined by .
- \begingroup%
- \nduset{show=values}%
- \ifndunormalize%
- \stepcounter{autorepr}%
- \nduConvertToRepr@internal{#1}{autorepr\arabic{autorepr}}#2%
- \nduResult{#1}[aligned]{autorepr\arabic{autorepr}}%
- \else%
- \nduAlignedValue@internal{#1}#2%
- \fi%
- \endgroup%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Formatting values
+%
+
+\prg_new_protected_conditional:Nnn \ndu_if_not_nil_or_zero:Nn {T,TF}
+{
+ % parameters
+ % #1: output result (tl)
+ % #2: value (tl)
+ % returns T if value should be output, otherwise F
+
+ \tl_if_blank:nTF {#2}
+ {
+ % only output something if we are replacing nil
+ \tl_if_empty:NTF {\l_ndu_replace_nil_with_tl}
+ {
+ \prg_return_false:
+ }
+ {
+ \tl_set_eq:NN #1 \l_ndu_replace_nil_with_tl
+ \prg_return_true:
+ }
+ }
+ {
+ \bool_if:nTF {
+ \l_ndu_treat_zero_as_nil_bool &&
+ \int_compare_p:n { #2 = 0 }
+ } {
+ % only output something if we are replacing nil
+ \tl_if_empty:NTF {\l_ndu_replace_nil_with_tl}
+ {
+ \prg_return_false:
+ }
+ {
+ \tl_set_eq:NN #1 \l_ndu_replace_nil_with_tl
+ \prg_return_true:
+ }
+ }
+ {
+ % else output directly
+ \tl_set:Nx #1 { #2 }
+ \prg_return_true:
+ }
+ }
+}
+\prg_generate_conditional_variant:Nnn \ndu_if_not_nil_or_zero:Nn
+{
+ Nx
+}
+{
+ T,TF
+}
+
+% placeholder tokens for \ndu_format_display_helper
+\tl_new:N \VALUE
+\tl_new:N \SYMBOL
+
+\tl_const:Nn \c__ndu_values_only_tl { values~only }
+\tl_const:Nn \c__ndu_symbols_only_tl { symbols~only }
+\tl_const:Nn \c__ndu_formatted_tl { formatted }
+\tl_const:Nn \c__ndu_numprint_tl { numprint }
+
+\cs_new_protected:Nn \ndu__numprint_helper:nn
+{
+ \numprint[#1]{#2}
+}
+
+\cs_new_protected:Nn \ndu_format_display_helper:Nnnn
+{
+ % parameters
+ % #1: output result (tl)
+ % #2: format (tl)
+ % #3: symbol (tl)
+ % #4: value (int)
+ \tl_case:Nn \l_ndu_display_choice_tl {
+ \c__ndu_symbols_only_tl {
+ \tl_set:Nn #1 { #3 }
+ }
+ \c__ndu_values_only_tl {
+ \tl_set:Nn #1 {
+ \bool_if:NTF \l_ndu_use_numprint_bool
+ { \ndu__numprint_helper:nn {} {#4} }
+ { #4 }
+ }
+ }
+ \c__ndu_formatted_tl {
+ \tl_set:Nn #1 { #2 }
+ \tl_replace_all:Nnn #1 { \SYMBOL } { #3 }
+ \tl_replace_all:Nnn #1 { \VALUE } {
+ \bool_if:NTF \l_ndu_use_numprint_bool
+ { \ndu__numprint_helper:nn {} {#4} }
+ { #4 }
+ }
+ }
+ \c__ndu_numprint_tl {
+ \tl_set:Nn #1 { \ndu__numprint_helper:nn {#3} {#4} }
+ }
+ }
+}
+\cs_generate_variant:Nn \ndu_format_display_helper:Nnnn {
+ NVVn,
+ NVVx
+}
+
+\cs_new_protected:Nn \ndu_format_values:NNNN
+{
+ % parameters
+ % #1: output result (tl)
+ % #2: unit group (seq)
+ % #3: values (seq)
+ % #4: separator (tl)
+ \seq_clear:N #1
+ \seq_clear_new:N \l__ndu_formatted_segments_seq
+
+ \seq_map_indexed_inline:Nn #3
+ {
+ \tl_clear_new:N \l__ndu_formatted_segment
+ \tl_clear_new:N \l__ndu_symbol_tl
+ \tl_set:Nx \l__ndu_symbol_tl { \tl_use:c { l_ndu_symbol_ \seq_item:Nn #2 {##1} _tl } }
+
+ \tl_clear_new:N \l__ndu_format_tl
+ \tl_if_empty:cTF { l_ndu_format_ \seq_item:Nn #2 {##1} _tl }
+ {
+ \tl_set_eq:NN \l__ndu_format_tl \l_ndu_default_format_tl
+ }
+ {
+ \tl_set_eq:Nc \l__ndu_format_tl { l_ndu_format_ \seq_item:Nn #2 {##1} _tl }
+ }
+
+ \ndu_if_not_nil_or_zero:NnT \l_tmpa_tl { ##2 }
+ {
+ \ndu_format_display_helper:NVVx
+ \l__ndu_formatted_segment
+ \l__ndu_format_tl
+ \l__ndu_symbol_tl
+ { \l_tmpa_tl }
+ \seq_put_right:Nx \l__ndu_formatted_segments_seq \l__ndu_formatted_segment
+ }
+
+ % stop when we hit the desired unit depth
+ \tl_set:Nx \l__ndu_unit_tl { \seq_item:Nn #2 {##1} }
+ \tl_if_eq:NNT \l__ndu_unit_tl \l_ndu_unit_depth_tl
+ {
+ \seq_map_break:
+ }
+ }
+ \tl_set:Nn #1 { \seq_use:Nn {\l__ndu_formatted_segments_seq} {#4} }
+}
+\cs_generate_variant:Nn \ndu_format_values:NNNN {
+ NcNN
+}
+
+
+\prg_new_protected_conditional:Nnn \ndu_if_valid_dim:n {F}
+{
+ % adapted from https://tex.stackexchange.com/questions/498976/testing-for-a-length
+ \regex_match:nnTF
+ { \A [+\-]? ((\d+(\.\d*)?)|(\.\d+)) \s* (pt|pc|in|bp|cm|mm|dd|cc|sp|ex|em) \Z}
+ { #1 } % test string
+ { \prg_return_true: }
+ { \prg_return_false: }
+}
+\prg_generate_conditional_variant:Nnn \ndu_if_valid_dim:n
+{
+ V
+}
+{
+ F
+}
+
+
+\cs_new_protected:Nn \ndu_make_box:Nnn
+{
+ % parameter
+ % #1: output result (box)
+ % #2: contents (tl)
+ % #3: box index
+ \box_clear_new:N #1
+ \dim_zero_new:N \l__ndu_cell_width_dim
+ \tl_set:Nx \l_tmpa_tl { \seq_item:Nn \l_ndu_cell_widths_seq { #3 } }
+ \ndu_if_valid_dim:VF \l_tmpa_tl
+ {
+ \seq_get_right:NN \l_ndu_cell_widths_seq \l_tmpa_tl
+ }
+ \dim_set:Nn \l__ndu_cell_width_dim { \l_tmpa_tl }
+ \hbox_set_to_wd:Nnn #1 { \l__ndu_cell_width_dim } { #2 }
+}
+\cs_generate_variant:Nn \ndu_make_box:Nnn {
+ cnn
+}
+
+
+\cs_new_protected:Nn \ndu_format_values_aligned:NNN
+{
+ % parameters
+ % #1: output result (tl)
+ % #2: unit group (seq)
+ % #3: values (seq)
+ \tl_set:Nn #1 { \leavevmode }
+
+ \seq_map_indexed_inline:Nn #2
+ {
+ \tl_clear_new:N \l__ndu_value_tl
+ \ndu_if_not_nil_or_zero:NxTF \l__ndu_value_tl { \seq_item:Nn #3 ##1 }
+ {
+ \ndu_make_box:cnn
+ { l__ndu_cell_ \int_to_alph:n {##1} _box }
+ { \hfill \tl_use:N \l__ndu_value_tl }
+ { ##1 }
+ }
+ {
+ \ndu_make_box:cnn
+ { l__ndu_cell_ \int_to_alph:n {##1} _box }
+ { \hfill }
+ { ##1 }
+ }
+
+ \tl_put_right:Nx #1 { \box_use:c { l__ndu_cell_ \int_to_alph:n {##1} _box } }
+
+ % stop when we hit the desired unit depth
+ \tl_if_eq:NnT \l_ndu_unit_depth_tl {##2}
+ {
+ \seq_map_break:
+ }
+ }
+}
+\cs_generate_variant:Nn \ndu_format_values_aligned:NNN {
+ NcN
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\newcommand\ndu@val@or@zero[1]{%
- \IfValueTF{#1}{%
- \ifblank{#1}{%
- 0%
- }{%
- #1%
- }%
- }{%
- 0%
- }%
-}
-
-\newcommand\nduConvertToRepr@helper[4]{%
- % convert from overlying unit and add value
- % #1 = unit group
- % #2 = repr name
- % #3 = segment
- % #4 = value
- \ndu@if@depth@at@least{#1}{#3}{%
- \ifnum#3=0%
- % no conversion at top level
- \else%
- \ifnduFactorDefined{#1}{#3}{%
- %\show#3%
- \csxdef{ndu@repr@#2}{\bigintcalcMul{\csuse{ndu@repr@#2}}{\nduFactor{#1}{#3}}}%
- }{%
- % there is no factor to the overlying unit
- % instead attempt to skip ahead to the underlying unit?
- \PackageError{non-decimal-units}{Cannot convert to representation because there is no conversion factor from \nduName{#1}{\the\numexpr#3-1\relax} to \nduName{#1}{#3}}{}%
- }%
- \fi%
- \csxdef{ndu@repr@#2}{\bigintcalcAdd{\csuse{ndu@repr@#2}}{\ndu@val@or@zero{#4}}}%
- \csxdef{ndu@repr@#2@unit}{\nduName{#1}{#3}}%
- }%
-}
-
-\newcommand\nduConvertToRepr@internal[9]{%
- % #1 = unit group
- % #2 = repr name
- % #3-9 = values
- \csdef{ndu@repr@#2}{0}%
- \nduConvertToRepr@helper{#1}{#2}{0}{#3}%
- \nduConvertToRepr@helper{#1}{#2}{1}{#4}%
- \nduConvertToRepr@helper{#1}{#2}{2}{#5}%
- \nduConvertToRepr@helper{#1}{#2}{3}{#6}%
- \nduConvertToRepr@helper{#1}{#2}{4}{#7}%
- \nduConvertToRepr@helper{#1}{#2}{5}{#8}%
- \nduConvertToRepr@helper{#1}{#2}{6}{#9}%
-}
-
-\NewDocumentCommand\nduConvertToRepr{ m O{} m > { \SplitArgument { 6 } { . } } m }{%
- \nduset{unit groups/#1,#2}%
- \nduConvertToRepr@internal{#1}{#3}#4%
-}
-
-\newcommand\nduFormatRepr@helper[3]{%
- % V = mod(R, F)
- % R = div(R - V, F)
- % #1 = unit group
- % #2 = repr name
- % #3 = segment (F)
- \ndu@if@depth@at@least{#1}{#3}{%
- \ifnum#3=0%
- \csxdef{ndu@repr@#2@result@#3}{\csuse{ndu@repr@#2}}%
- \else%
- \ifnduFactorDefined{#1}{#3}{%
- \csxdef{ndu@repr@#2@result@#3}{\bigintcalcMod{\csuse{ndu@repr@#2}}{\nduFactor{#1}{#3}}}%
- \csxdef{ndu@repr@#2}{\bigintcalcDiv{\bigintcalcSub{\csuse{ndu@repr@#2}}{\csuse{ndu@repr@#2@result@#3}}}{\nduFactor{#1}{#3}}}%
- }{%
- % there is no factor to the underlying unit
- % instead attempt to skip ahead to the overlying unit?
- \PackageError{non-decimal-units}{Cannot convert from representation because there is no conversion factor from \nduName{#1}{\the\numexpr#3-1\relax} to \nduName{#1}{#3}}{}%
- }%
- \fi%
- }%
-}
-
-\NewDocumentCommand\nduResult{ m O{} m }{%
- \nduResult@unitgroup{\nduAliasOrGroup{#1}}[#2]{#3}%
-}
-
-\NewDocumentCommand\nduResult@unitgroup{ m O{} m }{%
- % #1 = unit group
- % #2 = options
- % #3 = repr name
- \nduset{unit groups/#1}%
- \csdef{ndu@repr@tmp #3}{\csuse{ndu@repr@#3}}%
- \nduFormatRepr@helper{#1}{tmp #3}{6}%
- \nduFormatRepr@helper{#1}{tmp #3}{5}%
- \nduFormatRepr@helper{#1}{tmp #3}{4}%
- \nduFormatRepr@helper{#1}{tmp #3}{3}%
- \nduFormatRepr@helper{#1}{tmp #3}{2}%
- \nduFormatRepr@helper{#1}{tmp #3}{1}%
- \nduFormatRepr@helper{#1}{tmp #3}{0}%
- \edef\ndu@nextdelim{\pgfkeysvalueof{/ndu/unit groups/#1/segment separator}}%
- \edef\ndu@delim{}%
- \begingroup%
- \nduset{unit groups/#1,#2}%
- \ifndualigned%
- \nduset{show=values}%
- \nduAlignedValue@helper{#1}{0}{\csuse{ndu@repr@tmp #3@result@0}}%
- \nduAlignedValue@helper{#1}{1}{\csuse{ndu@repr@tmp #3@result@1}}%
- \nduAlignedValue@helper{#1}{2}{\csuse{ndu@repr@tmp #3@result@2}}%
- \nduAlignedValue@helper{#1}{3}{\csuse{ndu@repr@tmp #3@result@3}}%
- \nduAlignedValue@helper{#1}{4}{\csuse{ndu@repr@tmp #3@result@4}}%
- \nduAlignedValue@helper{#1}{5}{\csuse{ndu@repr@tmp #3@result@4}}%
- \nduAlignedValue@helper{#1}{6}{\csuse{ndu@repr@tmp #3@result@4}}%
- \else%
- \nduFormatValue@helper{#1}{0}{\csuse{ndu@repr@tmp #3@result@0}}%
- \nduFormatValue@helper{#1}{1}{\csuse{ndu@repr@tmp #3@result@1}}%
- \nduFormatValue@helper{#1}{2}{\csuse{ndu@repr@tmp #3@result@2}}%
- \nduFormatValue@helper{#1}{3}{\csuse{ndu@repr@tmp #3@result@3}}%
- \nduFormatValue@helper{#1}{4}{\csuse{ndu@repr@tmp #3@result@4}}%
- \nduFormatValue@helper{#1}{5}{\csuse{ndu@repr@tmp #3@result@4}}%
- \nduFormatValue@helper{#1}{6}{\csuse{ndu@repr@tmp #3@result@4}}%
- \fi%
- \endgroup%
-}
-
-\newcommand\nduMath[4]{%
- \nduMath@unitgroup{\nduAliasOrGroup{#1}}{#2}{#3}{#4}%
-}
-
-\newcommand\nduMath@unitgroup[4]{%
- % #1 = unit group
- % #2 = repr name
- % #3 = operator
- % #4 = value
- \nduset{unit groups/#1}%
- \ifcsvoid{ndu@repr@#2}{\csxdef{ndu@repr@#2}{0}}{}%
- \ifthenelse{\equal{#3}{+}}{%
- \nduConvertToRepr{#1}{tmp #2}{#4}%
- \csxdef{ndu@repr@#2}{\bigintcalcAdd{\csuse{ndu@repr@#2}}{\csuse{ndu@repr@tmp #2}}}%
- }{%
- \ifthenelse{\equal{#3}{-}}{%
- \nduConvertToRepr{#1}{tmp #2}{#4}%
- \csxdef{ndu@repr@#2}{\bigintcalcSub{\csuse{ndu@repr@#2}}{\csuse{ndu@repr@tmp #2}}}%
- }{%
- \ifthenelse{\equal{#3}{*}}{%
- \csxdef{ndu@repr@#2}{\bigintcalcMul{\csuse{ndu@repr@#2}}{#4}}%
- }{%
- \ifthenelse{\equal{#3}{/}}{%
- \csxdef{ndu@repr@#2}{\bigintcalcDiv{\csuse{ndu@repr@#2}}{#4}}%
- }{%
- \PackageError{non-decimal-units}{Unrecognized math operator: #3}{Only + - * / are allowed.}%
- }%
- }%
- }%
- }%
+% User commands
+%
+
+
+\cs_new_protected:Nn \ndu_set_options:nn
+{
+ % set keys for unit group
+ \tl_if_eq:cnF { l_ndu_options_#1_tl } { \c_novalue_tl }
+ {
+ \keys_set:nv { non-decimal-units } { l_ndu_options_#1_tl }
+ }
+
+ % set keys provided by command
+ \IfValueT {#2} { \keys_set:nn { non-decimal-units } { #2 } }
+}
+
+\NewDocumentCommand \nduValue { m o m } {
+ \tl_if_exist:cF { l_ndu_group_#1_seq }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-unit-group } { #1 }
+ }
+ \group_begin:
+ \ndu_set_options:nn {#1} {#2}
+
+ \tl_clear_new:N \l__ndu_result_tl
+ \int_zero_new:N \l__ndu_normalized_int
+ \seq_set_split:Nnn \l_tmpa_seq { . } {#3}
+
+ % should we normalize the input?
+ \bool_if:nT \l_ndu_normalize_bool
+ {
+ \ndu_seq_to_repr:NnN
+ \l__ndu_normalized_int
+ { #1 }
+ \l_tmpa_seq
+ \ndu_repr_to_seq:NnN
+ \l_tmpa_seq
+ { #1 }
+ \l__ndu_normalized_int
+ }
+
+ % are we outputting aligned cells?
+ \bool_if:NTF \l_ndu_aligned_bool
+ {
+ \ndu_format_values_aligned:NcN
+ \l__ndu_result_tl
+ { l_ndu_group_#1_seq }
+ \l_tmpa_seq
+ }
+ {
+ \ndu_format_values:NcNN
+ \l__ndu_result_tl
+ { l_ndu_group_#1_seq }
+ \l_tmpa_seq
+ \l_ndu_unit_separator_tl
+ }
+
+ % should we do any math?
+ \tl_if_empty:NF \l_ndu_current_variable_tl
+ {
+ \nduMath{#1}[#2]{\l_ndu_current_variable_tl}{\l_ndu_current_operator_tl}{#3}
+ }
+
+ % output
+ \tl_use:N \l__ndu_result_tl
+ \group_end:
+}
+
+\tl_const:Nn \c__ndu_plus_tl { + }
+\tl_const:Nn \c__ndu_minus_tl { - }
+
+\NewDocumentCommand \nduMath { m o m m m } {
+ \tl_if_exist:cF { l_ndu_group_#1_seq }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-unit-group } { #1 }
+ }
+ \group_begin:
+ \ndu_set_options:nn {#1} {#2}
+
+ \int_if_exist:cF { g_ndu_variable_#3_int } {
+ \int_zero_new:c { g_ndu_variable_#3_int }
+ }
+
+ \int_zero_new:N \l__ndu_operand_int
+
+ \bool_if:nTF
+ {
+ % TODO hacky, but works
+ \str_if_eq_p:nV {#4} \c__ndu_plus_tl ||
+ \str_if_eq_p:nV {#4} \c__ndu_minus_tl ||
+ \tl_if_eq_p:NN {#4} \c__ndu_plus_tl ||
+ \tl_if_eq_p:NN {#4} \c__ndu_minus_tl
+ }
+ {
+ % plus or minus means we use the representation of the provided value
+ \seq_set_split:Nnn \l_tmpa_seq { . } { #5 }
+ \ndu_seq_to_repr:NnN
+ \l__ndu_operand_int
+ { #1 }
+ \l_tmpa_seq
+ }
+ {
+ % otherwise (multiplication/division) we use the number provided directly
+ \int_set:Nn \l__ndu_operand_int { #5 }
+ }
+
+ \int_gset:cn { g_ndu_variable_#3_int } {
+ \int_use:c { g_ndu_variable_#3_int }
+ #4
+ \l__ndu_operand_int
+ }
+ \group_end:
+}
+
+\NewDocumentCommand \nduResult { m o m } {
+ \tl_if_exist:cF { l_ndu_group_#1_seq }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-unit-group } { #1 }
+ }
+ \group_begin:
+ \ndu_set_options:nn {#1} {#2}
+
+ \int_if_exist:cF { g_ndu_variable_#3_int } {
+ \int_zero_new:c { g_ndu_variable_#3_int }
+ }
+
+ \tl_clear_new:N \l__ndu_result_tl
+
+ \ndu_repr_to_seq:Nnc
+ \l_tmpa_seq
+ { #1 }
+ { g_ndu_variable_#3_int }
+
+ % are we outputting aligned cells?
+ \bool_if:NTF \l_ndu_aligned_bool
+ {
+ \ndu_format_values_aligned:NcN
+ \l__ndu_result_tl
+ { l_ndu_group_#1_seq }
+ \l_tmpa_seq
+ }
+ {
+ \ndu_format_values:NcNN
+ \l__ndu_result_tl
+ { l_ndu_group_#1_seq }
+ \l_tmpa_seq
+ \l_ndu_unit_separator_tl
+ }
+
+ % output
+ \tl_use:N \l__ndu_result_tl
+ \group_end:
+}
+
+\NewDocumentCommand \nduHeader { m o } {
+ \tl_if_exist:cF { l_ndu_group_#1_seq }
+ {
+ \msg_error:nnn { non-decimal-units } { missing-unit-group } { #1 }
+ }
+ \group_begin:
+ \ndu_set_options:nn {#1} {#2}
+ \tl_set:Nn \l__ndu_result_tl { \leavevmode }
+
+ % build boxes
+ \seq_set_eq:Nc \l_tmpa_seq { l_ndu_group_#1_seq }
+ \seq_map_indexed_inline:Nn \l_tmpa_seq
+ {
+ \ndu_make_box:cnn
+ { l__ndu_cell_ \int_to_alph:n {##1} _box }
+ { \hfill \tl_use:c { l_ndu_symbol_ ##2 _tl } }
+ { ##1 }
+ \tl_put_right:Nn \l__ndu_result_tl { \box_use:c { l__ndu_cell_ \int_to_alph:n {##1} _box } }
+
+ % stop when we hit the desired unit depth
+ \tl_if_eq:NnT \l_ndu_unit_depth_tl {##2}
+ {
+ \seq_map_break:
+ }
+ }
+
+ % output
+ \tl_use:N \l__ndu_result_tl
+ \group_end:
+}
+
+\NewDocumentCommand \nduSymbol { m } {
+ \tl_use:c { l_ndu_symbol_#1_tl }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Column type for tabularray
+%
+
+% TODO: using the font key is pretty hacky...
+% need to ask if theres a better option
+% https://github.com/lvjr/tabularray/issues
+
+\keys_define:nn { non-decimal-units }
+{
+ tabularray~column~type .code = {
+ \NewColumnType {#1}[2] { Q[r, cmd=\ndu_tblr_cell:nnn {##1} {##2}] }
+ } ,
+}
+
+\tl_clear_new:N \l__ndu_tblr_column_type_tl
+
+\tl_const:Nn \c__ndu_HEADER_tl { HEADER }
+\tl_const:Nn \c__ndu_RESULT_tl { RESULT }
+\tl_const:Nn \c__ndu_SKIP_tl { SKIP }
+
+\cs_new_protected:Nn \ndu_tblr_cell:nnn
+{
+ \keys_set:nn { non-decimal-units } {
+ aligned,
+ #2
+ }
+ \tl_set:Nn \l_tmpa_tl {#3}
+ \tl_case:NnF \l_tmpa_tl {
+ \c__ndu_HEADER_tl {
+ \nduHeader
+ { #1 }
+ }
+ \c__ndu_RESULT_tl {
+ \nduResult
+ { #1 }
+ { \l_ndu_current_variable_tl }
+ }
+ \c__ndu_SKIP_tl {
+ % nothing
+ }
+ }
+ {
+ % format value if no special token was hit
+ % do math only once per tblr cell
+ % Will https://github.com/lvjr/tabularray/issues/179 introduce
+ % elenganter solution?
+ \cs_if_exist:cTF { \ndu__tblr_cell_get_csname: }
+ % or use a specific bool, e.g., \ndu__do_math_bool
+ { \tl_clear:N \l_ndu_current_variable_tl }
+ { \cs_gset:cpn { \ndu__tblr_cell_get_csname: } {} }
+ \nduValue
+ { #1 }
+ { #3 }
+ }
+}
+
+% a csname distinct per tblr table, per cell
+\cs_new:Npn \ndu__tblr_cell_get_csname:
+ {
+ ndu__tblr_ \int_use:N \g__tblr_table_count_int
+ _cell_ \int_use:N \c@rownum _ \int_use:N \c@colnum
+ :
+ }
-\nduset{
- options/.cd,
- british/.code={\input{non-decimal-units.british}},
- danish/.code={\input{non-decimal-units.danish}},
-}
-
-\ProcessPgfPackageOptions{/ndu/options}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Setup
+%
+
+\keys_define:nn { non-decimal-units / options }
+{
+ british .code:n = { \input{non-decimal-units.british} } ,
+ danish .code:n = { \input{non-decimal-units.danish} } ,
+ german .code:n = { \input{non-decimal-units.german} } ,
+}
+
+\IfFormatAtLeastTF { 2022-06-01 } {
+ \ProcessKeyOptions [ non-decimal-units / options ]
+}{
+ \RequirePackage { l3keys2e }
+ \ProcessKeysOptions { non-decimal-units / options }
+} \ No newline at end of file