\documentclass[11pt]{article}

\usepackage[a4paper,margin=24mm]{geometry}
\usepackage{xcolor}
\usepackage{listings}
\usepackage[most]{tcolorbox}
\usepackage{booktabs}
\usepackage{array}
\usepackage{hyperref}
\usepackage{luanumbers}

\LuaNumbersSetup{
  decimals=1,
  rounding=half-up,
  pad-zeroes=true,
  integers=false,
  warnings=once
}

\definecolor{codebackground}{HTML}{F5F7FA}
\definecolor{codeframe}{HTML}{CBD5E1}
\definecolor{codekeyword}{HTML}{1D4ED8}
\definecolor{codecomment}{HTML}{64748B}
\definecolor{outputbackground}{HTML}{F0FDF4}
\definecolor{outputframe}{HTML}{16A34A}
\definecolor{warningbackground}{HTML}{FFF7ED}
\definecolor{warningframe}{HTML}{EA580C}

\lstdefinestyle{latexinput}{
  language=[LaTeX]TeX,
  basicstyle=\ttfamily\small,
  keywordstyle=\color{codekeyword}\bfseries,
  commentstyle=\color{codecomment}\itshape,
  backgroundcolor=\color{codebackground},
  frame=single,
  rulecolor=\color{codeframe},
  numbers=left,
  numberstyle=\scriptsize\color{codecomment},
  numbersep=10pt,
  breaklines=true,
  columns=fullflexible,
  keepspaces=true,
  showstringspaces=false,
  xleftmargin=4pt,
  framexleftmargin=4pt
}

\newtcolorbox{processedoutput}{
  title=Processed output,
  colback=outputbackground,
  colframe=outputframe,
  coltitle=white,
  fonttitle=\bfseries,
  boxrule=0.8pt,
  arc=2pt
}

\newtcolorbox{importantnote}{
  title=Important,
  colback=warningbackground,
  colframe=warningframe,
  coltitle=white,
  fonttitle=\bfseries,
  boxrule=0.8pt,
  arc=2pt
}

\newcommand\InputHeading{\par\smallskip\noindent\textbf{LaTeX input}\par\smallskip}
\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}}

\title{The \texttt{luanumbers} Package\\\large Document-Wide Decimal Adjustment from a Single Preamble Setup}
\author{Parsa Yazdi\\\small Developer and maintainer}
\date{Version 0.5.0, 10 June 2026}

\begin{document}
\maketitle

\section*{Summary}

\texttt{luanumbers} is a LuaLaTeX package that lets an author declare a
decimal-formatting policy once in the document preamble and apply it
automatically to ordinary decimal literals throughout prose and mathematics.
Existing numbers can remain in their natural LaTeX form: they do not normally
need to be wrapped individually in formatting commands, moved into special data
structures, or prepared with an additional number-formatting package. The Lua
implementation uses exact decimal-string arithmetic, preserves integers by
default, protects structural LaTeX data, and provides local exclusions for
selected sections, figures, tables, diagrams, and other objects. Explicit
formatting remains available for ambiguous or protected contexts where the
author's intent cannot be inferred safely. Documents using the package must be
compiled with LuaLaTeX.

\section*{Practical Advantages}

\begin{itemize}
  \item \textbf{One-time configuration:} precision, rounding mode, zero
    padding, and related behavior are declared together in the preamble.
  \item \textbf{Natural source text:} ordinary literals such as
    \texttt{3.14159} can be written directly instead of placing every value
    inside a dedicated formatting command.
  \item \textbf{Efficient document-wide revision:} changing one setup value
    can update the displayed precision across a long document without editing
    each occurrence manually.
  \item \textbf{Conservative automation:} integers, labels, references, file
    names, graphics coordinates, and ambiguous source are preserved according
    to documented safeguards.
  \item \textbf{Fine-grained control:} authors can exclude one selected object,
    protect recurring commands or environments, suspend processing temporarily,
    or request explicit formatting for an individual value.
  \item \textbf{Self-contained workflow:} the package supplies both the global
    automatic policy and the explicit per-value command, avoiding the need to
    combine separate number-rounding mechanisms for these tasks.
\end{itemize}

\clearpage
\tableofcontents

\section{Purpose and Requirements}

The \texttt{luanumbers} package is intended for documents whose decimal
precision should be controlled centrally. After one preamble setup, it adjusts
eligible decimal literals automatically across the document body. Authors can
therefore revise the document-wide precision without finding and rewriting
each number or marking every number with a special command. Exact
decimal-string arithmetic is used rather than binary floating point. The
package requires LuaLaTeX.

