% \iffalse meta-comment
%
% File: linguistix.dtx
%
% ----------------------------------------------------------
% The LaTeX bundle LinguisTiX v0.8
% Copyright © 2025, 2026 निरंजन
%
% This program is free software: you can redistribute it
% and/or modify it under the terms of the GNU General Public
% License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any
% later version.
%
% This program is distributed in the hope that it will be
% useful, but WITHOUT ANY WARRANTY; without even the implied
% warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
% PURPOSE. See the GNU General Public License for more
% details.
%
% You should have received a copy of the GNU General Public
% License along with this program. If not, see
% <https://www.gnu.org/licenses/>.
% ----------------------------------------------------------
%
% \fi
% \iffalse
%<*internal>
\iffalse
%</internal>
%<*readme>
------------------------------------------------------------
Bundle:       LinguisTiX
Version:      v0.8
Author:       निरंजन
Description:  Enhanced support for linguistics.
Repository:   puszcza.gnu.org.ua/projects/linguistix
License:      GPLv3+
------------------------------------------------------------
%</readme>
%<*internal>
\fi
%</internal>
%<*driver>
\begin{filecontents}[overwrite]{\jobname.bib}
@book{bringhurst,
  title             = {The elements of typographic style},
  author            = {Bringhurst, Robert},
  date              = {2004},
  publisher         = {Point Roberts, WA: Hartley \& Marks,
                        Publishers},
  edition           = {4}
}
@online{alan,
  author  = {Munn, Alan and Gregorio, Enrico},
  title   = {{\textsf{ExPex} fails with
    \textsf{unicode-math}. How to avoid the clash?}},
  url     = {https://tex.stackexchange.com/q/703094},
  date    = {2023-12-05},
  urldate = {2025-12-21}
}
\end{filecontents}
\documentclass{l3doc}
\usepackage{unicode-math}
\usepackage{linguistix}
\usepackage{xcolor}
\usepackage{longtable}
\usepackage{fontawesome5}
\usepackage{hyperxmp}
\usepackage[verbose=silent]{microtype}
\usepackage{cleveref}
\usepackage{hologo}
\linguistix{old style one,languages={british,marathi}}
\usepackage[style=authoryear,backend=biber]{biblatex}
\addbibresource{\jobname.bib}

\setlength{\LTpost}{0pt}
\setlength{\LTcapwidth}{4.5in}

\DeclareMicrotypeAlias{NewCMUncial10-Book.otf}{TU-basic}
\setquotestyle{british}

\colorlet{lngxredcolor}{red!50!black}
\colorlet{lngxgreencolor}{green!50!black}
\colorlet{lngxbluecolor}{blue!50!black}

\setmathfont[%
  CharacterVariant       = {1},%
  version                = {emptyset}%
]{NewCMMath-Book.otf}

\IfPackageLoadedT{lua-unicode-math}{%
  \DeclareMathVersion{emptyset}%
}

\urlstyle{tt}

\hypersetup{%
  unicode,%
  colorlinks,%
  linkcolor              = {lngxredcolor},%
  citecolor              = {lngxgreencolor},%
  urlcolor               = {lngxbluecolor},%
  pdftitle               = {The LinguisTiX bundle},%
  pdfauthor              = {निरंजन},%
  pdfsubject             = {%
    Enhanced support for linguistics.%
  },%
  pdfcreator             = {निरंजन},%
  pdfkeywords            = {Linguistics, LaTeX},%
  pdfcopyright           = {%
    The LaTeX bundle LinguisTiX\textLF
    Copyright © 2025, 2026 निरंजन\textLF
    This program is free software: you can redistribute it
    and/or modify it under the terms of the GNU General
    Public License as published by the Free Software
    Foundation, either version 3 of the License, or (at your
    option) any later version.%
  },%
  pdflicenseurl          = {gnu.org/licenses/gpl-3.0.html}%
}%

\newfontfamily\newcmnewone[%
  IgnoreFontspecFile,%
  Numbers                = {OldStyle}%
]{NewCM10-Book.otf}

\newfontfamily\newcmnewnum[%
  IgnoreFontspecFile%
]{NewCM10-Book.otf}

\newfontfamily\mrfnt[%
  IgnoreFontspecFile,%
  Script                 = {Devanagari},%
  Language               = {Marathi},%
  Renderer               = {HarfBuzz}%
]{Mukta-Light.ttf}

\newfontfamily\lngxcondensed[%
  IgnoreFontspecFile,%
  FakeStretch            = {0.7},%
  BoldFont               = {NewCMMono10-Bold.otf},%
  ItalicFont             = {NewCMMono10-BookItalic.otf},%
  Renderer               = {HarfBuzz}%
]{NewCMMono10-Book.otf}

\makeatletter

\setlength{\columnsep}{2pc}
\setlength{\columnseprule}{0.2pt}

\NewDocumentCommand \lngxtoc {  } {%
  %% Courtesy: John Kormylo
  %% https://tex.stackexchange.com/a/606678
  %% CC-BY-SA 4.0 International
  \setcounter{tocdepth}{1}%
  \section*{%
    \makebox[\linewidth][l]{\contentsname}%
    \@mkboth{%
      \MakeUppercase{\contentsname}%
    }{%
      \MakeUppercase{\contentsname}%
    }%
  }%
  \begin{multicols}{2}%
    \small
    \begingroup
    \hypersetup{hidelinks}%
    \@starttoc{toc}%
    \endgroup
  \end{multicols}%
}

\NewDocumentCommand \lngxdocumentation { m } {%
  \section[\csname lngx#1logo\endcsname]{%
    \csname lngx#1logo\endcsname\hfill
    \hyperref[lngx#1l3]{%
      \footnotesize\LaTeX3-interface%
    } \textbar{}
    \hyperref[lngx#1imp]{%
      \footnotesize Implementation%
    }%
  }%
  \label{lngx#1doc}%
  \addtocontents{toc}{%
    % Courtesy: samcarter
    % https://topanswers.xyz/tex?q=8120
    % LPPL 1.3c+
    \hspace*{0.5em}%
    \texorpdfstring{%
      \begingroup
      \scriptsize
      Interface\dots\
      \hyperref[lngx#1l3]{%
        \color{lngxredcolor}%
        \textsf{%
          \pageref{lngx#1l3}%
        }%
      };
      \scriptsize
      Implementation\dots\
      \hyperref[lngx#1l3]{%
        \color{lngxredcolor}%
        \texttt{%
          \addfontfeatures{%
            Numbers=OldStyle,CharacterVariant={6}%
          }%
          \pageref{lngx#1imp}%
        }%
      }%
      \endgroup
    }{%
      \csname lngx#1logo\endcsname
    }%
  }%
}

\NewDocumentCommand \lngxinterface { m } {%
  \phantomsection
  \subsection*{%
    \csname lngx#1logo\endcsname\hfill
    \hyperref[lngx#1doc]{%
      \footnotesize Documentation%
    } \textbar{}
    \hyperref[lngx#1imp]{%
      \footnotesize Implementation%
    }%
  }%
  \label{lngx#1l3}%
}

\NewDocumentCommand \lngximplementation { m } {%
  \phantomsection
  \subsection*{%
    \csname lngx#1logo\endcsname\hfill
    \hyperref[lngx#1doc]{%
      \footnotesize Documentation%
    } \textbar{}
    \hyperref[lngx#1l3]{%
      \footnotesize\LaTeX3-interface%
    }%
  }%
  \label{lngx#1imp}%
}

\NewDocumentCommand \bLaTeX {  } {%
  (\kern-0.035em\relax
  L\kern-.81ex\relax
  \raisebox{.6ex}{\textsc{a}}\kern-.23ex\relax
  )\kern-0.065em\relax
  \hbox{T}\kern-.4ex\relax
  \raisebox{-.5ex}{E}\kern-.3ex\relax
  X%
}
\makeatother

\colorlet{lngxpurplecolor}{blue!50!red}

\def\lngxtval{%
  \begingroup
  \color{lngxredcolor}%
  true%
  \endgroup
  \,|\,false%
}

\def\lngxfval{%
  true%
  \,|\,%
  \begingroup
  \color{lngxredcolor}%
  false%
  \endgroup
}

\ExplSyntaxOn
\cs_new_protected:Npn \lngx_plain_logo:n #1 {
  \group_begin:
  \lngx_logo_font:
  LinguisTi
  \color_group_begin:
  \color_select:n { lngx_purple_color }
  X
  \color_group_end:
  -
  #1
  \group_end:
}

\cs_gset_eq:NN \plainlngxlogo \lngx_plain_logo:n

\msg_redirect_name:nnn { l3doc }
                       { foreign-internal }
                       { none }

\RenewDocumentCommand \lngxlogo { O{} } {%
  \group_begin:
  \hypersetup { hidelinks }
  \hyperref [
    lngx
    \IfBlankTF { #1 } { } { #1 doc }
  ] {
    \lngx_logo_font:
    LinguisTi
    \color_group_begin:
    \color_select:n { lngx_purple_color }
    X
    \color_group_end:
    \IfBlankF { #1 } { - #1 }
  }
  \group_end:
}

\NewDocumentCommand \fn { v }{
  \phantomsection
  \__codedoc_function_index:n  { #1 }
  \__codedoc_function_label:nN { #1 } \c_false_bool
  #1
}

\RenewDocumentCommand \MacroLongFont {  } {
  \lngxcondensed
}
\ExplSyntaxOff

\makeatletter
\NewDocumentCommand \supportfootnote { +m } {%
  \begingroup
  \def\thefootnote{}%
  \let\@makefnmark\relax
  \let\@makefntext\relax
  \let\hyper@makecurrent\@empty
  \footnotetext{%
    \hspace*{-\parindent}%
    #1%
  }%
  \endgroup
}

\renewenvironment{theindex}{%
  \index@prologue
  \medskip

  \let\item\@idxitem \ignorespaces
}{}
\makeatother

\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% \title{^^A
%   \phantomsection\label{lngx}^^A
%   The \lngxpkg\ bundle^^A
% }
% \author{निरंजन}
% \date{^^A
%   \today\ (v0.8)\\[1ex]^^A
%   {^^A
%     \small\faIcon{home}\quad
%     \url{^^A
%       https://ctan.org/pkg/linguistix^^A
%     }\\[0.5ex]^^A
%     \small\faIcon{git-alt}\quad
%     \url{^^A
%       https://puszcza.gnu.org.ua/projects/linguistix^^A
%     }\\[0.5ex]^^A
%     \small\faIcon[regular]{comments}\quad
%     \url{^^A
%       https://matrix.to/\#/\#linguistix:matrix.org^^A
%     }^^A
%   }^^A
% }
%
% \maketitle
%
% \supportfootnote{^^A
%   The \lngxpkg\ bundle
%
%   \noindent
%   Copyright © 2025, 2026 निरंजन
%
%   This program is free software: you can redistribute it
%   and/or modify it under the terms of the \textsc{gnu}
%   General Public License as published by the Free Software
%   Foundation, either version 3 of the License, or (at your
%   option) any later version.
%
%   This program is distributed in the hope that it will be
%   useful, but \emph{\textbf{without any warranty}};
%   without even the implied warranty of
%   \emph{\textbf{merchantability}} or \emph{\textbf{fitness
%   for a particular purpose}}. See the \textsc{gnu} General
%   Public License for more details.
%
%   You should have received a copy of the GNU General
%   Public License along with this program. If not, see
%   \url{https://www.gnu.org/licenses/}.^^A
% }
%
% \begin{documentation}
%
% \begin{abstract}
%   There are quite a few \LaTeX\ packages that support
%   typesetting in linguistics, but most of them lack a
%   modern \LaTeX-like users syntax as well as a programming
%   interface. The \lngxpkg\ bundle fills this gap. It
%   contains several packages enhancing the general support
%   for linguistics in \LaTeX. This is a comprehensive
%   documentation of the same comprising of three parts. The
%   first one is the general users manual, the second one
%   documents the programming interface of the bundle,
%   whereas the last one is the documented implementation of
%   all the packages.
% \end{abstract}
%
% \lngxtoc ^^A Custom command defined in the preamble.
%
% \newpage
%
% ^^A Based on egreg’s answer:
% ^^A https://tex.stackexchange.com/a/102849
% \begingroup
% \thispagestyle{empty}^^A no header and footer.
% \vspace*{\stretch{1}}^^A some space at the top.
% \itshape             ^^A to get the text in italics.
% \raggedleft          ^^A flush to the right margin.
% Dedicated to Renuka who taught me rigour under the guise
% of linguistics\dots
% \par                 ^^A end the paragraph
% \vspace{\stretch{3}} ^^A space at bottom is thrice that
% \endgroup
% \newpage
%
% \section{Introduction}
%
% Linguistics is a discipline that studies the phenomenon of
% language and for this linguists analyse data from
% languages across the globe. In order to be able to present
% the data that is collected for this, linguists use several
% representational methods that lead to a fiasco when their
% typesetting is considered. In order to understand the
% complexity of the task at hand, first, let’s have a look
% at some of the problem cases. If you are an impatient
% reader and are just willing to read the users manual, you
% may skip reading the current section and start with
% \cref{lngxbasedoc} and the ones following it.
%
% \subsection{Phonetic symbols}
%
% Speech sounds are the building blocks of many human
% languages and the data collected from languages demands an
% unambiguous method of representation which is served by
% the International Phonetic Alphabet. For the longest time,
% the \textsc{tipa} package
% (\url{https://ctan.org/pkg/tipa}) was the one that
% produced phonetic symbols in \bLaTeX. Visually, it matches
% the default Computer Modern design of \bLaTeX, but
% \textsc{tipa} is not Unicode. It is set in a legacy
% encoding. With the recent developments, the New Computer
% Modern family supports all the \textsc{ipa} characters
% (even the ones that are missing in \textsc{tipa}). They
% are created keeping in mind the principles of Knuth’s
% Computer Modern. Additionally, the family also supports
% sans serif (recommended in presentations) and mono
% (recommended in coding context) families. It supports two
% weights, i.e., book and regular respectively. The book
% weight is slightly thicker than the regular weight, but
% the regular one matches the thickness of the Computer
% Modern design. Because of the increased thickness, the
% former looks better. The current document, for example, is
% typeset in the book weight of New Computer Modern. If you
% are like me, you probably don’t like using
% non-\LaTeX-fonts. The good news is that the requirements
% of linguistics are very well fulfilled by the recent
% developments in the New Computer modern family and it
% \emph{does} belong to the fraternity of \LaTeX-fonts.
%
% Apart from this, there are some other advantages of the
% New Computer Modern fonts. The \textsc{ipa} distinguishes
% between \ipatext{a} and \ipatext{ɑ}, but unfortunately, in
% Italic shape, the latter is a variant of the former. E.g.,
% |[a\textit{a}]| produces \enquote{[a\textit{a}]}. Whenever
% an author uses Italic shape for their transcription and
% use |a|, a wrong \textsc{ipa} symbol is printed with most
% fonts. This problem was kindly acknowledged by Antonis
% Tsolomitis, the developer of New Computer Modern. In the
% stylistic set dedicated for linguistics, the correct shape
% was added to the Italic shape by him. Thus,
% |\ipatext{a\textit{a}}| (a command from \lngxipalogo)
% renders \enquote{\ipatext{a\textit{a}}}. The package
% enables New Computer Modern family with stylistic set 05
% dedicated for \textsc{ipa}. It also adds the brackets or
% slashes around the argument as explained in
% \cref{lngxipadoc}.
%
% A similar problem is with the character |g|. E.g.,
% |[g\textit{g}]| produces \enquote{[g\textit{g}]}. Here,
% the situation is the other way round. The upright
% \enquote{g} is not recognised by the \textsc{ipa}. The
% \textsc{ipa} charts generally have the upright version of
% the Italic shape. To see what this means, try
% |\ipatext{g\textit{g}}|. It produces
% \ipatext{g\textit{g}} and not [g\textit{g}].
%
% In order to avail all of these features, I have set New
% Computer Modern as the default font-family of \lngxpkg.
% The bundle provides options to control these defaults.
% Users can use their preferred text and \textsc{ipa} fonts.
% There also is an option to use the regular weight of NewCM
% instead of the book weight.
%
% \section{Planned}
%
% I plan to develop this bundle further in order to support
% the typesetting of good quality examples with interlinear
% glossing. My model is to imitate the output of the
% \pkg{expex} package, but with a modern \LaTeX-like syntax.
%
% \section{Funding}
%
% I am a doctorate student without a fellowship (thanks to
% our education policies!) currently sustaining only with a
% full time job unrelated to linguistics that consumes most
% of my working hours. At times, it becomes difficult to
% continue the research, the job and the passion development
% projects. \lngxpkg\ needs funding in order to sustain. If
% you think you can support it, you can contact me on the
% email \textsc{id} found on the front page.
%
% As of 2025-05-29, I have recieved funding from the \TeX\
% users group’s \TeX\ development fund. They have decided to
% support the development of \enquote{linguistix-glossing}
% (the logo will be available once the package is ready).
%
% An experimental version of \lngxglossinglogo\ is released
% on 2026-01-19. This version is for testing and getting
% feedback from the community. This marks the completion of
% the first grant provided by the \TeX\ users group’s. The
% project will still continue to develop further, so funding
% initiatives will be highly appreciated.
%
% \section{Acknowledgements}
%
% This package relies the most on the New Computer Modern
% font family. I would like to express my gratitude to
% Antonis Tsolomitis who tirelessly worked on the set of
% \textsc{ipa} symbols and brought back the good old charm
% of \textsc{tipa}’s design in the modern Unicode world. I
% would like to thank Renuka and Avinash who taught me
% linguistics. They nourished my passion, helped me pursue
% my love for the subject as well as the computation that
% came along with it. I could have never imagined myself
% working on a package written in \LaTeX3’s syntax. Not so
% long ago, I used to find it very complicated. It’s mostly
% Jonathan Spratte and Florent Rougon’s help (and, at times,
% scolding :P) that helped me get used to it. I would also
% like to mention C.V.\ Radhakrishnan for being an important
% part of my journey in \LaTeX. Lastly, to all the free
% software people who have created this friendly and
% supportive world for people by investing their precious
% time and resources!
%
% Hardly in a week after the initial release, the \TeX\
% users group decided to financially support the development
% of a planned package in the bundle. I am grateful to them
% for their support.
%
% \section*{Documentation}
%
% The bundle is comprised of several packages that are
% developed for different purposes. In order to load all the
% packages of the bundle, one can issue:
%
% \begin{verbatim}
%     \usepackage{linguistix}
% \end{verbatim}
%
% This is the easiest method for getting all of
% \lngxpkg\ in one go. But, if you don’t need all the
% packages of the bundle, you may load the required packages
% separately. We will start with the elementary package that
% sets up things for other packages of the bundle.
%
% \lngxdocumentation{base}
%
% This package provides a single command that is used in all
% the other packages of the bundle. The command is:
%
% \begin{function}{\linguistix}
% \begin{syntax}
% \marg{key-value-list}
% \end{syntax}
% We have a single set of keys for the entire bundle. Each
% package appends keys to the same set. The argument of this
% central processor command is the comma-separated
% \meta{key-value-list}. So you can load any package of
% \lngxpkg\ and use the \cs[no-index]{linguistix} command.
% The only exception to this is \lngxnfsslogo. We will see
% how it is different in its section.
% \end{function}
%
% \lngxdocumentation{fixpex}
%
% This package offers a fix for the clash between
% \pkg{expex} and \pkg{(lua)-unicode-math}. It provides a
% single command.
%
% \begin{function}{\umgla}
% This is a replica of the \pkg{(lua)-unicode-math}-|\gla|.
% Since the \pkg{expex}-|\gla| is more relevant in
% linguistics, I set it as the default. If one needs to use
% \pkg{(lua)-unicode-math}-|\gla|, they can use this
% command.
% \end{function}
%
% \lngxdocumentation{fonts}
%
% This is a package that loads the New Computer Modern
% family for the entire document. The package sets fonts for
% both text and math. It has keys for customisation for
% both. Note that just loading this package does \emph{not}
% provide any support for \textsc{ipa}. For that one needs
% \lngxipalogo\ separately.
%
% Antonis suggested a typographic enhancement for the logo
% of \LaTeX. The default logo scales the \enquote{A} and
% that affects the \enquote{colour} of the font. This is why
% I renew the logo with the code given by Antonis. The
% original logo is also available with an alternative
% command.
%
% \begin{function}{\LaTeX,\ogLaTeX}
% \begin{syntax}
% {\normalfont\LaTeX}
% {\normalfont\ogLaTeX}
% \end{syntax}
% \end{function}
%
% The package provides only these commands. Let’s now have a
% look at the keys provided for the text.
%
% \subsection{Text}
%
% Most keys of this package are prefixed with the |text| in
% order to distinguish them from the maths and \textsc{ipa}
% ones. There aren’t any commands provided by the package.
% Most of the important features of the \pkg{fontspec}
% packakge are variablised with \pkg{l3keys}.
%
% The \enquote{old style numbers} have varying heights. Some
% numbers have ascenders and some have descenders (e.g.,
% 6789). According to \cite{bringhurst}, this makes them
% easier to read in running text. Lining numbers, on the
% other hand have uniform heights. They go well with all
% capital text (rare). Thus, for the general text, I enable
% this setting by default in \lngxfontslogo.
%
% Apart from that, the New Computer Modern font family
% provides an old-style shape for the number \enquote{1}
% (this exact shape!), but it is provided as a character
% variant. Different fonts may use these arbitrary slots for
% any character’s alternation. Therefore this setting should
% not be loaded blindly. Let’s have a look at the keys that
% can be employed to change these behaviours.
%
% \begin{function}{old style numbers,old style one}
% \begin{syntax}
% = \marg{truth value}\hfill\lngxtval
% = \marg{truth value}\hfill\lngxfval
% \end{syntax}
% If one wants to disable old style numbers, they may use
% the |old style numbers| key with the |false| value
% (default is |true|)\footnote{The possible and the default
%   values of keys are given at the right side in the
%   documentation and the defaults are highlighted in
%   red.}. Note that printing of old style numbers
% also depends on whether the font you select has old style
% numbers or not. The relevant settings are added by the
% package to the font automatically, but while selecting the
% font, make sure whether the old style table is present in
% the font or not.
%
% Suppose one wants the alternative shape of number
% \enquote{1} from the New Computer Modern family, they may
% use the key |old style one| (default is false; adding
% |true| is optional).
% \end{function}
%
% Let’s have a look at the three way distinction we get
% because of this.
%
% \begin{quote}
%   {\newcmnewone 0123456789}\hfill
%   \begingroup
%   \ttfamily\footnotesize\color{lngxredcolor}^^A
%   Old style with default 1^^A
%   \endgroup
%
%   0123456789\hfill
%   \texttt{\footnotesize Old style with the old 1}^^A
%
%   {\newcmnewnum 0123456789}\hfill
%   \texttt{\footnotesize Lining}^^A
% \end{quote}
%
% \begin{function}{^^A
% newcm,newcm sans,newcm mono,^^A
% newcm regular,newcm regular sans,newcm regular mono^^A
% }
% These are some keys that come in handy for setting New
% Computer Modern defaults. All the necessary values are
% stored in these. The keys that have |regular| in their
% names refer to the \enquote{regular} variants of New
% Computer Modern fonts. These variants match the colour and
% widths of the Latin Modern fonts. One may use these keys
% to override the defaults.
% \end{function}
%
% \subsection{Maths}
%
% \lngxfontslogo\ sets maths fonts also. I have used
% \pkg{lua-unicode-math} package which is faster and which
% is said to be the future of maths in \LaTeX. But, as of
% now it is highly experimental. If you want to stick to the
% stable \pkg{unicode-math} package. The trick is simply to
% load the same before loading \lngxpkg. That will suppress
% the loading of \pkg{lua-unicode-math}. In order to control
% the settings related to maths, the following keys can be
% used.
%
% \begin{function}{^^A
%   math,math features,math bold,math bold features^^A
% }
% \begin{syntax}
% = \marg{math font}
% = \marg{math font features}
% = \marg{bold math font}
% = \marg{bold math font features}
% \end{syntax}
% The |math| and |math bold| keys set the respective fonts
% (i.e., regular and bold fonts for mathematics
% respectively). The keys suffixed with |features| set the
% font features of the same.
% \end{function}
%
% \begin{function}{bourbaki's empty set}
% \begin{syntax}
% = \marg{truth value}\hfill\lngxtval
% \end{syntax}
% In \bLaTeX, the default shape of the \enquote{empty set}
% symbol is: \enquote{\mathversion{emptyset}$\emptyset$},
% but the symbol used by the Bourbaki group is still
% considered more correct and preferred by many (including
% me). New Computer Modern Math fonts provide it by default
% and the slashed zero is provided as a character variant.
% Since the Unicode-correct |$\emptyset$| is activated by
% the package, it always renders: \enquote{$\emptyset$} and
% not: \enquote{\mathversion{emptyset}$\emptyset$}. In order
% to change this behaviour, one may use this key and set it
% to false for getting the slashed-zero of original \bLaTeX.
% Hail plumbers union, \emph{\textsc{iykyk}! ;-)}
% \end{function}
%
% \newpage
%
% \lngxdocumentation{glossing}
%
% This package provides a suit for creating interlinear
% glosses. It is supported by \TeX\ users group’s devfund.
% The package attempts to be an all-in-one solution for
% glossing. It doesn’t provide any particular glosses. It
% only provides a method to create them. Using it, one may
% easily create packages like \plainlngxlogo{leipzig} to
% support a set of glosses. The glosses created by the
% package use the new code of the \LaTeX\ project as they
% are created in a tagging aware manner. Each gloss sets a
% hyperlink to its position in the list of glosses. Let’s
% take a look at its commands and options.
%
% \begin{function}{\glx,\glx*}
% \begin{syntax}
% \marg{comma separated list of glosses}
% \marg{comma separated list of glosses}
% \end{syntax}
% These simple commands take a comma separated list as their
% argument. All the items from the list are glosses (either
% created by the user or provided by a package). Cases of
% the items given in the list are ignored. Spaces around the
% items are ignored. The regular unstarred command prints
% the glosses related to each of the item in the comma
% separated list, whereas the starred variant prints their
% expansions. Have a look at the following example.
% \end{function}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \begin{verbatim}
%     \DocumentMetadata{tagging=on,lang={en-GB}}
%     \documentclass{article}
%     \usepackage{linguistix}
%
%     \begin{document}
%     \glx{prs,pst}\par
%     \glx{ prs, pst   }\par
%     \glx{ Prs,pSt}
%
%     \glx*{prs,pst}\par
%     \glx*{ prs, pst   }\par
%     \glx*{ Prs,pST}
%     \end{document}
% \end{verbatim}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \medskip
%
% The expansions of \glx{pst} and \glx{prs} (from
% \plainlngxlogo{leipzig} package) are \glx*{pst} and
% \glx*{prs} respectively. This example produces identical
% output in three lines for glosses and the same for its
% expansions. Notice that there is no format to the cases of
% the glosses and similarly one level of spaces are trimmed.
%
% \begin{function}{\newgloss,\renewgloss}
% \begin{syntax}
% \marg{gloss} \marg{expansion}
% \marg{gloss} \marg{expansion}
% \end{syntax}
% These commands create a new gloss or renew an existing
% one. They can be accessed with the \cs{glx} command as
% explained above. Using \cs{renewgloss} mid-document is not
% recommended as it will erase the data of page numbers for
% the previous (renewed) version of it.
% \end{function}
%
% \begin{function}{\listofglosses}
% \begin{syntax}
% \oarg{setup keys}
% \end{syntax}
% This command prints the list of glosses using the default
% settings. If the optional argument is used, the
% adjustments are made locally only for a single run. E.g.:
% \end{function}
%
% \listofglosses
%
% \begin{function}{\setupglossing}
% \begin{syntax}
% \marg{keys for formatting glosses}
% \end{syntax}
% This command takes one argument, i.e., the keys that
% control everything regarding the use of glosses and their
% expansions. The keys it takes are described in the section
% that follows.
% \end{function}
%
% \subsection{Setting up the glosses}
%
% The following keys can be passed to the command
% \cs{setupglossing}. They control the printing along with a
% lot of other things regarding glosses. All the
% customisation offered by the package can be accessed via
% this command.
%
% \begin{function}{format}
% \begin{syntax}
% = \marg{formatted element gloss/expansion}\hfill^^A
% gloss\,\textbar\,expansion
% \end{syntax}
% The |format| key is used for setting the format of either
% the gloss or the expansion. It’s a meta key that takes
% other key-val pair in the argument. The nested keys
% control the formatting of the respective elements.
% \end{function}
%
% \begin{function}{gloss,expansion}
% \begin{syntax}
% = \marg{formatting commands for glosses}\hfill^^A
% {\color{lngxredcolor}|\textsc{#1}|}
% = \marg{formatting commands for glosses}
% \end{syntax}
% These keys only work inside the meta key |format|. They
% set the commands that print either the gloss or the
% expansion. |#1| refers to the printed text of them. No
% special formatting is applied to expansions by default,
% but glosses are by default printed in \cs{textsc}.
% \end{function}
%
% \begin{function}{link color}
% \begin{syntax}
% = \marg{link color}\hfill{\color{lngxredcolor}black}
% \end{syntax}
% This option locally sets the colour for the hyperlinks. By
% default they are set to the black colour.
% \end{function}
%
% \begin{function}{sort}
% \begin{syntax}
% = \marg{sorting style}\hfill^^A
% {\color{lngxredcolor}alphabetical}\,\textbar\,use
% \end{syntax}
% This key controls how the keys printed in the list of
% glosses are ordered. They may be ordered alphabetically or
% following the sequence in which they were used, the former
% being the default.
% \end{function}
%
% \begin{function}{expansion case}
% \begin{syntax}
% = \marg{case}\hfill{\color{lngxredcolor}lowercase}^^A
%\,\textbar\,title case all\,\textbar\,title case first
% \end{syntax}
% The expansion can be printed in one of these three cases.
% The default printing happens in lowercase.
% \end{function}
%
% \begin{function}{style}
% \begin{syntax}
% = \marg{glossary style}\hfill^^A
% {\color{lngxredcolor}block}\,\textbar\,inline
% \end{syntax}
% The package offers two styles. The |inline| style prints
% the glosses and their expansions without page numbers in
% the flowing text, whereas the |block| style, in default
% settings prints them in a multicolumn block with an
% unnumbered section with the glossary name.
% \end{function}
%
% \begin{function}{columns}
% \begin{syntax}
% = \marg{number of columns}\hfill{\color{lngxredcolor}2}
% \end{syntax}
% The block style of glosses is printed in multicolumn
% layout by default. If the number of columns has to be
% adjusted, this key shall be used. The default value of it
% is 2. It works with only one column too.
% \end{function}
%
% \begin{function}{page numbers}
% \begin{syntax}
% = \marg{truth value}\hfill\lngxtval
% \end{syntax}
% By default, page numbers on which a particular gloss was
% used are printed in the |block| style. This can be turned
% off with this bool key.
% \end{function}
%
% \begin{function}{sectioning}
% \begin{syntax}
% = \marg{section level}\hfill{\color{lngxredcolor}section}
% \end{syntax}
% In |block| style, a section heading is printed. In order
% to choose the level of sectioning, this command can be
% used. The default is |section| which can be changed to any
% other desired level. In addition the key allows an option
% |null| which suppresses the use of any section heading.
% \end{function}
%
% \begin{function}{section number}
% \begin{syntax}
% = \marg{truth value}\hfill\lngxfval
% \end{syntax}
% By default, the section number for the glossary is turned
% off, but if one wants to print it, this bool key can be
% used with the |true| value.
% \end{function}
%
% \begin{function}{no bold}
% \begin{syntax}
% = \marg{truth value}\hfill\lngxfval
% \end{syntax}
% Generally, the glosses are printed in bold inside
% glossary. Some fonts don’t have bold small caps (e.g.,
% Latin Modern). If you need to stick to them, you can use
% this inverse bool key with true value in order to obtain
% non-bold glosses.
% \end{function}
%
% \begin{function}{separator}
% \begin{syntax}
% = \marg{separator between glosses or expansions}
% \end{syntax}
% This is a context-sensitive key. If used with \cs{glx},
% then it sets the separator between the glosses (|,␣|~is
% the default). If used with \cs{glx*}, it sets the
% separator between the expansions (|,␣|~is the default) and
% if used with the \cs{listofglosses}, it sets the separator
% between glosses and their expansions (|:␣|~is the
% default).
% \end{function}
%
% \begin{function}{entry separator}
% \begin{syntax}
% = \marg{separator between pairs of glosses and expansions}
% \end{syntax}
% Each pair of gloss and its expansion is separated using a
% token list controlled by this key. The default is |\par|.
% \end{function}
%
% \newpage
%
% \lngxdocumentation{ipa}
%
% This package sets the fonts exclusively for the
% \textsc{ipa}. The commands provided for switching to the
% \textsc{ipa} control all serif, sans serif and typewriter
% families. This package can be loaded standalone for
% loading \textsc{ipa} fonts as well as some switch commands
% useful in running text. New Computer Modern provides a
% special stylistic set dedicated for linguistics. It is
% enabled for \textsc{ipa} fonts automatically with this
% package. Only the legally marked up \textsc{ipa} is
% affected by the customisation provided by this package.
% For switching to the \textsc{ipa}, \lngxipalogo\ provides
% one command with a starred variant.
%
% \begin{function}{\ipatext,\ipatext*}
% \begin{syntax}
% \marg{phonetic transcription}
% \marg{phonemic transcription}
% \end{syntax}
% This is a command that resembles with the
% \pkg{\textsc{tipa}} command \cs[no-index]{textipa}. I have
% deliberately kept it distinct from it so that just in case
% somebody wants to use their old \textsc{tipa} code in a
% Unicode document, the commands won’t clash (I highly
% discourage doing this, though). The command comes with a
% starred variant. The behaviour of the un-starred command
% is to print the argument in brackets for phonetic
% transcription, e.g.: |\ipatext{aɪ̯ pʰiː eɪ̯}|^^A
% \,$\longrightarrow$\,\ipatext{aɪ̯ pʰiː eɪ̯} whereas the
% starred version prints it in slashes for phonemic
% transcription, e.g.: |\ipatext*{aɪ̯ pʰiː eɪ̯}|^^A
% \,$\longrightarrow$\,\ipatext*{aɪ̯ pʰiː eɪ̯}.
% \end{function}
%
% Suppose someone just wants to load the font without the
% brackets or slashes, they can use the following command
% for switching to the \textsc{ipa} without adding the
% aforementioned.
%
% \begin{function}{\lngxipa}
% This also is a command that switches to the
% \textsc{ipa}-only features (default as well as user
% added). This command, of course, leaks and that’s why
% \emph{should} be delimited. E.g., the following code
% lines produce {\lngxipa [aɪ̯ pʰiː eɪ̯]} and {\lngxipa /aɪ̯
% pʰiː eɪ̯/} respectively:
%
% \begin{verbatim}
%     {\lngxipa [aɪ̯ pʰiː eɪ̯]}
%     {\lngxipa /aɪ̯ pʰiː eɪ̯/}
% \end{verbatim}
% \end{function}
%
% \begin{function}{^^A
% ipa newcm,ipa newcm sans,ipa newcm mono,^^A
% ipa newcm regular,ipa newcm regular sans,^^A
% ipa newcm regular mono^^A
% }
% These keys reset the \textsc{ipa}-only fonts to New
% Computer Modern. They can be used even for resetting to
% New Computer Modern from another \textsc{ipa} font. In
% order to change or reset to the \textsc{ipa} defaults
% these keys can be used. They store the names of the New
% Computer Modern font family in the variables concerning
% \textsc{ipa}. The keys that contain |regular| in their
% name use the regular version of New Computer Modern that
% matches the colour of Latin Modern.
% \end{function}
%
% Let’s now see the combined table of font keys provided by
% both \lngxfontslogo\ and \lngxipalogo.
%
% \begingroup
% \begin{longtable}{%
%   l%
%   >{%
%     \lngxcondensed
%     \addfontfeature{FakeStretch=0.8}%
%   }l%
%   >{%
%     \lngxcondensed
%     \addfontfeature{FakeStretch=0.8}%
%   }l%
% }
%   \toprule
%   Family
%     & \lngxfontslogo
%       & \lngxipalogo \\
%   \midrule
%   \endfirsthead
%   \toprule
%   Family
%     & \lngxfontslogo
%       & \lngxipalogo \\
%   \midrule
%   \endhead
%   \midrule
%   \multicolumn{3}{r}{^^A
%     \small
%     \emph{Continued on the next page\dots}^^A
%   } \\
%   \bottomrule
%   \endfoot
%   \midrule
%   \multicolumn{3}{r}{^^A
%     \small
%     \emph{End of the table\dots}^^A
%   } \\
%   \bottomrule
%   \addlinespace
%   \caption{^^A
%     Font keys provided by \lngxfontslogo\ and \lngxipalogo
%   }\label{lngxfontstable}\\
%   \endlastfoot
%   Serif
%     & \fn{text main font}
%       & \fn{ipa main font} \\
%     & \fn{text upright}
%       & \fn{ipa upright} \\
%     & \fn{text upright features}
%       & \fn{ipa upright features} \\
%     & \fn{text bold upright}
%       & \fn{ipa bold upright} \\
%     & \fn{text bold upright features}
%       & \fn{ipa bold upright features} \\
%     & \fn{text italic}
%       & \fn{ipa italic} \\
%     & \fn{text italic features}
%       & \fn{ipa italic features} \\
%     & \fn{text bold italic}
%       & \fn{ipa bold italic} \\
%     & \fn{text bold italic features}
%       & \fn{ipa bold italic features} \\
%     & \fn{text slanted}
%       & \fn{ipa slanted} \\
%     & \fn{text slanted features}
%       & \fn{ipa slanted features} \\
%     & \fn{text bold slanted}
%       & \fn{ipa bold slanted} \\
%     & \fn{text bold slanted features}
%       & \fn{ipa bold slanted features} \\
%     & \fn{text swash}
%       & \fn{ipa swash} \\
%     & \fn{text swash features}
%       & \fn{ipa swash features} \\
%     & \fn{text bold swash}
%       & \fn{ipa bold swash} \\
%     & \fn{text bold swash features}
%       & \fn{ipa bold swash features} \\
%     & \fn{text small caps}
%       & \fn{ipa small caps} \\
%     & \fn{text small caps features}
%       & \fn{ipa small caps features} \\
%   \midrule
%   Sans serif
%     & \fn{text sans font}
%       & \fn{ipa sans font} \\
%     & \fn{text sans upright}
%       & \fn{ipa sans upright} \\
%     & \fn{text sans upright features}
%       & \fn{ipa sans upright features} \\
%     & \fn{text sans bold upright}
%       & \fn{ipa sans bold upright} \\
%     & \fn{text sans bold upright features}
%       & \fn{ipa sans bold upright features} \\
%     & \fn{text sans italic}
%       & \fn{ipa sans italic} \\
%     & \fn{text sans italic features}
%       & \fn{ipa sans italic features} \\
%     & \fn{text sans bold italic}
%       & \fn{ipa sans bold italic} \\
%     & \fn{text sans bold italic features}
%       & \fn{ipa sans bold italic features} \\
%     & \fn{text sans slanted}
%       & \fn{ipa sans slanted} \\
%     & \fn{text sans slanted features}
%       & \fn{ipa sans slanted features} \\
%     & \fn{text sans bold slanted}
%       & \fn{ipa sans bold slanted} \\
%     & \fn{text sans bold slanted features}
%       & \fn{ipa sans bold slanted features} \\
%     & \fn{text sans swash}
%       & \fn{ipa sans swash} \\
%     & \fn{text sans swash features}
%       & \fn{ipa sans swash features} \\
%     & \fn{text sans bold swash}
%       & \fn{ipa sans bold swash} \\
%     & \fn{text sans bold swash features}
%       & \fn{ipa sans bold swash features} \\
%     & \fn{text sans small caps}
%       & \fn{ipa sans small caps} \\
%     & \fn{text sans small caps features}
%       & \fn{ipa sans small caps features} \\
%   \midrule
%   Monospaced
%     & \fn{text mono font}
%       & \fn{ipa mono font} \\
%     & \fn{text mono upright}
%       & \fn{ipa mono upright} \\
%     & \fn{text mono upright features}
%       & \fn{ipa mono upright features} \\
%     & \fn{text mono bold upright}
%       & \fn{ipa mono bold upright} \\
%     & \fn{text mono bold upright features}
%       & \fn{ipa mono bold upright features} \\
%     & \fn{text mono italic}
%       & \fn{ipa mono italic} \\
%     & \fn{text mono italic features}
%       & \fn{ipa mono italic features} \\
%     & \fn{text mono bold italic}
%       & \fn{ipa mono bold italic} \\
%     & \fn{text mono bold italic features}
%       & \fn{ipa mono bold italic features} \\
%     & \fn{text mono slanted}
%       & \fn{ipa mono slanted} \\
%     & \fn{text mono slanted features}
%       & \fn{ipa mono slanted features} \\
%     & \fn{text mono bold slanted}
%       & \fn{ipa mono bold slanted} \\
%     & \fn{text mono bold slanted features}
%       & \fn{ipa mono bold slanted features} \\
%     & \fn{text mono swash}
%       & \fn{ipa mono swash} \\
%     & \fn{text mono swash features}
%       & \fn{ipa mono swash features} \\
%     & \fn{text mono bold swash}
%       & \fn{ipa mono bold swash} \\
%     & \fn{text mono bold swash features}
%       & \fn{ipa mono bold swash features} \\
%     & \fn{text mono small caps}
%       & \fn{ipa mono small caps} \\
%     & \fn{text mono small caps features}
%       & \fn{ipa mono small caps features} \\
% \end{longtable}
% \endgroup
%
% Apart from these, both the packages provide the following
% keys for appending to the extra features for the
% respective fonts:
%
% \begin{itemize}
% \ttfamily
% \item \fn{text extra features}
% \item \fn{text sans extra features}
% \item \fn{text mono extra features}
% \item \fn{ipa extra features}
% \item \fn{ipa sans extra features}
% \item \fn{ipa mono extra features}
% \end{itemize}
%
% \newpage
%
% \lngxdocumentation{languages}
%
% This package is intended to provide support for loading
% Unicode fonts as well as other necessary settings for
% using languages. It is a wrapper around the \textsf{babel}
% package, but it provides some other useful settings which
% \textsf{babel} doesn’t agree to add. This package is a
% little opinionated and pushes for \enquote{modern}
% practices e.g., Unicode, Lua\LaTeX, no-markup multilingual
% text etc. As of now, only a little support is available.
% If you want your language to be supported, you can ask for
% support at the bug tracker of the repository or you can
% send an email in the public mailing list for the project.
% You may subscribe to the mailing list at:
% \url{mail.gnu.org.ua/mailman/listinfo/linguistix-languages}.
% Here, I list down some \LaTeX-aspects that may demand some
% modifications in the default settings.
%
% \begin{description}
% \item[Fonts:] The package works with Unicode and does not
%   worry about legacy methods. If you want support for your
%   language, first and foremost, you should let me know
%   standard OpenType fonts suitable for your language. Note
%   that they should be freely licensed. I won’t support
%   proprietary software with \lngxpkg.
% \item[\pkg{babel} support:] As mentioned before, the
%   package adds on to the support provided by package
%   \pkg{babel}. So check if the language files\,--\,^^A
%   specifically the modern |.ini| files\,--\,have the
%   correct settings. Sometimes they may need to undergo
%   native-speakers scrutiny. Whatever is wrong in
%   \pkg{babel}, may not get corrected in \lngxpkg.
% \item[Numbers:] \LaTeX\ uses a lot of counters and all of
%   them, by default, print Latin numerals/characters. E.g.,
%   |\arabic{page}| prints the page number in Latin, but
%   |\roman{page}| prints the same in Roman convention,
%   i.e., ‘i, ii, \dots’. Does your language allow them?
%   E.g., Greek doesn’t like Latin alphabets, but doesn’t
%   mind Roman numerals. Instead of Latin alphabets, Greek
%   prefers to use its own numeral system. Marathi doesn’t
%   like any of these, but it doesn’t have alternative forms
%   of numeration, so it changes certain cases drastically.
%   E.g., in nested |enumerate| environment, Marathi renews
%   the printing of nested |\item|s as 1, 1.1, 1.1.1 and
%   1.1.1.1. This is reset to defaults when the language is
%   changed. Keeping this in mind, I am listing down some
%   places where I found non-native numbering (I might have
%   missed something in which case it deserves to be
%   reported as a bug, so feel free to do so!).
%   \begin{enumerate}
%   \item Page numbers (in front matter, main matter).
%   \item Part numbers.
%   \item Second, third and fourth levels of enumeration.
%   \end{enumerate}
% \item[\pkg{ExPex}:] Labels provided by \pkg{ExPex} package
%   (see: \url{tex.stackexchange.com/a/548668}).
% \item[Typography:] Language-specific conventions like
%   using Italic for emphasis. It is a Latin-script specific
%   convention (note that I don’t mean slanted when I say
%   Italic). Different languages have different conventions
%   of emphasising (e.g., Marathi uses bold font for
%   emphasis).
% \item[Miscellaneous:] Anything other than these.
% \end{description}
%
% I am very much willing to support multilingual typesetting
% for multiple languages, but I need to know the things
% mentioned in this list in order to provide the best suited
% output. Please consider submitting a detailed feature
% request. The documentation of supported languages is in
% separate \textsc{pdf}s. This documentation only describes
% the user-side commands provided by the package.
%
% \begin{function}{languages,\loadlanguages}
% \begin{syntax}
% \marg{list of languages}
% \marg{list of languages}
% \end{syntax}
% This key works with the central key-parser of \lngxpkg,
% i.e., |\linguistix|. It accepts one argument that is a
% list of languages user wants to load. Unlike
% \textsf{babel}, the first element of this list is set as
% the main language for the document. The command
% |\loadlanguages| has the identical behaviour. In fact, it
% is a wrapper around the key.
% \end{function}
% \begin{function}{\providelanguage}
% \begin{syntax}
% \marg{language options} \marg{language name}
% \end{syntax}
% This is a wrapper command over |\babelprovide|. The first
% argument is passed to the optional argument of
% |\babelprovide| and the second one to the mandatory
% argument of the same. For more information, please read
% \textsf{babel}’s manual.
%
% Languages supported by \lngxlanguageslogo\ are loaded with
% a package with that language’s name. If it is absent, the
% package produces a warning.
% \end{function}
%
% \begin{function}{native numbering}
% \begin{syntax}
% = \marg{strict/logical/off}
% \end{syntax}
% Many languages need native digits. Adding them in a
% multilingual document is quite complicated. This key sets
% the plugs provided for the socket of the same name.
% Language packages already take care of them, but if you
% want to change anything mid-document, you can use this
% key. It has three choices available as its value as seen
% below.
% \end{function}
%
% \begin{function}{strict}
% The ‘strict’ plug changes the \cs{lngx_counter:n} command
% to the counter of the main language of the document. That
% way all the counters are printed in the main language.
% \end{function}
%
% \begin{function}{logical}
% This plug changes the meaning of \cs{lngx_counter:n} to
% the |\localecounter| command provided by \pkg{babel}. It
% picks up the surrounding language and uses its native
% digits. E.g., when Marathi is being typeset, it will print
% counters in Marathi. When it is changed to English, it
% will start printing the same in English. Note that this
% will reflect in table of contents/tables/figures too. It
% is called logical numbering because it obeys \TeX’s logic
% more than what is generally considered the standard. E.g.,
% imagine you have an English section followed by a Marathi
% section on the same page. Both of them will follow their
% own numerals for default \TeX\ counters. Since both of
% them are on the same page, while shipping out, the last
% active language will be used for processing the page
% number (Marathi in this case). This creates a table of
% contents with Latin numeral as the section counter, but
% Marathi numeral as the page number. Only experiments can
% determine if an option like this can have valid use-cases,
% so it is provided. If you use it, be aware that the
% results might not be the most pleasant to your aesthetic
% values. They are so because of the logic of \TeX.
% \end{function}
%
% \begin{function}{off}
% It is equivalent of the |noop| plug when the other two are
% not used at all. It is only required when you want to go
% back to \LaTeX\ defaults. E.g., if you have turned strict
% native numbering in some language and you want it to go
% back to \LaTeX\ defaults, you may use this.
% \end{function}
%
% \newpage
%
% \lngxdocumentation{logos}
%
% This is a small package that provides commands for
% printing logos of the \lngxpkg\ bundle. The logo is
% printed in New Computer Modern Uncial font. It uses purple
% colour for the \enquote{X} in it and it is defined using
% \pkg{l3color} module. It provides one command that takes
% an optional argument. Obviously it is ‘|protect|ed’. It is
% as follows:
%
% \begin{function}{\lngxlogo}
% \begin{syntax}
% \oarg{package name}
% \end{syntax}
% The logo of the \meta{package name} from the \lngxpkg\
% bundle is printed with this command, e.g.,
% |\lngxlogo[fonts]|\,$\longrightarrow$\,\lngxfontslogo.
% \end{function}
%
% Sometimes, the logos might be required to be used in an
% expandable way, but optional arguments are not supported
% in expandable commands. Thus we create separate commands
% for separate packages. Even these ones have the |lngx|
% prefix. It is followed by the package name, e.g., |fonts|
% or |ipa| and finally the suffix |logo|. In the context of
% \pkg{hyperref}, their behaviour is different than in the
% context of normal text.
%
% \newpage
%
% \lngxdocumentation{nfss}
%
% This is an extension package to the existing \textsc{nfss}
% scheme of \LaTeX. The \textsc{nfss} mainly works on the
% four facets of the text, i.e., encoding, family, shape and
% series. These facets are reset to default by the
% |\normalfont| and |\selectfont| commands. These commands
% work on some internals that are reset with every usage of
% some commands that set them, e.g., |\rmfamily|,
% |\bfseries|. There isn’t any way to control this unless
% some internals are touched and there might be incidences
% where one does want to control them, e.g., try compiling
% the following code in Lua\LaTeX.
%
% \rule{0.7\linewidth}{0.5pt}
%
% \begin{verbatim}
%     \documentclass{article}
%
%     \begin{document}
%     \makeatletter
%     \fontencoding{OT1}\sffamily\itshape\bfseries
%     \selectfont
%     \f@encoding\ | \f@family\ | \f@series\ | \f@shape\quad
%     \normalfont
%     \f@encoding\ | \f@family\ | \f@series\ | \f@shape
%     \end{document}
% \end{verbatim}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \medskip
%
% As can be seen in the output, the first line shows the
% text in \textsc{ot}1 encoding, sans family, bold series
% and Italic shape. After |\normalfont|, every aspect of the
% text is reset to the default one. The default encoding is
% \textsc{tu}. We can see \textsc{tu} instead of
% \textsc{ot}1 after |\normalfont|. So is the case with
% family (default: |\rmfamily|), series (default:
% |\mdseries|) and shape (default: |\upshape|). This usually
% is okay, but sometimes it doesn’t fit the requirement.
% E.g., the following might be used with the intention of
% switching from the \textsc{ipa} font to the text font, but
% as can be seen, it doesn’t really change anything.
%
% \rule{0.7\linewidth}{0.5pt}
%
% \begin{verbatim}
%     \documentclass{article}
%     \usepackage{linguistix-fonts}
%     \usepackage{linguistix-ipa}
%     \linguistix{%
%       text upright           = {KpRoman-Regular.otf},%
%       text upright features  = {Color={green}},%
%       ipa upright            = {KpSans-Regular.otf},%
%       ipa upright features   = {Color={red}}%
%     }
%
%     \begin{document}
%     test \lngxipa test \normalfont test
%     \end{document}
% \end{verbatim}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \medskip
%
% The reason for this is the way \cs{lngxipa} is defined. It
% resets |\rmdefault|, |\sfdefault| and |\ttdefault| and
% uses |\normalfont| to initialise this new super font
% family (see:
% \url{https://tex.stackexchange.com/a/729805}). Setting a
% \enquote{super} font family effectively changes the
% behaviour of |\normalfont| permanently. By the way, this
% is not just something that \lngxpkg\ has to deal with.
% This situation may arise whenever one wants to have a font
% family command that sets all serif, sans serif and
% monospaced font families. \lngxnfsslogo\ is useful in such
% cases. It introduces the concept of \enquote{super} font
% family. It shouldn’t be confused with
% \hologo{LaTeX2e}’s \enquote{meta} font family. It refers
% to |rm|, |sf| or |tt| in the kernel. This package provides
% control over these facets. Let’s have a look at the macros
% it provides.
%
% \begin{function}[EXP]{^^A
% \IfEncodingTF,\IfEncodingT,\IfEncodingF,\CurrentEncoding
% }
% \begin{syntax}
% \marg{encoding} \marg{true code} \marg{false code}
% \marg{encoding} \marg{true code}
% \marg{encoding} \marg{false code}
% \end{syntax}
% If the current encoding matches with the given
% \meta{encoding}, it selects the true branch; false
% otherwise. The \cs{CurrentEncoding} macro expands to the
% current encoding.
% \end{function}
%
% \begin{function}[EXP]{^^A
% \IfMetaFamilyTF,\IfMetaFamilyT,\IfMetaFamilyF,^^A
% \CurrentMetaFamily
% }
% \begin{syntax}
% \marg{meta family} \marg{true code} \marg{false code}
% \marg{meta family} \marg{true code}
% \marg{meta family} \marg{false code}
% \end{syntax}
% If the current meta family matches with the given
% \meta{meta family}, it selects the true branch; false
% otherwise. The \cs{CurrentMetaFamily} macro expands to the
% current meta family.
% \end{function}
%
% \begin{function}[EXP]{^^A
% \IfSuperFamilyTF,\IfSuperFamilyT,\IfSuperFamilyF,^^A
% \CurrentSuperFamily
% }
% \begin{syntax}
% \marg{super family} \marg{true code} \marg{false code}
% \marg{super family} \marg{true code}
% \marg{super family} \marg{false code}
% \end{syntax}
% If the current super family matches with the given
% \meta{super family}, it selects the true branch; false
% otherwise. The \cs{CurrentSuperFamily} macro expands to
% the current super family.
% \end{function}
%
% \begin{function}[EXP]{^^A
%   \IfSeriesTF,\IfSeriesT,\IfSeriesF,\CurrentSeries
% }
% \begin{syntax}
% \marg{series} \marg{true code} \marg{false code}
% \marg{series} \marg{true code}
% \marg{series} \marg{false code}
% \end{syntax}
% If the current series matches with the given
% \meta{series}, it selects the true branch and false
% otherwise. The \cs{CurrentSeries} macro expands to the
% current series.
% \end{function}
%
% \begin{function}[EXP]{^^A
%   \IfShapeTF,\IfShapeT,\IfShapeF,\CurrentShape
% }
% \begin{syntax}
% \marg{shape} \marg{true code} \marg{false code}
% \marg{shape} \marg{true code}
% \marg{shape} \marg{false code}
% \end{syntax}
% If the current series matches with the given \meta{shape},
% it selects the true branch and false otherwise. The
% \cs{CurrentShape} macro expands to the current shape.
% \end{function}
%
% \begin{function}{\superfontfamily}
% \begin{syntax}
% \marg{family \textsc{id}}^^A
% \marg{rm=\marg{rm \textsc{nfss}},\ignorespaces^^A
% sf=\marg{sf \textsc{nfss}},tt=\marg{tt \textsc{nfss}}}
% \end{syntax}
% Every super font family has a \meta{family \textsc{id}},
% even the default one (i.e., |default|). This command
% creates a super family with the given \meta{family
% \textsc{id}}s. The \meta{meta family keys} argument
% accepts a list of specific keys, |rm|, |sf| and |tt|. They
% take the \textsc{nfss} family names of these meta families
% as arguments. One may define a font with, say,
% |\newfontfamily|, pass the |NFSSkeys=|\marg{key} option to
% it and use the \meta{key} in the suitable \meta{meta
% family key}. Note that using all these keys is \emph{not}
% mandatory. A super family may have $\leq 3$ keys.
% \end{function}
%
% \begin{function}{^^A
% \softsuperfontfamily,\softersuperfontfamily,^^A
% \softestsuperfontfamily
% }
% \begin{syntax}
% \marg{\textsc{id}}\ignorespaces^^A
% \marg{encoding,family,series,shape}
% \marg{\textsc{id}}
% \marg{\textsc{id}}
% \end{syntax}
% These commands loads the super font family with the given
% \meta{\textsc{id}}. The attributes listed in the second
% argument are the only choices available. The required
% super font family is loaded and the listed attributes are
% reset to the ones that were active before. All the four
% are not required. The number of attributes may be $\leq
% 4$. The \cs{softernormalfont} command excludes encoding
% and reactivates all the other attributes, whereas the
% \cs{softestnormalfont} command reactivates all of them.
% \end{function}
%
% \begin{function}{^^A
% \softnormalfont,\softernormalfont,\softestnormalfont
% }
% \begin{syntax}
% \marg{encoding,family,series,shape}
% \end{syntax}
% Similar to \cs{softsuperfontfamily} and friends, these
% commands switch back to the default super font family, but
% reactivate the previously active font attributes. The
% argument to \cs{softnormalfont} takes the list of the
% required font attributes. It can have $\leq 4$ values. Now
% try the following example:
% \end{function}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \begin{verbatim}
%     \documentclass{article}
%     \usepackage{linguistix}
%     \linguistix{%
%       text upright features  = {Color={green}},%
%       ipa upright features   = {Color={red}}%
%     }
%
%     \begin{document}
%     test \lngxipa test \softernormalfont test\par
%     \makeatletter
%     \sffamily\itshape\bfseries
%     \f@family\ | \f@series\ | \f@shape\quad
%     \softnormalfont{series}
%     \f@family\ | \f@series\ | \f@shape
%     \end{document}
% \end{verbatim}
%
% \rule{0.7\linewidth}{0.5pt}
%
% \medskip
%
% Better? :-)
%
% \section*{^^A
%   \texorpdfstring{^^A
%     \LaTeX3 interface for programmers^^A
%   }{^^A
%     LaTeX3 interface for programmers^^A
%   }^^A
% }
%
% In this section, we take a look at the public \LaTeX3
% commands of the bundle. These can be considered stable and
% can be used in production code.
%
% \lngxinterface{base}
%
% \begin{function}{\lngx_set_keys:n}
% \begin{syntax}
% \meta{keyval list}
% \end{syntax}
% This is the base command for \cs{linguistix}. It takes a
% comma separated list of \meta{keyval list} and parses it.
% \end{function}
%
% \lngxinterface{fixpex}
%
% No \LaTeX3 function provided by this package.
%
% \lngxinterface{fonts}
%
% \begin{function}{^^A
%   \g_lngx_old_style_bool,\g_lngx_old_style_one_bool,^^A
%   \g_lngx_bourbaki_bool
% }
% These are the two booleans that are used to check if the
% old style numbers, the old style one (i.e., \enquote{1})
% and Bourbaki’s emtpy set symbol (i.e.,
% \enquote{$\emptyset$}) is asked by the user.
% \end{function}
%
% \begin{function}{^^A
%   \lngx_set_main_font:nn,\lngx_set_main_font:VV,^^A
%   \lngx_set_sans_font:nn,\lngx_set_sans_font:VV,^^A
%   \lngx_set_mono_font:nn,\lngx_set_mono_font:VV,^^A
%   \lngx_set_math_font:nn,\lngx_set_math_font:VV^^A
% }
% \begin{syntax}
% \marg{features} \marg{font}
% \marg{features} \marg{font}
% \marg{features} \marg{font}
% \marg{features} \marg{font}
% \end{syntax}
% These commands take two arguments, retrieve the values of
% the data variables if |:VV| variants are used. These are
% wrapper commands around the font-setting commands of
% \pkg{fontspec} and \pkg{(lua)-unicode-math}, i.e.,
% |\setmainfont|, |\setsansfont|, |\setmonofont| and
% |\setmathfont|. The \meta{features} are passed to the
% optional argument and the \meta{font} is passed to the
% mandatory argument of the respective command from the
% aforementioned list.
% \end{function}
%
% \begin{function}{^^A
% \lngx_other_main_font:nnn,\lngx_other_main_font:nee,^^A
% \lngx_other_sans_font:nnn,\lngx_other_sans_font:nee,^^A
% \lngx_other_mono_font:nnn,\lngx_other_mono_font:nee^^A
% }
% \begin{syntax}
% \marg{language} \marg{features} \marg{font}
% \marg{language} \marg{features} \marg{font}
% \marg{language} \marg{features} \marg{font}
% \end{syntax}
% These commands take three arguments. These are wrapper
% commands around the font-setting commands of \pkg{babel}.
% The \meta{features} are passed to the optional argument
% and the \meta{font} is passed to the mandatory argument of
% the respective command from the aforementioned list.
% \end{function}
%
% \lngxinterface{glossing}
%
% \begin{function}{^^A
%   \lngx_gloss_format:n,\lngx_expansion_format:n
% }
% \begin{syntax}
% \marg{gloss}
% \marg{expansion}
% \end{syntax}
% This function is controlled by the key |format|. Its
% argument is the gloss or the expansion itself. According
% to the definition set in the key, the argument gets
% printed.
% \end{function}
%
% \begin{function}{\lngx_gloss_new:nn}
% \begin{syntax}
% \marg{gloss} \marg{expansion}
% \end{syntax}
% This function creates a new gloss. It is later equated
% with the \cs{newgloss} command.
% \end{function}
%
% \begin{function}{\lngx_gloss_list:}
% This functions prints the list of glosses and is equated
% with \cs{listofglosses}.
% \end{function}
%
% \begin{function}{lngx_multicols}
% \begin{syntax}
% \marg{section title}
% \end{syntax}
% This environment reads an integer variable, i.e.,
% \cs{l__lngx_glossary_columns_int}. It is controlled by the
% |columns| key. If its number is more than one (which, by
% default \emph{is} more than one), the |multicols|
% environment is used around the content that comes in
% between, or else no action is taken. It takes one
% compulsory argument, i.e., the content of the section
% title material. This environment should not be used
% outside this package.
% \end{function}
%
% \lngxinterface{ipa}
%
% This package provides a few wrapper functions around
% \pkg{fontspec}’s commands.
%
% \begin{function}{^^A
%   \lngx_set_main_ipa_font:nn,^^A
%   \lngx_set_main_ipa_font:VV,^^A
%   \lngx_main_ipa:,lngx_ipa_rm_nfss^^A
% }
% \begin{syntax}
% \marg{features} \marg{font}
% \end{syntax}
% These functions set the \textsc{ipa} fonts for the serif
% variants. The \meta{font} is set with \meta{features} for
% the serif \textsc{ipa}. The command to switch to this
% family is \cs{lngx_main_ipa:}. It can be accessed with the
% \textsc{nfss} family |lngx_ipa_rm_nfss|.
% \end{function}
%
% \begin{function}{^^A
%   \lngx_set_sans_ipa_font:nn,^^A
%   \lngx_set_sans_ipa_font:VV,^^A
%   \lngx_sans_ipa:,lngx_ipa_sf_nfss^^A
% }
% \begin{syntax}
% \marg{features} \marg{font}
% \end{syntax}
% These functions set the \textsc{ipa} fonts for the sans
% variants. The \meta{font} is set with \meta{features} for
% the sans \textsc{ipa}. The command to switch to this
% family is \cs{lngx_sans_ipa:}. It can be accessed with the
% \textsc{nfss} family |lngx_ipa_sf_nfss|.
% \end{function}
%
% \begin{function}{^^A
%   \lngx_set_mono_ipa_font:nn,^^A
%   \lngx_set_mono_ipa_font:VV,^^A
%   \lngx_mono_ipa:,lngx_ipa_tt_nfss^^A
% }
% \begin{syntax}
% \marg{features} \marg{font}
% \end{syntax}
% These functions set the \textsc{ipa} fonts for the mono
% variants. The \meta{font} is set with \meta{features} for
% the mono \textsc{ipa}. The command to switch to this
% family is \cs{lngx_mono_ipa:}. It can be accessed with the
% \textsc{nfss} family |lngx_ipa_nfss_nfss|.
% \end{function}
%
% \begin{function}{\lngx_ipa:,lngx_ipa}
% The \cs{lngx_ipa:} command loads the super family
% |lngx_ipa| (see the documentation of \lngxnfsslogo). The
% \cs{lngx_ipa:} function has a user-side command
% \cs{lngxipa} too.
% \end{function}
%
% \lngxinterface{languages}
%
% Here are the L3 functions defined for \lngxlanguageslogo.
%
% \begin{function}{\g_lngx_main_language_tl}
% A |tl| that globally stores the main language of the
% document.
% \end{function}
%
% \begin{function}{\g_lngx_languages_clist}
% A |clist| that globally stores the languages that are
% used.
% \end{function}
%
% \begin{function}{\lngx_languages:nn,\lngx_languages:VV}
% \begin{syntax}
% \marg{language options} \marg{language name}
% \meta{language options tl} \meta{language tl}
% \end{syntax}
% These functions read the |V|-type argument provided to
% them and pass it to the |\babelprovide| command for
% loading languages.
% \end{function}
%
% \begin{function}{\lngx_load_languages:n}
% \begin{syntax}
% \marg{list of languages}
% \end{syntax}
% This function loads the languages in \lngxpkg\ sense.
% \end{function}
%
% \begin{function}{\lngx_counter:n}
% This is a developers function provided for printing the
% counter based on the plug selected. It changes the meaning
% according to the active value of |native-numbering|
% socket.
% \end{function}
%
% \begin{function}{\lngx_misc_reset:}
% This function resets a lot of custom settings done by
% some languages. It has to be used inside \cs{addto} macro
% provided by the \pkg{babel} package.
% \end{function}
%
% \lngxinterface{logos}
%
% There are only two \LaTeX3 functions provided by this
% package.
%
% \begin{function}{\lngx_logo_font:}
% This function switches to the New Computer Modern Uncial
% font family.
% \end{function}
%
% \begin{function}{lngx_purple_color}
% I don’t like the default purple colour of the \pkg{xcolor}
% package (i.e., \colorbox{purple}{\phantom{x}}\,). Thus I
% have created a new colour using \pkg{l3color} module. It
% can be accessed using this variable. The color looks like:
% \colorbox{lngxpurplecolor}{\phantom{x}}.
% \end{function}
%
% \lngxinterface{nfss}
%
% This subsection discusses the programming interface
% \lngxnfsslogo\ provides.
%
% \begin{function}[EXP]{^^A
% \c_lngx_default_rmdefault_tl,^^A
% \c_lngx_default_sfdefault_tl,^^A
% \c_lngx_default_ttdefault_tl
% }
% \begin{syntax}
% \normalfont\normalsize^^A
% These |tl|s expand to the default values of the fonts^^A
% set at the |begindocument/end| hook. These are not^^A
% supposed to be changed and hence they are set with^^A
% the |c| prefix.
% \end{syntax}
% \end{function}
%
% \begin{function}[EXP]{^^A
% \l_lngx_current_encoding_tl,^^A
% \l_lngx_current_meta_family_tl,^^A
% \l_lngx_current_super_family_tl,^^A
% \l_lngx_current_series_tl,^^A
% \l_lngx_current_shape_tl
% }
% \begin{syntax}
% \normalfont\normalsize^^A
% These |tl|s expand to the current values of encoding,^^A
% meta family, super family, series and shape^^A
% respectively. Note that these are updated time to time^^A
% by the commands that change them (package-internal or^^A
% \LaTeX-internal).
% \end{syntax}
% \end{function}
%
% \begin{function}[EXP,pTF]{^^A
% \lngx_if_encoding:n,\lngx_if_meta_family:n,^^A
% \lngx_if_super_family:n,\lngx_if_series:n,\lngx_if_shape:n
% }
% \begin{syntax}
% \marg{encoding}
% \marg{encoding}\marg{true code}\marg{false code}
% \marg{meta font family}
% \marg{meta font family}\marg{true code}\marg{false code}
% \marg{super font family}
% \marg{super font family}\marg{true code}\marg{false code}
% \marg{series}
% \marg{series}\marg{true code}\marg{false code}
% \marg{shape}
% \marg{shape}\marg{true code}\marg{false code}
% \end{syntax}
% \end{function}
%
% \begin{function}[EXP,pTF]{^^A
% \lngx_if_meta_family_rm:,\lngx_if_meta_family_sf:,^^A
% \lngx_if_meta_family_tt:
% }
% \begin{syntax}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \end{syntax}
% These conditionals select the true branch if the |rm|,
% |sf|, |tt| families (respectively) are active, false
% otherwise.
% \end{function}
%
% \begin{function}[EXP,pTF]{^^A
% \lngx_if_series_md:,\lngx_if_series_bf:
% }
% \begin{syntax}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \end{syntax}
% These conditionals select the true branch if the |md|,
% |bf| series (respectively) are active, false otherwise.
% \end{function}
%
% \begin{function}[EXP,pTF]{^^A
% \lngx_if_shape_up:,\lngx_if_shape_it:,^^A
% \lngx_if_shape_sc:,\lngx_if_shape_ssc:,^^A
% \lngx_if_shape_sl:,\lngx_if_shape_sw:,^^A
% \lngx_if_shape_ulc:
% }
% \begin{syntax}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \phantom{x}
% \marg{true code}\marg{false code}
% \end{syntax}
% These conditionals select the true branch if the |up|,
% |it|, |sc|, |ssc|, |sl|, |sw|, |ulc| shapes (respectively)
% are active, false otherwise.
% \end{function}
%
% \begin{function}{\lngx_super_font_family:nn}
% \begin{syntax}
% \marg{family \textsc{id}}^^A
% \marg{rm=\marg{rm \textsc{nfss}},\ignorespaces^^A
% sf=\marg{sf \textsc{nfss}},tt=\marg{tt \textsc{nfss}}}
% \end{syntax}
% This function takes an \meta{\textsc{id}} and sets the
% |rm|, |sf|, |tt| values as requested by the user and
% creates a super font family.
% \end{function}
%
% \begin{function}{^^A
% \lngx_soft_super_font_family:nn,^^A
% \lngx_softer_super_font_family:n,^^A
% \lngx_softest_super_font_family:n
% }
% \begin{syntax}
% \marg{\textsc{id}}\ignorespaces^^A
% \marg{encoding,family,series,shape}
% \marg{\textsc{id}}
% \marg{\textsc{id}}
% \end{syntax}
% The \cs{lngx_soft_super_font_family:nn} sets super family
% marked by the \meta{\textsc{id}} and reactivates the
% currently active font attributes listed in the second
% argument. The other two do the same, but without the list.
% the |softer| one omits the encoding and the |softest| one
% reactivate all of them.
% \end{function}
%
% \begin{function}{^^A
% \lngx_soft_normal_font:n,^^A
% \lngx_softer_normal_font:,^^A
% \lngx_softest_normal_font:
% }
% \begin{syntax}
% \marg{\textsc{id}}
% \end{syntax}
% Quite similar to the soft super family functions, these
% ones set the default font family and reactivate the font
% attributes. The |soft| one sets the attributes listed in
% the argument. The |softer| one omits encoding and
% reactivates the rest and the |softest| one reactivates
% all.
% \end{function}
% \end{documentation}
%
% \newpage
%
% \begin{implementation}
% \section*{Implementation}
%
% In this section the code of this bundle is documented.
% Each package in the bundle is documented in a separate
% subsection.
%
% \subsection*{\lngxpkg}
%
% Provide the package with its basic information.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage{linguistix}
                    {2026-02-02}
                    {v0.8}
                    {%
                      The ‘LinguisTiX’ bundle: Enhanced
                      support for linguistics.%
                    }
%    \end{macrocode}
% When one loads \lngxpkg, all the packages of the bundle
% are loaded automatically. That’s the only content of the
% umbrella package \lngxpkg. All the packages are loaded
% conditionally (i.e., only if not loaded already).
%    \begin{macrocode}

\IfPackageLoadedF { linguistix-base } {
  \RequirePackage { linguistix-base }
}
\IfPackageLoadedF { linguistix-fonts } {
  \RequirePackage { linguistix-fonts }
}
\IfPackageLoadedF { linguistix-glossing } {
  \RequirePackage { linguistix-glossing }
}
\IfPackageLoadedF { linguistix-ipa } {
  \RequirePackage { linguistix-ipa }
}
\IfPackageLoadedF { linguistix-languages } {
  \RequirePackage { linguistix-languages }
}
\IfPackageLoadedF { linguistix-leipzig } {
  \RequirePackage { linguistix-leipzig }
}
\IfPackageLoadedF { linguistix-logos } {
  \RequirePackage { linguistix-logos }
}
\IfPackageLoadedF { linguistix-nfss } {
  \RequirePackage { linguistix-nfss }
}
%</package>
%    \end{macrocode}
% \newpage
% \lngximplementation{base}
% Set the essentials of the package.
%    \begin{macrocode}
%<*base>
\ProvidesExplPackage{linguistix-base}
                    {2026-02-02}
                    {v0.8}
                    {%
                      The base package of the ‘LinguisTiX’
                      bundle.%
                    }
%    \end{macrocode}
% \begin{macro}{\lngx_set_keys:n}
% I use the \pkg{l3keys} module of \LaTeX3 for creating the
% key-values used in this bundle. In order to get a
% singleton parser for all the packages of the bundle, I
% have create this parsing command that is used throughout
% the bundle.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_set_keys:n #1 {
  \keys_set:nn { lngx_keys } { #1 }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\linguistix}
% I equate this command with a user-side macro here and end
% the \lngxbaselogo\ package.
%    \begin{macrocode}

\cs_gset_eq:NN \linguistix \lngx_set_keys:n
%</base>
%    \end{macrocode}
% \end{macro}
% \newpage
% \lngximplementation{fixpex}
% The \pkg{unicode-math} and \pkg{lua-unicode-math} packages
% define |\gla| command which clashes with the same command
% defined by the \pkg{expex} package. Of course, the
% \pkg{expex}-|\gla| is more relevant in linguistics. Thus I
% will save that and provide a new command for the
% \pkg{(lua)-unicode-math}-|\gla|. This is not relevant to
% people who are not using \pkg{expex}. Thus, the settings
% are loaded only conditionally.
%    \begin{macrocode}
%<*fixpex>
\ProvidesExplPackage{linguistix-fixpex}
                    {2026-02-02}
                    {v0.8}
                    {%
                      To fix the clash between ‘expex’ and
                      (lua-unicode-math).%
                    }
%    \end{macrocode}
% This package is useful only if either \pkg{expex} or
% \pkg{(lua)-unicode-math} is loaded. Otherwise, it is of no
% use. Thus, I create a message when either of them is not
% loaded.
%    \begin{macrocode}

\msg_new:nnn { fixpex } { pkg_not_loaded } {
  The~ ‘LinguisTiX-fixpex’~ package~ is~ a~ first-aid~
  for~ resolving~ the~ clash~ between~
  ‘(lua)-unicode-math’\\ and~ ‘expex’.~ It~ should~ only~
  be~ used~ if~ at~ least\\ one~ of~ the~ two~ is~ loaded.~
  Here~ ‘LinguisTiX-fixpex’\\ is~ not~ needed~ as~ you~
  ‘#1’~ is~ not~ loaded.
}
%    \end{macrocode}
% I first start the hook |begindocument/before|.
%    \begin{macrocode}

\hook_gput_code:nnn { begindocument / before } { . } {
%    \end{macrocode}
% The \pkg{(lua)-unicode-math} package defines |\gla| after
% |\begin{document}|, so the fix needs to be added after
% that is done. For that, I start the |begindocument/end|
% hook.
%    \begin{macrocode}
  \IfPackageLoadedTF { expex } {
    \exp_args:Ne
    \IfPackageLoadedTF {
      \sys_if_engine_luatex:TF {
        \IfPackageLoadedF { unicode-math } {
          unicode-math
        } {
          lua-unicode-math
        }
      } {
        unicode-math
      }
    } {
      \hook_gput_code:nnn { begindocument / end } { . } {
%    \end{macrocode}
% \begin{macro}{\umgla}
% This replicates the \pkg{(lua)-unicode-math}-|\gla| for
% future use.
%    \begin{macrocode}
        \cs_gset_eq:NN \umgla \gla
%    \end{macrocode}
% \end{macro}
% The \pkg{expex}-|\gla| is then equated to the internal
% function of the package that does the actual function
% \parencite{alan}.
%    \begin{macrocode}
        \cs_gset_eq:NN \gla   \glw@gla
      }
%    \end{macrocode}
% In the false branch of \pkg{(lua)-unicode-math}, I issue
% an info message that is not visible on the terminal, but
% is printed in the log file.
%    \begin{macrocode}
    } {
      \msg_info:nnn { fixpex } { pkg_not_loaded } {
        (lua)-unicode-math
      }
    }
%    \end{macrocode}
% Similarly, I do it for \pkg{expex}.
%    \begin{macrocode}
  } {
    \msg_info:nnn { fixpex } { pkg_not_loaded } {
      expex
    }
  }
}
%</fixpex>
%    \end{macrocode}
% \newpage
% \lngximplementation{fonts}
% Package essentials first.
%    \begin{macrocode}
%<*font>
\ProvidesExplPackage{linguistix-fonts}
                    {2026-02-02}
                    {v0.8}
                    {%
                      The font-assistant package of the
                      ‘LinguisTiX’ bundle.%
                    }
%    \end{macrocode}
% Then, I load \pkg{unicode-math} or \pkg{lua-unicode-math}
% (depending on the engine used), \lngxnfsslogo\ and
% \lngxbaselogo\ (if they are not already loaded).
%    \begin{macrocode}

\IfPackageLoadedF { linguistix-base } {
  \RequirePackage { linguistix-base }
}

\sys_if_engine_luatex:TF {
  \IfPackageLoadedF { unicode-math } {
    \IfPackageLoadedF { lua-unicode-math } {
      \RequirePackage { fontspec, lua-unicode-math }
    }
  }
} {
  \IfPackageLoadedF { unicode-math } {
    \RequirePackage { unicode-math }
  }
}

\IfPackageLoadedF { linguistix-fixpex } {
  \RequirePackage { linguistix-fixpex }
}
%    \end{macrocode}
% \begin{macro}{\LaTeX,\ogLaTeX}
% We save the original code for the |\LaTeX| logo and then
% renew the command.
%    \begin{macrocode}

\NewCommandCopy \ogLaTeX \LaTeX

\RenewDocumentCommand \LaTeX {  } {%
  L\kern-.81ex\relax
  \raisebox{.6ex}{\textsc{a}}\kern-.23ex\relax
  \hbox{T}\kern-.4ex\relax
  \raisebox{-.5ex}{E}\kern-.3ex\relax
  X%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% old style numbers,\g_lngx_old_style_bool,^^A
% old style one,\g_lngx_old_style_one_bool,^^A
% bourbaki's empty set,\g_lngx_bourbaki_bool
% }
% I use the |.bool_gset:N| key-type of \pkg{l3keys} for
% developing these boolean keys.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  old~ style~ numbers
  .bool_gset:N           = {
    \g_lngx_old_style_bool
  },
  old~ style~ one
  .bool_gset:N           = {
    \g_lngx_old_style_one_bool
  },
  bourbaki's~ empty~ set
  .bool_gset:N           = {
    \g_lngx_bourbaki_bool
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \g__lngx_text_main_fonts_prop,^^A
% \g__lngx_text_main_font_features_tl,^^A
% text upright,text upright features,text bold upright,text
% bold upright features,text italic,text italic
% features,text bold italic,text bold italic features,text
% slanted,text slanted features,text bold slanted,text bold
% slanted features,text swash,text swash features,text bold
% swash,text bold swash features,text small caps,text small
% caps features^^A
% }
% In the first few versions of the package, I used to save
% the font-names and their features in token lists, but I
% found a better way to deal with this later which was using
% |prop| lists. I had released the |tl|s publicly (with a
% single |_| after the scope marker), which means ideally
% they should be available forever, but for performance and
% maintenance the newer approach is much preferred and hence
% I decided to shift to |prop| lists from v0.6. This time, I
% am correcting the mistake I made before. The |prop| lists
% that save the keys is not public. It need not be. Only the
% key-value pairs are public. They are unchanged anyway.
% This section describes the implementation of serif text
% fonts. All these keys have a common pattern of code. For
% the convenience of maintenance, I have created a
% comma-separated-list and used the elements of this list
% inside the common code.
% (See: \url{https://topanswers.xyz/tex?q=8074#a7689}.)
%    \begin{macrocode}

\prop_gclear_new:N \g__lngx_text_main_fonts_prop
\tl_gclear_new:N \g__lngx_text_main_font_features_tl

\clist_map_inline:nn {
  upright,
  bold~ upright,
  italic,
  bold~ italic,
  slanted,
  bold~ slanted,
  swash,
  bold~ swash,
  small~ caps
} {
%    \end{macrocode}
% All the keys here are prefixed with the word |text| in
% order to distinguish them from the keys provided by the
% \lngxipalogo\ package. The argument of these keys should
% be expanded for which I use |\prop_gput:Nne| function.
% Each |#1| is replaced by the items from clist and the loop
% is repeated, whereas |##1| is the argument passed to the
% key by user.
%    \begin{macrocode}
  \keys_define:nn { lngx_keys } {
    text~ #1
    .code:n                = {
%    \end{macrocode}
% I start a group first. Then clear and set a temporary
% string variable. I make the text of the key titlecased as
% required by \pkg{fontspec} and remove the spaces. Lastly,
% the word |Font| is appended. So, |bold italic| becomes
% |BoldItalicFont|.
%    \begin{macrocode}
      \group_begin:
      \str_clear:N \l_tmpa_str
      \str_set:Ne \l_tmpa_str {
        \text_titlecase_all:n { #1 }
        Font
      }
      \str_replace_all:Nnn \l_tmpa_str { ~ } { }
%    \end{macrocode}
% The string is used inside the relevant |prop|-key and
% group is ended.
%    \begin{macrocode}
      \prop_gput:Nne \g__lngx_text_main_fonts_prop
                     { text~ #1 }
                     { \str_use:N \l_tmpa_str = { ##1 } }
      \group_end:
    },
%    \end{macrocode}
% Same is repeated for features.
%    \begin{macrocode}
    text~ #1~ features
    .code:n                = {
      \group_begin:
      \str_clear:N \l_tmpa_str
      \str_set:Ne \l_tmpa_str {
        \text_titlecase_all:n { #1 }
        Features
      }
      \str_replace_all:Nnn \l_tmpa_str { ~ } { }
      \prop_gput:Nne \g__lngx_text_main_fonts_prop
                     { text~ #1~ features }
                     {
                       \str_use:N \l_tmpa_str = { ##1 }
                     }
      \group_end:
    }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{text extra features}
% This key adds to the property that stores the extra
% features for the serif fonts.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  text~ extra~ features
  .prop_gput:N           = \g__lngx_text_main_fonts_prop
}
%    \end{macrocode}
% \end{macro}
% \newpage
% \begin{macro}{^^A
% \g__lngx_text_sans_fonts_prop,^^A
% \g__lngx_text_sans_font_features_tl,^^A
% \g__lngx_text_mono_fonts_prop,^^A
% \g__lngx_text_mono_font_features_tl,^^A
% text sans upright,text sans upright features,text sans
% bold upright,text sans bold upright features,text sans
% italic,text sans italic features,text sans bold
% italic,text sans bold italic features,text sans
% slanted,text sans slanted features,text sans bold
% slanted,text sans bold slanted features,text sans
% swash,text sans swash features,text sans bold swash,text
% sans bold swash features,text sans small caps,text sans
% small caps features,text mono upright,text mono upright
% features,text mono bold upright,text mono bold upright
% features,text mono italic,text mono italic features,text
% mono bold italic,text mono bold italic features,text mono
% slanted,text mono slanted features,text mono bold
% slanted,text mono bold slanted features,text mono
% swash,text mono swash features,text mono bold swash,text
% mono bold swash features,text mono small caps,text mono
% small caps features^^A
% }
% Since the only difference between the upcoming keys is
% that of the word |sans| and |mono|, we combine them
% together and use a nested |clist|. The rest of the
% mechanism is identical.
%    \begin{macrocode}

\prop_gclear_new:N \g__lngx_text_sans_fonts_prop
\tl_gclear_new:N \g__lngx_text_sans_font_features_tl

\prop_gclear_new:N \g__lngx_text_mono_fonts_prop
\tl_gclear_new:N \g__lngx_text_mono_font_features_tl

\clist_map_inline:nn {
  sans,
  mono
} {
  \clist_map_inline:nn {
    upright,
    bold~ upright,
    italic,
    bold~ italic,
    slanted,
    bold~ slanted,
    swash,
    bold~ swash,
    small~ caps
  } {
    \keys_define:nn { lngx_keys } {
      text~ #1~ ##1
      .code:n                = {
        \group_begin:
        \str_clear:N \l_tmpa_str
        \str_set:Ne \l_tmpa_str {
          \text_titlecase_all:n { ##1 }
          Font
        }
        \str_replace_all:Nnn \l_tmpa_str { ~ } { }
        \prop_gput:cne { g__lngx_text_ #1 _fonts_prop }
                       { text~ #1~ ##1 }
                       { ####1 }
        \group_end:
      },
      text~ #1~ ##1~ features
      .code:n                = {
        \group_begin:
        \str_clear:N \l_tmpa_str
        \str_set:Ne \l_tmpa_str {
          \text_titlecase_all:n { #1 }
          Features
        }
        \str_replace_all:Nnn \l_tmpa_str { ~ } { }
        \prop_gput:cne { g__lngx_text_ #1 _fonts_prop }
                       { text~ #1~ ##1~ features }
                       {
                         \str_use:N \l_tmpa_str = { ####1 }
                       }
        \group_end:
      }
    }
  }
  \keys_define:nn { lngx_keys } {
    text~ #1~ extra~ features
    .prop_gput:c           = {
                               g__lngx_text_ #1 _fonts_prop
                             }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \g__lngx_text_main_font_tl,\g__lngx_text_sans_font_tl,^^A
% \g__lngx_text_mono_font_tl,^^A
% text main font,text sans font,text mono font^^A
% }
% These keys add the parameter that sets the main font for
% text. They set an internal token list which is retrieved
% later by font setting command.
%    \begin{macrocode}

\clist_map_inline:nn {
  main,
  sans,
  mono
} {
  \keys_define:nn { lngx_keys } {
    text~ #1~ font
    .tl_gset:c             = { g__lngx_text_ #1 _font_tl }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \g__lngx_math_fonts_prop,^^A
% \g__lngx_math_features_tl,^^A
% \g__lngx_math_bold_fonts_prop,^^A
% \g__lngx_math_bold_features_tl,^^A
% math,math features,math bold,math bold features^^A
% }
% The following are the keys set for math. They use the same
% mechanism as before.
%    \begin{macrocode}

\prop_gclear_new:N \g__lngx_math_fonts_prop
\tl_gclear_new:N \g__lngx_math_features_tl

\prop_gclear_new:N \g__lngx_math_bold_fonts_prop
\tl_gclear_new:N \g__lngx_math_bold_features_tl

\keys_define:nn { lngx_keys } {
  math
  .tl_gset:N               = \g__lngx_math_font_tl,
  math~ bold
  .tl_gset:N               = \g__lngx_math_bold_font_tl,
  math~ features
  .prop_gput:N           = \g__lngx_math_fonts_prop,
  math~ bold~ features
  .prop_gput:N           = \g__lngx_math_bold_fonts_prop
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm}
% This key is of type |.meta:n|. It sets certain other keys
% that enable the New Computer Modern fonts in book weight
% and in all of the serif, sans serif and monospaced
% families.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm
  .meta:n                = {
    text~ main~ font       = { NewCM10-Book.otf },
    text~ sans~ font       = { NewCMSans10-Book.otf },
    text~ mono~ font       = { NewCMMono10-Book.otf },
    math                   = { NewCMMath-Book.otf },
    math~ bold             = { NewCMMath-Bold.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm sans}
% This is a |.meta:n| key that sets the default fonts to the
% sans family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm~ sans
  .meta:n                = {
    main~ font             = { NewCMSans10-Book.otf },
    sans~ font             = { NewCMSans10-Book.otf },
    mono~ font             = { NewCMMono10-Book.otf },
    math                   = { NewCMSansMath-Regular.otf },
    math~ bold             = { NewCMSansMath-Regular.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm mono}
% This is a |.meta:n| key that sets the default fonts to the
% monospaced family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm~ mono
  .meta:n                = {
    main~ font             = { NewCMMono10-Book.otf },
    sans~ font             = { NewCMSans10-Book.otf },
    mono~ font             = { NewCMMono10-Book.otf },
    math                   = { NewCMSansMath-Regular.otf },
    math~ bold             = { NewCMSansMath-Regular.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm regular}
% This is a |.meta:n| key that sets the default fonts to the
% regular variant of the New Computer Modern family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm~ regular
  .meta:n                = {
    main~ font             = { NewCM10-Regular.otf },
    sans~ font             = { NewCMSans10-Regular.otf },
    mono~ font             = { NewCMMono10-Regular.otf },
    math                   = { NewCMMath-Regular.otf },
    math~ bold             = { NewCMMath-Bold.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm regular sans}
% This is a |.meta:n| key that sets the default fonts to the
% regular sans variant of the New Computer Modern family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm~ regular~ sans
  .meta:n                = {
    main~ font             = { NewCMSans10-Regular.otf },
    sans~ font             = { NewCMSans10-Regular.otf },
    mono~ font             = { NewCMMono10-Regular.otf },
    math                   = { NewCMMath-Regular.otf },
    math~ bold             = { NewCMMath-Bold.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{newcm regular mono}
% This is a |.meta:n| key that sets the default fonts to the
% regular monospaced variant of the New Computer Modern
% family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  newcm~ regular~ mono
  .meta:n                = {
    main~ font             = { NewCMMono10-Regular.otf },
    sans~ font             = { NewCMSans10-Regular.otf },
    mono~ font             = { NewCMMono10-Regular.otf },
    math                   = { NewCMMath-Regular.otf },
    math~ bold             = { NewCMMath-Bold.otf },
  }
}
%    \end{macrocode}
% \end{macro}
% Then we load the |bourbaki's empty set| boolean. This gets
% read later while setting the math font.
%    \begin{macrocode}

\lngx_set_keys:n {
  bourbaki's~ empty~ set,
%    \end{macrocode}
% Then we load the |old style numbers| boolean.
%    \begin{macrocode}
  old~ style~ numbers,
  newcm
}
%    \end{macrocode}
% \begin{macro}{^^A
% \lngx_set_main_font:nn,\lngx_set_sans_font:nn,^^A
% \lngx_set_mono_font:nn,\lngx_set_math_font:nn^^A
% }
% If \lngxlanguageslogo\ package is loaded, I load the fonts
% with |\babelfont| command. In case it is not loaded, the
% fonts are set with |\setxxxxcommand|-type commands
% provided by \pkg{fontspec}.
%    \begin{macrocode}

\IfPackageLoadedF { linguistix-languages } {
  \cs_new_protected:Npn \lngx_set_main_font:nn #1#2 {
    \setmainfont [ #1 ] { #2 }
  }
  \cs_new_protected:Npn \lngx_set_sans_font:nn #1#2 {
    \setsansfont [ #1 ] { #2 }
  }
  \cs_new_protected:Npn \lngx_set_mono_font:nn #1#2 {
    \setmonofont [ #1 ] { #2 }
  }
}
%    \end{macrocode}
% A wrapper command is provided for loading math fonts.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_set_math_font:nn #1#2 {
  \setmathfont [ #1 ] { #2 }
}
%    \end{macrocode}
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_set_math_bold_font:nn #1#2 {
  \IfPackageLoadedT { lua-unicode-math } {
    \DeclareMathVersion { bold }
  }
  \setmathfont [
    #1,
    version              = { bold }
  ] { #2 }
}
%    \end{macrocode}
% All of these commands should expand their arguments, so I
% provide the appropriate variants.
%    \begin{macrocode}

\cs_generate_variant:Nn \lngx_set_main_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_sans_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_mono_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_math_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_math_bold_font:nn { VV }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \__lngx_build_main_font_features:,^^A
% \__lngx_build_sans_font_features:,^^A
% \__lngx_build_mono_font_features:,^^A
% \__lngx_build_math_font_features:,^^A
% \__lngx_build_bold_math_font_features:,^^A
% \g__lngx_text_main_font_features_tl,^^A
% \g__lngx_text_sans_font_features_tl,^^A
% \g__lngx_text_mono_font_features_tl,^^A
% \g__lngx_math_font_features_tl,^^A
% \g__lngx_bold_math_font_features_tl
% }
% These are some internal functions that basically iterate
% on the |prop| list items and each of them is put to the
% right of the respective token list. This way only the
% functions that are added by the user are exported to the
% font setting command.
%    \begin{macrocode}

\clist_map_inline:nn {
  main,
  sans,
  mono
} {
  \cs_new_protected:cpn {
    __lngx_build_ #1 _font_features:
  } {
    \prop_map_inline:cn { g__lngx_text_ #1 _fonts_prop } {
      \tl_gput_right:cn {
                          g__lngx_text_ #1 _font_features_tl
                        } { ####2 }
    }
  }
}

\cs_new_protected:Npn \__lngx_build_math_features: {
  \prop_map_inline:Nn \g__lngx_math_fonts_prop {
    \tl_gput_right:Nn \g__lngx_math_features_tl {
      { ##2 }
    }
  }
}

\cs_new_protected:Npn \__lngx_build_math_bold_features: {
  \prop_map_inline:Nn \g__lngx_math_bold_fonts_prop {
    \tl_gput_right:Nn \g__lngx_math_bold_features_tl {
      { ##2 }
    }
  }
}
%    \end{macrocode}
% \end{macro}
% Now I start the pre-|begindocument| hook.
%    \begin{macrocode}

\hook_gput_code:nnn { begindocument / before } { . } {
%    \end{macrocode}
% If the boolean for old style numbers is true, I set the
% |Numbers| key to |OldStyle|. Similarly, if the
% NewCM-specific old one is requested, I turn the
% character-variant on.
%    \begin{macrocode}
  \lngx_set_keys:n {
    text~ extra~
    features               = {
      \bool_if:NT \g_lngx_old_style_bool {
        Numbers              = { OldStyle },
        \bool_if:NT \g_lngx_old_style_one_bool {
          CharacterVariant     = { 6 }
        }
      }
    },
    text~ sans~ extra~
    features               = {
      \bool_if:NT \g_lngx_old_style_bool {
        Numbers              = { OldStyle },
        \bool_if:NT \g_lngx_old_style_one_bool {
          CharacterVariant     = { 6 }
        }
      }
    }
  }
%    \end{macrocode}
% All the font features are built using the internal
% functions and then fonts are set.
%    \begin{macrocode}
  \__lngx_build_main_font_features:
  \lngx_set_main_font:VV
    \g__lngx_text_main_font_features_tl
    \g__lngx_text_main_font_tl
  \__lngx_build_sans_font_features:
  \lngx_set_sans_font:VV
    \g__lngx_text_sans_font_features_tl
    \g__lngx_text_sans_font_tl
  \__lngx_build_mono_font_features:
  \lngx_set_mono_font:VV
    \g__lngx_text_mono_font_features_tl
    \g__lngx_text_mono_font_tl
  \__lngx_build_math_features:
  \lngx_set_math_font:VV \g__lngx_math_features_tl
                         \g__lngx_math_font_tl
  \IfPackageLoadedT { unicode-math } {
    \__lngx_build_math_bold_features:
    \lngx_set_math_bold_font:VV
      \g__lngx_math_bold_features_tl
      \g__lngx_math_bold_font_tl
  }
}
%</font>
%    \end{macrocode}
% \newpage
% \lngximplementation{glossing}
%    \begin{macrocode}
%<*glossing>
\ProvidesExplPackage{linguistix-glossing}
                    {2026-02-02}
                    {v0.8}
                    {%
                      Accessible glossing with LinguisTiX%
                    }
%    \end{macrocode}
% In order to print the multi-column glossary, I load the
% \cs{multicol} package.
%    \begin{macrocode}

\IfPackageLoadedF { multicol } {
  \RequirePackage { multicol }
}
%    \end{macrocode}
% Then I declare some variables that will be used for
% generating the glossing-auxiliary.
%    \begin{macrocode}

\bool_new:N       \l_lngx_expansion_bool
\tl_clear_new:N   \l_lngx_gloss_separator_tl
\tl_clear_new:N   \l_lngx_expansion_separator_tl
\tl_clear_new:N   \l_lngx_glossary_separator_tl
\dim_zero_new:N   \l_lngx_i_have_dim
\dim_zero_new:N   \l_lngx_i_need_dim
\dim_zero_new:N   \l_lngx_remain_dim
\dim_zero_new:N   \l_lngx_i_hack_dim
\int_gzero_new:N  \g__lngx_page_ref_int
\str_clear_new:N  \l_lngx_gls_language_str
\str_clear_new:N  \l__lngx_gls_sorting_order_str
\str_clear_new:N  \l__lngx_gls_expansion_case_str
\str_clear_new:N  \l__lngx_glossary_style_str
\str_clear_new:N  \l__lngx_separator_str
\seq_gclear_new:N \g__lngx_gls_use_order_seq

\str_set:Nn \l__lngx_separator_str { gloss }
%    \end{macrocode}
% Glossaries are hyperlinked with complex and cryptic
% labels. Some readers read the labels loudly when using
% assistive technology. In order to dodge that, I add the
% text to the Contents key. It uses Ulrike’s ideas:
% \url{tex.stackexchange.com/a/758083/174620}.
%    \begin{macrocode}

\IfPDFManagementActiveT {
  \socket_if_exist:nT { hyp / link / GoTo / Contents } {
    \socket_new_plug:nnn { hyp / link / GoTo / Contents }
                         { text } {
      \pdfstringdef \__lngx_tmp_text: { #2 }
      \pdfannot_dict_put:nne { link / GoTo } { Contents } {
        ( \__lngx_tmp_text: )
      }
    }
  }
}
%    \end{macrocode}
% After these initial declarations, I move to the socket
% that controls the description of the gloss. The socket
% itself has no arguments.
%    \begin{macrocode}

\socket_new:nn { lngx / description / gloss } { 0 }
%    \end{macrocode}
% \begin{macro}{\__lngx_gloss_description:}
% When the socket is assigned the |on| plug, it defines the
% expandable internal command for glossing description. It
% is then used inside the tagging socket. The same command
% is made inactive when the socket is assigned the |off|
% plug. By default the |off| plug is assigned (this is
% experimental and may change after reviews from the blind
% people). The socket is activated by using it.
%    \begin{macrocode}

\socket_new_plug:nnn { lngx / description / gloss } { on } {
  \cs_set:Npn \__lngx_gloss_description: { Gloss~ }
}

\socket_new_plug:nnn { lngx / description / gloss }
                     { off } {
  \cs_set_eq:NN \__lngx_gloss_description: \prg_do_nothing:
}

\socket_assign_plug:nn { lngx / description / gloss }
                       { off }

\socket_use:n { lngx / description / gloss }
%    \end{macrocode}
% \end{macro}
% Then I declare the tagging socket for glossing which takes
% two arguments. It should follow the default tagging which
% is why I use the |default| plug (which is the only plug
% the package does and will offer). The code is based on
% suggestions by Ulrike Fischer
% (\url{github.com/latex3/tagging-project/discussions/975}).
% The |E| tag is used for ‘expansion’ which more or less
% suits the nature of glosses. So it is used here. The
% command \cs{__lngx_gloss_description:} is controlled by
% the socket and is expandable.
%    \begin{macrocode}

\NewTaggingSocket { lngx / gloss } { 2 }

\NewTaggingSocketPlug { lngx / gloss } { default } {
  \mode_leave_vertical:
  \tag_mc_end:
  \exp_args:Ne
  \tag_struct_begin:n {
    tag                    = { Span },
    E                      = {
      \__lngx_gloss_description: #2
    }
  }
  \tag_mc_begin:n {
    tag                    = { Span }
  }
%    \end{macrocode}
% The argument is printed with the package-controlled
% formatting command. First I check if the \pkg{hyperref}
% package is loaded. If it is loaded, the link colour is
% changed to the one stored in the variable
% \cs{g_lngx_gloss_link_color_str} (black, by default).
%    \begin{macrocode}
  \IfPackageLoadedTF { hyperref } {
    \group_begin:
    \str_clear:N \l_tmpa_str
    \str_set:Nn \l_tmpa_str { #1 }
    \exp_args:Ne \hypersetup {
      linkcolor            = {
        \exp_not:V \g__lngx_gloss_link_color_str
      }
    }
%    \end{macrocode}
% The socket for adding text into the Contents directory is
% used here.
%    \begin{macrocode}
    \IfPDFManagementActiveT {
      \socket_if_exist:nT { hyp / link / GoTo / Contents } {
        \socket_assign_plug:nn {
          hyp / link / GoTo / Contents
        } { text }
      }
    }
    \lngx_gloss_format:n {
      \hyperlink { lngx_ #1 _glossary } { #1 }
    }
    \group_end:
  } {
%    \end{macrocode}
% If \pkg{hyperref} is not loaded, the text is simply
% printed with the formatting command.
%    \begin{macrocode}
    \lngx_gloss_format:n { #1 }
  }
  \tag_mc_end:
  \tag_struct_end:
  \tag_mc_begin:n { }
}
%    \end{macrocode}
% I assign the default tagging plug to the socket I just
% defined.
%    \begin{macrocode}

\AssignTaggingSocketPlug { lngx / gloss } { default }
%    \end{macrocode}
% \begin{macro}{format}
% Now I define the key for adjusting the formatting of the
% glosses. It controls several keys contained in a separate
% set. In short, this key will take another keys as
% arguments.
%    \begin{macrocode}

\keys_define:nn { lngx_glossing } {
  format
  .meta:nn               = { lngx / gloss / format } { #1 },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{link color,\g__lngx_gloss_link_color_str}
% This option sets the colour used for glossing links. It is
% set to |black| by default.
%    \begin{macrocode}
  link~ color
  .str_gset:N            = \g__lngx_gloss_link_color_str,
  link~ color
  .initial:n             = { black },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{sort,\l__lngx_gls_sorting_order_str}
% Glosses can be sorted alphabetically or as they are used.
% The choice key for that is as follows. By default glosses
% are sorted alphabetically.
%    \begin{macrocode}
  sort
  .choices:nn            = { alphabetical, use } {
    \str_set_eq:NN \l__lngx_gls_sorting_order_str
                   \l_keys_choice_str
  },
  sort
  .initial:n             = { alphabetical },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
%   expansion case,\l__lngx_gls_expansion_case_str
% }
% The expansion can be printed in lower case, title case
% (with the first letter capitalised for all the words) or
% title case (with the first letter capitalised only for the
% first word). The default is lower case.
%    \begin{macrocode}
  expansion~ case
  .choices:nn            = {
    lowercase, title~ case~ all, title~ case~ first
  } {
    \str_set_eq:NN \l__lngx_gls_expansion_case_str
                   \l_keys_choice_str
  },
  expansion~ case
  .initial:n             = { lowercase },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{style,\l__lngx_glossary_style_str}
% The glossary can be printed in two styles given below.
% The default is |block|.
%    \begin{macrocode}
  style
  .choices:nn            = { block, inline } {
    \str_set_eq:NN \l__lngx_glossary_style_str
                   \l_keys_choice_str
  },
  style
  .initial:n             = { block },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{columns,\l__lngx_glossary_columns_int}
% There is an option to change the number of columns used
% for printing the glossary. It is controlled here. Default
% is 2.
%    \begin{macrocode}
  columns
  .int_set:N             = \l__lngx_glossary_columns_int,
  columns
  .initial:n             = { 2 },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
%   page numbers,\l__lngx_glosses_page_number_bool
% }
% Page numbers can be turned off with the following boolean.
% By default, they are active.
%    \begin{macrocode}
  page~ numbers
  .bool_set:N            =
    \l__lngx_glosses_page_number_bool,
  page~ numbers
  .initial:n             = { true },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{sectioning,\l__lngx_gls_sectioning_str}
% The section used for printing the glossary title is
% controlled by the following command. By default, I use
% \cs{section} for printing the title.
%    \begin{macrocode}
  sectioning
  .str_set:N             = \l__lngx_gls_sectioning_str,
  sectioning
  .initial:n             = { section },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% section number,\l__lngx_gls_section_number_bool
% }
% This controls if the sectioning level should be numbered
% or unnumbered. The default is false.
%    \begin{macrocode}
  section~ number
  .bool_set:N            = \l__lngx_gls_section_number_bool,
  section~ number
  .initial:n             = { false },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{no bold,\l__lngx_gls_bold_bool}
% The |no bold| key is defined as an inverse boolean. By
% default the key is set to false (resulting in the
% controlled boolean being true).
%    \begin{macrocode}
  no~ bold
  .bool_set_inverse:N    = \l__lngx_gls_bold_bool,
  no~ bold
  .initial:n             = { false },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{separator,\l__lngx_separator_tl}
% The separator between the glosses is controlled using this
% key. It controls the separator for inline glosses,
% expansion of glosses as well as glosses seen in the
% glossary. Each of these functions set a string variable
% which is expanded when this key is used. The default value
% of the string variable is gloss and the default value for
% this key is |,~|, which means by default the separator
% between glosses is a comma followed by a space.
%    \begin{macrocode}
  separator
  .code:n                = {
    \tl_set:cn {
      l_lngx_
      \str_use:N \l__lngx_separator_str
      _separator_tl
    } { #1 }
  },
  separator
  .initial:n             = { ,~ },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{entry separator,\l__lngx_entry_separator_tl}
% The separator between glossary entries is controlled using
% this key. The default is a |\par| token.
%    \begin{macrocode}
  entry~ separator
  .tl_set:N              = \l__lngx_entry_separator_tl,
  entry~ separator
  .initial:n             = { \par }
}
%    \end{macrocode}
% \end{macro}
% Sometimes language-specific settings are needed. I define
% the language string variable with the information
% retrieved from the lang key of the \textsc{pdf}.
%    \begin{macrocode}

\IfPDFManagementActiveT {
  \str_set:Ne \l_lngx_gls_language_str {
    \GetDocumentProperties { document / lang }
  }
}
%    \end{macrocode}
% \begin{macro}{gloss,\lngx_gloss_format:n}
% The formatting of glosses is defined here. By default they
% are printed in small caps.
%    \begin{macrocode}

\keys_define:nn { lngx / gloss / format  } {
  gloss
  .cs_gset_protected:Np  = \lngx_gloss_format:n #1,
  gloss
  .initial:n             = { \textsc { #1 } },
%    \end{macrocode}
% \end{macro}
% \begin{macro}{expansion,\lngx_expansion_format:n}
% The formatting of expansions is defined here. There is no
% change in the printing in the defaults.
%    \begin{macrocode}
  expansion
  .cs_gset_protected:Np  = \lngx_expansion_format:n #1,
  expansion
  .initial:n             = { #1 }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\setupglossing}
% A wrapper around these options is provided.
%    \begin{macrocode}

\NewDocumentCommand \setupglossing { m } {
  \keys_set:nn { lngx_glossing } { #1 }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\newgloss,\lngx_gloss_new:nn}
% A function that creates new glosses starts here. It takes
% 2 arguments.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_gloss_new:nn #1#2 {
%    \end{macrocode}
% First and foremost, the string received as the first
% argument should change its case to lowercase. It is done
% by \cs{str_lowercase:n}. I will use a temporary string
% variable for storing the converted value. This needs to be
% done locally so I start a group and clear the local |str|
% variable.
%    \begin{macrocode}
  \group_begin:
  \str_clear:N \l_tmpa_str
  \str_set:Ne \l_tmpa_str { \str_lowercase:n { #1 } }
%    \end{macrocode}
% Every gloss has its expansion stored in a token list
% associated to it. The token list is declared here and it
% is set to the expansion (i.e., |#2|).
%    \begin{macrocode}
  \tl_gclear_new:c {
    g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
  }
  \seq_gclear_new:c {
    g_lngx_ \str_use:N \l_tmpa_str _pages_seq
  }
  \tl_gset:cn {
    g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
  } { #2 }
%    \end{macrocode}
% Whenever a gloss is defined, an internal protected command
% is defined. It doesn’t take any argument.
%    \begin{macrocode}
  \cs_new_protected:cpn {
    __lngx_gloss_ \str_use:N \l_tmpa_str :
  } {
%    \end{macrocode}
% The arguments are passed to the tagging socket. Since the
% tagging socket doesn’t expand everything, an exhaustive
% expansion is performed with the help of \cs{exp_args:Nee}.
% This is done only if the \cs{DocumentMetadata} command is
% used.
%    \begin{macrocode}
    \IfDocumentMetadataTF {
      \exp_args:Nee \UseTaggingSocket
                    { lngx / gloss }
                    { \str_use:N \l_tmpa_str }
                    { #2 }
    } {
      \IfPackageLoadedTF { hyperref } {
        \group_begin:
        \exp_args:Ne \hypersetup {
          linkcolor            = {
            \exp_not:V \g__lngx_gloss_link_color_str
          }
        }
        \IfPDFManagementActiveT {
          \socket_if_exist:nT {
            hyp / link / GoTo / Contents
          } {
            \socket_assign_plug:nn {
              hyp / link / GoTo / Contents
            } { text }
          }
        }
        \lngx_gloss_format:n {
          \hyperlink { lngx_ #1 _glossary } { #1 }
        }
        \group_end:
      } {
        \lngx_gloss_format:n { #1 }
      }
    }
%    \end{macrocode}
% I use \cs{label}-\cs{ref} mechanism for saving the page
% numbers of the glosses. An internal integer called
% \cs{g__lngx_page_ref_int} is used to generate unique
% numbers. The kernel provides \cs{seq_remove_duplicates:N},
% but as it iterates on each and every item, it is slow. The
% duplicates can be avoided if the items are added to the
% sequence conditionally and only when they don’t exist
% already in the sequence. This way duplicates are not
% generated at all. This method is used for adding to the
% sequences that respectively store the page numbers of
% glosses and the order in which they were used. Imagine if
% a gloss is used twice on a page, it doesn’t make sense to
% add the same page number twice. Similarly, if a gloss is
% used, it is added to the sequence of used glosses. It
% doesn’t make sense to add it 10 times again and removing
% the 9 duplicates later.
%    \begin{macrocode}
    \int_gincr:N \g__lngx_page_ref_int
    \exp_args:Ne
    \label { lngx_gloss_ \int_use:N \g__lngx_page_ref_int }
    \cs_if_exist:cT {
      r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int
    } {
      \group_begin:
      \tl_clear:N \l_tmpa_tl
      \tl_set:Ne \l_tmpa_tl {
        \exp_not:N \use_ii:nnnnn
        \use:c {
          r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int
        }
      }
      \seq_if_in:cVF {
        g_lngx_ \str_use:N \l_tmpa_str _pages_seq
      } \l_tmpa_tl {
        \seq_gput_right:ce {
          g_lngx_ \str_use:N \l_tmpa_str _pages_seq
        } {
          \exp_not:N \use_ii:nnnnn
          \use:c {
            r @ lngx_gloss_ \int_use:N \g__lngx_page_ref_int
          }
        }
      }
      \group_end:
    }
    \seq_if_in:NeF \g__lngx_gls_use_order_seq {
      \str_use:N \l_tmpa_str
    } {
      \seq_gput_right:Ne \g__lngx_gls_use_order_seq
                         { \str_use:N \l_tmpa_str }
    }
  }
  \group_end:
}

\cs_gset_eq:NN \newgloss \lngx_gloss_new:nn
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\renewgloss}
% Implementing the \cs{renewgloss} command is actually quite
% easy. The definition of \cs{lngx_gloss_new:nn} uses only a
% single command that errors if the control sequence is
% already defined, i.e., \cs{cs_new_protected:cpn}. In order
% to renew a gloss, simply undefining the existing command
% declared with \cs{lngx_gloss_new:nn} suffices. Later the
% arguments are passed to the same command again. No \LaTeX3
% equivalent for this is provided.
%    \begin{macrocode}

\NewDocumentCommand \renewgloss { m m } {
  \cs_undefine:c { __lngx_gloss_ #1 : }
  \lngx_gloss_new:nn { #1 } { #2 }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\glx}
% The command to use a gloss takes three arguments where the
% first is an optional asterisk. If it is used, the
% expansion of the gloss is printed without any special
% tags, just as plain text. Otherwise the internal command
% for printing the gloss is used with the third argument.
% The third argument is a clist. Any number of glosses can
% be added to the list. The action is then repeated on each
% and every item of the list. The second argument is a list
% of options for customising the output. Everything is
% computed locally so that for the settings don’t leak. I
% perform the action on the first item as desired, then the
% same is applied to the remaining items with a preceding
% separator. So that all the items are separated properly.
%    \begin{macrocode}

\NewDocumentCommand \glx { s O{ } m } {
  \group_begin:
  \IfBooleanT { #1 } {
    \bool_set_true:N \l_lngx_expansion_bool
    \str_set:Nn \l__lngx_separator_str { expansion }
    \keys_set:nn { lngx_glossing } {
      separator              = { , \c_space_tl }
    }
  }
  \keys_set:nn { lngx_glossing } { #2 }
  \tl_clear:N \l_tmpa_tl
  \seq_clear:N \l_tmpa_seq
  \seq_set_from_clist:Nn \l_tmpa_seq { #3 }
  \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
  \str_set:Ne \l_tmpa_str {
    \exp_args:Ne \str_lowercase:n {
      \tl_use:N \l_tmpa_tl
    }
  }
  \bool_if:NTF \l_lngx_expansion_bool {
    \str_case:Vn \l__lngx_gls_expansion_case_str {
      { lowercase } {
        \text_lowercase:n {
          \tl_use:c {
            g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
          }
        }
      }
      { title~ case~ all } {
        \text_titlecase_all:n {
          \tl_use:c {
            g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
          }
        }
      }
      { title~ case~ first } {
        \text_titlecase_first:n {
          \tl_use:c {
            g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
          }
        }
      }
    }
  } {
    \use:c { __lngx_gloss_ \str_use:N \l_tmpa_str : }
  }
  \seq_if_empty:NF \l_tmpa_seq {
    \seq_map_inline:Nn \l_tmpa_seq {
      \group_begin:
      \str_clear:N \l_tmpa_str
      \str_set:Ne \l_tmpa_str {
        \exp_args:Ne \str_lowercase:n { ##1 }
      }
      \bool_if:NTF \l_lngx_expansion_bool {
        \str_case:Vn \l__lngx_gls_expansion_case_str {
          { lowercase } {
            \tl_use:N \l_lngx_expansion_separator_tl
            \text_lowercase:n {
              \tl_use:c {
                g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
              }
            }
          }
          { title~ case~ all } {
            \tl_use:N \l_lngx_expansion_separator_tl
            \text_titlecase_all:n {
              \tl_use:c {
                g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
              }
            }
          }
          { title~ case~ first } {
            \tl_use:N \l_lngx_expansion_separator_tl
            \text_titlecase_first:n {
              \tl_use:c {
                g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
              }
            }
          }
        }
      } {
        \tl_use:N \l_lngx_gloss_separator_tl
        \use:c { __lngx_gloss_ \str_use:N \l_tmpa_str : }
      }
      \group_end:
    }
  }
  \group_end:
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\__lngx_dotfill:nnn}
% For the dotfill between the gloss and the expansion, I
% create a custom internal command. The code is based on
% user Jonathan P.\ Spratte’s answer seen here:
% \url{topanswers.xyz/tex?q=8155#a7758}. The dotfill should
% not be tagged at all and in fact it should be suppressed
% so that the readers don’t go ‘dot, dot, dot, dot \dots’
% (Frank has convinced us forever with his \textsc{tug} 2025
% talk).
%    \begin{macrocode}

\cs_new_protected:Npn \__lngx_dotfill:nnn #1#2#3 {
  %% Courtesy: Jonathan P. Spratte
  %% topanswers.xyz/tex?q=8155#a7758 (LPPL)
  \l__lngx_entry_separator_tl
  \smallskip
  \group_begin:
  \rightskip             = 0pt plus -1fil \prg_do_nothing:
  \parfillskip           = 0pt plus 1fil  \prg_do_nothing:
  \leftskip              = 1em plus 1fil  \prg_do_nothing:
  \finalhyphendemerits   = 0              \prg_do_nothing:
  \parindent             = -1em           \prg_do_nothing:
  \bool_if:NT \l__lngx_gls_bold_bool { \textbf } {
    \lngx_gloss_format:n {
      #1
    }
    \tl_use:N \l_lngx_glossary_separator_tl
  }
  #2
  \leavevmode
  \quad
  \IfDocumentMetadataT {
    \tag_mc_end:
    \tag_struct_begin:n {
      tag                    = { Span },
      actualtext             = { }
    }
    \tag_mc_begin:n {
      tag                    = { Span }
    }
  }
  \cleaders
    \hbox to 0.44em { \hss . \hss }
    \hskip 0.5cm plus 1fill \prg_do_nothing:
  \IfDocumentMetadataT {
    \tag_mc_end:
    \tag_struct_end:
    \tag_mc_begin:n { }
  }
  \quad
  \kern 0pt \prg_do_nothing:
  \em #3
  \l__lngx_entry_separator_tl
  \group_end:
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{lngx_multicols}
% Here I define the custom multicolumn environment which
% does nothing if the number of columns is 1.
%    \begin{macrocode}

\NewDocumentEnvironment { lngx_multicols } { m } {
  \int_compare:nNnTF { 1 } < {
    \int_use:N \l__lngx_glossary_columns_int
  } {
    \begin { multicols } {
      \int_use:N \l__lngx_glossary_columns_int
    } [ #1 ]
  } { #1 }
  \noindent
} {
  \int_compare:nNnT { 1 } < {
    \int_use:N \l__lngx_glossary_columns_int
  } {
    \end { multicols }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngx_gloss_list:}
% Finally we come to the command that prints the glosses.
% First it sets the boolean for creating the aux file to
% false.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_gloss_list: {
  \bool_gset_false:N \g_lngx_trigger_aux_file_bool
%    \end{macrocode}
% I start a group, clear a scratch sequence and set it equal
% to the sequence that stores the order of the glosses. If
% the aux file is read, the |aux| flag is added to the
% variable, or else it is read on the fly.
%    \begin{macrocode}
  \group_begin:
  \seq_clear:N \l_tmpa_seq
  \seq_set_eq:NN \l_tmpa_seq \g__lngx_gls_use_order_seq
%    \end{macrocode}
% If the sorting order is set to |alphabetical|, the
% sequence needs to get sorted. For that, I use \LaTeX3’s
% mechanism for sorting strings.
%    \begin{macrocode}
  \str_case:Vn \l__lngx_gls_sorting_order_str {
    { alphabetical } {
      \seq_sort:Nn \l_tmpa_seq {
        \str_compare:nNnTF { ##1 } > { ##2 } {
          \sort_return_swapped:
        } {
          \sort_return_same:
        }
      }
    }
  }
%    \end{macrocode}
% If the style used is |inline|, the glosses come after the
% each other. That means the default entry separator, i.e.,
% |\par| must be changed. Here I set it to |,~| by default
% (locally). The separator between the gloss and the entry
% is defined as a colon followed by a space.
%    \begin{macrocode}
  \str_if_eq:VnTF \l__lngx_glossary_style_str { inline } {
    \group_begin:
    \keys_set:nn { lngx_glossing } {
      separator              = { \c_colon_str \c_space_tl },
      entry~ separator       = { ,~ }
    }
%    \end{macrocode}
% Then each item from the sequence is popped (from the
% left). It is then passed to a string variable to get rid
% of the catcodes. The string variable is then used in
% \cs{MakeLinkTarget*}. The gloss is then printed with its
% separator in bold shape.
%    \begin{macrocode}
    \tl_clear:N \l_tmpa_tl
    \str_clear:N \l_tmpa_str
    \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
    \str_set:NV \l_tmpa_str \l_tmpa_tl
    \tag_mc_end:
    \tag_struct_begin:n {
      tag                    = { Span },
    }
    \tag_mc_begin:n {
      tag                    = { Span }
    }
    \MakeLinkTarget * {
      lngx_ \str_use:N \l_tmpa_str _glossary
    }
    \bool_if:NT \l__lngx_gls_bold_bool { \textbf } {
      \lngx_gloss_format:n {
        \tl_use:N \l_tmpa_tl
        \tl_use:N \l_lngx_glossary_separator_tl
      }
    }
    \tag_mc_end:
    \tag_struct_end:
%    \end{macrocode}
% Then it is checked in which case the expansion is
% requested. According to that the |tl| is printed.
%    \begin{macrocode}
    \str_case:Vn \l__lngx_gls_expansion_case_str {
      { lowercase } {
        \lngx_expansion_format:n {
          \text_lowercase:n {
            \tl_use:c {
              g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
            }
          }
        }
      }
      { title~ case~ all } {
        \lngx_expansion_format:n {
          \text_titlecase_all:n {
            \tl_use:c {
              g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
            }
          }
        }
      }
      { title~ case~ first } {
        \lngx_expansion_format:n {
          \text_titlecase_first:n {
            \tl_use:v {
              g_lngx_ \str_use:N \l_tmpa_str _expansion_tl
            }
          }
        }
      }
    }
%    \end{macrocode}
% After printing one entry successfully, if there are any
% more items left in the sequence, they are printed with the
% same method, but with an entry separator at the beginning.
%    \begin{macrocode}
    \seq_if_empty:NF \l_tmpa_seq {
      \seq_map_inline:Nn \l_tmpa_seq {
        \group_begin:
        \tl_use:N \l__lngx_entry_separator_tl
        \MakeLinkTarget * { lngx_ ##1 _glossary }
        \textbf {
          \lngx_gloss_format:n {
            ##1
            \tl_use:N \l_lngx_glossary_separator_tl
          }
        }
        \str_case:Vn \l__lngx_gls_expansion_case_str {
          { lowercase } {
            \lngx_expansion_format:n {
              \text_lowercase:n {
                \exp_not:v { g_lngx_ ##1 _expansion_tl }
              }
            }
          }
          { title~ case~ all } {
            \lngx_expansion_format:n {
              \text_titlecase_all:n {
                \exp_not:v { g_lngx_ ##1 _expansion_tl }
              }
            }
          }
          { title~ case~ first } {
            \lngx_expansion_format:n {
              \text_titlecase_first:n {
                \exp_not:v { g_lngx_ ##1 _expansion_tl }
              }
            }
          }
        }
        \group_end:
      }
    }
    \group_end:
  } {
%    \end{macrocode}
% If the style is not |inline|, then the default |block|
% style is assumed and firstly the word ‘glossary’ is
% printed in a sectioning command controlled by the keys.
% The \cs{glossaryname} command is provided by \pkg{babel}.
% If it is undefined, that means the user hasn’t loaded
% \pkg{babel}. In that case, I define the command with the
% string |Glossary|.
%    \begin{macrocode}
    \ProvideDocumentCommand \glossaryname { } { Glossary }
%    \end{macrocode}
% Then the |lngx_multicols| environment starts which
% doesn’t do anything if the number of columns is 1.
%    \begin{macrocode}
    \begin { lngx_multicols } {
      \str_if_eq:VnF \l__lngx_gls_sectioning_str { null } {
        \use:e {
          \exp_not:N \use:c
          { \str_use:N \l__lngx_gls_sectioning_str }
          \bool_if:NF \l__lngx_gls_section_number_bool { * }
          { \exp_not:N \glossaryname }
        }
      }
    }
      \seq_map_inline:Nn \l_tmpa_seq {
%    \end{macrocode}
% In this style, even the page numbers are printed along
% with glosses. We save the page numbers in a temporary
% sequence which is locally cleared.
%    \begin{macrocode}
        \group_begin:
        \seq_clear:N \l_tmpb_seq
        \seq_map_inline:cn { g_lngx_ ##1 _pages_seq } {
%    \end{macrocode}
% The pages are hyperlinked with the internal \textsc{pdf}
% names.
%    \begin{macrocode}
          \seq_put_right:Ne \l_tmpb_seq { ####1 }
        }
%    \end{macrocode}
% The page numbers are separated using dotfill. Before the
% glosses, \cs{MakeLinkTarget*} is used.
%    \begin{macrocode}
        \__lngx_dotfill:nnn {
          \MakeLinkTarget * { lngx_ ##1 _glossary }
          ##1
        } {
%    \end{macrocode}
% The case of expansion is checked and then the appropriate
% casing commands are used for expansions.
%    \begin{macrocode}
          \str_case:Vn \l__lngx_gls_expansion_case_str {
            { lowercase } {
              \lngx_expansion_format:n {
                \text_lowercase:n {
                  \exp_not:v { g_lngx_ ##1 _expansion_tl }
                }
              }
            }
            { title~ case~ all } {
              \lngx_expansion_format:n {
                \text_titlecase_all:n {
                  \exp_not:v { g_lngx_ ##1 _expansion_tl }
                }
              }
            }
            { title~ case~ first } {
              \lngx_expansion_format:n {
                \text_titlecase_first:n {
                  \exp_not:v { g_lngx_ ##1 _expansion_tl }
                }
              }
            }
          }
        } {
%    \end{macrocode}
% The list of page numbers is printed.
%    \begin{macrocode}
          \seq_use:Nn \l_tmpb_seq { ,~ }
        }
        \group_end:
      }
    \end { lngx_multicols }
  }
  \group_end:
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\listofglosses}
% Here is the command that defines the user-side command for
% printing the glosses. It defines the separator by default
% if not provided. All settings are local in order to avoid
% leaking. \cs{l_lngx_separator_tl} is the generic string
% that is used inside the |separator| key that sets the
% separator contextually. This command uses the \LaTeX3
% function for printing the glosses.
%    \begin{macrocode}

\NewDocumentCommand \listofglosses { O { } } {
  \group_begin:
  \str_set:Nn \l__lngx_separator_str { glossary }
  \keys_set:nn { lngx_glossing } {
    separator            = { \c_colon_str \c_space_tl }
  }
  \keys_set:nn { lngx_glossing } { #1 }
  \lngx_gloss_list:
  \group_end:
}
%</glossing>
%    \end{macrocode}
% \end{macro}
% \newpage
% \lngximplementation{ipa}
%    \begin{macrocode}
%<*ipa>
\ProvidesExplPackage{linguistix-ipa}
                    {2026-02-02}
                    {v0.8}
                    {%
                      A package for typesetting the IPA
                      (International Phonetic Alphabet) from
                      the ‘LinguisTiX’ bundle.%
                    }
%    \end{macrocode}
% Then, I load \pkg{unicode-math} or \pkg{lua-unicode-math}
% (depending on the engine used), \lngxnfsslogo\ and
% \lngxbaselogo\ (if they are not already loaded).
%    \begin{macrocode}

\sys_if_engine_luatex:TF {
  \IfPackageLoadedF { unicode-math } {
    \IfPackageLoadedF { lua-unicode-math } {
      \RequirePackage { fontspec, lua-unicode-math }
    }
  }
} {
  \IfPackageLoadedF { unicode-math } {
    \RequirePackage { unicode-math }
  }
}

\IfPackageLoadedF { linguistix-base } {
  \RequirePackage { linguistix-base }
}

\IfPackageLoadedF { linguistix-nfss } {
  \RequirePackage { linguistix-nfss }
}

\IfPackageLoadedF { linguistix-fixpex } {
  \RequirePackage { linguistix-fixpex }
}
%    \end{macrocode}
% \begin{macro}{\ipatext,\ipatext*}
% The |\ipatext| command along with its starred variant is
% developed here.
% \begin{macrocode}

\NewDocumentCommand \ipatext { s m } {
  \IfBooleanTF { #1 } {
    {
      \lngxipa
      / #2 /
    }
  } {
    {
      \lngxipa
      [ #2 ]
    }
  }
}
%    \end{macrocode}
% \end{macro}
% \newpage
% \begin{macro}{^^A
% \g__lngx_ipa_main_fonts_prop,^^A
% \g__lngx_ipa_main_font_features_tl,^^A
% ipa upright,ipa upright features,ipa bold upright,ipa bold
% upright features,ipa italic,ipa italic features,ipa bold
% italic,ipa bold italic features,ipa slanted,ipa slanted
% features,ipa bold slanted,ipa bold slanted features,ipa
% swash,ipa swash features,ipa bold swash,ipa bold swash
% features,ipa small caps,ipa small caps features,^^A
% }
% These variables store the values for fonts and features
% for the serif \textsc{ipa}.
%    \begin{macrocode}

\prop_gclear_new:N \g__lngx_ipa_main_fonts_prop
\tl_gclear_new:N \g__lngx_ipa_main_font_features_tl

\clist_map_inline:nn {
  upright,
  bold~ upright,
  italic,
  bold~ italic,
  slanted,
  bold~ slanted,
  swash,
  bold~ swash,
  small~ caps
} {
%    \end{macrocode}
% All the keys here are prefixed with the word |ipa| in
% order to distinguish them from the keys provided by the
% \lngxfontslogo\ package. These keys have identical method
% as their text counterparts, though.
%    \begin{macrocode}
  \keys_define:nn { lngx_keys } {
    ipa~ #1
    .code:n                = {
      \group_begin:
      \str_clear:N \l_tmpa_str
      \str_set:Ne \l_tmpa_str {
        \text_titlecase_all:n { #1 }
        Font
      }
      \str_replace_all:Nnn \l_tmpa_str { ~ } { }
      \prop_gput:Nne \g__lngx_ipa_main_fonts_prop
                     { ipa~ #1 }
                     { \str_use:N \l_tmpa_str = { ##1 } }
      \group_end:
    },
    ipa~ #1~ features
    .code:n                = {
      \group_begin:
      \str_clear:N \l_tmpa_str
      \str_set:Ne \l_tmpa_str {
        \text_titlecase_all:n { #1 }
        Features
      }
      \str_replace_all:Nnn \l_tmpa_str { ~ } { }
      \prop_gput:Nne \g__lngx_ipa_main_fonts_prop
                     { ipa~ #1~ features }
                     {
                       \str_use:N \l_tmpa_str = { ##1 }
                     }
      \group_end:
    }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa extra features}
% This key adds to the property that stores the extra
% features for the serif fonts.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ extra~ features
  .prop_gput:N           = \g__lngx_ipa_main_fonts_prop
}
%    \end{macrocode}
% \end{macro}
% \newpage
% \begin{macro}{^^A
% \g__lngx_ipa_sans_fonts_prop,^^A
% \g__lngx_ipa_sans_font_features_tl,^^A
% \g__lngx_ipa_mono_fonts_prop,^^A
% \g__lngx_ipa_mono_font_features_tl,^^A
% ipa sans upright,ipa sans upright features,ipa sans
% bold upright,ipa sans bold upright features,ipa sans
% italic,ipa sans italic features,ipa sans bold
% italic,ipa sans bold italic features,ipa sans
% slanted,ipa sans slanted features,ipa sans bold
% slanted,ipa sans bold slanted features,ipa sans
% swash,ipa sans swash features,ipa sans bold swash,ipa
% sans bold swash features,ipa sans small caps,ipa sans
% small caps features,ipa mono upright,ipa mono upright
% features,ipa mono bold upright,ipa mono bold upright
% features,ipa mono italic,ipa mono italic features,ipa
% mono bold italic,ipa mono bold italic features,ipa mono
% slanted,ipa mono slanted features,ipa mono bold
% slanted,ipa mono bold slanted features,ipa mono
% swash,ipa mono swash features,ipa mono bold swash,ipa
% mono bold swash features,ipa mono small caps,ipa mono
% small caps features^^A
% }
% Since the only difference between the upcoming keys is
% that of the word |sans| and |mono|, we combine them
% together and use a nested |clist|. The rest of the
% mechanism is identical.
%    \begin{macrocode}

\prop_gclear_new:N \g__lngx_ipa_sans_fonts_prop
\tl_gclear_new:N \g__lngx_ipa_sans_font_features_tl
\prop_gclear_new:N \g__lngx_ipa_mono_fonts_prop
\tl_gclear_new:N \g__lngx_ipa_mono_font_features_tl

\clist_map_inline:nn {
  sans,
  mono
} {
  \clist_map_inline:nn {
    upright,
    bold~ upright,
    italic,
    bold~ italic,
    slanted,
    bold~ slanted,
    swash,
    bold~ swash,
    small~ caps
  } {
    \keys_define:nn { lngx_keys } {
      ipa~ #1~ ##1
      .code:n                = {
        \group_begin:
        \str_clear:N \l_tmpa_str
        \str_set:Ne \l_tmpa_str {
          \text_titlecase_all:n { ##1 }
          Font
        }
        \str_replace_all:Nnn \l_tmpa_str { ~ } { }
        \prop_gput:cne { g__lngx_ipa_ #1 _fonts_prop }
                       { ipa~ #1~ ##1 }
                       { ####1 }
        \group_end:
      },
      ipa~ #1~ ##1~ features
      .code:n                = {
        \group_begin:
        \str_clear:N \l_tmpa_str
        \str_set:Ne \l_tmpa_str {
          \text_titlecase_all:n { #1 }
          Features
        }
        \str_replace_all:Nnn \l_tmpa_str { ~ } { }
        \prop_gput:cne { g__lngx_ipa_ #1 _fonts_prop }
                       { ipa~ #1~ ##1~ features }
                       {
                         \str_use:N \l_tmpa_str = { ####1 }
                       }
        \group_end:
      }
    }
  }
  \keys_define:nn { lngx_keys } {
    ipa~ #1~ extra~ features
    .prop_gput:c           = {
                               g__lngx_ipa_ #1 _fonts_prop
                             }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \g__lngx_ipa_main_font_tl,\g__lngx_ipa_sans_font_tl,^^A
% \g__lngx_ipa_mono_font_tl,ipa main font,ipa sans font,ipa
% mono font^^A
% }
% These keys provide keys to set fonts for \textsc{ipa}.
%    \begin{macrocode}

\clist_map_inline:nn {
  main,
  sans,
  mono
} {
  \keys_define:nn { lngx_keys } {
    ipa~ #1~ font
    .tl_gset:c             = { g__lngx_ipa_ #1 _font_tl }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm}
% This key is of type |.meta:n|. It sets certain other keys
% that enable the New Computer Modern fonts in book weight
% and in all of the serif, sans serif and monospaced
% families for \textsc{ipa}. Stylistic set 5 of NewCM is
% dedicated to linguistics. So we use it here. For correct
% diacritic placement, we need HarfBuzz renderer. That also
% is loaded here.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCM10-Book.otf },
    ipa~ sans~ font        = { NewCMSans10-Book.otf },
    ipa~ mono~ font        = { NewCMMono10-Book.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm sans}
% This is a |.meta:n| key that sets the default \textsc{ipa}
% font to the sans family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm~ sans
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCMSans10-Book.otf },
    ipa~ sans~ font        = { NewCMSans10-Book.otf },
    ipa~ mono~ font        = { NewCMMono10-Book.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm mono}
% This is a |.meta:n| key that sets the default \textsc{ipa}
% fonts to the monospaced family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm~ mono
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCMMono10-Book.otf },
    ipa~ sans~ font        = { NewCMSans10-Book.otf },
    ipa~ mono~ font        = { NewCMMono10-Book.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm regular}
% This is a |.meta:n| key that sets the default fonts to the
% regular variant of the New Computer Modern family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm~ regular
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCM10-Regular.otf },
    ipa~ sans~ font        = { NewCMSans10-Regular.otf },
    ipa~ mono~ font        = { NewCMMono10-Regular.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm regular sans}
% This is a |.meta:n| key that sets the default \textsc{ipa}
% fonts to the regular sans variant of the New Computer
% Modern family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm~ regular~ sans
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCMSans10-Regular.otf },
    ipa~ sans~ font        = { NewCMSans10-Regular.otf },
    ipa~ mono~ font        = { NewCMMono10-Regular.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{ipa newcm regular mono}
% This is a |.meta:n| key that sets the default \textsc{ipa}
% fonts to the regular monospaced variant of the New
% Computer Modern family.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  ipa~ newcm~ regular~ mono
  .meta:n                = {
    ipa~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ sans~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ mono~ extra~
    features               = {
      Renderer               = {HarfBuzz},
      StylisticSet           = {05}
    },
    ipa~ main~ font        = { NewCMMono10-Regular.otf },
    ipa~ sans~ font        = { NewCMSans10-Regular.otf },
    ipa~ mono~ font        = { NewCMMono10-Regular.otf }
  }
}
%    \end{macrocode}
% \end{macro}
% We set the |ipa newcm| key by default.
%    \begin{macrocode}

\lngx_set_keys:n {ipa~ newcm}
%    \end{macrocode}
% \begin{macro}{^^A
%   \lngx_set_main_ipa_font:nn,\lngx_main_ipa:,^^A
%   lngx_ipa_rm_nfss,^^A
%   \lngx_set_sans_ipa_font:nn,\lngx_sans_ipa:,^^A
%   lngx_ipa_sf_nfss,^^A
%   \lngx_set_mono_ipa_font:nn,\lngx_mono_ipa:,^^A
%   lngx_ipa_tt_nfss^^A
% }
% Here, I develop font-setting commands for \textsc{ipa}.
% These commands are set with |\setfontfamily|, so they
% keep overriding the definitions of the same command names.
% These commands set \textsc{nfss} families that we use
% later for setting the \textsc{ipa} fonts. These functions
% and \textsc{nfss} families are public, but manipulating
% them has effects (mostly desired) at several other places,
% so use them with caution.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_set_main_ipa_font:nn #1#2 {
  \setfontfamily \lngx_main_ipa: [
    #1,
    NFSSFamily             = { lngx_ipa_rm_nfss }
  ] { #2 }
}

\cs_new_protected:Npn \lngx_set_sans_ipa_font:nn #1#2 {
  \setfontfamily \lngx_sans_ipa: [
    #1,
    NFSSFamily             = { lngx_ipa_sf_nfss }
  ] { #2 }
}

\cs_new_protected:Npn \lngx_set_mono_ipa_font:nn #1#2 {
  \setfontfamily \lngx_mono_ipa: [
    #1,
    NFSSFamily             = { lngx_ipa_tt_nfss }
  ] { #2 }
}

\cs_generate_variant:Nn \lngx_set_main_ipa_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_sans_ipa_font:nn { VV }
\cs_generate_variant:Nn \lngx_set_mono_ipa_font:nn { VV }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{lngx_ipa}
% Here, I create a \enquote{super font family} with
% |\lngx_super_font_family:nn|, a macro provided by
% \lngxnfsslogo. Please see the documentation of that
% package for more information. Note that |lngx_ipa| is a
% super family responsible for all the \textsc{ipa}-related
% functions of the package. It is associated with the
% \textsc{nfss} families defined just now for the
% \textsc{ipa}.
%    \begin{macrocode}

\lngx_super_font_family:nn { lngx_ipa } {
  rm                     = { lngx_ipa_rm_nfss },
  sf                     = { lngx_ipa_sf_nfss },
  tt                     = { lngx_ipa_tt_nfss }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngxipa,\lngx_ipa:}
% I use |\lngx_softer_super_font_family:n| provided by
% \lngxnfsslogo for defining this switch to the
% \textsc{ipa}.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_ipa: {
  \lngx_softer_super_font_family:n { lngx_ipa }
}

\cs_gset_eq:NN \lngxipa \lngx_ipa:
%    \end{macrocode}
% \end{macro}
% Now, I have used the exact same method that I described in
% the implementation of \lngxfontslogo\ for setting the size
% variants. This is done with lazy evaluation, just before
% |\begin{document}|.
%    \begin{macrocode}

\clist_map_inline:nn {
  main,
  sans,
  mono
} {
  \cs_new_protected:cpn {
    lngx_build_ #1 _ipa_font_features:
  } {
    \prop_map_inline:cn { g__lngx_ipa_ #1 _fonts_prop } {
      \tl_gput_right:cn {
                          g__lngx_ipa_ #1 _font_features_tl
                        } { ####2 }
    }
  }
}

\hook_gput_code:nnn { begindocument / before } { . } {
  \lngx_build_main_ipa_font_features:
  \lngx_set_main_ipa_font:VV
    \g__lngx_ipa_main_font_features_tl
    \g__lngx_ipa_main_font_tl
  \lngx_build_sans_ipa_font_features:
  \lngx_set_sans_ipa_font:VV
    \g__lngx_ipa_sans_font_features_tl
    \g__lngx_ipa_sans_font_tl
  \lngx_build_mono_ipa_font_features:
  \lngx_set_mono_ipa_font:VV
    \g__lngx_ipa_mono_font_features_tl
    \g__lngx_ipa_mono_font_tl
}
%</ipa>
%    \end{macrocode}
% \newpage
% \lngximplementation{languages}
%    \begin{macrocode}
%<*lang>
\ProvidesExplPackage{linguistix-languages}
                    {2026-02-02}
                    {v0.8}
                    {%
                      An assistant package for automatically
                      loading fonts and more settings for
                      languages.%
                    }
%    \end{macrocode}
% \lngxbaselogo\ is loaded (if not already done) for the
% key-value parser.
%    \begin{macrocode}

\IfPackageLoadedF { linguistix-base } {
  \RequirePackage { linguistix-base }
}
%    \end{macrocode}
% The \textsf{babel} package is loaded with |provide*=*|
% option as it mandates the use of modern mechanism.
%    \begin{macrocode}

\IfPackageLoadedF { babel } {
  \RequirePackage [ provide * = * ] { babel }
}
%    \end{macrocode}
% \begin{macro}{\g_lngx_main_language_tl}
% I declare a |tl| that I will use for storing the main
% language. It is publicly available.
%    \begin{macrocode}

\tl_new:N \g_lngx_main_language_tl
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\g_lngx_languages_clist}
% I declare a |clist| that I will use for storing languages.
% It is publicly available.
%    \begin{macrocode}

\clist_new:N \g_lngx_languages_clist
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngx_languages:nn,\providelanguage}
% I develop a wrapper macro with a |:VV| variant.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_languages:nn #1#2 {
  \babelprovide [ #1 ] { #2 }
}

\cs_generate_variant:Nn \lngx_languages:nn { VV }
\cs_gset_eq:NN \providelanguage \lngx_languages:nn
%    \end{macrocode}
% \end{macro}
% The \pkg{babel} package produces an \enquote{info} message
% if the fonts are not set with |\babelfont|. Mostly they
% aren’t set with this mechanism, so this warning is
% inevitable in default situations. Imagine loading
% \lngxfontslogo\ first and then loading this package. The
% fonts are already set with |\setmainfont| and friends.
% Thus we will be prompted with this warning always. In
% order to avoid that, I renew the wrapper functions around
% |\setmainfont| to |\babelfont|. Note that this only
% affects the usage when \lngxfontslogo\ is loaded. If you
% use \lngxlanguageslogo\ and then use |\setmainfont|-like
% commands, you will get |babel|’s warning and I have no
% intention to suppress that behaviour.
%    \begin{macrocode}

\IfPackageLoadedTF { linguistix-fonts } {
  \cs_gset_protected:Npn \lngx_set_main_font:nn #1#2 {
    \babelfont { rm } [ #1 ] { #2 }
  }
  \cs_gset_protected:Npn \lngx_set_sans_font:nn #1#2 {
    \babelfont { sf } [ #1 ] { #2 }
  }
  \cs_gset_protected:Npn \lngx_set_mono_font:nn #1#2 {
    \babelfont { tt } [ #1 ] { #2 }
  }
} {
  \cs_new_protected:Npn \lngx_set_main_font:nn #1#2 {
    \babelfont { rm } [ #1 ] { #2 }
  }
  \cs_new_protected:Npn \lngx_set_sans_font:nn #1#2 {
    \babelfont { sf } [ #1 ] { #2 }
  }
  \cs_new_protected:Npn \lngx_set_mono_font:nn #1#2 {
    \babelfont { tt } [ #1 ] { #2 }
  }
}
%    \end{macrocode}
% \begin{macro}{^^A
%   \lngx_other_main_font:nnn,^^A
%   \lngx_other_sans_font:nnn,^^A
%   \lngx_other_mono_font:nnn
% }
% The following macros set fonts for other languages using
% the |\babelfont| command.
%    \begin{macrocode}

\cs_gset_protected:Npn \lngx_other_main_font:nnn #1#2#3 {
  \babelfont [ #1 ] { rm } [ #2 ] { #3 }
}

\cs_gset_protected:Npn \lngx_other_sans_font:nnn #1#2#3 {
  \babelfont [ #1 ] { sf } [ #2 ] { #3 }
}

\cs_gset_protected:Npn \lngx_other_mono_font:nnn #1#2#3 {
  \babelfont [ #1 ] { tt } [ #2 ] { #3 }
}

\cs_generate_variant:Nn \lngx_other_main_font:nnn { nee }
\cs_generate_variant:Nn \lngx_other_sans_font:nnn { nee }
\cs_generate_variant:Nn \lngx_other_mono_font:nnn { nee }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngx_load_languages:n,\loadlanguages}
% I provide a simple macro that only does the job of loading
% languages, both in \LaTeX3 style, as well as the in the
% plain style.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_load_languages:n #1 {
  \lngx_set_keys:n { languages = { #1 } }
}

\cs_gset_eq:NN \loadlanguages \lngx_load_languages:n
%    \end{macrocode}
% \end{macro}
% I equate the \cs{arabic} command to a new command I want
% to provide. This is done in order to get control over the
% default \LaTeX\ counters. The command is manipulated when
% plugs are activated.
% \begin{macro}{\lngx_counter:n}
%    \begin{macrocode}

\cs_gset_eq:NN \lngx_counter:n \arabic
%    \end{macrocode}
% \end{macro}
% Now all the default counters are changed from \cs{arabic}
% to \cs{lngx_counter:n}.
%    \begin{macrocode}

\cs_set:Npn \thechapter {
  \lngx_counter:n { chapter }
}
\cs_set:Npn \thesection {
  \lngx_counter:n { section }
}
\cs_set:Npn \thesubsection {
  \lngx_counter:n { subsection }
}
\cs_set:Npn \thesubsubsection {
  \lngx_counter:n { subsubsection }
}
\cs_set:Npn \theparagraph {
  \lngx_counter:n { section }
}
\cs_set:Npn \thesubparagraph {
  \lngx_counter:n { section }
}
\cs_set:Npn \thepage {
  \lngx_counter:n { page }
}
\cs_set:Npn \thefigure {
  \lngx_counter:n { figure }
}
\cs_set:Npn \thetable {
  \lngx_counter:n { table }
}
\cs_set:Npn \thefootnote {
  \lngx_counter:n { footnote }
}
\cs_set:Npn \thempfootnote {
  \lngx_counter:n { mpfootnote }
}
\cs_set:Npn \theequation {
  \lngx_counter:n { equation }
}
%    \end{macrocode}
% Here, I define the socket |lngx/native-numbering|.
%    \begin{macrocode}

\socket_new:nn { lngx / native-numbering } { 0 }
%    \end{macrocode}
% \begin{macro}{strict}
% This plug sets the numbering strictly to the main
% language. If used, the function \cs{lngx_counter:n} is
% changed to the respective |\xxxxcounter| command (where
% |xxxx| stands for the main language of the document).
%    \begin{macrocode}

\socket_new_plug:nnn { lngx / native-numbering }
                     { strict } {
  \cs_gset_eq:Nc \lngx_counter:n {
    \tl_use:N \g_lngx_main_language_tl counter
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{logical}
% Here, I define the |logical| plug for
% |lngx/native-numbering|. The mechanism is pretty similar
% as the one used for |strict|, but here I don’t renew it to
% the main language counter, but instead I use the
% |\localecounter| command provided by the \pkg{babel}
% package. The counters are then printed contextually (and
% \TeX-logically).
%    \begin{macrocode}

\socket_new_plug:nnn { lngx / native-numbering }
                     { logical } {
  \cs_gset_protected:Npn \lngx_counter:n ##1 {
    \localecounter { digits } { ##1 }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{off}
% If the |off| plug is selected, then native digits are not
% needed. Thus the \cs{lngx_counter:n} is set to the
% unmodified \cs{arabic} again.
%    \begin{macrocode}

\socket_new_plug:nnn { lngx / native-numbering} { off } {
  \cs_gset_eq:NN \lngx_counter:n \arabic
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{native numbering}
% The three choices for the |native numbering| key, i.e.,
% |strict|, |logical| and |off| are defined here. All of
% them activate the plugs of their name with the
% |lngx/native-numbering| socket.
%    \begin{macrocode}

\cs_generate_variant:Nn \socket_assign_plug:nn { ne }

\keys_define:nn { lngx_keys } {
  native~ numbering
  .choices:nn            = { strict,logical,off } {
    \socket_assign_plug:ne { lngx / native-numbering } {
      \str_use:N \l_keys_choice_str
    }
    \socket_use:n { lngx / native-numbering }
  },
%    \end{macrocode}
% Similarly, we set the default value to on.
%    \begin{macrocode}
  native~ numbering
  .default:n             = { strict }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngx_misc_reset:}
% Despite having sufficient control with the two plugs,
% there are some additional settings required by some
% languages that are often not needed by most others. E.g.,
% Marathi renews the way enumerated lists are printed and
% that is supposed to be renewed when the language is
% changed. I provide a shorthand to be used for resetting
% such settings. It can be used in the packages of languages
% that don’t need special settings.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_misc_reset: {
  \cs_set:Npn \theenumii { \alph { enumii } }
  \cs_set:Npn \labelenumii { ( \theenumii ) }
  \cs_set:Npn \theenumiii { \roman { enumiii } }
  \cs_set:Npn \labelenumiii { \theenumiii . }
  \cs_set:Npn \theenumiv { \Alph { enumiv } }
  \cs_set:Npn \labelenumiv { \theenumiv . }
  \IfPackageLoadedT { expex } {
    \lingset { labeltype = alpha }
  }
  \cs_gset_eq:NN \emph \textit
}
%    \end{macrocode}
% \end{macro}
% Here, I write a message to be issued when user loads an
% unsupported language.
%    \begin{macrocode}

\msg_new:nnn { linguistix-languages } { no_support } {
  ‘#1’~ is~ not~ supported.\\
  If~ you~ want~ it~ to~ be~ supported,~ please~ report~
  to~ the~ maintainers.
}
%    \end{macrocode}
% \begin{macro}{languages}
% I use the |.code:n| type for developing the |languages|
% key.
%    \begin{macrocode}

\keys_define:nn { lngx_keys } {
  languages
  .code:n                = {
%    \end{macrocode}
% I pass the argument of this key to a global |clist|. It is
% stored for public use.
%    \begin{macrocode}
    \clist_gset:Nn \g_lngx_languages_clist { #1 }
%    \end{macrocode}
% Since this is a public |clist| for accessing the names of
% the languages, I copy it to a temporary one so that the
% items of public interest are not lost during the
% operations.
%    \begin{macrocode}
    \clist_set_eq:NN \l_tmpa_clist \g_lngx_languages_clist
%    \end{macrocode}
% I check if the |clist| is empty or not. If it is empty,
% that means the user used the key without a value. In that
% case, \textsf{babel} already loads an
% \enquote{info}-message saying that no language is loaded.
% So we ignore the branch and silently move to the false
% branch.
%    \begin{macrocode}
    \clist_if_empty:NF \l_tmpa_clist {
%    \end{macrocode}
% In the false branch, I pop out the first element from the
% clist to |\l_tmpa_tl|. This is the first language passed
% by the user. In \lngxlanguageslogo, I assume that it is
% intended to be the first language. It is important to pop
% the element out because the settings used for the main
% language are different than the ones used for other
% languages.
%    \begin{macrocode}
      \clist_pop:NN \l_tmpa_clist \l_tmpa_tl
%    \end{macrocode}
% Since this |tl| stores the language that is going to be
% the main one, I equate it to another public |tl| that I
% will be using later in language files.
%    \begin{macrocode}
      \tl_set_eq:NN \g_lngx_main_language_tl \l_tmpa_tl
%    \end{macrocode}
% In |\l_tmpb_tl|, I save the options that need to go with
% the language stored in |\l_tmpa_tl|. The package used to
% have |onchar| option loaded conditionally with Lua\LaTeX,
% but to avoid potential clashes, now it has moved to the
% individual package files of languages. Now I directly load
% the |main| option which makes the concerned language the
% \enquote{main} language of the document.
%    \begin{macrocode}
      \tl_set:Ne \l_tmpb_tl {
        main,
%    \end{macrocode}
% To load the data from |ini| files, I use the |import|
% parameter.
%    \begin{macrocode}
        import
      }
%    \end{macrocode}
% I use the |\babelprovide| wrapper we saw earlier with the
% values of the first language.
%    \begin{macrocode}
      \lngx_languages:VV \l_tmpb_tl \l_tmpa_tl
%    \end{macrocode}
% I scan if the package for this language is available. If
% it is, it is loaded.
%    \begin{macrocode}
      \file_if_exist:nTF { linguistix - \l_tmpa_tl . sty } {
        \exp_args:Ne \RequirePackage
                     { linguistix - \l_tmpa_tl }
      } {
%    \end{macrocode}
% If it is not, I issue the |no_ldf| warning message. It
% takes one argument that is the name of the language. It is
% extracted using the |V| argument type.
%    \begin{macrocode}
        \msg_warning:nnV { linguistix-languages }
                         { no_support }
                         \l_tmpa_tl
      }
%    \end{macrocode}
% The temporary |tl|s are cleared.
%    \begin{macrocode}
      \tl_clear:N \l_tmpa_tl
      \tl_clear:N \l_tmpb_tl
%    \end{macrocode}
% I again check if the |clist| is empty. If it is, it means
% the user is typesetting a monolingual document as they
% don’t need any other language than the \enquote{main} one.
%    \begin{macrocode}
      \clist_if_empty:NF \l_tmpa_clist {
%    \end{macrocode}
% Now I have to repeat the same actions for all the pending
% languages. I do it with |\clist_map_inline:Nn|.
%    \begin{macrocode}
        \clist_map_inline:Nn \l_tmpa_clist {
          \clist_pop:NN \l_tmpa_clist \l_tmpa_tl
          \tl_set:Ne \l_tmpb_tl { import }
          \lngx_languages:VV \l_tmpb_tl \l_tmpa_tl
          \file_if_exist:nTF {
            linguistix - \l_tmpa_tl . sty
          } {
            \exp_args:Ne \RequirePackage
                         { linguistix - \l_tmpa_tl }
          } {
            \msg_warning:nnV { linguistix-languages }
                             { no_ldf }
                             \l_tmpa_tl
          }
          \tl_clear:N \l_tmpa_tl
          \tl_clear:N \l_tmpb_tl
        }
      }
    }
  }
}
%</lang>
%    \end{macrocode}
% \end{macro}
% \newpage
% \lngximplementation{logos}
%    \begin{macrocode}
%<*logos>
\ProvidesExplPackage{linguistix-logos}
                    {2026-02-02}
                    {v0.8}
                    {%
                      Logos of the ‘LinguisTiX’ bundle.%
                    }
%    \end{macrocode}
% The \pkg{fontspec} package (if not already loaded).
%    \begin{macrocode}

\IfPackageLoadedF { fontspec } {
  \RequirePackage { fontspec }
}
%    \end{macrocode}
% \begin{macro}{\lngx_logo_font:}
% This is a command that switches to the New Computer Modern
% Uncial font family.
% \begin{macrocode}

\newfontfamily \lngx_logo_font: [
  UprightFont            = { NewCMUncial10-Book.otf },
  UprightFeatures        = {
    SizeFeatures           = {
      {
        Size                   = {-8},
        Font                   = {NewCMUncial08-Book.otf}
      },
      {
        Size                   = {8-},
        Font                   = {NewCMUncial10-Book.otf}
      },
    }
  },
  BoldFont               = { NewCMUncial10-Bold.otf },
  BoldFeatures           = {
    SizeFeatures           = {
      {
        Size                   = {-8},
        Font                   = {NewCMUncial08-Bold.otf}
      },
      {
        Size                   = {8-},
        Font                   = {NewCMUncial10-Bold.otf}
      },
    }
  }
]{ NewCMUncial10-Book.otf }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{lngx_purple_color}
% The following defines the |lngx_purple_color|.
%    \begin{macrocode}

\color_set:nn { lngx_purple_color } { blue ! 50 ! red }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lngxlogo}
% Here, I define the commands for printing various logos.
%    \begin{macrocode}

\NewDocumentCommand \lngxlogo { O{} } {%
  \group_begin:
  \lngx_logo_font:
  LinguisTi
  \color_group_begin:
  \color_select:n { lngx_purple_color }
  X
  \color_group_end:
  \IfBlankF { #1 } { - #1 }
  \group_end:
}
%    \end{macrocode}
% \end{macro}
% Since we need expandable commands, I use the non-protected
% function, |\cs_new:Npn| for defining them.
%    \begin{macrocode}

\cs_new:Npn \lngxpkg {
  \IfPackageLoadedTF { hyperref } {
    \texorpdfstring {
      \lngxlogo
    } {
      LinguisTiX
    }
  } {
    \lngxlogo
  }
}
%    \end{macrocode}
% Here, I define all the logos with a |clist|. The package
% names are stored in the |clist| and then used at
% appropriate positions.
%    \begin{macrocode}

\clist_map_inline:nn {
  base,examples,fixpex,fonts,ipa,languages,logos,nfss,
  marathi,british,american,english,greek,malayalam,glossing,
  leipzig
} {
%    \end{macrocode}
% |#1| is substituted with the package name. First, for the
% command-name itself, then as the optional argument of
% |\lngxlogo| and then in the \textsc{pdf}-string.
%    \begin{macrocode}
  \cs_new:cpn { lngx #1 logo } {
    \texorpdfstring {
      \lngxlogo [ #1 ]
    } {
      LinguisTiX - #1
    }
  }
}
%</logos>
%    \end{macrocode}
% \lngximplementation{nfss}
%    \begin{macrocode}
%<*nfss>
\ProvidesExplPackage{linguistix-nfss}
                    {2026-02-02}
                    {v0.8}
                    {%
                      An extension to the core NFSS commands
                      from the ‘LinguisTiX’ bundle.%
                    }
%    \end{macrocode}
% I need a few temporary |tl|s. I declare them here. As
% noted by the use of |__|, these are package-internal
% |tl|s. Even though I don’t have any intention to change
% them, these are better not touched by the users.
%    \begin{macrocode}

\tl_new:N \l__lngx_normalfont_tmp_tl
\tl_new:N \l__lngx_selectfont_tmp_tl
\tl_new:N \l__lngx_family_tmp_tl
\tl_new:N \l__lngx_nfss_tmp_tl
%    \end{macrocode}
% These |tl|s are required for saving some values that are
% accessed later by the package as well as by the users.
%    \begin{macrocode}

\tl_new:N \l_lngx_current_encoding_tl
\tl_new:N \l_lngx_current_meta_family_tl
\tl_new:N \l_lngx_current_super_family_tl
\tl_new:N \l_lngx_current_series_tl
\tl_new:N \l_lngx_current_shape_tl
%    \end{macrocode}
% \begin{macro}{^^A
% \c_lngx_default_rmdefault_tl,^^A
% \c_lngx_default_sfdefault_tl,^^A
% \c_lngx_default_ttdefault_tl
% }
% Here, I start the |begindocument/end| hook. After the
% document has started, a lot of initialisation can be
% assumed to have happened. I set some publicly available
% |tl|s here.
%    \begin{macrocode}

\hook_gput_code:nnn { begindocument / end } { . } {
  \tl_const:Ne \c_lngx_default_rmdefault_tl { \rmdefault }
  \tl_const:Ne \c_lngx_default_sfdefault_tl { \sfdefault }
  \tl_const:Ne \c_lngx_default_ttdefault_tl { \ttdefault }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \l_lngx_current_encoding_tl,^^A
% \l_lngx_current_meta_family_tl,^^A
% \l_lngx_current_super_family_tl,^^A
% \l_lngx_current_series_tl,^^A
% \l_lngx_current_shape_tl
% }
% First, I set the value |default| for the initial super
% font family.
%    \begin{macrocode}
  \tl_set:Nn \l_lngx_current_super_family_tl { default }
%    \end{macrocode}
% The current encoding is saved in the relevant |tl|.
%    \begin{macrocode}
  \tl_set:Ne \l_lngx_current_encoding_tl {
    \encodingdefault
  }
%    \end{macrocode}
% When the package was first released, there was no public
% interface for guessing the current meta family, but from
% |ltnews42|, |\@currentmetafamily| became available. Thanks
% Frank for pointing this out.
%    \begin{macrocode}
  \tl_set:Ne \l_lngx_current_meta_family_tl {
    \@currentmetafamily % new from ltnews42, thanks Frank!
  }
%    \end{macrocode}
% Here, the series and shape |tl|s are set to their
% defaults.
%    \begin{macrocode}
  \tl_set:Nn \l_lngx_current_series_tl { md }
  \tl_set:Nn \l_lngx_current_shape_tl { up }
}
%    \end{macrocode}
% \end{macro}
% The |\selectfont| command overrides the encoding. I trick
% the command by saving the encoding that was active before
% |\selectfont| in a temporary |tl|.
%    \begin{macrocode}

\hook_gput_code:nnn { cmd / selectfont / before } { . } {
  \tl_set:Ne \l__lngx_selectfont_tmp_tl { \f@encoding }
}
%    \end{macrocode}
% After the processing of |\selectfont|, I equate the
% temporary |tl| with the one that the package is tracking.
% This way, the effect of |\selectfont| remains unchanged,
% but we still save the values that were there before using
% it. Only encoding needs this special setting. Other
% attributes aren’t reset by |\selectfont|.
%    \begin{macrocode}

\hook_gput_code:nnn { cmd / selectfont / after } { . } {
  \tl_set_eq:NN \l_lngx_current_encoding_tl
                \l__lngx_selectfont_tmp_tl
  \tl_clear:N   \l__lngx_selectfont_tmp_tl
}
%    \end{macrocode}
% Now, after each |\XXfamily| commands, I save the family
% name in the respective |tl| for accessing later. All of
% these commands too reset the encoding. I repeat my trick
% for them too.
%    \begin{macrocode}

\hook_gput_code:nnn { cmd / rmfamily / before } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { rm }
  \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding }
}

\hook_gput_code:nnn { cmd / rmfamily / after } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { rm }
  \tl_set_eq:NN \l_lngx_current_encoding_tl
                \l__lngx_family_tmp_tl
  \tl_clear:N   \l__lngx_family_tmp_tl
}

\hook_gput_code:nnn { cmd / sffamily / before } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { sf }
  \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding }
}

\hook_gput_code:nnn { cmd / sffamily / after } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { sf }
  \tl_set_eq:NN \l_lngx_current_encoding_tl
                \l__lngx_family_tmp_tl
  \tl_clear:N   \l__lngx_family_tmp_tl
}

\hook_gput_code:nnn { cmd / ttfamily / before } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { tt }
  \tl_set:Ne \l__lngx_family_tmp_tl { \f@encoding }
}

\hook_gput_code:nnn { cmd / ttfamily / after } { . } {
  \tl_set:Nn \l_lngx_current_meta_family_tl { tt }
  \tl_set_eq:NN \l_lngx_current_encoding_tl
                \l__lngx_family_tmp_tl
  \tl_clear:N   \l__lngx_family_tmp_tl
}
%    \end{macrocode}
% After the series commands, I save the series name in the
% |tl|. Note that, I don’t use the traditional \LaTeX\
% labels |m|, |bx| etc. Using, |md| and |bx| is more
% intuitive, plus they also can be used in the argument of
% |\use:c| directly.
%    \begin{macrocode}

\hook_gput_code:nnn { cmd / mdseries / after } { . } {
  \tl_set:Nn \l_lngx_current_series_tl { md }
}

\hook_gput_code:nnn { cmd / bfseries / after } { . } {
  \tl_set:Nn \l_lngx_current_series_tl { bf }
}
%    \end{macrocode}
% For shape related commands too, I save the names that are
% more closer to their respective commands.
%    \begin{macrocode}

\hook_gput_code:nnn { cmd / upshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { up }
}

\hook_gput_code:nnn { cmd / itshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { it }
}

\hook_gput_code:nnn { cmd / scshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { sc }
}

\hook_gput_code:nnn { cmd / sscshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { ssc }
}

\hook_gput_code:nnn { cmd / slshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { sl }
}

\hook_gput_code:nnn { cmd / swshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { sw }
}

\hook_gput_code:nnn { cmd / ulcshape / after } { . } {
  \tl_set:Nn \l_lngx_current_shape_tl { ulc }
}
%    \end{macrocode}
%
% \begin{macro}[pTF]{\lngx_if_encoding:n}
% I provide a conditional for checking the current encoding
% with the given argument.
%    \begin{macrocode}

\prg_new_conditional:Nnn \lngx_if_encoding:n {
  p,
  T,
  F,
  TF
} {
  \tl_if_eq:NnTF \l_lngx_current_encoding_tl { #1 } {
    \prg_return_true:
  } {
    \prg_return_false:
  }
}

%    \end{macrocode}
% \end{macro}
% \begin{macro}{\IfEncodingTF,\IfEncodingT,\IfEncodingF}
% For non-\LaTeX3 contexts, these simpler alternatives are
% provided.
%    \begin{macrocode}

\cs_new_eq:NN \IfEncodingTF \lngx_if_encoding:nTF
\cs_new_eq:NN \IfEncodingT  \lngx_if_encoding:nT
\cs_new_eq:NN \IfEncodingF  \lngx_if_encoding:nF
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{\lngx_if_meta_family:n}
% A conditional for checking the meta family with the given
% argument.
%    \begin{macrocode}

\prg_new_conditional:Nnn \lngx_if_meta_family:n {
  p,
  T,
  F,
  TF
} {
  \tl_if_eq:NnTF \l_lngx_current_meta_family_tl { #1 } {
    \prg_return_true:
  } {
    \prg_return_false:
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \IfMetaFamilyTF,^^A
% \IfMetaFamilyT,^^A
% \IfMetaFamilyF
% }
% User-facing conditionals for meta family.
%    \begin{macrocode}

\cs_new_eq:NN \IfMetaFamilyTF \lngx_if_meta_family:nTF
\cs_new_eq:NN \IfMetaFamilyT  \lngx_if_meta_family:nT
\cs_new_eq:NN \IfMetaFamilyF  \lngx_if_meta_family:nF
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{\lngx_if_super_family:n}
% A conditional for checking the super family with the given
% argument.
%    \begin{macrocode}

\prg_new_conditional:Nnn \lngx_if_super_family:n {
  p,
  T,
  F,
  TF
} {
  \tl_if_eq:NnTF \l_lngx_current_super_family_tl { #1 } {
    \prg_return_true:
  } {
    \prg_return_false:
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \IfSuperFamilyTF,^^A
% \IfSuperFamilyT,^^A
% \IfSuperFamilyF
% }
% User-facing conditionals for super family.
%    \begin{macrocode}

\cs_new_eq:NN \IfSuperFamilyTF \lngx_if_super_family:nTF
\cs_new_eq:NN \IfSuperFamilyT  \lngx_if_super_family:nT
\cs_new_eq:NN \IfSuperFamilyF  \lngx_if_super_family:nF
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{\lngx_if_series:n}
% A conditional for checking the current series with the
% given argument.
%    \begin{macrocode}

\prg_new_conditional:Nnn \lngx_if_series:n {
  p,
  T,
  F,
  TF
} {
  \tl_if_eq:NnTF \l_lngx_current_series_tl { #1 } {
    \prg_return_true:
  } {
    \prg_return_false:
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\IfSeriesTF,\IfSeriesT,\IfSeriesF}
% Its user-side macros.
%    \begin{macrocode}

\cs_new_eq:NN \IfSeriesTF \lngx_if_series:nTF
\cs_new_eq:NN \IfSeriesT  \lngx_if_series:nT
\cs_new_eq:NN \IfSeriesF  \lngx_if_series:nF
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{\lngx_if_shape:n}
% A conditional for checking the current shape with the
% current argument.
%    \begin{macrocode}

\prg_new_conditional:Nnn \lngx_if_shape:n {
  p,
  T,
  F,
  TF
} {
  \tl_if_eq:NnTF \l_lngx_current_shape_tl { #1 } {
    \prg_return_true:
  } {
    \prg_return_false:
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\IfShapeTF,\IfShapeT,\IfShapeF}
% User-side macros for the same.
%    \begin{macrocode}

\cs_new_eq:NN \IfShapeTF \lngx_if_shape:nTF
\cs_new_eq:NN \IfShapeT  \lngx_if_shape:nT
\cs_new_eq:NN \IfShapeF  \lngx_if_shape:nF
%    \end{macrocode}
% \end{macro}
% Now I will use the |\clist_map_inline:nn| technique for
% generating multiple conditionals of the same pattern. For
% that, I need a |cnn| variant of |\prg_new_conditional:Nnn|
% that I create with the following.
%    \begin{macrocode}

\cs_generate_variant:Nn \prg_new_conditional:Nnn { cnn }
%    \end{macrocode}
%
% \begin{macro}[pTF]{^^A
% \lngx_if_meta_family_rm:,\lngx_if_meta_family_sf:,^^A
% \lngx_if_meta_family_tt:
% }
% These are separate conditionals for |rm|, |sf| and |tt|
% families. They don’t require arguments. No user side
% commands are provided for these.
%    \begin{macrocode}

\clist_map_inline:nn {
  rm,
  sf,
  tt
} {
  \prg_new_conditional:cnn { lngx_if_meta_family_ #1 : } {
    p, T, F, TF
  } {
    \tl_if_eq:NnTF \l_lngx_current_meta_family_tl { #1 } {
      \prg_return_true:
    } {
      \prg_return_false:
    }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{^^A
% \lngx_if_series_md:,\lngx_if_series_bf:
% }
% Separate conditionals for both the series.
%    \begin{macrocode}

\clist_map_inline:nn {
  md,
  bf
} {
  \prg_new_conditional:cnn { lngx_if_series_ #1 : } {
    p, T, F, TF
  } {
    \tl_if_eq:NnTF \l_lngx_current_series_tl { #1 } {
      \prg_return_true:
    } {
      \prg_return_false:
    }
  }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}[pTF]{^^A
% \lngx_if_shape_up:,\lngx_if_shape_it:,^^A
% \lngx_if_shape_sc:,\lngx_if_shape_ssc:,^^A
% \lngx_if_shape_sl:,\lngx_if_shape_sw:,^^A
% \lngx_if_shape_ulc:
% }
% Separate conditionals for all the shapes.
%    \begin{macrocode}

\clist_map_inline:nn {
  up,
  it,
  sc,
  ssc,
  sl,
  sw,
  ulc
} {
  \prg_new_conditional:cnn { lngx_if_shape_ #1 : } {
    p, T, F, TF
  } {
    \tl_if_eq:NnTF \l_lngx_current_shape_tl { #1 } {
      \prg_return_true:
    } {
      \prg_return_false:
    }
  }
}
%    \end{macrocode}
% \end{macro}
% These keys are used in the argument of
% |\lngx_super_font_family:nn|. This is why they are
% separated from the set |lngx_keys|. We create new |tl|s
% using these keys that save the |rm|, |sf| and |tt|
% defaults of the new super font family.
% |\l__lngx_nfss_tmp_tl| is defined by the command that
% creates the super font family.
%    \begin{macrocode}

\clist_map_inline:nn {
  rm,
  sf,
  tt
} {
  \keys_define:nn { lngx_nfss } {
    #1
    .code:n                = {
      \tl_gclear_new:c {
        g_lngx_ \l__lngx_nfss_tmp_tl _ #1 default _tl
      }
      \tl_gset:cn {
        g_lngx_ \l__lngx_nfss_tmp_tl _ #1 default _tl
      } { ##1 }
    }
  }
}
%    \end{macrocode}
% \begin{macro}{^^A
% \lngx_super_font_family:nn,\superfontfamily^^A
% }
% I first set the temporary |tl| with the name of the super
% font family retrieved from the first argument.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_super_font_family:nn #1#2 {
  \tl_set:Ne \l__lngx_nfss_tmp_tl { #1 }
%    \end{macrocode}
% Now, I pass the second argument to the key-set I just
% defined. The temporary |tl| is cleared. This function
% comes with a user-side macro.
%    \begin{macrocode}
  \keys_set:nn { lngx_nfss } { #2 }
  \tl_clear:N \l__lngx_nfss_tmp_tl
}

\cs_gset_eq:NN \superfontfamily
               \lngx_super_font_family:nn
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_soft_super_font_family:nn,\softsuperfontfamily
% }
% I set the |tl| that saves the current font family to the
% first argument.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_soft_super_font_family:nn #1#2 {
  \tl_set:Ne \l_lngx_current_super_family_tl { #1 }
%    \end{macrocode}
% I first check if the |tl|s for rm, sf and tt are empty or
% not. Only if they are not, I use their content in the
% respective |\XXdefault|. This makes the use of all the
% keys optional. Only the keys that the user has used are
% processed here.
%    \begin{macrocode}
  \clist_map_inline:nn {
    rm,
    sf,
    tt
  } {
    \tl_if_empty:cF { g_lngx_ #1 _ ##1 default_tl } {
      \cs_set:cpe { ##1 default } {
        \tl_use:c { g_lngx_ #1 _ ##1 default _tl }
      }
    }
  }
%    \end{macrocode}
% After setting the |\XXdefault|, I use the |\normalfont| to
% initialise the super font family.
%    \begin{macrocode}
  \normalfont
%    \end{macrocode}
% Now all the aspects are reset. But, we have them saved in
% our |tl|s. So now depending on the attributes that the
% user wants to retrieve, I call those attributes again. The
% second argument is (expected to be) a comma-separated list
% of all such attributes. Thus, we change the super font
% family, but retain the already active attributes. This
% command has a user-facing macro.
%    \begin{macrocode}
  \clist_map_inline:nn { #2 } {
    \str_case:nn { ##1 } {
      { encoding } {
        \exp_args:NV \fontencoding
                     \l_lngx_current_encoding_tl
      }
      { family } {
        \use:c {
          \l_lngx_current_meta_family_tl family
        }
        \exp_args:NV \fontencoding
                     \l_lngx_current_encoding_tl
        \selectfont
      }
      { series } {
        \use:c {
          \l_lngx_current_series_tl series
        }
      }
      { shape }  {
        \use:c {
          \l_lngx_current_shape_tl shape
        }
      }
    }
  }
}

\cs_gset_eq:NN \softsuperfontfamily
               \lngx_soft_super_font_family:nn
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_softer_super_font_family:n,\softersuperfontfamily
% }
% This function excludes the encoding and resets all the
% other attributes. It comes with a user-side macro.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_softer_super_font_family:n #1 {
  \lngx_soft_super_font_family:nn { #1 } {
    family,
    series,
    shape
  }
}

\cs_gset_eq:NN \softersuperfontfamily
               \lngx_softer_super_font_family:n
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_softest_super_font_family:n,\softestsuperfontfamily
% }
% This function resets all the attributes. It is available
% as a user-side macro.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_softest_super_font_family:n #1 {
  \lngx_soft_super_font_family:nn { #1 } {
    encoding,
    family,
    series,
    shape
  }
}

\cs_gset_eq:NN \softestsuperfontfamily
               \lngx_softest_super_font_family:n
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_soft_normal_font:n,\softnormalfont
% }
% Following the same logic, I now provide the command for
% resetting to the default super family, but retaining the
% active attributes. I provide a user-side macro for this.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_soft_normal_font:n #1 {
  \tl_set:Ne \l_lngx_current_super_family_tl { default }
  \clist_map_inline:nn {
    rm,
    sf,
    tt
  } {
    \cs_set:cpe { ##1 default } {
      \tl_use:c { c_lngx_default_ ##1 default _tl }
    }
  }
  \normalfont
  \clist_map_inline:nn { #1 } {
    \str_case:nn { ##1 } {
      { encoding } {
        \exp_args:NV \fontencoding
                     \l_lngx_current_encoding_tl
      }
      { family } {
        \use:c {
          \l_lngx_current_meta_family_tl family
        }
        \exp_args:NV \fontencoding
                     \l_lngx_current_encoding_tl
        \selectfont
      }
      { series } {
        \use:c {
          \l_lngx_current_series_tl series
        }
      }
      { shape }  {
        \use:c {
          \l_lngx_current_shape_tl shape
        }
      }
    }
  }
}

\cs_gset_eq:NN \softnormalfont \lngx_soft_normal_font:n
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_softer_normal_font:,\softernormalfont
% }
% This is a parallel to the \enquote{softer} super family
% command for the default super family.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_softer_normal_font: {
  \lngx_soft_normal_font:n {
    family,
    series,
    shape
  }
}

\cs_gset_eq:NN \softernormalfont \lngx_softer_normal_font:
%    \end{macrocode}
% \end{macro}
% \begin{macro}{^^A
% \lngx_softest_normal_font:,\softestnormalfont
% }
% This is a parallel to the \enquote{softest} super family
% command for the default super family.
%    \begin{macrocode}

\cs_new_protected:Npn \lngx_softest_normal_font: {
  \lngx_soft_normal_font:n {
    encoding,
    family,
    series,
    shape
  }
}

\cs_gset_eq:NN \softestnormalfont \lngx_softest_normal_font:
%    \end{macrocode}
% \end{macro}
% \begin{macro}[EXP]{^^A
% \CurrentEncoding,\CurrentMetaFamily,\CurrentSeries,^^A
% \CurrentShape
% }
% Lastly, we create the commands that print the current
% values of the font attributes and end the package.
%    \begin{macrocode}
\cs_new:Npn \CurrentEncoding {
  \tl_use:N \l_lngx_current_encoding_tl
}
\cs_new:Npn \CurrentMetaFamily {
  \tl_use:N \l_lngx_current_meta_family_tl
}
\cs_new:Npn \CurrentSuperFamily {
  \tl_use:N \l_lngx_current_super_family_tl
}
\cs_new:Npn \CurrentSeries {
  \tl_use:N \l_lngx_current_series_tl
}
\cs_new:Npn \CurrentShape {
  \tl_use:N \l_lngx_current_shape_tl
}
%</nfss>
%    \end{macrocode}
% \end{macro}
% \end{implementation}
% \newpage
% \printbibliography
% \newpage
% \PrintIndex
% \Finale
