% \iffalse meta-comment
%
% Copyright (C) 2025 Valentin Dao
% 
% This file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3 of this license or (at your option) any later
% version. The latest version of this license is in:
% 
%   http://www.latex-project.org/lppl.txt
% 
% and version 1.3c or later is part of all distributions of
% LaTeX version 2008-05-04 or later.
% 
% This work has the LPPL maintenance status 'maintained'
% and the current maintainer is Valentin Dao (vdao.texdev@gmail.com).
% 
% This work consists of the files intexgral.ins, intexgral-fr.dtx and intexgral-en.dtx, along with the derived files intexgral.sty, intexgral-fr.pdf, and intexgral-en.pdf.
% 
% The repository of this work can be found at:
% 
%   https://github.com/ankaa3908/intexgral
%
%<*driver>
% \fi
% \iffalse
\documentclass[11pt, a4paper]{l3doc}

\usepackage{amsmath}

\usepackage{fontspec}
\usepackage{unicode-math}

\setmainfont{ChronicleTextG3}[
  Extension         = .otf,
  UprightFont       = *-Roman-Pro,
  ItalicFont        = *-Italic-Pro,
  BoldFont          = *-Bold-Pro,
  BoldItalicFont    = *-BoldIta-Pro,
]

\setsansfont{Whitney}[
  Extension        = .otf,
  UprightFont      = *-Medium,
  ItalicFont       = *-MediumItalic,
  BoldFont         = *-Bold,
  BoldItalicFont   = *-BoldItalic,
  UprightFeatures  = 
    {
      StylisticSet = 1, 
      StylisticSet = 10, 
      StylisticSet = 11, 
    },
  BoldFeatures     = 
    {
      StylisticSet = 1, 
      StylisticSet = 10, 
      StylisticSet = 11, 
    },
  ItalicFeatures   = 
    {
      StylisticSet = 1, 
      StylisticSet = 10, 
      StylisticSet = 11, 
      StylisticSet = 8, 
      StylisticSet = 9  
    }
]

\newfontface{\smbold}{Whitney-Semibold.otf}

\setmonofont{MonaspaceArgon}[
  Scale                   = 0.8,
  Extension               = .otf,
  UprightFont             = *-Medium,
  UprightFeatures         = 
    {
      CharacterVariant    = {1:0,31:1},
      Ligatures           = Common,
      Contextuals         = Alternate
    },
  BoldFont                = *-SemiBold,
  ItalicFont              = *-MediumItalic,
  BoldItalicFont          = *-SemiBoldItalic
]

\setmathfont{NewCMMath-Regular.otf}

\usepackage{intexgral}
\RenewDifferential{\odif}{\symup{d}}

\usepackage[
  a4paper,
  marginparwidth  = 30mm,
  top             = 3cm,
  bottom          = 2cm,
  left            = 44mm,
  right           = 30mm,
  marginparsep    = 2mm,
  ]{geometry}

\usepackage{fancyhdr}
\fancyhf{}
\fancyfoot[C]{\small\sffamily\itshape---\space\thepage\space\kern0.4mm\/---}
\renewcommand{\headrulewidth}{0pt}
\pagestyle{fancy}

\usepackage{fontawesome5}
\usepackage{microtype}

\usepackage[addtotoc]{abstract}

\usepackage[silence, infograb]{codedescribe}
\PkgInfoSetAliases

\definecolor{RoyalBlue}{RGB}{0, 35, 102}
\definecolor{RoyalRed}{RGB}{157, 16, 45}
\definecolor{RoyalGreen}{HTML}{48845F}
\definecolor{urlcolour}{HTML}{B42F5E}

\definecolor{packagecolour}{HTML}{B86B00}
\definecolor{keycolour}{HTML}{004766}
\definecolor{macrocolour}{HTML}{047658}
\definecolor{optioncolour}{HTML}{630476}

\newlabelset{english}
  {
    new       = \textsf{new},
    update    = \textsf{updated},
    note      = \textsf{N.B},
    remark    = \textsf{remark},
    and       = \textsf{and},
    or        = \textsf{or},
    months    = 
      {
        janvier, février, mars, avril,
        mai, juin, juillet, août,
        septembre, octobre, novembre, décembre
      }
  }

\selectlabelset{english}

\lstset{
  gobble=2,
  alsoletter={*-}
}

\setnewcodekey{intexgral}{
  ruleht        = 0,
  texcsstyle    = \bfseries\color{RoyalBlue},
  texcs2        = 
    {
      integral,
      IntegralSetup,
      differentials,
      intexgralsetup,
    },
  texcs2style   = \color{macrocolour},
  emph          = 
    {
      true,
      false,
      default,
      nested,
      product,
    },
  keywd         = 
    {
      equation,
      limits,
      limits*,
      mode,
      symbol,
      nint,
      llimit,
      ulimit,
      domain,
      domain*,
      boundary,
      variables,
      jacobian,
      diff-vec,
      diff-star,
      diff-symb,
      diff-options,
      defaultvar,
      defaultvar*,
      vectorstyle,
      domainstyle,
      symbolskip,
      hide-diff,
      single,
      double,
      triple,
      quadruple,
      contour,
      surface,
      volume
    },
  codeprefix    = {},
  resultprefix  = {}
}

\defgroupfmt{code}{color=macrocolour}
\defobjectfmt{pkg}{pkg}{color=packagecolour, font=\sffamily}
\defobjectfmt{option}{option}{color=optioncolour, shape preadj=thin, shape posadj=thin, noshape}
\defgroupfmt{keys}{color=keycolour, noshape}

\usepackage{luacode}

\begin{luacode}
  function fontcopyright(fontname)
    local font = fontloader.open(kpse.find_file(fontname, 'opentype fonts'))
    if font then
      local metrics = fontloader.to_table(font)
      local copyright = metrics.copyright:gsub("https?://%S+$", "")
      local copyright = copyright:gsub("Copyright%s%(C%)", "\\copyright\\")
      local copyright = copyright:gsub("&", "\\&")
      tex.print('\\textit{' .. metrics.fullname .. '}\\par')
      if not string.find(copyright, "missing") then
        tex.print(copyright)
      end
    end
  end
\end{luacode}

\usepackage{changelog}
\usepackage{enumitem}
\renewenvironment{changelogitemize}
  {\begin{itemize}[label=\raisebox{0.5ex}{$\scriptscriptstyle\blacktriangleright$}]}
  {\end{itemize}}

\usepackage[normalem]{ulem}

\usepackage{polyglossia}
\setmainlanguage{english}

\usepackage{csquotes}
\usepackage[perpage]{footmisc}

\usepackage{titlesec}
\titleformat*{\section}{\sffamily\LARGE\bfseries}
\titleformat*{\subsection}{\sffamily\Large\bfseries}
\titleformat*{\subsubsection}{\smbold\large}

\setlength{\parindent}{0pt}

\usepackage[totoc=true, columnsep=25pt]{idxlayout}

\usepackage{hyperref}
\hypersetup{
  pdfauthor   = {Valentin Dao},
  pdftitle    = {The intexgral package},
  pdfcreator  = {LuaLaTeX with hyperref package},
  colorlinks  = true,
  linkcolor   = RoyalBlue,
  urlcolor    = urlcolour,
}

\usepackage{cleveref}

\EnableCrossrefs

\begin{document}
  \DocInput{intexgral-en.dtx}