\begin{importantnote}
Automatic processing is intentionally conservative. Structural data, protected
commands, protected environments, URLs, versions, and other ambiguous values
are preserved. Use \verb|\LuaNumber| when formatting must be explicit.
\end{importantnote}

\section{Installation and Compilation}

Place \texttt{luanumbers.sty} and \texttt{luanumbers.lua} beside the document,
or install both files in a local TeX tree. Compile with:

\begin{lstlisting}[style=latexinput,language=bash,numbers=none]
lualatex document.tex
\end{lstlisting}

The package cannot be used with pdfLaTeX or XeLaTeX.

\section{Basic Setup}

\InputHeading
\LuaNumbersOff
\begin{lstlisting}[style=latexinput]
\usepackage{luanumbers}

\LuaNumbersSetup{
  decimals=1,
  rounding=half-up,
  pad-zeroes=true,
  integers=false,
  warnings=once
}
\end{lstlisting}
\LuaNumbersOn

With this configuration, decimal literals are shown with one decimal place,
while integers remain unchanged.

\section{Input and Output}

\InputHeading
\LuaNumbersOff
\begin{lstlisting}[style=latexinput]
Pi is approximately 3.14159265.
The measured value is 3.00 units.
The correction is -1.234 units.
There are 7 complete samples.
\end{lstlisting}
\LuaNumbersOn

\begin{processedoutput}
Pi is approximately 3.14159265.
The measured value is 3.00 units.
The correction is -1.234 units.
There are 7 complete samples.
\end{processedoutput}

The decimal values become \texttt{3.1}, \texttt{3.0}, and \texttt{-1.2}.
The integer \texttt{7} is not changed.

\subsection{Mathematics}

\InputHeading
\LuaNumbersOff
\begin{lstlisting}[style=latexinput]
\[
  1.23456 + 9.87654 = 11.11110
\]
\end{lstlisting}
\LuaNumbersOn

\begin{processedoutput}
\[
  1.23456 + 9.87654 = 11.11110
\]
\end{processedoutput}

\subsection{Scientific Notation}

Scientific notation is preserved by default. Thus \texttt{6.022e2} becomes
\texttt{6.0e2} with the one-decimal setup. A literal such as \texttt{6e2} is
unchanged when \texttt{integers=false}.

\subsection{Explicit Formatting}

\verb|\LuaNumber| always formats its argument using the active settings:

\begin{lstlisting}[style=latexinput]
The result is \LuaNumber{12.3456}.
\end{lstlisting}

It is also the preferred command for values in ambiguous contexts or protected
environments.

\section{Configuration Reference}

\begin{center}
\begin{tabular}{@{}lll@{}}
\toprule
Setting & Default & Accepted values \\
\midrule
\texttt{decimals} & \texttt{2} & Integer from 0 to 100 \\
\texttt{rounding} & \texttt{half-up} & \texttt{half-up}, \texttt{half-even}, \texttt{truncate}, \texttt{floor}, \texttt{ceil} \\
\texttt{pad-zeroes} & \texttt{true} & Boolean \\
\texttt{integers} & \texttt{false} & Boolean \\
\texttt{preserve-exponent} & \texttt{true} & Boolean \\
\texttt{normalize-negative-zero} & \texttt{true} & Boolean \\
\texttt{input-decimal} & \texttt{dot} & \texttt{dot}, \texttt{comma}, \texttt{both} \\
\texttt{auto-protect} & \texttt{true} & Boolean \\
\texttt{warnings} & \texttt{once} & \texttt{off}, \texttt{once}, \texttt{all}, \texttt{error} \\
\bottomrule
\end{tabular}
\end{center}

\subsection{Rounding Modes}

\texttt{half-up} rounds a decimal tie away from zero. \texttt{half-even}
rounds a tie toward an even final digit. \texttt{truncate} discards excess
digits. \texttt{floor} rounds toward negative infinity and \texttt{ceil}
rounds toward positive infinity.

\section{Exact Decimal Arithmetic}

The formatter operates on digit strings. It therefore handles values such as
\texttt{2.675}, very large decimal strings, and halfway cases without first
converting them to a Lua floating-point number. It also supports leading
decimals such as \texttt{.125}, decimal commas when configured, Unicode minus
signs, and negative-zero normalization.

Automatic mode does not interpret a trailing form such as \texttt{3.} because
it is indistinguishable from sentence punctuation. The explicit command
\verb|\LuaNumber{3.}| can format that form safely.

\section{Local Object Exclusion}

The recommended way to preserve one particular object is the built-in
\texttt{luanumbersexclude} environment. Only source inside that specific
wrapper is excluded. Other sections, figures, tables, and objects of the same
type continue to use automatic rounding.

