From b6ebe06eec54ea49e01aab3a29ad9c298953d1a0 Mon Sep 17 00:00:00 2001
From: Robert Alessi <alessi@robertalessi.net>
Date: Mon, 21 Apr 2025 22:43:46 +0200
Subject: new feature: negative apparatus

---
 ekdosis.dtx | 596 +++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 389 insertions(+), 207 deletions(-)

(limited to 'ekdosis.dtx')

diff --git a/ekdosis.dtx b/ekdosis.dtx
index 6673d37..5d7876a 100644
--- a/ekdosis.dtx
+++ b/ekdosis.dtx
@@ -59,7 +59,7 @@ Alessi <alessi@robertalessi.net>
 %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
 %<package>\ProvidesPackage{ekdosis}
 %<*package>
-    [2025/04/19 v1.5-dev Typesetting TEI xml-compliant critical editions]
+    [2025/04/21 v1.5-dev Typesetting TEI xml-compliant critical editions]
 %</package>
 %<*driver>
 \begin{filecontents}[noheader,overwrite]{bibdata.xml}
@@ -2056,6 +2056,20 @@ yesterday.
 % used as values of the |wit| optional argument, it is recommended to
 % use |sources| and |resp| to refer to either category
 % respectively as described below.\\
+% \DescribeOption{nowit} \newfeature[v1.5]
+% |nowit|$=$\verb+true|false+\\
+% This named argument does not need a value as it defaults to |true|
+% if used. When used in a positive apparatus, |nowit| instructs
+% \pkg{ekdosis} to remove the witnesses attached to the lemma text
+% with the result of printing a negative entry. In a positive
+% apparatus, this can be a way of suggesting an aberration. In a
+% negative apparatus, |nowit=false| inserts a positive entry, which
+% implies that the rejected variant is well attested or judged worthy
+% of consideration as a serious alternative. For details on the method
+% of encoding positive or negative apparatus criticus, the reader is
+% invited to refer to the commands and options described
+% \vpagerefrange{ref:set-neg-app}{ref:apparatus-settings-e} and
+% \vnref{sec:layout-layers}.\\
 % \DescribeOption{source} |source|$=$\meta{csv list of
 % sources}\phts\label{ref:lem-source}\newfeature[v1.1]\\
 % A \enquote{source} refers to any type of document consulted by the
@@ -3891,6 +3905,23 @@ texts=latin[xml:lang="la"]+\textcolor{red}{;}+
 % \vref{ref:type-note}\===namely
 % \cs{note}\oarg{options}\marg{text}\===a language different from the
 % one that is selected in the edition text.
