From last six months or so I am trying to develop a package which tries to modernize an old package, but I am stuck in the middle of it because of my inability to understand how the old package is producing the output. I don't want to lose motivation and stop developing it. I will first show the output with the old package and then show what I have done to enhance it. This package has a very complicated UI and API. I am trying to keep the UI constant, but change. The development of my new package can be tracked [here](https://git.gnu.org.ua/linguistix.git/). As I am planning to demonstrate a lot of things, I won't add screenshots, but instead request you all to install the package and test it. If you are unsure you can use the following code on a terminal: ```bash git clone git://git.gnu.org.ua/linguistix.git mkdir -p ~/texmf cd linguistix l3build install ``` I have tried to document the code for both users and developers. Agreeably it should be developed more and I am planning to give some time to it, but first I need to tackle the potential bugs in my current code and then I will move further. As the code so far deals with a lot of things, I will post multiple questions for the ease of reviewing and keeping track of things myself. This one deals with only one or two basic functionalities of the two packages. The package that I am trying to redevelop is called [`expex`](https://ctan.org/pkg/expex). It is for typesetting linguistic examples. The following is the basic use of it. ``` \documentclass{article} \usepackage{lipsum} \usepackage{expex} \begin{document} \lipsum[1-1] \ex Hello world.\xe \lipsum[1-1] \end{document} ``` At the current stage my package can duplicate this. Just changing `expex` to `linguistix` should do. For this I have used the following code in my package: The major useful change this has made in my opinion is that using LaTeX's label-ref mechanism. The `expex` package has `\getref` (& `\getfullref` which we will see later) for referring to the examples, but it has certain limitations. See for example: ``` \documentclass{article} \usepackage{lipsum} \usepackage{expex} \begin{document} Refer to example no.~(\getref{demo}). \ex<demo> Hello world.\xe Refer to example no.~(\getref{demo}). \end{document} ``` Compare this with both the packages to see the change. Also as the `expex` package is very old, it cannot support hyperlinking the examples, which `linguistix` does! So IMO this is one significant change that has occurred in the output. Here I have used a lot of spacing macros of LaTeX whereas `expex` uses TeX macros. I don't have a proper knowledge of whether what I have used produces the exact same results or not, I am just doing the comparison based on the visual outputs which might be insufficient. If you know the technicalities of TeX vs. LaTeX spacing, any suggestions regarding them will be highly appreciated. I would also like my reviewers to comment on how optimal the package interface is at the current stage. My preferred coding-style is LaTeX2e with `xparse`, but I can shift to old TeX-style code anytime when needed for boosting the performance. I am not very used to `expl3` and hence I tend to avoid writing in that style. I have certain internal macros which I have written in `xparse`. I have heard that it is a bad practice, but since I didn't know how to write them in LaTeX2e style, as of now I have kept them in `xparse` only. Any comments regarding that will be welcomed. As I said earlier, it is a pretty long code and even small definitions such as \ex have a lot of things embedded in them, so I will humbly request you all to focus on small chunks of code while reviewing. And well, if you want to submit your suggestion as merge requests, I do accept git-patches on the [tracker](https://puszcza.gnu.org.ua/bugs/?func=additem&group=linguistix) of this repository. It is a slightly off-beat method. You just have to make your changes in the git repository, create a git-patch and attach it in the discussion. I am also adding the code of the recent .sty here as some users prefer all the code to be added in the question itself, but as it is very long and contains a lot of things which I haven't explained in this post, potential reviewers are advised to refer to the documentation only which has explanations given for all the small snippets of code. ``` \ProvidesPackage{linguistix}[2022/07/18 v0.1-exp Enhanced support for linguistics.] \RequirePackage{xparse} \RequirePackage{textcomp} \RequirePackage[normalem]{ulem} \RequirePackage{amsmath,amssymb} \RequirePackage{expkv-def,expkv-opt} \NewDocumentCommand{ \head }{ m }{{#1\textdegree}} \NewDocumentCommand{ \mvcp }{ m }{% \textlangle #1\textrangle } \NewDocumentCommand{ \rmcp }{ m }{% \textlangle\sout{#1}\textrangle } \DeclareTextCommand{\textnull}{TU}{$\varnothing$} \DeclareTextCommand{\textnull}{OT1}{$\varnothing$} \DeclareTextCommand{\textnull}{T1}{$\varnothing$} \DeclareTextCommand{\textempty}{TU}{$\emptyset$} \DeclareTextCommand{\textempty}{OT1}{$\emptyset$} \DeclareTextCommand{\textempty}{T1}{$\emptyset$} \ExplSyntaxOn \NewDocumentCommand{\lng@replace}{ m m }{ \ifx#1X \str_set:Nn \l__lng_tl { #2 } \regex_replace_all:nnN { X } { {\c{theexcnt}} } \l__lng_tl \l__lng_tl \else \str_set:Nn \l__lng_tl { #2 } \regex_replace_all:nnN { A } { \c{theexptcnt} } \l__lng_tl \l__lng_tl \fi } %% Courtesy: https://topanswers.xyz/tex?q=2020#a2273 \int_new:N \l__lng_tmpa_int \NewDocumentCommand { \lng@count } { s m m o }{ \IfBooleanTF {#1} { \lng_count:nVn {#2} #3 {#4} } { \lng_count:nnn {#2} {#3} {#4} } } \cs_new_protected:Nn \lng_count:nnn { \regex_count:nnN {#1} {#2} \l__lng_tmpa_int \IfValueTF {#3} { \int_set_eq:NN #3 \l__lng_tmpa_int } { \int_to_arabic:n { \l__lng_tmpa_int } } } \cs_generate_variant:Nn \lng_count:nn { nV } \ExplSyntaxOff \ekvdefinekeys{lingset}{% skip aboveexskip = {\lng@aboveexskip}, skip belowexskip = {\lng@belowexskip}, skip numoffset = {\lng@numoffset}, skip textoffset = {\lng@textoffset}, skip labeloffset = {\lng@labeloffset}, skip belowglpreambleskip = {\lng@belowglpreambleskip}, skip aboveglpreambleskip = {\lng@aboveglpreambleskip}, skip aboveglftskip = {\lng@aboveglftskip}, store everygla = {\lng@gla@font}, new code exnoformat = {% \def\lng@exnoformat{% {% \lng@replace{X}{#1}% }% }% }, new code labelformat = {% \def\lng@labelformat{% {% \lng@replace{A}{#1}% }% }% }, choice style = {% wrap = {\def\lng@begingl@style{wrap}},% nlevel = {\def\lng@begingl@style{nlevel}}% } } \ekvoProcessLocalOptions{lingset} \NewDocumentCommand{ \lingset }{ m }{% \ekvset{lingset}{#1}% } \lingset{% aboveexskip = {2.7ex plus 0.8ex minus 0.8ex},% belowexskip = {2.7ex plus 0.8ex minus 0.8ex},% exnoformat = {(X)},% everygla = {\normalfont},% labelformat = {A.},% numoffset = {0pt},% textoffset = {1em},% labeloffset = {1em},% belowglpreambleskip = {1ex},% aboveglpreambleskip = {1ex},% aboveglftskip = {1ex}% } \newcounter{excnt} \newcounter{exptcnt} \renewcommand*{\theexptcnt}{\alph{exptcnt}} \NewDocumentCommand{ \ex }{ d{<}{>} O{} }{% \begingroup \lingset{#2}% \vspace{\lng@aboveexskip}% \refstepcounter{excnt}% \par\noindent \begin{minipage}[h]{\linewidth}% \hspace{\lng@numoffset}% \lng@exnoformat \edef\lng@ref@label{#1}% \hspace{\lng@textoffset}% \label{\lng@ref@label}% \ignorespaces } \newsavebox{\lng@tmpexbox} \newlength{\w@lng@tmpexbox} \NewDocumentCommand{ \pex }{ d{<}{>} O{} }{% \begingroup \lingset{#2}% \vspace{\lng@aboveexskip}% \refstepcounter{excnt}% \par\noindent \begin{minipage}[h]{\linewidth}% \hspace{\lng@numoffset}% \lng@exnoformat \edef\lng@ref@label{#1}% \label{\lng@ref@label}% \RenewDocumentCommand{ \a }{ d{<}{>} }{% \refstepcounter{exptcnt}% \IfValueT{##1}{% \def\lng@fullref@label{##1}% \label{\lng@fullref@label}% }% \sbox\lng@tmpexbox{% \hspace{\lng@numoffset}% \lng@exnoformat \hspace{\lng@labeloffset}% }% \settowidth{\w@lng@tmpexbox}{% \usebox{\lng@tmpexbox}% }% \ifnum\value{exptcnt}>1\relax \par\noindent \hspace{\w@lng@tmpexbox}% \lng@labelformat \hspace{\lng@textoffset}% \else \hspace{\lng@labeloffset}% \lng@labelformat \hspace{\lng@textoffset}% \fi \@ifnextchar\par\@gobble\relax \ignorespaces }% \setcounter{exptcnt}{0}% \ignorespaces } \newcount\lng@gla@dashes \newcount\lng@gla@equals \newcount\lng@glb@dashes \newcount\lng@glb@equals \newcount\lng@gla@dsneqs \newcount\lng@glb@dsneqs \newcount\lng@cnt@checks \newif\iflng@glpreamble@used \lng@glpreamble@usedfalse \newif\iflng@nlevel \providecommand{\@thirdofthree}[3]{3} \NewDocumentCommand{ \begingl }{ O{glstyle=wrap} }{% \begingroup \NewDocumentCommand{ \glpreamble }{ u{//} }{% \lng@glpreamble@usedtrue \vspace{\lng@aboveglpreambleskip}% \noindent ##1% \par \vspace{\lng@belowglpreambleskip}% }% \NewDocumentCommand{ \gla }{ u{//} }{% \iflng@glpreamble@used \sbox\lng@tmpexbox{% \hspace{\lng@numoffset}% \lng@exnoformat \hspace{\lng@labeloffset}% \lng@labelformat \hspace{\lng@textoffset}% }% \settowidth{\w@lng@tmpexbox}{% \usebox{\lng@tmpexbox}% }% \noindent \hspace{\w@lng@tmpexbox}% \fi \lng@count{-}{##1}[\lng@gla@dashes]% \lng@count{=}{##1}[\lng@gla@equals]% \lng@count{[-=]}{##1}[\lng@gla@dsneqs]% ##1% \NewDocumentCommand{ \glb }{ u{//} }{% \sbox\lng@tmpexbox{% \hspace{\lng@numoffset}% \lng@exnoformat \hspace{\lng@labeloffset}% \lng@labelformat \hspace{\lng@textoffset}% }% \settowidth{\w@lng@tmpexbox}{% \usebox{\lng@tmpexbox}% }% \noindent \hspace{\w@lng@tmpexbox}% ####1% \lng@count{-}{####1}[\lng@glb@dashes]% \lng@count{=}{####1}[\lng@glb@equals]% \lng@count{[-=]}{####1}[\lng@glb@dsneqs]% \ifnum\lng@gla@dsneqs=\lng@glb@dsneqs\relax \ifnum\lng@gla@dashes>\lng@glb@dashes\relax % \gla -==// % \gla ===// \PackageError{linguistix}% {% Found less dashes and more equals in the gloss% \MessageBreak than in the transcription% }% {% Unbalanced number of dashes and/or equals in one of your examples. Please% \MessageBreak correct the code.% }% \else \ifnum\lng@gla@dashes=\lng@glb@dashes\relax % \gla -==// % \glb -==// % The only case where the user have glossed % without errors, hence this is silent. \else % \gla -==// % \glb --=// \PackageError{linguistix}% {% Found more dashes and less equals in the gloss% \MessageBreak than in the transcription% }% {% Unbalanced number of dashes and/or equals in one of your examples. Please% \MessageBreak correct the code.% }% \fi \fi \else \ifnum\lng@gla@dashes=\lng@glb@dashes\relax \ifnum\lng@gla@equals>\lng@glb@equals\relax % \gla -==// % \glb -=// \PackageError{linguistix}% {% Found less equals in the gloss than in the% \MessageBreak transcription% }% {% Unbalanced number of dashes and/or equals in one of your examples. Please% \MessageBreak correct the code.% }% \else % \gla -==// % \glb -===// \PackageError{linguistix}% {% Found more equals in the gloss than in the% \MessageBreak transcription% }% {% Unbalanced number of dashes and/or equals in one of your examples. Please% \MessageBreak correct the code.% }% \fi \fi \ifnum\lng@gla@equals=\lng@glb@equals\relax \ifnum\lng@gla@dashes>\lng@glb@dashes\relax % \gla -==// % \glb ==// \PackageError{linguistix}% {% Found less dashes in the gloss than in the% \MessageBreak transcription% }{}% \else % \gla -==// % \glb --==// \PackageError{linguistix}% {% Found more dashes in the gloss than in the transcription% }{}% \fi \fi % Here we have unbalanced number of the total % dashes and equals used in \gla and \glb. We have % produced errors where one of dashes or equals % were equal in number. Now we check if both of % them are unequal. \ifnum \ifnum\lng@gla@dashes=\lng@glb@dashes\@sptoken % \gla-dashes=\gla-dashes \ifnum\lng@gla@equals=\lng@glb@equals\@sptoken % \gla-equals=\glb-equals 1% Print 1 when true \else 0% Print 0 when false \fi \else 0% Print 0 when false \fi =% 1\@sptoken \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi {}% {% \ifnum\lng@gla@dashes>\lng@glb@dashes\relax % \gla --// % \gla -// \PackageError{linguistix}% {% Found less dashes in the gloss than in the transcription% }{}% \else % \gla -// % \gla --// \PackageError{linguistix}% {% Found more dashes in the gloss than in the transcription% }{}% \fi \ifnum\lng@gla@equals>\lng@glb@equals\relax % \gla ==// % \gla =// \PackageError{linguistix}% {% Found less equals in the gloss than in the transcription% }{}% \else % \gla =// % \gla ==// \PackageError{linguistix}% {% Found more equals in the gloss than in the transcription% }{}% \fi }% \fi \par }%\glc \par }% \NewDocumentCommand{ \glft }{ u{//} }{% \vspace{\lng@aboveglftskip}% \sbox\lng@tmpexbox{% \hspace{\lng@numoffset}% \lng@exnoformat \hspace{\lng@labeloffset}% \lng@labelformat \hspace{\lng@textoffset}% }% \settowidth{\w@lng@tmpexbox}{% \usebox{\lng@tmpexbox}% }% \noindent \hspace{\w@lng@tmpexbox}% ##1% }% \NewDocumentCommand{ \endgl }{ }{% \endgroup }% } \NewDocumentCommand{ \xe }{ }{% \end{minipage}% \endgroup \vspace{\lng@belowexskip}% } \NewDocumentCommand{ \getref }{ m }{\ref{#1}} \NewDocumentCommand{ \lng@getfullref }{ m m }{% \ref{#1}\ref{#2}% } \NewDocumentCommand{ \getfullref }{ O{.} >{\SplitList{#1}} m }{% \lng@getfullref#2 } \NewDocumentCommand{ \nextx }{ }{% \addtocounter{excnt}{1}% \theexcnt \addtocounter{excnt}{-1}% \PackageWarning{linguistix}{% You are highly discouraged to use the \string\nextx\space \MessageBreak command. Please instead use the real label-ref% \MessageBreak mechanism of LaTeX (i.e. \string\label{x}, \string\ref{x}). For% \MessageBreak discussion related to this, please refer to the% \MessageBreak section titled `What to avoid from package expex?'% \MessageBreak in the documentation of the linguistix package.% \MessageBreak I found \string\nextx }% } \NewDocumentCommand{ \lastx }{ }{% \theexcnt \PackageWarning{linguistix}{% You are highly discouraged to use the \string\lastx\space \MessageBreak command. Please instead use the real label-ref% \MessageBreak mechanism of LaTeX (i.e. \string\label{x}, \string\ref{x}). For% \MessageBreak discussion related to this, please refer to the% \MessageBreak section titled `What to avoid from package expex?'% \MessageBreak in the documentation of the linguistix package.% \MessageBreak I found \string\lastx }% } \endinput ```