The wrapper can contain the object's heading, caption, label, body, and nested
environments. All numeric source within it is copied to TeX unchanged.
Generated metadata files such as \texttt{.aux}, \texttt{.toc}, \texttt{.lof},
and \texttt{.lot} are never rewritten, so protected headings and labels remain
stable across repeated LaTeX passes.

\subsection{One Selected Section}

\begin{lstlisting}[style=latexinput]
\begin{luanumbersexclude}
\section{Experimental results 3.14159}
\label{sec:results-3.14159}

This selected section preserves 3.14159 exactly.
\end{luanumbersexclude}

\section{Discussion 3.14159}
This later section is processed normally: 3.14159.
\end{lstlisting}

The first heading, label, and section body are preserved. The second section
is outside the wrapper, so its decimal literals use the configured precision.
The exclusion ends exactly at \verb|\end{luanumbersexclude}|; it does not alter
all other section commands.

\subsection{One Selected Figure}

\begin{lstlisting}[style=latexinput]
\begin{luanumbersexclude}
\begin{figure}
  \centering
  \includegraphics[width=0.75\textwidth]{result-3.14159.pdf}
  \caption{Unmodified measurement 3.14159}
  \label{fig:result-3.14159}
\end{figure}
\end{luanumbersexclude}
\end{lstlisting}

Only this figure is isolated. Its graphics options, file name, caption, label,
and body remain unchanged. A later figure outside the wrapper is unaffected by
this exclusion policy.

\subsection{One Selected Table}

\begin{lstlisting}[style=latexinput]
\begin{luanumbersexclude}
\begin{table}
  \centering
  \caption{Raw values from dataset 2.7}
  \label{tab:raw-2.7}
  \begin{tabular}{cc}
    1.2345 & 9.8765 \\
  \end{tabular}
\end{table}
\end{luanumbersexclude}
\end{lstlisting}

This preserves the selected table's data and metadata without disabling
automatic rounding in other tables.

\begin{importantnote}
The \verb|\label| command is protected by default even without a local wrapper,
so label keys such as \texttt{fig:result-3.14159} are not rewritten. The local
wrapper additionally preserves the selected object's visible caption, heading,
body, and other numeric source.
\end{importantnote}

\section{Globally Protected Environment Types}

The package protects these environments by default:

\begin{center}
\texttt{tikzpicture}, \texttt{axis}, \texttt{pgfpicture},
\texttt{verbatim}, \texttt{verbatim*}, \texttt{lstlisting},
\texttt{minted}, \texttt{filecontents}, and \texttt{filecontents*}.
\end{center}

All numeric source inside a protected environment is passed through unchanged.
For graphics environments, this refers only to the package's \emph{automatic
input rewriting}. The explicit \verb|\LuaNumber{...}| command still works
inside a protected environment because TeX executes that command after the
input line has been preserved. This distinction prevents coordinates and data
from being changed while still allowing selected visible labels to be rounded.
Register one environment or a comma-separated list in the preamble only when
\emph{every instance} of that environment type should be excluded:

\begin{lstlisting}[style=latexinput]
\LuaNumbersProtectEnvironment{mydiagram}

\LuaNumbersProtectEnvironments{
  mydiagram
}
\end{lstlisting}

Remove protection with the corresponding singular or plural command:

\begin{lstlisting}[style=latexinput]
\LuaNumbersUnprotectEnvironment{mydiagram}
\LuaNumbersUnprotectEnvironments{mydiagram,otherdiagram}
\end{lstlisting}

\begin{importantnote}
Registering \texttt{figure} or \texttt{table} here is global: every matching
float in the document is preserved. To isolate one particular figure or table,
use \texttt{luanumbersexclude} around that object instead.
\end{importantnote}

\section{Protected Commands}

Arguments of common structural commands are protected by default, including
references, citations, URLs, file names, graphics options, length settings,
and TikZ/PGF setup commands.

Document-specific commands can be registered in the preamble when every use of
that command should have protected arguments:

\begin{lstlisting}[style=latexinput]
\LuaNumbersProtectCommands{
  caption,
  custommetadata
}
\end{lstlisting}

This applies globally to every registered command. Use the local
\texttt{luanumbersexclude} wrapper to preserve only one particular section or
caption. Command names may be written with or without their leading backslash.
Multiline braced arguments are tracked until their closing brace.

The related singular and removal operations are:

\begin{lstlisting}[style=latexinput,numbers=none]
\LuaNumbersProtectCommand{command}
\LuaNumbersUnprotectCommand{command}
\LuaNumbersUnprotectCommands{command-a,command-b}
\end{lstlisting}