+%
+% \DescribeMacro{\SetNegativeApparatus}
+% \phts\label{ref:set-neg-app}\newfeature[v1.5]
+% \cs{SetNegativeApparatus} removes the witnesses
+% attached to the lemma text and sets the apparatus criticus in
+% negative form, leaving the reading of lemma text to be understood.
+% 
+% \DescribeMacro{\SetPositiveApparatus}
+% \newfeature[v1.5] \cs{SetPositiveApparatus} prints the witnesses
+% attached to the lemma text and sets the apparatus criticus in
+% positive form, which is the default.
+%
+% \DescribeMacro{\SetTEINegativeApparatus}
+% \DescribeMacro{\SetTEIPositiveApparatus}
+% \newfeature[v1.5] \cs{SetTEINegativeApparatus} and
+% \cs{SetTEIPositiveApparatus} do the same as described above for the
+% apparatus criticus converted in \texttt{TEI xml}.
 % 
 % \paragraph{General Command}
 % \DescribeMacro{\SetApparatus} \cs{SetApparatus}\marg{csv list of
@@ -3944,7 +3975,21 @@ texts=latin[xml:lang="la"]+\textcolor{red}{;}+
 % command as described in \vref{ref:type-note}\===namely
 % \cs{note}\oarg{options}\marg{text}\===a language different from the
 % one that is selected in the edition text. |languagename| can be any
-% value accepted by \pkg{babel} or \pkg{polyglossia}.
+% value accepted by \pkg{babel} or \pkg{polyglossia}.\\
+% \DescribeOption{negative} \verb+negative=true|false+
+% \hfill\tcboxverb{Default: false}\\
+% \addlines
+% This named argument does not need a value as it defaults to |true|
+% if used. |negative=true| sets the apparatus criticus in print in
+% negative form as described above \vpageref{ref:set-neg-app}, whereas
+% |negative=false| can set it back in positive form, which is the
+% default.\\
+% \DescribeOption{TEInegative} \verb+TEInegative=true|false+
+% \hfill\tcboxverb{Default: false}\\
+% This named argument does not need a value as it defaults to |true|
+% if used. |TEINegative=true| has the \texttt{TEI xml} apparatus
+% converted in negative form, whereas |TEINegative=true| can be used
+% to set it back in positive form, which is the default.
 % \phts\label{ref:apparatus-settings-e}
 %
 % As an example, an apparatus criticus with references to line numbers
@@ -4043,6 +4088,8 @@ texts=latin[xml:lang="la"]+\textcolor{red}{;}+
 % \DescribeOption{norule}
 % \DescribeOption{lang}\phts\label{ref:apps-lang-opt}
 % \DescribeOption{notelang}
+% \DescribeOption{negative}
+% \DescribeOption{TEInegative}
 % With regard to layout, any declared layer inherits the default values
 % described above in \vref{sec:single-layer-app}. That said, as the
 % optional argument of \cs{DeclareApparatus} accepts the exact same
@@ -8534,7 +8581,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \paragraph{\textsf{ekdosis} Symbol}
 % \begin{macro}{\eKd}
-% \changes{v1.5}{2025/04/19}{Prints \textsf{ekdosis} indentifying
+% \changes{v1.5}{2025/04/21}{Prints \textsf{ekdosis} indentifying
 % symbol} As of v1.5, \pkg{ekdosis} has its own identifying
 % symbol. It is produced by \cs{eKd} and best printed with the Old
 % Standard Greek font.
@@ -8799,7 +8846,7 @@ Sample text with a \textcolor{red}{word} in red.
 % \begin{macro}{\teidirectE}
 % \changes{v1.3}{2021/08/18}{direct insertion of elements in the
 % \texttt{TEI xml} file}
-% \changes{v1.5}{2025/04/19}{direct insertion of empty elements in the
+% \changes{v1.5}{2025/04/21}{direct insertion of empty elements in the
 % \texttt{TEI xml} file}
 % \cs{teidirect}\oarg{xml attributes}\marg{xml element}\marg{code}
 % does nothing in \LaTeX. It is only used to insert elements in the
@@ -8814,7 +8861,7 @@ Sample text with a \textcolor{red}{word} in red.
 % \end{macro}
 % \end{macro}
 % \begin{macro}{\getTEIxmlid}
-% \changes{v1.5}{2025/04/19}{returns \texttt{TEI xml:ids} from a
+% \changes{v1.5}{2025/04/21}{returns \texttt{TEI xml:ids} from a
 % csv-list of ids} This command returns from a csv-list of unique
 % identifiers declared in commands such as \cs{DeclareWitness} and the
 % like a space-separated list of their corresponding |xml:id|s, each
@@ -8908,6 +8955,7 @@ Sample text with a \textcolor{red}{word} in red.
 % or multiple-layer context:---
 %    \begin{macrocode}
 \newif\ifekd@mapps
+\newif\ifekdl@nowit
 %    \end{macrocode}
 % Now the key-value options can be defined:---
 %    \begin{macrocode}
@@ -8928,24 +8976,40 @@ Sample text with a \textcolor{red}{word} in red.
   store notelang = \notelang@val,
   initial direction = LR,
   initial delim = {},
-  initial ehook = {\csname ekd@end@apparatus\endcsname}
+  initial ehook = {\csname ekd@end@apparatus\endcsname},
+  choice negative = {true=\def\negative@val{yes},
+    false=\def\negative@val{no}},
+  initial negative = false,
+  default negative = true,
+  unknown-choice negative = \PackageError{ekdosis}{unknown
+    negative=#1}{`negative' must be either `true' or `false'.},
+  choice TEInegative = {true=\def\TEInegative@val{yes},
+    false=\def\TEInegative@val{no}},
+  initial TEInegative = false,
+  default TEInegative = true,
+  unknown-choice TEInegative = \PackageError{ekdosis}{unknown
+    TEInegative=#1}{`TEInegative' must be either `true' or `false'.}
 }
 %    \end{macrocode}
 % \begin{macro}{\DeclareApparatus}
-% \cs{DeclareApparatus}\marg{apparatus name}\oarg{options} is a
-% preamble-only command. As a mandatory argument, it takes the name of
-% the new layer of notes to be inserted in the apparatus block. Then,
-% the following seven key-value options can be used to lay out the
-% layer: \verb+direction=LR|RL+, |rule|, |delim| (the delimiter between
-% entries), |sep| (the separator between lemma part and readings or
-% notes), |bhook| (\LaTeX{} code inserted as the layer begins),
-% |ehook| (\LaTeX{} code inserted as the layer ends), |maxentries|
-% (if set and |maxentries >= 10|, the number of entries at which a
-% \cs{pagebreak} is issued):---
+%   \cs{DeclareApparatus}\marg{apparatus name}\oarg{options} is a
+%   preamble-only command. As a mandatory argument, it takes the name
+%   of the new layer of notes to be inserted in the apparatus
+%   block. Then, the following eleven key-value options can be used to
+%   lay out the layer: \verb+direction=LR|RL+, |rule| |norule|,
+%   |delim| (the delimiter between entries), |sep| (the separator
+%   between lemma part and readings or notes), |bhook| (\LaTeX{} code
+%   inserted as the layer begins), |ehook| (\LaTeX{} code inserted as
+%   the layer ends), |maxentries| (if set and |maxentries >= 10|, the
+%   number of entries at which a \cs{pagebreak} is issued), |lang|,
+%   |notelang| (the language to be applied) |negative|, |TEInegative|
+%   (the form of the apparatus criticus, either positive or
+%   negative):---
 %    \begin{macrocode}
 \NewDocumentCommand{\DeclareApparatus}{m O{}}{
   \newbool{subsq@unit@#1}
   \booltrue{subsq@unit@#1}
+  \newbool{ekdl@nowit@#1}
   \unless\ifekd@mapps\global\ekd@mappstrue\fi
   \bgroup
   \ekvset{ekd@newapp}{#2}
@@ -8960,7 +9024,9 @@ Sample text with a \textcolor{red}{word} in red.
     \luastringO{\ehook@val},
     \luastringO{\limit@val},
     \luastringO{\lang@val},
-    \luastringO{\notelang@val}
+    \luastringO{\notelang@val},
+    \luastringO{\negative@val},
+    \luastringO{\TEInegative@val}
     )}
   \egroup
 }
@@ -9119,7 +9185,20 @@ Sample text with a \textcolor{red}{word} in red.
     \ltx@ifpackageloaded{polyglossia}{\languagename}{}},
   store notelang = \ekd@singleapp@note@lang,
   initial notelang = \ltx@ifpackageloaded{babel}{\languagename}{%
-  \ltx@ifpackageloaded{polyglossia}{\languagename}{}}
+    \ltx@ifpackageloaded{polyglossia}{\languagename}{}},
+  choice negative = {true=\ekdl@nowittrue,
+    false=\ekdl@nowitfalse},
+  initial negative = false,
+  default negative = true,
+  unknown-choice negative = \PackageError{ekdosis}{unknown
+    negative=#1}{`negative' must be either `true' or `false'.},
+  choice TEInegative = {
+    true=\luadirect{ekdosis.set_negpos_apparatus("neg")},
+    false=\luadirect{ekdosis.set_negpos_apparatus("pos")}},
+  initial TEInegative = false,
+  default TEInegative = true,
+  unknown-choice TEInegative = \PackageError{ekdosis}{unknown
+    TEInegative=#1}{`TEInegative' must be either `true' or `false'.}  
 }
 %    \end{macrocode}
 % \begin{macro}{\SetApparatus}
@@ -9211,13 +9290,47 @@ Sample text with a \textcolor{red}{word} in red.
 % \end{macro}
 % \begin{macro}{\footnoteruletrue}
 % \begin{macro}{\footnoterulefalse}
-% As \pkg{ekdosis} takes care of drawing a rule separating the main
-% text from the apparatus block as well as layers of notes from each
-% other inside this block, it may not be desirable to have
-% the standard \LaTeX{} \enquote{footnoterule} printed on every page
-% of the edition text. \cs{footnoterulefalse} removes it while
-% \cs{footnoteruletrue} leaves it untouched. The latter is set by
-% default.
+%   As \pkg{ekdosis} takes care of drawing a rule separating the main
+%   text from the apparatus block as well as layers of notes from each
+%   other inside this block, it may not be desirable to have the
+%   standard \LaTeX{} \enquote{footnoterule} printed on every page of
+%   the edition text. \cs{footnoterulefalse} removes it while
+%   \cs{footnoteruletrue} leaves it untouched. The latter is set by
+%   default.
+% \begin{macro}{\SetNegativeApparatus}
+%   \changes{v1.5}{2025/04/21}{sets the apparatus criticus in negative
+%   form.}
+% \begin{macro}{\SetPositiveApparatus}
+%   \changes{v1.5}{2025/04/21}{sets the apparatus criticus in positive
+%   form.}
+%   \cs{SetNegativeApparatus} and \cs{SetPositiveApparatus} are two
+%   argument-less commands. The former has the witnesses attached to
+%   the lemma text removed from the apparatus criticus in print, while
+%   the latter prints the apparatus criricus in positive form, which
+%   is the default.
+% \begin{macro}{\SetTEINegativeApparatus}
+%   \changes{v1.5}{2025/04/21}{sets the \texttt{TEI xml} apparatus
+%   criticus in negative form.}
+% \begin{macro}{\SetTEIPositiveApparatus}
+%   \changes{v1.5}{2025/04/21}{sets the \texttt{TEI xml} apparatus
+%   criticus in positive form.}
+%   \cs{SetTEINegativeApparatus} and \cs{SetTEIPositiveApparatus} do
+%   the same as described above for the apparatus criticus converted
+%   in \texttt{TEI xml}.
+%    \begin{macrocode}
+\NewDocumentCommand{\SetNegativeApparatus}{}{\ekdl@nowittrue}
+\NewDocumentCommand{\SetPositiveApparatus}{}{\ekdl@nowitfalse}
+\NewDocumentCommand{\SetTEINegativeApparatus}{}{%
+  \luadirect{ekdosis.set_negpos_apparatus("neg")}%
+}
+\NewDocumentCommand{\SetTEIPositiveApparatus}{}{%
+  \luadirect{ekdosis.set_negpos_apparatus("pos")}%
+}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
 %    \begin{macrocode}
 \newif\iffootnoterule
 \footnoteruletrue
@@ -9290,7 +9403,7 @@ Sample text with a \textcolor{red}{word} in red.
 \newlength{\ekd@app@localheight}
 %    \end{macrocode}
 % \begin{macro}{\localappheight}
-% \changes{v1.5}{2025/04/19}{changes the height of the apparatus
+% \changes{v1.5}{2025/04/21}{changes the height of the apparatus
 % criticus}
 % \cs{localappheight}\marg{dimen} can be used to change locally the
 % length of \cs{ekd@app@height} set by the |appheight| option of
@@ -9309,7 +9422,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\addtoappheight}
-% \changes{v1.5}{2025/04/19}{increases or decreases the height of the
+% \changes{v1.5}{2025/04/21}{increases or decreases the height of the
 % apparatus criticus}
 % As the name suggests, in contrast to \cs{localappheight},
 % \cs{addtoappheight}\marg{dimen} is used to increase or decrease
@@ -9598,7 +9711,7 @@ Sample text with a \textcolor{red}{word} in red.
 % The following commands are provided to set and control the maximum
 % number of lines printed on each page.
 % \begin{macro}{\setmaxlines}
-% \changes{v1.5}{2025/04/19}{limits the number of lines per page}
+% \changes{v1.5}{2025/04/21}{limits the number of lines per page}
 % \cs{setmaxlines}\marg{n}, where \meta{n} is a positive integer
 % $\geq 1$, can be used either in the preamble or at any point of the
 % document to set the maximum number of lines to be printed on each
@@ -9609,7 +9722,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\localmaxlines}
-% \changes{v1.5}{2025/04/19}{changes the maximum number of lines
+% \changes{v1.5}{2025/04/21}{changes the maximum number of lines
 % locally}
 % Once a maximum number of lines per page has been set,
 % \cs{localmaxlines}\marg{n} can be used to adjust this number on a
@@ -9622,7 +9735,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\addtomaxlines}
-% \changes{v1.5}{2025/04/19}{adds or subtracts lines from a given page}
+% \changes{v1.5}{2025/04/21}{adds or subtracts lines from a given page}
 % Unlike \cs{localmaxlines}, \cs{addtomaxlines}\meta{n} takes as
 % argument the number of lines one wishes to add or substract from the
 % number that has been set by \cs{setmaxlines}. As a result, \meta{n}
@@ -9635,7 +9748,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\nomaxlines}
-% \changes{v1.5}{2025/04/19}{unsets \cs{setmaxlines}}
+% \changes{v1.5}{2025/04/21}{unsets \cs{setmaxlines}}
 % \cs{nomaxlines} unsets any limit previously set by \cs{setmaxlines}.
 %    \begin{macrocode}
 \def\nomaxlines{\luadirect{tex.sprint(ekdosis.resetlocalmaxlines())}}
@@ -9699,7 +9812,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\App}
-% \changes{v1.5}{2025/04/19}{To be used conjointly with
+% \changes{v1.5}{2025/04/21}{To be used conjointly with
 % \texttt{ekdosis.el}}
 % In contrast to \cs{app}, \cs{App} takes two mandatory arguments and
 % accepts one optional argument like so:
@@ -10040,8 +10153,14 @@ Sample text with a \textcolor{red}{word} in red.
 \newif\ifekdl@nodelim
 \newif\ifekdl@forcedelim
 \newif\ifekdl@ilabel
+% \newif\ifekdl@nowit % defined above
 \ekvdefinekeys{lem}{
   code wit = \def\ekdlr@wit{#1},
+  choice nowit = {true=\ekdl@nowittrue,
+    false=\ekdl@nowitfalse},
+  default nowit = true,
+  unknown-choice nowit = \PackageError{ekdosis}{unknown
+    nowit=#1}{`nowit' must be either `true' or `false'.},
   code source = \def\ekdlr@source{#1},
   code resp = \def\ekdlr@resp{#1},
   code alt  = \def\ekdlr@alt{#1},
@@ -10136,6 +10255,9 @@ Sample text with a \textcolor{red}{word} in red.
   \ekdl@forcenumfalse
   \ekdl@nonumfalse
   \ekdl@ilabelfalse
+  \ifekd@mapps
+    \luadirect{tex.sprint(ekdosis.setapp_neg_pos(\luastringO{\ekdan@type}))}%
+  \fi
   \ekvset{lem}{#1}%
   \ifekdl@ilabel
   \luadirect{ekdosis.dolnlab(\luastringN{#2},
@@ -10145,12 +10267,12 @@ Sample text with a \textcolor{red}{word} in red.
   \fi
   \null
   \ekd@test@lang
-  \ifekd@mapps%
-    \ifnum%
+  \ifekd@mapps
+    \ifnum
     \luadirect{tex.sprint(ekdosis.get_bagunits(\luastringO{\ekdan@type}))}
     = 1
     \boolfalse{subsq@unit@\ekdan@type}%
-    \fi%
+    \fi
     \luadirect{ekdosis.increment_bagunits(\luastringO{\ekdan@type})}%
     \def\ekd@munit@delim{%
       \luadirect{tex.sprint(ekdosis.getappdelim(\luastringO{\ekdan@type}))}}%
@@ -10231,7 +10353,9 @@ Sample text with a \textcolor{red}{word} in red.
       \ifrtl@app
         \ifdefined\ekdlr@postwit%
           \space\unexpanded\expandafter{\ekdlr@postwit}\else\fi
-        \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+        \unless\ifekdl@nowit
+          \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+        \fi
         \ifdefined\ekdlr@prewit%
           \space\unexpanded\expandafter{\ekdlr@prewit}\space\else\fi
         \ifdefined\ekdlr@resp\space\getsiglum{\ekdlr@resp}\else\fi
@@ -10239,7 +10363,9 @@ Sample text with a \textcolor{red}{word} in red.
       \else
         \ifdefined\ekdlr@prewit%
           \space\unexpanded\expandafter{\ekdlr@prewit}\space\else\fi
-        \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+        \unless\ifekdl@nowit
+          \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+        \fi
         \ifdefined\ekdlr@postwit%
           \space\unexpanded\expandafter{\ekdlr@postwit}\else\fi
         \ifdefined\ekdlr@source\space\getsiglum{\ekdlr@source}\else\fi
@@ -10290,7 +10416,9 @@ Sample text with a \textcolor{red}{word} in red.
       \fi
       \ifdefined\ekdlr@prewit%
         \space\unexpanded\expandafter{\ekdlr@prewit}\space\else\fi
-      \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+      \unless\ifekdl@nowit
+        \ifdefined\ekdlr@wit\space\getsiglum{\ekdlr@wit}\else\fi
+      \fi
       \ifdefined\ekdlr@postwit%
         \space\unexpanded\expandafter{\ekdlr@postwit}\else\fi
       \ifdefined\ekdlr@source\space\getsiglum{\ekdlr@source}\else\fi
@@ -10684,7 +10812,7 @@ Sample text with a \textcolor{red}{word} in red.
 }
 %    \end{macrocode}
 % \begin{macro}{\SetFootnotes}
-%   \changes{v1.5}{2025/04/19}{footnotes combined into a single
+%   \changes{v1.5}{2025/04/21}{footnotes combined into a single
 %   paragraph} \cs{SetFootnotes}\marg{options} can be used in the
 %   preamble or at any point of the document. |layout=paragraph|
 %   instructs \pkg{ekdosis} to combine all footnotes into a single
@@ -10915,7 +11043,7 @@ Sample text with a \textcolor{red}{word} in red.
 % \end{macro}
 % \paragraph{Lacunae}
 % \begin{macro}{\ilabel}
-% \changes{v1.5}{2025/04/19}{recalls and sets the ending label of
+% \changes{v1.5}{2025/04/21}{recalls and sets the ending label of
 % lemmas used to mark lacunae in witnesses} When \cs{lem} has been
 % used with the optional argument |ilabel=<label>|,
 % \cs{ilabel}\marg{label} must be used to mark the point where the
@@ -11255,7 +11383,7 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}{\ekdEOprint}
-% \changes{v1.5}{2025/04/19}{Sets headers and footers on
+% \changes{v1.5}{2025/04/21}{Sets headers and footers on
 % \enquote{paired} facing pages}
 % To set headers and footers on \enquote{paired} facing pages,
 % \cs{ekdEOprint} accepts two mandatory, self-evident arguments, like
@@ -11295,7 +11423,7 @@ Sample text with a \textcolor{red}{word} in red.
 % counter to set the value of the page numbers. This counter should be
 % incremented every two pages.
 % \begin{counter}{pairedpage}
-% \changes{v1.5}{2025/04/19}{A counter incremented every two pages}
+% \changes{v1.5}{2025/04/21}{A counter incremented every two pages}
 % |pairedpage| is first set as a global counter:---
 %    \begin{macrocode}
 \newcounter{pairedpage}
@@ -11303,19 +11431,19 @@ Sample text with a \textcolor{red}{word} in red.
 %    \end{macrocode}
 % \end{counter}
 % \begin{macro}{\setpairedpagenum}
-%   \changes{v1.5}{2025/04/19}{sets the same page number on paired
+%   \changes{v1.5}{2025/04/21}{sets the same page number on paired
 %   pages} \cs{setpairedpagenum}\marg{number} is used just ahead of
 %   the alignment environment to set the number of the first left-hand
 %   paired page.
 % \begin{macro}{\setpairedpage}
-%   \changes{v1.5}{2025/04/19}{sets the page number of the first paired
+%   \changes{v1.5}{2025/04/21}{sets the page number of the first paired
 %   page} \cs{setpairedpage} is an argument-less command meant to be
 %   issued in commands used to set headers or footers before
 %   \cs{thepage}. This command has the counter |pairedpage|
 %   incremented on right-hand pages only, and sets |page| $\leftarrow$
 %   |pairedpage| on every page.
 % \begin{macro}{\resetpagenumber}
-%   \changes{v1.5}{2025/04/19}{resets normal running page numbers}
+%   \changes{v1.5}{2025/04/21}{resets normal running page numbers}
 %   \cs{resetpagenumber} must be used right out of \enquote{mirrored}
 %   paired pages alignment environments. This argument-less command
 %   corrects any numbering error on the page following the edition
@@ -12333,7 +12461,13 @@ local function app_totei(str)
 		 opt = string.sub(opt, 2, -2)
 		 arg = string.sub(arg, 2, -2)
 		 opt = get_attr_value(opt, "type")
-		 if opt ~= "" then opt = " type=\""..opt.."\"" else end
+		 if opt ~= ""
+		 then
+		    opti = "apptype={"..opt.."}"
+		    opt = " type=\""..opt.."\""
+		    arg = string.gsub(arg, "(\\lem%s?%[)", "%1"..opti..",")
+		 else
+		 end
 		 return app_totei(string.format("<%s%s>%s</%s>",
 						cmd, opt, arg, cmd))
    end)
@@ -12365,6 +12499,201 @@ local function rdgGrp_totei(str)
    return str
 end
 
+-- handle multiple layers in apparatuses
+--
+local apparatuses = {}
+local bagunits = {}
+local glimit = nil
+local gunits = 0
+
+function ekdosis.newapparatus(teitype,
+			      appdir,
+			      apprule,
+			      appdelim,
+			      appsep,
+			      appsubsep,
+			      appbhook,
+			      appehook,
+			      applimit,
+			      applang,
+			      appnotelang,
+                              appnegative,
+			      appTEInegative)
+   if isintable(apparatuses, teitype)
+   then
+      tex.print("\\unexpanded{\\PackageWarning{ekdosis}{\""
+		   ..teitype..
+		   "\" already exists.}}")
+   else
+      table.insert(apparatuses, {a = teitype,
+				 direction = appdir,
+				 rule = apprule,
+				 delim = appdelim,
+				 sep = appsep,
+				 subsep = appsubsep,
+				 bhook = appbhook,
+				 ehook = appehook,
+				 limit = applimit,
+				 lang = applang,
+				 notelang = appnotelang,
+				 negative = appnegative,
+				 TEInegative = appTEInegative})
+   end
+   bagunits[teitype] = 1
+   return true
+end
+
+function ekdosis.getapplang(teitype)
+   i = get_a_index(teitype, apparatuses)
+   if apparatuses[i].lang ~= ""
+   then
+      return apparatuses[i].lang
+   else
+      return "\\languagename"
+   end
+end
+
+function ekdosis.getappnotelang(teitype)
+   i = get_a_index(teitype, apparatuses)
+   if apparatuses[i].notelang ~= ""
+   then
+      return apparatuses[i].notelang
+   else
+      return "\\languagename"
+   end
+end
+
+function ekdosis.setapp_neg_pos(teitype)
+   i = get_a_index(teitype, apparatuses)
+   if apparatuses[i].negative == "yes"
+   then
+      return "\\csname ekdl@nowittrue\\endcsname"
+   else
+      return ""
+   end
+end
+
+local function getapp_TEI_neg_pos(teitype)
+   i = get_a_index(teitype, apparatuses)
+   if apparatuses[i].TEInegative == "yes"
+   then
+      return "yes"
+   else
+      return "no"
+   end
+end
+
+function ekdosis.getappdelim(str)
+   for i = 1,#apparatuses
+   do
+      if apparatuses[i].a == str then
+	 delimfound = apparatuses[i].delim
+	 break
+      end
+   end
+   return delimfound
+end
+
+function ekdosis.get_bagunits(teitype)
+   return bagunits[teitype]
+end
+
+local function getapplimit(teitype)
+   for i = 1,#apparatuses
+   do
+      if apparatuses[i].a == teitype then
+	 limitfound = apparatuses[i].limit
+	 break
+      end
+   end
+   if tonumber(limitfound) ~= nil
+   then
+      if tonumber(limitfound) < 10
+      then
+	 return 0
+      else
+	 return limitfound
+      end
+   else
+      return 0
+   end
+end
+
+function ekdosis.limit_bagunits(teitype)
+   local limit = tonumber(getapplimit(teitype))
+   if glimit then
+      glimit = tonumber(glimit)
+      gunits = tonumber(gunits)
+      if glimit >= 10 and gunits >= glimit
+      then
+	 bagunits[teitype] = 2
+	 gunits = 0
+	 return "\\pagebreak"
+      else
+	 if limit >= 10 and bagunits[teitype] >= limit
+	 then
+	    bagunits[teitype] = 2
+	    gunits = 0
+	    return "\\pagebreak"
+	 else
+	    return ""
+	 end
+      end
+   else
+      if limit >= 10 and bagunits[teitype] >= limit
+      then
+	 bagunits[teitype] = 2
+	 gunits = 1
+	 return "\\pagebreak"
+      else
+	 return ""
+      end
+   end
+end
+
+function ekdosis.addto_bagunits(teitype, n)
+   n = tonumber(n)
+   if glimit then gunits = gunits - n end
+   if tonumber(getapplimit(teitype)) ~= 0
+   then
+      bagunits[teitype] = bagunits[teitype] - n
+   end
+end
+
+function ekdosis.increment_bagunits(teitype)
+   if glimit then gunits = gunits + 1 end
+   bagunits[teitype] = (bagunits[teitype] or 0) + 1
+end
+
+function ekdosis.setglimit(n)
+   if math.tointeger(n)
+   then
+      glimit = math.tointeger(math.abs(n))
+   else
+      glimit = nil
+   end
+end
+
+local function reset_bagunits()
+   if glimit then gunits = 0 end
+   for i = 1,#apparatuses
+   do
+      bagunits[apparatuses[i].a] = 1
+   end
+end
+
+local negative_apparatus = false
+
+function ekdosis.set_negpos_apparatus(str)
+   if str == "neg"
+   then
+      negative_apparatus = true
+   else
+      negative_apparatus = false
+   end
+   return true
+end
+
 local function lem_rdg_totei(str)
    str = gsub(str,
 	      spcenc^-1 *
@@ -12379,8 +12708,20 @@ local function lem_rdg_totei(str)
 		 arg = string.sub(arg, 2, -2)
 		 -- opt = get_attr_value(opt, "wit")
 		 --
-		 teiwit = get_attr_value(opt, "wit")
-		 if teiwit ~= "" then teiwit = " wit=\""..ekdosis.getsiglum(teiwit, "tei").."\"" else end
+		 teiapptype = get_attr_value(opt, "apptype")
+		 if next(apparatuses) ~= nil
+		 then
+		    if teiapptype == "" then teiapptype = "default" end
+		    if getapp_TEI_neg_pos(teiapptype) == "yes" then negative_apparatus = true end
+		 else
+		 end
+		 if negative_apparatus and cmd == "lem"
+		 then
+		    teiwit = ""
+		 else
+		    teiwit = get_attr_value(opt, "wit")
+		    if teiwit ~= "" then teiwit = " wit=\""..ekdosis.getsiglum(teiwit, "tei").."\"" else end
+		 end
 		 teisource = get_attr_value(opt, "source")
 		 if teisource ~= "" then teisource = " source=\""..ekdosis.getsiglum(teisource, "tei").."\"" else end
 		 teiresp = get_attr_value(opt, "resp")
@@ -13881,165 +14222,6 @@ function ekdosis.setheightandprintapparatus()
    end
 end
 
--- handle multiple layers in apparatuses
---
-local apparatuses = {}
-local bagunits = {}
-local glimit = nil
-local gunits = 0
-
-function ekdosis.newapparatus(teitype,
-			      appdir,
-			      apprule,
-			      appdelim,
-			      appsep,
-			      appsubsep,
-			      appbhook,
-			      appehook,
-			      applimit,
-			      applang,
-			      appnotelang)
-   if isintable(apparatuses, teitype)
-   then
-      tex.print("\\unexpanded{\\PackageWarning{ekdosis}{\""
-		   ..teitype..
-		   "\" already exists.}}")
-   else
-      table.insert(apparatuses, {a = teitype,
-				 direction = appdir,
-				 rule = apprule,
-				 delim = appdelim,
-				 sep = appsep,
-				 subsep = appsubsep,
-				 bhook = appbhook,
-				 ehook = appehook,
-				 limit = applimit,
-				 lang = applang,
-				 notelang = appnotelang})
-   end
-   bagunits[teitype] = 1
-   return true
-end
-
-function ekdosis.getapplang(teitype)
-   i = get_a_index(teitype, apparatuses)
-   if apparatuses[i].lang ~= ""
-   then
-      return apparatuses[i].lang
-   else
-      return "\\languagename"
-   end
-end
-
-function ekdosis.getappnotelang(teitype)
-   i = get_a_index(teitype, apparatuses)
-   if apparatuses[i].notelang ~= ""
-   then
-      return apparatuses[i].notelang
-   else
-      return "\\languagename"
-   end
-end
-
-function ekdosis.getappdelim(str)
-   for i = 1,#apparatuses
-   do
-      if apparatuses[i].a == str then
-	 delimfound = apparatuses[i].delim
-	 break
-      end
-   end
-   return delimfound
-end
-
-function ekdosis.get_bagunits(teitype)
-   return bagunits[teitype]
-end
-
-local function getapplimit(teitype)
-   for i = 1,#apparatuses
-   do
-      if apparatuses[i].a == teitype then
-	 limitfound = apparatuses[i].limit
-	 break
-      end
-   end
-   if tonumber(limitfound) ~= nil
-   then
-      if tonumber(limitfound) < 10
-      then
-	 return 0
-      else
-	 return limitfound
-      end
-   else
-      return 0
-   end
-end
-
-function ekdosis.limit_bagunits(teitype)
-   local limit = tonumber(getapplimit(teitype))
-   if glimit then
-      glimit = tonumber(glimit)
-      gunits = tonumber(gunits)
-      if glimit >= 10 and gunits >= glimit
-      then
-	 bagunits[teitype] = 2
-	 gunits = 0
-	 return "\\pagebreak"
-      else
-	 if limit >= 10 and bagunits[teitype] >= limit
-	 then
-	    bagunits[teitype] = 2
-	    gunits = 0
-	    return "\\pagebreak"
-	 else
-	    return ""
-	 end
-      end
-   else
-      if limit >= 10 and bagunits[teitype] >= limit
-      then
-	 bagunits[teitype] = 2
-	 gunits = 1
-	 return "\\pagebreak"
-      else
-	 return ""
-      end
-   end
-end
-
-function ekdosis.addto_bagunits(teitype, n)
-   n = tonumber(n)
-   if glimit then gunits = gunits - n end
-   if tonumber(getapplimit(teitype)) ~= 0
-   then
-      bagunits[teitype] = bagunits[teitype] - n
-   end
-end
-
-function ekdosis.increment_bagunits(teitype)
-   if glimit then gunits = gunits + 1 end
-   bagunits[teitype] = (bagunits[teitype] or 0) + 1
-end
-
-function ekdosis.setglimit(n)
-   if math.tointeger(n)
-   then
-      glimit = math.tointeger(math.abs(n))
-   else
-      glimit = nil
-   end
-end
-
-local function reset_bagunits()
-   if glimit then gunits = 0 end
-   for i = 1,#apparatuses
-   do
-      bagunits[apparatuses[i].a] = 1
-   end
-end
-
 function ekdosis.appin(str, teitype)
    local f = io.open(tex.jobname.."_tmp.ekd", "a+")
    if next(apparatuses) == nil
-- 
cgit v1.2.3