\end{document}
%</driver>
% \fi
%
% \PkgInfoGet{intexgral}{author}{\fileauthor}
% \PkgInfoGet{intexgral}{version}{\fileversion}
% \PkgInfoGet{intexgral}{date}{\filedate}
% \PkgInfoGet{intexgral}{creation}{\filecreationdate}
%
% \title{^^A
% The \href{https://ctan.org/pkg/intexgral}{\textsf{intexgral}} package^^A
% \thanks{This file describes v\fileversion, last updated \filedate}
% }
% 
% \author{
% \fileauthor
% \thanks{E-mail: \href{mailto:vdao.texdev@gmail.com}{\ttfamily vdao.texdev@gmail.com}}
% }
% 
% \date{Released \filecreationdate}
% 
% \maketitle
% 
% \begin{abstract}
% While integral composition is prevalent in \LaTeX, it often proves to be impractical. When the expression becomes complex, it is then difficult to modify its various elements in an illegible source code. To address this problem, the \tsobj[pkg]{intexgral} package offers a central macro whose only argument is the integrand. Everything else (symbol, limits, variables\dots) can be modified using a \tsobj[meta]{key=value} interface. Unlike the traditional method, where the user chooses the limit order with the active characters \verb|_| and \verb|^|, the package had to establish a convention. Thus, for the two keys that will deal with limits, the assumed input will be \verb|_|\tsobj[meta]{lower limit}\verb|^|\tsobj[meta]{upper limit}. Since this package is written in \tsobj{expl3}, it depends on the \LaTeX3 group of packages \tsobj[pkg]{l3kernel} and \tsobj[pkg]{l3package}. In addition, \tsobj[pkg]{intexgral} uses the \tsobj[pkg]{derivative}\footnote{Available on \textsc{ctan} under: \url{https://ctan.org/pkg/derivative}} package to facilitate the manipulation of differentials, as well as \tsobj[pkg]{pkginfograb}\footnote{Available on \textsc{ctan} under: \url{https://ctan.org/pkg/pkginfograb}}.
% \end{abstract}
% 
% \newpage
% \tableofcontents
% \newpage
% 
% \subsection*{License}
% 
% \copyright\ 2025 Valentin Dao, published under the \LaTeX\ Project Public License (\textsc{lppl}) 1.3c
% 
% \subsection*{Fonts}
% 
% \directlua{fontcopyright('ChronicleTextG3-Roman-Pro.otf')}
% 
% \vspace*{\baselineskip}
% 
% \begingroup
% \sffamily
% \directlua{fontcopyright('Whitney-Medium.otf')}
% \endgroup
%
% \vspace*{\baselineskip}
% 
% \begingroup
% \ttfamily
% \directlua{fontcopyright('MonaspaceArgon-Medium.otf')}
% \copyright\ 2023, GitHub \url{https://github.com/githubnext/monaspace}
% \endgroup
% 
% \subsection*{Repository}
%
% \href{https://github.com/ankaa3908/intexgral/tree/main}{\faGithub\ See GitHub repository}.
%
% \subsection*{Acknowledgements}
%
% Many thanks to Plante and Slurpy for accompanying me on this adventure of learning \TeX, your pieces of advice were priceless. I’d also like to thank Anthony, who has always kindly reviewed the new versions and given me ideas for those to come.
% 
% \newpage
%
% \section{Package options}
% 
% \begin{codedescribe}[macro, new={v2.0.0}]{\intexgralsetup}
%   \begin{codesyntax}
%     \tsobj[macro]{\intexgralsetup}\tsargs[marg]{package options}
%   \end{codesyntax}
%   These options can be declared in a classic way with \tsobj[macro]{\usepackage} or with the present macro in the preamble:
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{invert-limits}
%   \begin{codesyntax}[key]
%     \tsobj[key]{invert-limits}=\tsobj[option, meta or]{true,\uline{false}}
%   \end{codesyntax}
%   This key inverts the limit order convention. The entirety of the document can only follow one convention.
% \end{codedescribe}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{invert-diff}
%   \begin{codesyntax}[key]
%     \tsobj[key]{invert-diff}=\tsobj[option, meta or]{true,\uline{false}}
%   \end{codesyntax}
%   It is common to see the differentials placed before the integrand in physics papers. This key hence swaps their position.
% \end{codedescribe}
% 
% \begin{codedescribe}[key, new={v3.0.0}]{limits-mode}
%   \begin{codesyntax}[key]
%     \tsobj[key]{limits-mode}=\tsobj[option, meta or]{limits,\uline{nolimits}}
%   \end{codesyntax}
%   Applies \tsobj[macro]{\limits} or \tsobj[macro]{\nolimits} to every single integral.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{italic, upright}
%   \begin{codesyntax}[key]
%     \tsobj[key]{italic}=\tsobj[option, meta or]{true,\uline{false}}
%     \tsobj[key]{upright}=\tsobj[option, meta or]{\uline{true},false}
%   \end{codesyntax}
%   These are the two keys of the \tsobj[pkg]{derivative} package.
% \end{codedescribe}
% 
% \section{Presentation of the main macro}
% 
% \begin{codedescribe}[macro, update={v3.0.0}]{\integral}
%   \begin{codesyntax}
%     \tsmacro{\integral}[list of keys]{integrand}
%   \end{codesyntax}
%   This macro is used to typeset integrals. It must, of course, be used in math mode only. Here is a first example in its simplest form:
% \end{codedescribe}
% 
% \begin{codestore}[1]
%   \begin{equation}
%     \integral{x}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{1}
% 
% Since this macro focuses on the use of keys, the first part of this documentation will present them, grouping them by domain. The second part will introduce a few additional macros that complement the use of certain keys. The rest of this document will outline the other features of the package.
% 
% \section{List of keys}
% 
% \subsection{Integration limits}
% 
% \subsubsection{Defining the limits}
% 
% \begin{codedescribe}[key]{limits, limits*}
%   \begin{codesyntax}[key]
%     \tsobj[key]{limits}=\tsargs[marg]{mixed-list}, \tsargs[arg]{keyword}
%     \tsobj[key]{limits*}=\tsargs[marg]{mixed-list}, \tsargs[arg]{keyword}
%   \end{codesyntax}
%   This key determines the integration limits to be used, following the convention explained in the abstract. In its simplest form, the value of the key takes as its argument a list of elements separated by commas (\emph{comma-separated values} or \tsobj[meta]{csv-list}\footnotemark[1]).
% \end{codedescribe}
% 
% \begin{codestore}[2]
%   \begin{equation}
%     \integral[limits={1, 10}]{f(x)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{2}
% 
% The notable advantage of the \tsobj[key]{limits} key is that you can specify the integration limits for several integrals, and the package automatically typesets the corresponding symbols. To separate pairs of limits, we use a semicolon (\emph{semicolon-separated values} or \tsobj[meta]{ssv-list}\footnotemark[1]).
% 
% \footnotetext[1]{We therefore mean by \tsobj[meta]{mixed-list} that \tsobj[key]{limits} can accept a set of \tsobj[meta]{csv-list} in a more general \tsobj[meta]{ssv-list}.}
% 
% \begin{codestore}[3]
%   \begin{equation}
%     \integral[limits={1, 2; 3, 4}, variables={x, y}]{f(x, y)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{3}
% 
% It is also possible to specify predefined limits using keywords (see \cref{subsec:limits}). Finally, the starred variant allows the limits of the integral to be expressed as an interval. The direction of the brackets automatically adjusts itself to the presence of $\pm$\verb|\infty|.
% 
% \begin{codestore}[4]
%   \begin{equation}
%     \integral[limits*={1, 10}]{f(x)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{4}
% 
% \subsection{Display modes}
% 
% \begin{codedescribe}[key, new={v3.0.0}]{mode}
%   \begin{codesyntax}[key]
%     \tsobj[key]{mode}=\tsobj[option, meta or]{\uline{default},nested,product}
%   \end{codesyntax}
%   \emph{Solely} when the \tsobj[key]{limits} key is used, it is possible to choose between three distinct display styles. Each of these is fully compatible with the \tsobj[key]{invert-diff} option.
%   \begin{describelist*}{option}
%     \describe{default}{Typesets all the symbols, then the integrand, then the variables. As the macro operates by default in this mode, it is not necessary to use the key with this value.}
%     \describe{nested}{Typesets a nested integral where the symbol and integrand alternate before all the variables are written.}
%     \describe{product}{Typesets a product of integrals where the symbol, integrand, and variables alternate.}
%   \end{describelist*}
%   Of course, nothing prevents you from using the \tsobj[macro]{\integral} macro several times in a row to produce the same result as in the example below. However, for those who would prefer to obtain the result with a single macro, this method is permitted.
%   \begin{tsremark}[\textcolor{RoyalRed}{important:}]
%     For the last two modes, the integral will be \emph{cut off} in a certain way. In order to perform this action correctly, the same method must be used as with \tsobj[key]{limits}, i.e. by using a semicolon.
%   \end{tsremark}
% \end{codedescribe}
% 
% \begin{center}
%   \textsc{mode}\kern1ex \tsobj[option]{default}
% \end{center}
% 
% \begin{codestore}[5]
%   \begin{equation}
%     \integral[limits={1, 2; 3, 4; 5, 6}, variables={x, y, z}, mode=default]{xyz}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{5}
% 
% \begin{center}
%   \textsc{mode}\kern1ex \tsobj[option]{nested}
% \end{center}
% 
% \begin{codestore}[6]
%   \begin{equation}
%     \integral[limits={1, 2; 3, 4; 5, 6}, variables={z, y, x}, mode=nested]{x;y;z}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{6}
% 
% \begin{center}
%   \textsc{mode}\kern1ex \tsobj[option]{product}
% \end{center}
% 
% \begin{codestore}[7]
%   \begin{equation}
%     \integral[limits={1, 2; 3, 4; 5, 6}, variables={x, y, z}, mode=product]{x;y;z}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{7}
% 
% To function correctly, it is obvious that the keys \tsobj[key]{limits} and \tsobj[key]{variables} (see \ref{subsubsec:variables}), as well as the integrand, must have the same number of elements. If this is not the case, compilation will not fail, but the expression of the integral may no longer make sense. Numerous warning messages will be displayed to inform you of this.
%
% \subsection{Symbol (and more about limits)}
% 
% The \tsobj[key]{limits(*)} keys are very useful when typesetting a definite integral. However, this only covers final expressions where the limits of each variable have been specified. For more general cases — indefinite integrals \nobreak — they are relatively inconvenient. To typeset a double integral over a surface $S$, one would have to write \verb|limits={,;S,}|. Needless to say, this is rather inconvenient for the user and not optimal for the package. Furthermore, the glyph would not be correct. The set of keys below therefore offers an easy way to modify both the symbol and the bounds.
% 
% \subsubsection{Selecting a symbol}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{symbol}
%   \begin{codesyntax}[key]
%     \tsobj[key]{symbol}=\tsobj[meta]{control sequence}
%   \end{codesyntax}
%   This key accepts a macro designating an integral symbol. Any symbol previously defined by a control sequence is acceptable. If you attempt to use one that is not defined, it will be substituted with \tsobj[macro]{\int} and a warning message will be issued.
%   \begin{tsremark}[\textcolor{RoyalGreen}{remark:}]
%     Apart from verifying the existence of the macro, no specific checks are performed, and the value of the key is used as is to compose the symbol. This implies two things in particular. First, the symbol will depend on how it is defined. For instance, \tsobj[pkg]{amsmath} and \tsobj[pkg]{unicode-math} do not define \tsobj[macro]{\iint} in the same way. The result will naturally be different. Furthermore, if you assign a \emph{defined} macro as the key argument but it does not correspond to an integral symbol, the package will ignore it and still use the given symbol. In addition to the mathematical inconsistency that this may represent, it is likely to lead, under certain circumstances, to low-level errors.
%   \end{tsremark}
% \end{codedescribe}
% 
% \begin{codestore}[8]
%   \begin{equation}
%     \integral[symbol=\iint, llimit=S, variables={x, y}]{f(x, y)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{8}
% 
% \subsubsection{Generating many integrals}
% 
% \begin{codedescribe}[key]{nint}
%   \begin{codesyntax}[key]
%     \tsobj[key]{nint}=\tsobj[meta]{integer}
%   \end{codesyntax}
%   This key accepts an integer $n$ which allows $n$ integrals to be composed. It is advisable to use this key only if the number of symbols exceeds 4 to favour the glyphs defined by the mathematical font used.
% \end{codedescribe}
% 
% \begin{codestore}[9]
%   \begin{equation}
%     \integral[nint=5, llimit=\Omega, variables={x_1, x_2, x_3, x_4, x_5}]{f(x_1, x_2, x_3, x_4, x_5)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{9}
% 
% \subsubsection{Defining boundaries on an ad hoc basis}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{llimit, ulimit}
%   \begin{codesyntax}[key]
%     \tsobj[key]{llimit}=\tsobj[meta]{lower limit}
%     \tsobj[key]{ulimit}=\tsobj[meta]{upper limit}
%   \end{codesyntax}
%   These two keys allow you to specify the lower and upper limits, respectively. They are only suitable if a single symbol is displayed. If you need to specify both limits, the \tsobj[key]{limits} key should be used instead.
% \end{codedescribe}
% 
% \begin{codestore}[10]
%   \begin{equation}
%     \integral[llimit={x^2 + y^2 \leq 1}, variables={x, y}]{f(x, y)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{10}
% 
% \subsubsection{Recurring limits motif}
% 
% Lower limits sometimes follow common patterns that can be generalised with keys, thus avoiding overloading the argument of \tsobj[key]{llimit}.
% 
% \begin{codedescribe}[key, update={v3.0.0}]{domain, domain*}
%   \begin{codesyntax}[key]
%     \tsobj[key]{domain}=\tsargs[marg]{*-list}
%     \tsobj[key]{domain*}=\tsargs[marg]{*-list}
%   \end{codesyntax}
%   These keys accept a list delimited by an asterisk. Each element of the list is then parsed as follows:
%   \begin{itemize}
%     \item The first token of the item is passed \tsobj[macro]{\mathbb} (preceded by \tsobj[macro]{\uppercase} in case the \textsc{shift} key is too far away for your fingers).
%     \item The remaining tokens --- which may be empty --- are placed as superscript (or subscript for the starred variant of the key).
%   \end{itemize}
% \end{codedescribe}
% 
% \begin{codestore}[11]
%   \begin{equation}
%     \integral[symbol=\iint, domain={r*r}, variables={x, y}]{xy}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{11}
% 
% \begin{codedescribe}[key]{boundary}
%   \begin{codesyntax}[key]
%     \tsobj[key]{boundary}=\tsargs[marg]{lower limit}
%   \end{codesyntax}
%   This key simply places the symbol $\partial\,$ before the lower bound.
% \end{codedescribe}
% 
% \begin{codestore}[12]
%   \begin{equation}
%     \integral[symbol=\oint, boundary=S, diff-vec]{G(\vec r)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{12}
% 
% \subsection{Differentials}
% 
% \subsubsection{Specifying the integration variables}\label{subsubsec:variables}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{variables}
%   \begin{codesyntax}[key]
%     \tsobj[key]{variables}=\tsargs[marg]{csv-list}, \tsobj[meta]{keyword}, \tsobj[option]{none}
%   \end{codesyntax}
%   This key allows you to define the variables of the integral in the form of a \tsobj[meta]{csv-list}. Like \tsobj[key]{limits}, the key can accept a keyword as an argument. This behaviour is also explained later (see \cref{subsec:variablekey}).
%   \begin{tsremark}[\textcolor{RoyalGreen}{note:}]
%     If no variable is specified, i.e. \tsobj[key]{variables} is not called, the package automatically sets \enquote{$\odif{x}$} (or \enquote{$\odif{\vec{r}}$} if \tsobj[key]{diff-vec} is active). Furthermore, if \tsobj[option]{none} is passed as a value, no variable will be displayed.
%   \end{tsremark}
% \end{codedescribe}
% 
% \begin{codestore}[13]
%   \begin{equation}
%     \integral[variables=t]{t^2}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{13}
%
% \subsubsection{Inlcuding the Jacobian}
% 
% \begin{codedescribe}[key]{jacobian}
%   \begin{codesyntax}[key]
%     \tsobj[key]{jacobian}
%   \end{codesyntax}
%   This key enables the display of the Jacobian when defined by \tsobj[macro]{\NewVariableKeyword}.
% \end{codedescribe}
% 
% \begin{codestore}[14]
%   \begin{equation}
%     \integral[limits={0, R; 0, 2\pi; 0, \pi}, variables=spherical, mode=product, jacobian]{;;}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{14}
% 
% As mentioned earlier, \tsobj[pkg]{derivative} is used by the package to compose differentials. The set of keys to follow, whose names will be prefixed with \enquote{\texttt{diff-}}\footnote{Although the key \tsobj[key]{diff-vec} is not linked to \tsobj[pkg]{derivative}.}, thus allows you to apply the features of the macro \tsobj[macro]{\odif}.
% 
% \subsubsection{Modifying the differential symbol}
% 
% \begin{codedescribe}[key]{diff-symb}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-symb}=\tsargs[meta]{differential macro}
%   \end{codesyntax}
%   This key allows you to change the style of differentials among those defined by \tsobj[macro]{\NewDifferential}.
% \end{codedescribe}
% 
% \begin{codestore}[15]
%   \NewDifferential{\feynmandiff}{\mathcal{D}}
%   \begin{equation}
%     \integral[variables={q(t)}, diff-symb=\feynmandiff]{e^{+\dfrac{\imath S[q(t)]}{\hbar}}}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{15}
% 
% \subsubsection{Creating a path integral}
% 
% \begin{codedescribe}[key]{diff-vec}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-vec}
%   \end{codesyntax}
%   This key applies a vector to each variable in addition to a centred dot. It is only compatible with the \tsobj[option]{default} mode.  
% \end{codedescribe}
% 
% \begin{codestore}[16]
%   \begin{equation}
%     \integral[double=S, variables=S, diff-vec]{\vec F}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{16}
% 
% \subsubsection{Opting for the starred variant}
% 
% \begin{codedescribe}[key]{diff-star}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-star}
%   \end{codesyntax}
%   Activating this key is equivalent to using \tsobj[macro]{\odif*} or its variants.
% \end{codedescribe}
% 
% \begin{codestore}[17]
%   \begin{equation}
%     \integral[double, variables={x, y}, diff-star]{x^2 \exp(y)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{17}
% 
% \subsubsection{Designating options}
% 
% \begin{codedescribe}[key]{diff-options}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-options}=\tsargs[marg]{keyval list}
%   \end{codesyntax}
%   This key accepts a list of keys as it would have been written as an optional argument of \tsobj[macro]{\odif} or its variants. For example, \verb|diff-options={order={2, 3}, var=all}| will be interpreted as \verb|\odif[order={2, 3}, var=all]{...}|.
% \end{codedescribe}
% 
% \begin{codestore}[18]
%   \begin{equation}
%     \integral[diff-options={order=4}]{\bar\psi(x)(\imath\gamma^\mu\partial_\mu-m)\psi(x)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{18}
% 
% \section{Additional macros}
% 
% In addition to the wide range of keys defined by the package, a few macros also enhance their uses.
% 
% \subsection{Custom differentials placement}
% 
% \begin{codedescribe}[macro]{\differentials}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\differentials}
%   \end{codesyntax}
%   Although the \tsobj[key]{invert-diff} option exists, it is often desirable to be able to place differentials wherever one wishes. For example, they are frequently seen in the numerator of a fraction when the numerator is 1. To meet this need, the package provides the macro \tsobj[macro]{\differentials}. For the \tsobj[option]{default} and \tsobj[option]{nested} modes, the macro typesets all differentials at once. With \tsobj[option]{product}, the macro must be repeated between each semicolon.

% \end{codedescribe}
% 
% \begin{codestore}[19]
%   \begin{equation}
%     \integral{\frac{\differentials}{x}}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{19}
% 
% \subsection{Looking back at the \emph{limits} key}\label{subsec:limits}
% 
% \begin{codedescribe}[macro]{\NewLimitsKeyword, \RenewLimitsKeyword, \ProvideLimitsKeyword, \DeclareLimitsKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewLimitsKeyword}\tsargs[marg]{keyword}\tsargs[marg]{limits}
%   \end{codesyntax}
%   It is common to have to specify the same limits in an integral. To make them easier to write, the \tsobj[key]{limits(*)} keys accept, in addition to explicit limits, a keyword designating a pair of them predefined by one of these four macros:
%   \begin{describelist*} {macro}
%     \describe{\NewLimitsKeyword}{Creates a new keyword and issues an error if it already exists.}
%     \describe{\RenewLimitsKeyword}{Redefines a keyword and issues an error if it does not already exist.}
%     \describe{\ProvideLimitsKeyword}{Only creates a new keyword if it does not already exist. No message will be issued if this is the case.}
%     \describe{\DeclareLimitsKeyword}{Creates a new keyword regardless, overwriting any previous definition.}
%   \end{describelist*}
%   Here is the list of keywords already defined by the package and the limits they contain:
%   \begin{describelist*}{option}
%   \describe{ab}{$a, b$}
%   \describe{unit}{$0, 1$}
%   \describe{real}{$-\infty, \infty$}
%   \describe{positive}{$0, \infty$}
%   \describe{negative}{$-\infty, 0$}
%   \describe{circle}{$0, 2\pi$}
%   \describe{sircle}{$0, \pi$}
%   \describe{qcircle}{$0, \frac\pi 2$}
%   \describe{height}{$0, H$}
%   \describe{radius}{$0, R$}
%   \describe{length}{$0, L$}
%   \describe{time}{$0, T$}
%   \end{describelist*}
%   \begin{tsremark}[\textcolor{RoyalGreen}{remark:}]
%     Keywords contain both limits of an integral at the same time. They must therefore be preceded and/or followed by semicolons.
%   \end{tsremark}
%   \begin{tsremark}[\textcolor{RoyalRed}{important:}]
%     Due to the implementation of \tsobj[macro]{\NewLimitsKeyword} and its variants, the user \emph{must} follow the package's limit order convention, even if \tsobj[key]{invert-limits} is set to \tsobj[option]{true}
%   \end{tsremark}
%   We could therefore modify the expression of an integral as follows:
% \end{codedescribe}
% 
% \begin{codestore}[20]
%   \begin{equation}
%     \integral[limits={radius;circle;scircle}, variables={\rho, z, \phi}]{\rho z \phi}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{20}
% 
% It is entirely possible to combine these keywords with the more explicit syntax of \tsobj[key]{limits}.
% 
% \begin{codestore}[21]
%   \begin{equation}
%     \integral[limits={time; 34, 40; height}, variables={h, \omega, t}]{h \omega t}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{21}
% 
% \subsection{Looking back at the \emph{variables} key}\label{subsec:variablekey}
% 
% \begin{codedescribe}[macro]{\NewVariableKeyword, \RenewVariableKeyword, \ProvideVariableKeyword, \DeclareVariableKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewVariableKeyword}\tsargs[marg]{keyword}\tsargs[marg]{variables}\tsargs[oarg]{jacobian}
%   \end{codesyntax}
%   Similarly, the same groups of variables often reappear. We can therefore also define keywords containing a set of pre-registered variables. The variants of this macro behave in the same way as for \tsobj[macro]{\NewLimitsKeyword}. The only difference is that here it is possible to define a Jacobian, in the form of a \tsobj[meta]{csv-list} if necessary. Its display is then controlled by the \tsobj[key]{jacobian} key as explained above. Here is the list of variable keywords already defined by the package, with the Jacobian for some of them:
%   \begin{describelist*}{option}
%     \describe{cartesian}{$x, y, z$}
%     \describe{planar}{$x, y$}
%     \describe{polar}{$r, \theta \: (r)$}
%     \describe{cylindrical}{$r, \theta, z \: (r)$}
%     \describe{spherical}{$r, \theta, \phi \: (r^2, \sin\theta)$}
%   \end{describelist*}
% \end{codedescribe}
% 
% \begin{codestore}[22]
%   \begin{equation}
%     \integral[triple=V, variables=spherical]{f(x, y, z)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{22}
% 
% \subsection{Looking back at the \emph{symbol} key}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\NewSymbolKeyword, \RenewSymbolKeyword, \ProvideSymbolKeyword, \DeclareSymbolKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewSymbolKeyword}\tsargs[marg]{key}\tsargs[marg]{symbol}
%   \end{codesyntax}
%   In order to typeset indefinite integrals, the package essentially offers two keys: \tsobj[key]{symbol} and \tsobj[key]{llimit}. Although they are simple to use, it is still laborious to write both of them with their values. This is why \tsobj[pkg]{intexgral} provides so-called \emph{shortcut} keys, whose purpose is to combine the selection of the symbol and the limits. Unlike the two previous macros, this involves creating entirely new keys, rather than simply specific values assigned to \tsobj[key]{symbol}. On their own, these keys modify the integral symbol. The value of these keys corresponds to the lower bound. Here is the list of all \emph{symbol-key} defined by the package:
%   \begin{describelist*}{key}
%     \describe{single}{used symbol = \tsobj[macro]{\int}}
%     \describe{double}{used symbol = \tsobj[macro]{\iint}}
%     \describe{triple}{used symbol = \tsobj[macro]{\iiint}}
%     \describe{quadruple}{used symbol = \tsobj[macro]{\iiiint}}
%     \describe{contour}{used symbol = \tsobj[macro]{\oint}}
%     \describe{surface}{used symbol = \tsobj[macro]{\oiint}}
%     \describe{volume}{used symbol = \tsobj[macro]{\oiiint}}
%   \end{describelist*}
%   \begin{tsremark}[\textcolor{RoyalRed}{important:}]
%   Allowing users to create their own keys for the \tsobj[macro]{\integral} macro poses a risk that will be explained in more detail in the next section. For now, just remember that all these macros\footnote{With the exception of \tsobj[macro]{\DeclareSymbolKeyword}, which assumes that the user knows what they are doing.} will issue a warning message if you attempt to create a new \emph{symbol-key} with the same name as a group of defined limits.
%   \end{tsremark}
% \end{codedescribe}
%
% \begin{codestore}[23]
%   \begin{equation}
%     \integral[contour=\mathcal{C}, diff-vec]{f(\vec r)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{23}
% 
% \section{\emph{Special} syntax}
% 
% \subsection{Presentation of the syntax}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\integral}
%   \begin{codesyntax}
%     \tsmacro{\integral}[limits:variables(+j):mode]{integrand}
%   \end{codesyntax}
%   With regard to definite integrals, the user will be required to use a maximum of four keys to compose them: \tsobj[key]{limits}, \tsobj[key]{variables}, \tsobj[key]{mode} and \tsobj[key]{jacobian}. However, they can be criticised for the same reason as before; writing these four keys, which can take quite long arguments, runs counter to the main objective of this package. Thus, the user can designate as an optional argument of \tsobj[macro]{\integral} a syntax called \emph{special} that is unique to \tsobj[pkg]{intexgral}. The logic is as follows:
%   \begin{itemize}
%     \item You specify a \emph{valid} argument for the \tsobj[key]{limits} key.
%     \item You specify a \emph{valid} argument for the \tsobj[key] {variables}
%     \item You specify a \emph{valid} argument for the \tsobj[key]{mode} key
%   \end{itemize}
%   And you separate everything with a colon. Let's look at an example to better understand.
% \end{codedescribe}
% 
% \begin{codestore}[24]
%   \begin{equation}
%     \integral[1, 2; 4, 5:y, x:nested]{x; y}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{24}
% 
% We mean by \emph{valid argument} that all forms of values accepted by the four keys can also be likewise adopted by the special syntax. This hence includes keywords.
% 
% \begin{codestore}[25]
%   \begin{equation}
%     \integral[radius;circle;scircle:spherical:product]{r;\theta;\phi}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{25}
% 
%  To include the Jacobian, simply write \texttt{+j} after the argument of \tsobj[key]{variables}. The mode can also be indicated using only an initial.
% 
% \begin{codestore}[26]
%   \begin{equation}
%     \integral[radius;circle;scircle:spherical+j:p]{;;}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{26}
% 
% It is important to reiterate that in the classic configuration of the optional argument, it is of course not mandatory to specify the four keys mentioned. The same applies to this syntax. Since the key \tsobj[key]{mode} is not necessary for \tsobj[option]{default}, this part can be omitted.
% 
% \begin{codestore}[27]
%   \begin{equation}
%     \integral[1, 2; 3, 4:x, y]{xy}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{27}
% 
% You can also take advantage of the automatic placement of \enquote{$\odif{x}$} with this syntax, ignoring \tsobj[key]{variables}.
% 
% \begin{codestore}[28]
%   \begin{equation}
%     \integral[1, 10]{x}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{28}
% 
% \subsection{Functioning of the syntax}
% 
% From the user's point of view, it is relatively simple to choose which syntax to adopt. However, the package must be able to distinguish between the two. Without going into too much detail\footnote{The more courageous among you are still invited to read the source code.} about the implementation, it is brought to your attention that the package attempts to extract the first key from the optional argument\footnote{Or at least, the group of tokens that it thinks corresponds to a key.} and checks whether it exists. This is why, if you create a key with \tsobj[macro]{\NewSymbolKeyword} whose name can probably be used as integration limits, \tsobj[pkg]{intexrgal} may incorrectly evaluate the nature of the optional argument.
% 
% \section{Additional parameters}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\IntegralSetup}
%   \begin{codesyntax}[macro]
%   \tsmacro{\IntegralSetup}{parameter list}
%   \end{codesyntax}
%   This macro allows you to modify parameters related to certain keys using the syntax \tsobj[meta]{key=value}. All assignments made are local, so the macro can be placed in a group if necessary. Here is an example of the macro with the package's default assignments:
% \end{codedescribe}
% 
% \begin{codestore}[defaultparam]
%   \IntegralSetup
%     {
%       defaultvar  = {x},
%       defaultvar* = {r},
%       vectorstyle = \vec,
%       domainstyle = \mathbb,
%       symbolskip  = {-6mu},
%       hide-diff   = false
%     }
% \end{codestore}
% 
% \tscode*[intexgral]{defaultparam}
% 
% \begin{codedescribe}[key]{defaultvar, defaultvar*}
%   \begin{codesyntax}[key]
%     \tsobj[key]{defaultvar}=\tsargs[marg]{variables}
%   \end{codesyntax}
%   This key modifies the variable automatically inserted when \tsobj[key]{variables} is not used. The argument may correspond to a keyword defined by \tsobj[macro]{\NewVariableKeyword}. The starred variant of the key controls the integration parameter to be typeset with \tsobj[key]{diff-vec}.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{vectorstyle}
%   \begin{codesyntax}[key]
%     \tsobj[key]{vectorstyle}=\tsobj[meta]{control sequence}
%   \end{codesyntax}
%   This key modifies the macro to be applied to variables when \tsobj[key]{diff-vec} is in action. It is therefore possible to alter the style of the vector: bold, underlined, or even another style from a particular package --- \tsobj[pkg]{esvect} for example.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{domainstyle}
%   \begin{codesyntax}[key]
%     \tsobj[key]{domainstyle}=\tsobj[meta]{control sequence}
%   \end{codesyntax}
%   Similarly, you can change the macro to be applied for keys \tsobj[key]{domain(*)}.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{symbolskip}
%   \begin{codesyntax}[key]
%     \tsobj[key]{symbolskip}=\tsobj[meta]{muexpr}
%   \end{codesyntax}
%   When the \tsobj[option]{default} mode is in effect, the package inserts kerning between symbols to bring them slightly closer together. The default dimension ($-6$mu) can thus be adjusted according to the mathematical font in use.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{hide-diff}
%   \begin{codesyntax}[key]
%     \tsobj[key]{hide-diff}=\tsobj[option, meta or]{true,\uline{false}}
%   \end{codesyntax}
%   When a large part of the document requires differentials not to be included, it is possible to extend the more specific action of \tsobj[key]{variables}\texttt{=}\tsobj[option]{none} over time.
% \end{codedescribe}
% 
% \newpage
% 
% \addcontentsline{toc}{section}{Changelog}
% \phantomsection
% \begin{changelog}[sectioncmd=\section*]
% 
% \begin{version}[v=3.0.0, date=09-12-2025]
% \added
% \item Special syntax.
% \item Keys \tsobj[key]{domain*} and \tsobj[key]{mode}.
% \item Macros \tsobj[macro]{\IntegralSetup} and \tsobj[macro]{\NewSymbolKeyword}.
% \removed 
% \item Macros \tsobj[macro]{\defaultdiff}, \tsobj[macro]{\defaultdiff}, \tsobj[macro]{\defaultvdiff} et \tsobj[macro]{\vdiffstyle} in favour of \tsobj[macro]{\IntegralSetup}.
% \item Keys controlling both symbol and limit, now managed at a higher level by \tsobj[macro]{\NewSymbolKeyword}.
% \item \tsobj[key]{int-split} key, in favour of \tsobj[key]{mode}.
% \item \tsobj[macro]{\NewInegralSymbol} macro.
% \changed
% \item The names of some keys (\tsobj[key]{variable} in \tsobj[key]{variables}, \tsobj[key]{lower-lim} and \tsobj[key]{upper-lim} in \tsobj[key]{llimit} and \tsobj[key]{ulimit}, \tsobj[key]{int-symb} in \tsobj[key]{symbol}, \tsobj[key]{invert-differintials} and \tsobj[key]{hide-differentials} in \tsobj[key]{invert-diff} and \tsobj[key]{hide-diff}).
% \item \tsobj[key]{jacobian} and \tsobj[key]{diff-star} no longer require a boolean value. Simply writing them will now enable their features.
% \item \tsobj[key]{hide-diff} assigned to a local option rather than a package one.
% \item \tsobj[key]{limits-mode} assigned to a package option rather than a macro key
% \end{version}
% 
% \begin{version}[v=v2.0.1, date=13-09-2025]
% \fixed
% \item  Compatibiliy issue between unicode-math and amssyb depending on the loading order (\href{https://github.com/ankaa3908/intexgral/issues/2}{problem \#2}).
% \end{version}
% 
% \begin{version}[v=2.0.0, date=09-09-2025]
% \added 
% \item Macros \tsobj[macro]{\intexgralsetup}, \tsobj[macro]{\defaultdiff},\tsobj[macro]{\defaultvdiff} and \tsobj[macro]{\vdiffstyle}.
% \changed
% \item Warning messages related to non-existing symbols. They are now only triggered when the integral is typeset.
% \removed
% \item \tsobj[key]{diff-vec-style} key in favour of \tsobj[macro]{\vdiffstyle}.
% \item Warning message about misuse of semi-colon in conjunction with the \tsobj[key]{int-split} key.
% \fixed 
% \item Bug where the integrand was not reset when \tsobj[macro]{\integral} was used successively in the same \TeX\ group (\href{https://tex.stackexchange.com/questions/749990/issue-with-integral-command-from-intexgral-package-in-math-mode}{details here}).
% \item \tsobj[pkg]{expl3} log leftovers that shouldn't have been there.
% \end{version}
% 
% \begin{version}[v=1.1.0, date=29-07-2025]
% \added
% \item Starred variatn for the keys controlling both symbol and limit (keys \tsobj[key]{single}, \tsobj[key]{contour} etc).
% \end{version}
% 
% \shortversion{v=1.0.0, date=26-07-2025, changes=Initial version.}
% 
% \end{changelog}
%
% \newpage
%
% \PrintIndex
% \phantomsection
%
% \newpage
%
% \section*{Implementation}
% \addcontentsline{toc}{section}{Implementation}
% \phantomsection
% \CodelineNumbered
% 
% The implementation will be explained in more detail in a later version\dots
%
%    \begin{macrocode}
%<*package>
%<@@=intexgral>
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}[2025-05-14]
\RequirePackage{pkginfograb}

% Package declaration

\pkginfograbProvidesExplPackage{intexgral}
  {
    name         = {intexgral}   ,
    author       = {Valentin Dao},
    date         = {2025-12-24}  ,
    creation     = {2025-07-26}  ,
    version      = {3.0.0}       ,
    description  = {A LaTeX package for typesetting integrals.}
  }

\msg_new:nnn { intexgral } { expl3-too-old }
  {
    Your~expl3~installation~is~too~old,~
    "intexgral"~requires~expl3~dated~2025-05-14~or~later.\iow_newline:
    Package~loading~has~been~aborted.\iow_newline:
    \msg_see_documentation_text:n { intexgral }
  }

% expl3 version verification

\@ifpackagelater{expl3}{2025-05-14}{}
  { \msg_critical:nn { intexgral } { expl3-too-old } }

% Verifies is \mathbb is defined (default domain style)

\hook_gput_code:nnn { begindocument/before } { . } 
  { \cs_if_exist:NF \mathbb { \RequirePackage{amsfonts} } }

% Definition of data types for package options

\bool_new:N \l_@@_invert_limits_bool
\bool_new:N \l_@@_deactivate_differentials_bool
\bool_new:N \l_@@_invert_differentials_bool
\tl_new:N \l_@@_limits_style_tl

% Package options

\keys_define:nn { intexgral }
  {
    invert-limits .bool_set:N = \l_@@_invert_limits_bool,
    invert-limits .usage:n    = { preamble },
    invert-limits .initial:n  = { false },

    invert-diff .bool_set:N = \l_@@_invert_differentials_bool,
    invert-diff .usage:n    = { preamble },
    invert-diff .initial:n  = { false },

    limits-mode .choice:,
    limits-mode / limits .code:n =
      { \tl_set_eq:NN \l_@@_limits_style_tl \tex_limits:D },
    limits-mode / nolimits .code:n =
      { \tl_set_eq:NN \l_@@_limits_style_tl \tex_nolimits:D },

    limits-mode .usage:n   = { preamble },
    limits-mode .initial:n = { nolimits },

    italic .choice:,
      italic / true .code:n  =
        { \PassOptionsToPackage{italic=true}{derivative} },
      italic / false .code:n =
        { \PassOptionsToPackage{italic=false}{derivative} },

    upright .choice:,
      upright / true .code:n  =
        { \PassOptionsToPackage{upright=true}{derivative} },
      upright / false .code:n =
        { \PassOptionsToPackage{upright=false}{derivative} },
  }

% Loads the package options and "derivative" package

\ProcessKeyOptions[intexgral]

\RequirePackage{derivative}

% Warning/Error/Info messages

\cs_new:Nn \@@_warning_msg_header: {
  (
    integral~no.~
    \int_use:N\g_@@_integral_number_int\c_space_tl
    \msg_line_context:
  )
  \iow_newline:
}

\msg_new:nnnn { intexgral } { symb-key-alr-def }
  { Symbol~key~"\tl_trim_spaces:n{#1}"~is~already~defined. }
  { Use~\token_to_str:N \RenewSymbolKeyword\ instead. }

\msg_new:nnnn { intexgral } { symb-key-not-def }
  { Symbol~key~"\tl_trim_spaces:n{#1}"~is~not~defined. }
  { Use~\token_to_str:N \NewSymbolKeyword\ instead. }

\msg_new:nnnn { intexgral } { diff-group-alr-def }
  { Differential~group~"\tl_trim_spaces:n{#1}"~is~already~defined. }
  { Use~\token_to_str:N \RenewVarKeyword\ instead. }

\msg_new:nnnn { intexgral } { diff-group-not-def }
  { Differential~group~"\tl_trim_spaces:n{#1}"~is~not~defined. }
  { Use~\token_to_str:N \NewVarKeyword\ instead. }

\msg_new:nnnn { intexgral } { lim-group-alr-def }
  { Limits~group~"\tl_trim_spaces:n{#1}"~is~already~defined. }
  { Use~\token_to_str:N \RenewLimitsKeyword\ instead. }

\msg_new:nnnn { intexgral } { lim-group-not-def }
  { Limits~group~"\tl_trim_spaces:n{#1}"~is~not~defined. }
  { Use~\NewLimitsKeyword\ instead. }

\msg_new:nnn { intexgral } { key-exists-for-lim }
  {
    Symbol~key~already~defined~with~
    \token_to_str:N \NewLimitsKeyword\ \@@_warning_msg_header:
    Key~"#1"~already~exists~for~predefined~limits.~
    This~can~disrupt~the~functioning~of~the~special~syntax.
  }

\msg_new:nnn { intexgral } { unknown-symb }
  {
    Unknown~integral~symbol~\@@_warning_msg_header:
    The~symbol~\tl_trim_spaces:n{#1}~has~been~replaced~with~
    \token_to_str:N\int.
  }

\msg_new:nnn { intexgral } { unequal-dim }
  {
    Inconsistent~structure~\@@_warning_msg_header:
    The~number~of~integrals~(#1),~integrands~(#2),~and~
    differentials~(#3)~does~not~match.
  }

\msg_new:nnn { intexgral } { no-jacobian }
  {
    Jacobian~unavailable~\@@_warning_msg_header:
    A~Jacobian~was~requested~for~the~"#1"~keyword,
    ~but~none~was~declared~for~the~latter.
  }

\msg_new:nnn { intexgral } { diff-not-sup }
  {
    Macro~\token_to_str:N\differentials\ 
    not~supported~\@@_warning_msg_header:
    You~can't~use~\token_to_str:N\differentials\
    with~"nested"~mode~alongside~inverted~differentials.~
    I~will~simply~ignore~them.
  }

\msg_new:nnn { intexgral } { diff-vec-not-supp }
  {
    Key~"diff-vec"~not~supported~\@@_warning_msg_header:
    You~can't~use~"diff-vec"~with~"#1"~mode.~I~will~simply~ignore~this~key.
  }

\msg_new:nnn { intexgral } { use-glyph-instead }
  {
    Consider~using~the~dedicated~glyph~\@@_warning_msg_header:
    The~key~"nint"~was~used~with~fewer~than~
    5~regular~integral~signs.
  }

% Argument specifiers variants

\cs_generate_variant:Nn \regex_if_match:nnTF    { nVTF }
\cs_generate_variant:Nn \@@_new_limits_group:nn { nV   }
\cs_generate_variant:Nn \str_if_eq:nnTF         { neTF }
\cs_generate_variant:Nn \str_if_eq:nnF          { neF  }
\cs_generate_variant:Nn \keys_if_exist:nnTF     { nVTF }
\cs_generate_variant:Nn \seq_use:Nn             { Ne   }
\cs_generate_variant:Nn \str_if_eq_p:nn         { en   }

% DATA TYPES

\tl_new:N \l_@@_key_name_tl
\tl_new:N \l_@@_integrand_tl
\tl_new:N \l_@@_domain_style_tl
\tl_new:N \l_@@_lower_limit_tl
\tl_new:N \l_@@_upper_limit_tl
\tl_new:N \l_@@_integral_symbol_tl
\tl_new:N \l_@@_differential_options_i_tl
\tl_new:N \l_@@_differential_options_ii_tl
\tl_new:N \l_@@_vectorial_differential_style_tl
\tl_new:N \l_@@_independent_differential_options_tl
\tl_new:N \l_@@_domain_char_tl
\tl_new:N \l_@@_domain_dimension_tl
\tl_new:N \l_@@_default_differential_tl
\tl_new:N \l_@@_default_vector_differential_tl
\tl_const:Nn \c_@@_left_bracket_tl { [ }
\tl_const:Nn \c_@@_right_bracket_tl { ] }

\tl_set_eq:NN \l_@@_integral_symbol_tl \int

\bool_new:N \l_@@_manual_differentials_bool
\bool_new:N \l_@@_custom_variables_bool
\bool_new:N \l_@@_separate_integral_bool
\bool_new:N \l_@@_vectorial_differential_bool
\bool_new:N \l_@@_jacobian_bool
\bool_new:N \l_@@_starred_differential_bool
\bool_new:N \l_@@_has_order_bool
\bool_new:N \l_@@_has_var_bool

\bool_set_false:N \l_@@_vectorial_differential_bool
\bool_set_false:N \l_@@_manual_differentials_bool
\bool_set_false:N \l_@@_custom_variables_bool
\bool_set_false:N \l_@@_separate_integral_bool
\bool_set_false:N \l_@@_has_order_bool
\bool_set_false:N \l_@@_has_var_bool

\clist_new:N \l_@@_variable_i_clist
\clist_new:N \l_@@_variable_ii_clist

\seq_new:N \l_@@_integrand_seq
\seq_new:N \l_@@_integral_symbol_seq
\seq_new:N \l_@@_jacobian_seq
\seq_new:N \l_@@_differential_seq
\seq_new:N \l_@@_limits_seq
\seq_new:N \l_@@_upper_limits_seq
\seq_new:N \l_@@_lower_limits_seq
\seq_new:N \l_@@_differential_var_i_seq
\seq_new:N \l_@@_differential_var_ii_seq
\seq_new:N \l_@@_differential_order_i_seq
\seq_new:N \l_@@_differential_order_ii_seq
\seq_new:N \l_@@_domain_seq

\str_new:N \l_@@_display_mode_str

\muskip_new:N \l_@@_inline_symbol_muskip

\prop_new:N \g_@@_limits_keyword_prop
\prop_new:N \g_@@_differential_group_keyword_prop

\int_new:N \l_@@_integral_sequence_int
\int_gzero_new:N \g_@@_integral_number_int

% TeX macros adapted to expl3 syntax

\cs_new_protected:Npn \@@_mkern:N #1
  { \tex_mkern:D #1 \scan_stop: }

\cs_new_protected:Npn \@@_mathchoice:nnnn #1#2#3#4
  { \mathchoice{#1}{#2}{#3}{#4} }

% SYMBOL

% General form of the symbol (glyph, limits mode, lower limit, upper limit)

\cs_new_protected:Npn \@@_parse_integral_symbol:
  {
    \tl_use:N \l_@@_integral_symbol_tl
    \tl_use:N \l_@@_limits_style_tl
    \c_math_subscript_token
      { \l_@@_lower_limit_tl }
    \c_math_superscript_token
      { \l_@@_upper_limit_tl }
  }

% Generates the symbols after <limits> is executed

\cs_new_protected:Nn \@@_generate_integral_sequence:
  {
    \int_set:Nn \l_@@_integral_sequence_int
      {
        \seq_if_empty:NTF \l_@@_lower_limits_seq
          { \seq_count:N \l_@@_upper_limits_seq }
          { \seq_count:N \l_@@_lower_limits_seq }
      }
    \exp_args:NV
    \int_step_inline:nn \l_@@_integral_sequence_int
      {
        \seq_put_right:Nn \l_@@_integral_symbol_seq
          {
            \@@_set_limits:nn
              { \seq_item:Nn \l_@@_lower_limits_seq { ##1 } }
              { \seq_item:Nn \l_@@_upper_limits_seq { ##1 } }
            \@@_parse_integral_symbol:
          }
      }
  }

% LIMITS

% Inverts the limit order convention

\cs_new_protected:Npn \@@_set_limits:nn #1#2
  {
    \bool_if:NTF \l_@@_invert_limits_bool
      {
        \tl_set:Nn \l_@@_lower_limit_tl { #2 }
        \tl_set:Nn \l_@@_upper_limit_tl { #1 }
      }
      {
        \tl_set:Nn \l_@@_lower_limit_tl { #1 }
        \tl_set:Nn \l_@@_upper_limit_tl { #2 }
      }
  }

% Creates a keyword containing predefined limits

\cs_new_protected:Npn \@@_new_limits_group:nn #1#2
  { \prop_put:Nnn \g_@@_limits_keyword_prop { #1 } { #2 } }

% Verifies if the argument corresponds to a valid keyword

\cs_new:Npn \@@_parse_integral_limit:n #1
  {
    \prop_if_in:NnTF \g_@@_limits_keyword_prop { #1 }
      { \prop_item:Nn \g_@@_limits_keyword_prop { #1 } }
      { #1 }
  }

% Splits the argument of the key to prepare for parsing

\cs_new_protected:Npn \@@_parse_limits:n #1
  {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \seq_clear:N \l_@@_lower_limits_seq
    \seq_clear:N \l_@@_upper_limits_seq
    \seq_set_split:NnV \l_@@_limits_seq { ; } \l_tmpa_tl
  }

% Limits under regular form

\cs_new_protected:Nn \@@_set_limits_regular:
  {
    \seq_map_inline:Nn \l_@@_limits_seq
      {
        \clist_set:Ne \l_tmpa_clist
          { \@@_parse_integral_limit:n { ##1 } }
        \seq_put_right:Ne \l_@@_lower_limits_seq
          { \clist_item:Nn \l_tmpa_clist { 1 } }
        \seq_put_right:Ne \l_@@_upper_limits_seq
          { \clist_item:Nn \l_tmpa_clist { 2 } }
      }
  }

% Limits under interval form

\cs_new_protected:Npn \@@_set_limits_starred:
  {
    \seq_map_indexed_inline:Nn \l_@@_limits_seq
      {
        \clist_set:Ne \l_tmpa_clist 
          { \@@_parse_integral_limit:n { ##2 } }
        \bool_if:NTF \l_@@_invert_limits_bool
          {
            \tl_set:Ne \l_@@_lower_limit_tl
              {
                \clist_item:Nn \l_tmpa_clist { 2 }
                \tex_mathpunct:D,
                \clist_item:Nn \l_tmpa_clist { 1 }
              }
          }
          {
            \tl_set:Ne \l_@@_lower_limit_tl
              {
                \clist_item:Nn \l_tmpa_clist { 1 }
                \tex_mathpunct:D,
                \clist_item:Nn \l_tmpa_clist { 2 }
              }
          }
            \bool_if:NTF \l_@@_invert_limits_bool
              { \seq_put_right:Ne \l_@@_upper_limits_seq }
              { \seq_put_right:Ne \l_@@_lower_limits_seq }
          {
            \str_case_e:nnF { \clist_item:Nn \l_tmpa_clist { 1 } }
              {
                { -\infty } { \tex_left:D \c_@@_right_bracket_tl }
              }
              { \tex_left:D \c_@@_left_bracket_tl }
            \tl_use:N \l_@@_lower_limit_tl
            \str_case_e:nnF { \clist_item:Nn \l_tmpa_clist { 2 } }
              {
                { +\infty } { \tex_right:D \c_@@_left_bracket_tl }
              }
              { \tex_right:D \c_@@_right_bracket_tl }
            }
      }
  }

% VARIABLES

% Creates a keyword containing predefined variables

\cs_new_protected:Npn \@@_new_differential_group:nnn #1#2#3
  {
    \prop_put:Nnn \g_@@_differential_group_keyword_prop
      { #1 } { #2 }
    \tl_if_blank:nF { #3 }
      {
        \clist_set:Nn \l_tmpa_clist { #3 }
        \seq_set_from_clist:cN
          { g_@@_#1_jacobian_seq }
          \l_tmpa_clist
      }
  }

% expl3 equivalent of \odif(*)

\cs_new:Npn \@@_differentials:nn #1#2
  {
    \bool_if:NTF \l_@@_starred_differential_bool
      { \odif*[#1]{#2} }
      { \odif[#1]{#2} }
  }

% Extracts the whole "order" <keyval> 

\cs_new_protected:Npn \@@_extract_differential_order:n #1
  {
    \regex_extract_once:nnNT
      { order\s*=\s*\{?\s*(\d+(?:\s*,\s*\d+)*)\s*\}? }
      { #1 } \l_@@_differential_order_i_seq
      { \bool_set_true:N \l_@@_has_order_bool }
    \clist_set:Ne \l_tmpa_clist
      { \seq_item:Nn \l_@@_differential_order_i_seq { 2 } }
    \seq_set_from_clist:NN 
      \l_@@_differential_order_ii_seq
      \l_tmpa_clist
  }

% Extracts the whole "var" <keyval> 

\cs_new_protected:Npn \@@_extract_differential_var:n #1
  {
    \regex_extract_once:nnNTF
      { var\s*=\s*(none|all|\{\s*(\d+(?:\s*,\s*\d+)*\s*)\}) }
      { #1 }
      \l_@@_differential_var_i_seq
      { \bool_set_true:N \l_@@_has_var_bool }
      {
        \str_if_in:nnT { #1 } { var }
          {
            \seq_put_left:Nn \l_@@_differential_var_i_seq { var }
            \bool_set_true:N \l_@@_has_var_bool
          }
      }
    \clist_set:Ne \l_tmpa_clist 
      { \seq_item:Nn \l_@@_differential_var_i_seq { 3 } }
    \seq_set_from_clist:NN
      \l_@@_differential_var_ii_seq
      \l_tmpa_clist
  }

% Extracts all keys other than "order" and "var"

\cs_new_protected:Npn \@@_remove_differential_order_and_var:n #1
  {
    \tl_set:Nn \l_@@_independent_differential_options_tl { #1 }
    \regex_replace_all:nnN
      {
        order\s*=\s*\{?\s*\d+(\s*,\s*\d+)*\s*\}?\s*,?
        |
        [^-]var(?:\s*=\s*(?:none|all|\{\s*\d+(?:\s*,\s*\d+)*\s*\}))?,?
      }
      {  }
      \l_@@_independent_differential_options_tl
  }

% Reassembles the variables 

\cs_new_protected:Npn \@@_parse_variable:nn #1#2
  {
    \clist_set:Nn \l_tmpa_clist { #2 }
    \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
    \tl_if_empty:nF { #1 }
      {
        \@@_extract_differential_order:n { #1 }
        \@@_extract_differential_var:n { #1 }
        \@@_remove_differential_order_and_var:n { #1 }
      }
    \seq_map_indexed_inline:Nn \l_tmpa_seq {
      \tl_if_empty:nF { #1 }
        {
          \tl_put_right:NV 
            \l_@@_differential_options_ii_tl
            \l_@@_independent_differential_options_tl
          \bool_if:NT \l_@@_has_order_bool
            {
              \tl_put_right:Ne \l_@@_differential_options_ii_tl
                {
                  ,order=
                  \seq_item:Nn \l_@@_differential_order_ii_seq { ##1 }
                }
            }
          \bool_if:NT \l_@@_has_var_bool
            {
              \int_compare:nNnTF
              { \seq_count:N \l_@@_differential_var_i_seq }
              =
              { 1 }
              {
                \tl_put_right:Nn 
                  \l_@@_differential_options_ii_tl
                  { var }
              }
              {
                \str_if_eq:neF { none }
                  { \seq_item:Nn \l_@@_differential_var_i_seq { 2 } }
                    {
                      \str_if_eq:neTF { all }
                        { \seq_item:Nn 
                            \l_@@_differential_var_i_seq 
                            { 2 }
                        }
                        {
                          \tl_put_right:Nn
                            \l_@@_differential_options_ii_tl
                            { var }
                        }
                        {
                          \seq_if_in:NnT
                            \l_@@_differential_var_ii_seq
                            { ##1 }
                            {
                              \seq_pop_left:NN
                                \l_@@_differential_var_ii_seq 
                                \l_tmpa_tl
                              \tl_put_right:Nn
                                \l_@@_differential_options_ii_tl
                                { ,var }
                            }
                        }
                    }
              }
            }
        }
      \seq_put_right:Ne \l_@@_differential_seq
        {
          \@@_differentials:nn
            { \exp_not:V \l_@@_differential_options_ii_tl }
            { \seq_item:Nn \l_tmpa_seq { ##1 } }
        }
      \tl_clear:N \l_@@_differential_options_ii_tl
    }
  }

% Executes all previous macros to push tokens into the variable sequence

\cs_new_protected:Npn \@@_parse_differentials:
  {
    \bool_if:NTF \l_@@_vectorial_differential_bool
      {
        \clist_map_inline:Nn \l_@@_variable_i_clist
          {
            \clist_put_right:Nn \l_@@_variable_ii_clist
              { \l_@@_vectorial_differential_style_tl{##1} }
          }
        \bool_if:NTF \l_@@_custom_variables_bool
          {
            \exp_args:NVV \@@_parse_variable:nn
              \l_@@_differential_options_i_tl
              \l_@@_variable_ii_clist
          }
          {
            \exp_args:NV \@@_parse_variable:nn
              \l_@@_differential_options_i_tl
              { 
                \l_@@_vectorial_differential_style_tl
                  { \l_@@_default_vector_differential_tl } 
              }
          }
      }
      {
        \bool_if:NTF \l_@@_custom_variables_bool
          {
            \exp_args:NVV \@@_parse_variable:nn
              \l_@@_differential_options_i_tl
              \l_@@_variable_i_clist
          }
          {
            \exp_args:NV \@@_parse_variable:nn
              \l_@@_differential_options_i_tl
              { \l_@@_default_differential_tl }
          }
      }
  }

% SPECIAL SYNTAX

% Cuts off the value of a key

\cs_new:Npn \@@_retrieve_key_name:w #1=#2\q_stop { #1 }

% Extracts first key name of optional argument

\cs_new_protected:Npn \@@_extract_first_key_name:n #1
  {
    \clist_set:Nn \l_tmpa_clist { #1 }
    \tl_set:Ne \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist { 1 } }
    \tl_if_in:NnTF \l_tmpa_tl { = }
      { 
        \tl_set:Ne \l_@@_key_name_tl 
          { 
            \exp_last_unbraced:NV
            \@@_retrieve_key_name:w \l_tmpa_tl \q_stop 
          } 
      }
      { \tl_set_eq:NN \l_@@_key_name_tl \l_tmpa_tl }
  }

% Sets the keys as usual, or sets them up manually if special syntax is in use

\cs_new_protected:Npn \@@_parse_macro_keys:n #1
  {
    \keys_if_exist:nVTF { integral } \l_@@_key_name_tl
      { \keys_set:nn { integral } { #1 } }
      {  
        \regex_split:nnN { : } { #1 } \l_tmpa_seq
        \int_compare:nNnT { \seq_count:N \l_tmpa_seq } < { 2 }
          {
            \seq_put_right:NV
              \l_tmpa_seq
              \l_@@_default_differential_tl 
          }
        \int_compare:nNnT { \seq_count:N \l_tmpa_seq } < { 3 }
          { \seq_put_right:Nn \l_tmpa_seq { d } }
        \seq_set_split:Nne \l_tmpb_seq 
          { + } 
          { \seq_item:Nn \l_tmpa_seq { 2 } }
        \keys_set:ne { integral }
          {
            limits    = { \seq_item:Nn \l_tmpa_seq { 1 } },
            variables = { \seq_item:Nn \l_tmpb_seq { 1 } },
            mode      =
              { 
                \str_case:enF { \seq_item:Nn \l_tmpa_seq { 3 } }
                  {
                    { d       } { default }
                    { n       } { nested  }
                    { p       } { product }
                    { default } { default }
                    { nested  } { nested  }
                    { product } { product }
                  }
                { default }
              },
            \bool_if:nT
              {
                \int_compare_p:nNn { \seq_count:N \l_tmpb_seq } > { 1 }
                &&
                \str_if_eq_p:en { \seq_item:Nn \l_tmpb_seq { 2 } } { j }
              }
              { jacobian }
          }
      }
  }

% PRELIMINARY CONFIGURATIONS

% Verifies that <limits> and <variables> (and <integrand>) have the same size

\cs_new_protected:Nn \@@_check_sequence_size:
  {
    \int_compare:nNnTF
      { \seq_count:N \l_@@_integral_symbol_seq }
      =
      { \seq_count:N \l_@@_integrand_seq }
        {
          \int_compare:nNnF
            { \seq_count:N \l_@@_integrand_seq }
            =
            { \seq_count:N \l_@@_differential_seq }
              {
                \msg_warning:nneee { intexgral } { unequal-dim }
                  { \seq_count:N \l_@@_integral_symbol_seq }
                  { \seq_count:N \l_@@_integrand_seq       }
                  { \seq_count:N \l_@@_differential_seq    }
              }
        }
        {
          \msg_warning:nneee { intexgral } { unequal-dim }
            { \seq_count:N \l_@@_integral_symbol_seq }
            { \seq_count:N \l_@@_integrand_seq       }
            { \seq_count:N \l_@@_differential_seq    }
        }
  }

% Performs preparatory actions before executing the main macro

\cs_new_protected:Nn \@@_integral_preconfiguration:
  {
    \int_gincr:N \g_@@_integral_number_int

    \bool_if:NT \l_@@_separate_integral_bool
      { 
        \seq_set_split:NnV 
          \l_@@_integrand_seq 
          { ; } 
          \l_@@_integrand_tl 
      }

    \seq_if_empty:NT \l_@@_integral_symbol_seq
      {
        \seq_put_right:Nn \l_@@_integral_symbol_seq
          { \@@_parse_integral_symbol: }
      }

    \seq_if_empty:NT \l_@@_integrand_seq
      {
        \seq_put_right:NV
          \l_@@_integrand_seq
          \l_@@_integrand_tl
      }

    \bool_if:NF \l_@@_deactivate_differentials_bool
      { \@@_parse_differentials: }

    \regex_if_match:nVTF { \c{differentials} } \l_@@_integrand_tl
      { \bool_set_true:N \l_@@_manual_differentials_bool }
      { \bool_set_false:N \l_@@_manual_differentials_bool }

    \bool_if:NT \l_@@_separate_integral_bool
      { \@@_check_sequence_size: }
  }

% Default mode

\cs_new_protected:Nn \@@_print_default_integral:
  {
    \bool_if:NT \l_@@_manual_differentials_bool
      {
        \cs_set_protected:Npn \differentials
          { \seq_use:Nn \l_@@_differential_seq {  } }
      }
    \seq_use:Nn \l_@@_integral_symbol_seq 
      { \@@_mkern:N \l_@@_inline_symbol_muskip }
    \bool_if:nT
      { 
        \l_@@_invert_differentials_bool
        &&
        !\l_@@_manual_differentials_bool
      }
      { 
        \seq_use:Nn \l_@@_differential_seq {  } \tex_mathop:D{} \! 
        \bool_if:NT \l_@@_vectorial_differential_bool { \cdot \: }
      }
    \seq_use:Nn \l_@@_integrand_seq {  }
    \bool_if:NT \l_@@_jacobian_bool
      { \seq_use:Nn \l_@@_jacobian_seq {  } }
    \bool_if:nT
      { 
        !\l_@@_invert_differentials_bool
        &&
        !\l_@@_manual_differentials_bool
      }
      {
        \bool_if:NT \l_@@_vectorial_differential_bool { \cdot }
        \seq_use:Nn \l_@@_differential_seq {  } 
      }
  }

% Nested mode

\cs_new_protected:Nn \@@_print_nested_integral: 
  {
    \bool_if:NT \l_@@_manual_differentials_bool
      {
        \cs_set_protected:Npn \differentials
          { \seq_use:Nn \l_@@_differential_seq {  } }
      }
    \bool_if:NT \l_@@_vectorial_differential_bool
      { \msg_warning:nnn { intexgral } { diff-vec-not-supp } { nested } }
    \int_step_inline:nn { \seq_count:N \l_@@_integral_symbol_seq }
      {
        \seq_item:Nn \l_@@_integral_symbol_seq { ##1 }
        \bool_if:NTF \l_@@_invert_differentials_bool
          { 
            \bool_if:NT \l_@@_manual_differentials_bool
              {
                \msg_warning:nn { intexgral } { diff-not-sup }
                \cs_set_eq:NN \differentials \scan_stop:
              }
            \seq_item:Nn \l_@@_differential_seq { ##1 } 
            \tex_mathop:D{} \!
          }
          {
            \seq_item:Nn \l_@@_integrand_seq { ##1 }
            \bool_if:NT \l_@@_jacobian_bool
              { \seq_item:Nn \l_@@_jacobian_seq { ##1 } }
          }
      }
    \bool_if:NTF \l_@@_invert_differentials_bool
      {
        \seq_use:Nn \l_@@_integrand_seq {}
        \bool_if:NT \l_@@_jacobian_bool
          { \seq_use:Nn \l_@@_jacobian_seq {  } }
      }
      {
        \bool_if:NF \l_@@_manual_differentials_bool
          {
            \seq_use:Nn \l_@@_differential_seq {}
          }
      }
  }

% Product mode

\cs_new_protected:Nn \@@_print_product_integral: 
  {
    \bool_if:NT \l_@@_manual_differentials_bool
      {
        \cs_set_protected:Npn \differentials
          { 
            \seq_gpop_left:NN \l_tmpa_tl 
            \tl_use:N \l_tmpa_tl
          }
      }
    \bool_if:NT \l_@@_vectorial_differential_bool
      { \msg_warning:nnn { intexgral } { diff-vec-not-supp } { product } }
    \int_step_inline:nn { \seq_count:N \l_@@_integral_symbol_seq }
      {
        \seq_item:Nn \l_@@_integral_symbol_seq { ##1 }
        \bool_if:nT
          {
            \l_@@_invert_differentials_bool
            &&
            !\l_@@_manual_differentials_bool
          }
          {
            \seq_item:Nn
              \l_@@_differential_seq { ##1 }
            \tex_mathop:D{} \!
          }
      \seq_item:Nn \l_@@_integrand_seq { ##1 }
      \bool_if:NT \l_@@_jacobian_bool
        { \seq_item:Nn \l_@@_jacobian_seq { ##1 } }
      \bool_if:nT
        {
          !\l_@@_invert_differentials_bool
          &&
          !\l_@@_manual_differentials_bool
        }
        { \seq_item:Nn \l_@@_differential_seq { ##1 } }
      }
  }

% General macro for typesetting 

\cs_new_protected:Nn \@@_print_integral:
  {
    \@@_integral_preconfiguration:
    \str_case:VnF \l_@@_display_mode_str
      {
        { default } { \@@_print_default_integral: }
        { nested  } { \@@_print_nested_integral:  }
        { product } { \@@_print_product_integral: }
      }
      { \@@_print_default_integral: }
    \seq_gclear:N \l_@@_differential_seq
  }

% KEYS

\keys_define:nn { integral } {

  % LIMITS

  mode .choice:,
    mode / default .code:n =
      {
        \bool_set_false:N \l_@@_separate_integral_bool
        \str_set:Nn \l_@@_display_mode_str { default }
      },
    mode / nested .code:n =
      {
        \bool_set_true:N \l_@@_separate_integral_bool
        \str_set:Nn \l_@@_display_mode_str { nested }
      },
    mode / product .code:n =
      {
        \bool_set_true:N \l_@@_separate_integral_bool
        \str_set:Nn \l_@@_display_mode_str { product }
      },
    mode .default:n = { default },

  limits .code:n =
    {
      \@@_parse_limits:n { #1 }
      \@@_set_limits_regular:
      \@@_generate_integral_sequence:
    },

  limits* .code:n =
    {
      \@@_parse_limits:n { #1 }
      \@@_set_limits_starred:
      \@@_generate_integral_sequence:
    },

  llimit .tl_set:N = \l_@@_lower_limit_tl,

  ulimit .tl_set:N = \l_@@_upper_limit_tl,

  symbol .code:n =
    {
      \cs_if_exist:NTF #1
        { \tl_set_eq:NN \l_@@_integral_symbol_tl #1 }
        { 
          \msg_warning:nnn { intexgral } { unknown-symb } { #1 } 
          \tl_set_eq:NN \l_@@_integral_symbol_tl \int
        }
    },

  % SYMBOL SHORTCUT

  nint .code:n =
    {
      \int_compare:nNnT { #1 } < { 5 }
        { \msg_warning:nn { intexgral } { use-glyph-instead } }

      \tl_clear:N \l_@@_integral_symbol_tl

      \int_step_inline:nn { #1 }
        {
          \tl_put_right:Nn \l_@@_integral_symbol_tl
            { \int }
          \int_compare:nNnT { ##1 } < { #1 }
            {
              \tl_put_right:Nn \l_@@_integral_symbol_tl
                {
                  \@@_mathchoice:nnnn
                    { \tex_mkern:D -12mu \scan_stop: }
                    { \tex_mkern:D -8mu \scan_stop: }
                    { \tex_mkern:D -4mu \scan_stop: }
                    { \tex_mkern:D -2mu \scan_stop: }
                }
            }
        }
    },

  % LIMITS SHORTCUTS

  domain .code:n =
    {
      \tl_set:Nn \l_tmpa_tl { #1 }
      \seq_set_split:NnV \l_@@_domain_seq { * } \l_tmpa_tl
      \seq_map_inline:Nn \l_@@_domain_seq
        {
          \tl_if_empty:NF \l_@@_lower_limit_tl
            { \tl_put_right:Nn \l_@@_lower_limit_tl { \times } }
          \tl_set:Ne \l_@@_domain_char_tl
            { \exp_args:Ne \str_uppercase:n { \tl_head:n { ##1 } } }
          \tl_set:Ne \l_@@_domain_dimension_tl
            { \tl_tail:n { ##1 } }
          \tl_put_right:Ne \l_@@_lower_limit_tl
            {
              \exp_not:N \l_@@_domain_style_tl
                { \l_@@_domain_char_tl }
              \c_math_superscript_token { \l_@@_domain_dimension_tl }
            }
        }
    },

  domain* .code:n =
    {
      \tl_set:Nn \l_tmpa_tl { #1 }
      \seq_set_split:NnV \l_@@_domain_seq { * } \l_tmpa_tl
      \seq_map_inline:Nn \l_@@_domain_seq
        {
          \tl_if_empty:NF \l_@@_lower_limit_tl
            { \tl_put_right:Nn \l_@@_lower_limit_tl { \times } }
          \tl_set:Ne \l_@@_domain_char_tl
            { \exp_args:Ne \str_uppercase:n { \tl_head:n { ##1 } } }
          \tl_set:Ne \l_@@_domain_dimension_tl
            { \tl_tail:n { ##1 } }
          \tl_put_right:Ne \l_@@_lower_limit_tl
            {
              \exp_not:N \l_@@_domain_style_tl
                { \l_@@_domain_char_tl }
              \c_math_subscript_token { \l_@@_domain_dimension_tl }
            }
        }
    },

  boundary .code:n =
    { \tl_set:Nn \l_@@_lower_limit_tl { \partial #1 } },

  % VARIABLES

  variables .code:n =
    {
      \bool_set_true:N \l_@@_custom_variables_bool
      \str_if_eq:nnTF { #1 } { none }
        { \bool_set_true:N \l_@@_deactivate_differentials_bool }
        {
          \prop_get:NnNTF 
            \g_@@_differential_group_keyword_prop { #1 } \l_tmpa_tl
              {
                \clist_set:NV \l_@@_variable_i_clist \l_tmpa_tl
                \seq_if_exist:cTF { g_@@_#1_jacobian_seq }
                  {
                    \seq_set_eq:Nc
                      \l_@@_jacobian_seq 
                      { g_@@_#1_jacobian_seq }
                  }
                  { \msg_warning:nnn { intexgral } { no-jacobian } { #1 } }
              }
              { \clist_set:Nn \l_@@_variable_i_clist { #1 } }
        }
    },

  jacobian .code:n =
    { \bool_set_true:N \l_@@_jacobian_bool },
  diff-vec .code:n =
    { \bool_set_true:N \l_@@_vectorial_differential_bool },
  diff-star .code:n =
    { \bool_set_true:N \l_@@_starred_differential_bool },

  diff-symb .code:n =
    {
      \cs_set:Npn \@@_differentials:nn ##1##2 {
        \bool_if:NTF \l_@@_starred_differential_bool
          { #1*[##1]{##2} }
          { #1[##1]{##2} }
      }
    },

  diff-options .tl_set:N = \l_@@_differential_options_i_tl,
}

\keys_define:nn { IntegralSetup }
  {
    defaultvar .code:n =
      {
        \prop_get:NnNTF
          \g_@@_differential_group_keyword_prop
          { #1 }
          \l_tmpa_tl
          {
            \tl_set_eq:NN
              \l_@@_default_differential_tl
              \l_tmpa_tl
          }
          { \tl_set:Nn \l_@@_default_differential_tl { #1 } }
      },
    defaultvar* .code:n =
      {
        \prop_get:NnNTF
          \g_@@_differential_group_keyword_prop
          { #1 }
          \l_tmpa_tl
          { 
            \tl_set_eq:NN
              \l_@@_default_vector_differential_tl
              \l_tmpa_tl
          }
          { \tl_set:Nn \l_@@_default_vector_differential_tl { #1 } }
      },
    vectorstyle .tl_set:N   = \l_@@_vectorial_differential_style_tl,
    domainstyle .tl_set:N   = \l_@@_domain_style_tl,
    symbolskip  .tl_set:N   = \l_@@_inline_symbol_muskip,
    hide-diff   .bool_set:N = \l_@@_deactivate_differentials_bool,
  }

% END USER MACROS

% Limits keywords

\NewDocumentCommand\NewLimitsKeyword{ m m }
  {
    \prop_get:NnNTF \g_@@_limits_keyword_prop { #1 } \l_tmpa_tl
      { \msg_error:nnn { intexgral } { lim-group-alr-def } { #1 } }
      {
        \bool_if:NTF \l_@@_invert_limits_bool
          {
            \clist_set:Nn \l_tmpa_clist { #2 }
            \clist_reverse:N \l_tmpa_clist
            \@@_new_limits_group:nV { #1 } \l_tmpa_clist
          }
          { \@@_new_limits_group:nn { #1 } { #2 } }
      }
  }

\NewDocumentCommand\RenewLimitsKeyword{ m m }
  {
    \prop_pop:NnNTF \g_@@_limits_keyword_prop { #1 } \l_tmpa_tl
      {
        \bool_if:NTF \l_@@_invert_limits_bool
          {
            \clist_set:Nn \l_tmpa_clist { #2 }
            \clist_reverse:N \l_tmpa_clist
            \@@_new_limits_group:nV { #1 } \l_tmpa_clist
          }
          { \@@_new_limits_group:nn { #1 } { #2 } }
      }
      { \msg_error:nnn { intexgral } { lim-group-not-def } }
  }

\NewDocumentCommand\ProvideLimitsKeyword{ m m }
  {
    \prop_get:NnNF \g_@@_limits_keyword_prop { #1 } \l_tmpa_tl
      {
        \bool_if:NTF \l_@@_invert_limits_bool
          {
            \clist_set:Nn \l_tmpa_clist { #2 }
            \clist_reverse:N \l_tmpa_clist
            \@@_new_limits_group:nV { #1 } \l_tmpa_clist
          }
          { \@@_new_limits_group:nn { #1 } { #2 } }
      }
  }

\NewDocumentCommand\DeclareLimitsKeyword{ m m }
  {
    \prop_pop:NnNT \g_@@_limits_keyword_prop { #1 } \l_tmpa_tl
      {
        \bool_if:NTF \l_@@_invert_limits_bool
          {
            \clist_set:Nn \l_tmpa_clist { #2 }
            \clist_reverse:N \l_tmpa_clist
            \@@_new_limits_group:nV { #1 } \l_tmpa_clist
          }
          { \@@_new_limits_group:nn { #1 } { #2 } }
      }
  }

% Variable keywords

\NewDocumentCommand\NewVariableKeyword{ m m o }
  {
    \prop_get:NnNTF \g_@@_differential_group_keyword_prop { #1 }
      \l_tmpa_tl
      { \msg_error:nnn { intexgral } { diff-group-alr-def } { #1 } }
      { \@@_new_differential_group:nnn { #1 } { #2 } { #3 } }
  }

\NewDocumentCommand\RenewVariableKeyword{ m m o }
  {
    \prop_pop:NnNTF \g_@@_differential_group_keyword_prop { #1 }
      \l_tmpa_tl
      {
        \seq_clear:c { g_@@_#1_jacobian_seq }
        \@@_new_differential_group:nnn { #1 } { #2 } { #3 }
      }
      { \msg_error:nnn { intexgral } { diff-group-not-def } { #1 } }
  }

\NewDocumentCommand\ProvideVariableKeyword{ m m o }
  {
    \prop_get:NnNF \g_@@_differential_group_keyword_prop { #1 }
      \l_tmpa_tl
      { \@@_new_differential_group:nnn { #1 } { #2 } { #3 } }
  }

\NewDocumentCommand\DeclareVariableKeyword{ m m o }
  {
    \prop_pop:NnNT \g_@@_differential_group_keyword_prop { #1 }
      \l_tmpa_tl
      {
        \seq_clear:c { g_@@_#1_jacobian_seq }
        \@@_new_differential_group:nnn { #1 } { #2 } { #3 }
      }
  }

% Symbol keys

\NewDocumentCommand\NewSymbolKeyword{ m m }
  {
    \prop_if_in:NnT \g_@@_limits_keyword_prop { #1 }
      { \msg_warning:nnn { intexgral } { key-exists-for-lim } { #1 } }
    \keys_if_exist:nnTF { integral } { #1 }
      { \msg_error:nnn { intexgral } { symb-key-alr-def } { #1 } }
      {
        \keys_define:nn { integral }
          {
            #1 .meta:n =
              {
                symbol=#2,
                llimit=##1
              },
          }
      }
  }

\NewDocumentCommand\RenewSymbolKeyword{ m m }
  {
    \prop_if_in:NnT \g_@@_limits_keyword_prop { #1 }
      { \msg_warning:nnn { intexgral } { key-exists-for-lim } { #1 } }
    \keys_if_exist:nnTF { integral } { #1 }
      {
        \keys_define:nn { integral }
          {
            #1 .undefine:
            #1 .meta:n =
              {
                symbol=#2,
                llimit=##1
              }
          }
      }
      { \msg_error:nnn { intexgral } { symb-key-not-def } }
  }

\NewDocumentCommand\ProvideSymbolKeyword{ m m }
  {
    \prop_if_in:NnT \g_@@_limits_keyword_prop { #1 }
      { \msg_warning:nnn { intexgral } { key-exists-for-lim } { #1 } }
    \keys_if_exist:nnF { integral } { #1 }
      {
        \keys_define:nn { integral }
          {
            #1 .meta:n =
              {
                symbol=#2,
                llimit=##1
              },
          }
      }
  }

\NewDocumentCommand\DeclareSymbolKeyword{ m m }
  {
    \keys_define:nn { integral }
      {
        #1 .undefine:
        #1 .meta:n =
          {
            symbol=#2,
            llimit=##1
          },
      }
  }

\NewDocumentCommand\IntegralSetup{ m }
  { \keys_set:nn { IntegralSetup } { #1 } }

\NewDocumentCommand\integral{ O{} m }
  {
    \group_begin:
    \tl_if_empty:nF { #1 }
      {
        \@@_extract_first_key_name:n { #1 }
        \@@_parse_macro_keys:n { #1 }
      }
    \tl_set:Nn \l_@@_integrand_tl { #2 }
    \@@_print_integral:
    \group_end:
  }

% Preamble only

\@onlypreamble\intexgralsetup

% Included keywords

% Symbol keywords
\NewSymbolKeyword{single}     {\int}
\NewSymbolKeyword{double}     {\iint}
\NewSymbolKeyword{triple}     {\iiint}
\NewSymbolKeyword{quadruple}  {\iiiint}
\NewSymbolKeyword{contour}    {\oint}
\NewSymbolKeyword{surface}    {\oiint}
\NewSymbolKeyword{volume}     {\oiiint}

% Limits keywords 
\NewLimitsKeyword{ab}        {a, b}
\NewLimitsKeyword{real}      {-\infty, \infty}
\NewLimitsKeyword{positive}  {0, \infty}
\NewLimitsKeyword{negative}  {-\infty, 0}
\NewLimitsKeyword{unit}      {0, 1}
\NewLimitsKeyword{circle}    {0, 2\pi}
\NewLimitsKeyword{scircle}   {0, \pi}
\NewLimitsKeyword{qcircle}   {0, \frac{\pi}{2}}
\NewLimitsKeyword{height}    {0, H}
\NewLimitsKeyword{radius}    {0, R}
\NewLimitsKeyword{length}    {0, L}
\NewLimitsKeyword{time}      {0, T}

% Variable keywords
\NewVariableKeyword{cartesian}    {x, y, z}
\NewVariableKeyword{planar}       {x, y}
\NewVariableKeyword{polar}        {r, \theta}        [r]
\NewVariableKeyword{cylindrical}  {r, \theta, z}     [r]
\NewVariableKeyword{spherical}    {r, \theta, \phi}  [r^2, \sin\theta]

% Default parameters

\IntegralSetup
  {
    defaultvar  = {x},
    defaultvar* = {r},
    vectorstyle = \vec,
    domainstyle = \mathbb,
    symbolskip  = {-6mu},
    hide-diff   = false
  }

\ExplSyntaxOff
%    \end{macrocode}