\section{TikZ, PGFPlots, and Beamer}

The package does \emph{not} automatically rewrite numeric literals inside
\texttt{tikzpicture}, \texttt{pgfpicture}, or \texttt{axis}. This is deliberate:
the same literal may be a coordinate, dimension, transformation, plot datum, or
style parameter, and rounding it could alter the graphic rather than merely its
printed text.

The resulting behavior is:

\LuaNumbersOff
\begin{center}
\begin{tabular}{@{}L{0.42\linewidth}L{0.18\linewidth}L{0.29\linewidth}@{}}
\toprule
Source context & Automatic rounding & Recommended control \\
\midrule
Ordinary text outside graphics & Yes & \texttt{\string\LuaNumbersSetup} \\
TikZ coordinates and dimensions & No & Leave protected \\
Plain numeric text in a TikZ node & No & Use \texttt{\string\LuaNumber} \\
PGFPlots coordinates and tables & No & Leave protected \\
PGFPlots-generated tick labels & No & Use PGFPlots number formatting \\
\bottomrule
\end{tabular}
\end{center}
\LuaNumbersOn

Explicit \verb|\LuaNumber| calls are still processed inside protected graphics
environments. For example, the geometry below is copied unchanged, but the
visible value in the node is rounded to the package precision:

\begin{lstlisting}[style=latexinput]
\begin{tikzpicture}
  \draw (0.00,0.00) rectangle (3.26,1.74);
  \node at (1.63,0.87)
    {Value: \LuaNumber{3.14159}};
\end{tikzpicture}
\end{lstlisting}

\LuaNumbersOff
Thus, with one decimal place, \texttt{(3.26,1.74)} remains exactly a TikZ
coordinate while the node displays \texttt{Value: 3.1}. A plain node such as
\verb|\node {Value: 3.14159};| would retain \texttt{3.14159}, because it has not
requested explicit formatting.
\LuaNumbersOn

PGFPlots creates tick labels from plot data after reading the source. Configure
those labels through PGFPlots rather than by changing the underlying data:

\begin{lstlisting}[style=latexinput]
\pgfplotsset{
  tick label style={/pgf/number format/.cd,
    fixed, fixed zerofill, precision=1}
}
\end{lstlisting}

It is possible to opt into automatic source rewriting globally:

\begin{lstlisting}[style=latexinput]
\LuaNumbersUnprotectEnvironment{tikzpicture}
\LuaNumbersUnprotectEnvironment{axis}
\end{lstlisting}

This affects every numeric literal in every matching environment, including
coordinates and dimensions, so it is not the recommended method for formatting
displayed labels.

The same behavior works when TikZ is nested inside a Beamer frame. Ordinary
frame text remains subject to automatic rounding, while the graphics source is
preserved and explicit \verb|\LuaNumber| calls inside the graphic still work.

\section{Warnings and Ambiguous Input}

Automatic mode leaves suspicious values unchanged and issues a warning when a
number appears in a context resembling a URL, date, ratio, key-value setting,
grouped number, or version. Examples include:

\LuaNumbersOff
\begin{lstlisting}[style=latexinput,numbers=none]
https://host/3.14159
key=3.14159
1,234.56
1.2.3
\end{lstlisting}
\LuaNumbersOn

Set \texttt{warnings=error} during validation or continuous integration to stop
compilation whenever such a case requires review. Use \verb|\LuaNumber| when
the suspicious value is definitely display text.

\section{Manual Suspension}

Automatic processing can be suspended for exceptional source regions:

\begin{lstlisting}[style=latexinput]
\LuaNumbersOff
This value is preserved exactly: 3.14159265.
\LuaNumbersOn
\end{lstlisting}

Place these commands on separate source lines. Registered environment and
command protection is preferable for recurring structures, while
\texttt{luanumbersexclude} is preferable for one selected document object.

\section{Limitations}

The package processes LuaTeX input lines before TeX expands macros. It cannot
infer semantic intent from arbitrary macro-generated source, numbers assembled
from several macros, or environments whose begin/end commands are generated
indirectly. Automatic processing is therefore a convenience layer, while
\verb|\LuaNumber| remains the deterministic interface.

When \texttt{integers=true}, integer arguments expected by LaTeX commands may
be converted to decimal strings. Use that setting cautiously and protect
structural commands that require literal integers.

\section{Development and Verification}

From the project root:

\begin{lstlisting}[style=latexinput,language=bash,numbers=none]
make doc          # build this manual
make examples     # build TikZ/PGFPlots and Beamer examples
make test         # run Lua assertions and compile the smoke test
make clean        # remove generated TeX files
\end{lstlisting}

\end{document}
