% \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{french}
  {
    new       = \NoAutoSpacing\textsf{nouveau},
    update    = \NoAutoSpacing\textsf{mise à jour},
    note      = \NoAutoSpacing\textsf{N.B},
    remark    = \NoAutoSpacing\textsf{remarque},
    and       = \NoAutoSpacing\textsf{et},
    or        = \NoAutoSpacing\textsf{ou},
    months    = 
      {
        janvier, février, mars, avril,
        mai, juin, juillet, août,
        septembre, octobre, novembre, décembre
      }
  }

\selectlabelset{french}

\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[
  variant               = french,
  autospacetypewriter   = false,
  frenchfootnote        = true
  ]{french}

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

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

\DeclareTranslation{French}{changelog}{Historique des modifications}

\setlength{\parindent}{0pt}

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

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

\usepackage{cleveref}

\EnableCrossrefs

\begin{document}
  \DocInput{intexgral-fr.dtx}
\end{document}
%</driver>
% \fi
%
% \PkgInfoGet{intexgral}{author}{\fileauthor}
% \PkgInfoGet{intexgral}{version}{\fileversion}
% \PkgInfoGet{intexgral}{date}{\filedate}
% \PkgInfoGet{intexgral}{creation}{\filecreationdate}
% 
% \ExplSyntaxOn
% \seq_gset_split:Nne \g_tmpa_seq { - } { \filedate }
% \seq_reverse:N \g_tmpa_seq
% \xdef\filedate{ \seq_use:Nnnn \g_tmpa_seq {} { - } { - } }
% \seq_gclear:N \g_tmpa_seq
% \seq_gset_split:Nne \g_tmpa_seq { - } { \filecreationdate }
% \seq_reverse:N \g_tmpa_seq
% \xdef\filecreationdate{ \seq_use:Nnnn \g_tmpa_seq {} { - } { - } }
% \ExplSyntaxOff
% 
% \tstitle{^^A
%   title   = {{\huge L'extension \href{https://ctan.org/pkg/intexgral}{\textsf{intexgral}}}\medbreak {\Large v\fileversion}},
%   author  = {\fileauthor\footnote{E-mail: \href{mailto:vdao.texdev@gmail.com}{\ttfamily vdao.texdev@gmail.com}}},
%   date    = {\the\day\ifnum\day=1\textsuperscript{er}\fi\space\tsdate}
% }
%
% \begin{center}
% \rule{12.5cm}{0.6pt}
% \begin{abstract}
%   Tandis que la composition d'intégrales est très fréquente en \LaTeX, cette dernière s'avère souvent peu pratique. Lorsque l'expression se complexifie, il devient alors difficile d'en modifier les différents éléments dans un code source peu lisible. Pour répondre à ce problème, le package \tsobj[pkg]{intexgral} met à disposition une macro centrale dont le seul argument est l'intégrande. Tout le reste (les symboles, les bornes, les variables d'intégration\dots) pourra aisément être modifié grâce à une interface \tsobj[meta]{clé=valeur}. Contrairement à la méthode classique, où l'utilisateur choisit l'ordre des bornes avec les caractères actifs \verb|_| et \verb|^|, le package a dû fixer une convention. Ainsi, pour les deux clés gérant les bornes qui seront présentées, l'entrée supposée sera \verb|_|\tsobj[meta]{borne inférieure}\verb|^|\tsobj[meta]{borne supérieure}. Ce package étant écrit en \tsobj[pkg]{expl3}, il dépend donc des packages \LaTeX3 \tsobj[pkg]{l3kernel} et \tsobj[pkg]{l3package}. De plus, \tsobj[pkg]{intexgral} utilise le package \tsobj[pkg]{derivative}\footnote{Disponible sur \textsc{ctan} sous: \url{https://ctan.org/pkg/derivative}} afin de faciliter la manipulation de différentielles, ainsi que le package \tsobj[pkg]{pkginfograb}\footnote{Disponible sur \textsc{ctan} sous: \url{https://ctan.org/pkg/pkginfograb}}.
% \end{abstract}
% \rule{12.5cm}{0.6pt}
% \end{center}
% 
% \newpage
% \tableofcontents
% \newpage
% 
% \subsection*{Licence}
% 
% \copyright\ 2025 Valentin Dao, publié sous la \LaTeX\ Project Public License (\textsc{lppl}) 1.3c
% 
% \subsection*{Polices}
% 
% \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*{Dépôt}
% 
% \href{https://github.com/ankaa3908/intexgral/tree/main}{\faGithub\ Voir dépôt GitHub}.
% 
% \subsection*{Remerciements}
% 
% Un grand merci à Plante et Slurpy de m'avoir accompagné dans cette aventure que fut l'apprentissage de \TeX, vos conseils ont été précieux. Je tiens également à remercier Anthony pour avoir toujours gentiment révisé les nouvelles versions et m'avoir donné des idées pour celles à venir.
% 
% \newpage
% 
% \section{Options de package}
% 
% \begin{codedescribe}[macro, new={v2.0.0}]{\intexgralsetup}
%   \begin{codesyntax}
%     \tsobj[macro]{\intexgralsetup}\tsargs[marg]{options de package}
%   \end{codesyntax}
%   Ces options peuvent être déclarées de façon classique avec \tsobj[macro]{\usepackage} ou bien avec \tsobj[macro]{\intexgralsetup} dans le préambule.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{invert-limits}
%   \begin{codesyntax}[key]
%     \tsobj[key]{invert-limits}=\tsobj[option, meta or]{true,\uline{false}}
%   \end{codesyntax}
%   Cette clé permet d’inverser la convention d’ordre des limites. Le document ne peut suivre qu’une seule 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}
%   Il est courant de voir les variables d'intégration placées avant l’intégrande dans les articles de physique. Cette clé intervertit donc leurs positionnements.
% \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}
%   Applique \tsobj[macro]{\limits} ou \tsobj[macro]{\nolimits} à toutes les intégrales.
% \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}
%   Ce sont les deux clés du package \tsobj[pkg]{derivative}.
% \end{codedescribe}
% 
% \section{Présentation de la macro principale}
% 
% \begin{codedescribe}[macro, update={v3.0.0}]{\integral}
%   \begin{codesyntax}
%     \tsmacro{\integral}[list de clés]{intégrande}
%   \end{codesyntax}
%   Cette macro est celle qui permet de composer les intégrales. Elle doit naturellement être utilisée en mode mathématique uniquement. En voici un premier exemple sous sa forme la plus simple:
% \end{codedescribe}
% 
% \begin{codestore}[1]
%   \begin{equation}
%     \integral{x}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{1}
% 
% Puisque cette macro est axée autour de l'utilisation de clés, la première partie de cette documentation les présentera en les regroupant par domaines. La seconde partie quant à elle introduira les quelques macros annexes qui viennent compléter l'usage de certaines clés. Le reste de ce document exposera les autres fonctionnalités du package.
% 
% \section{Liste des clés}
% 
% \subsection{Bornes d'intégration}
% 
% \subsubsection{Définir les bornes}
% 
% \begin{codedescribe}[key]{limits, limits*}
%   \begin{codesyntax}[key]
%     \tsobj[key]{limits}=\tsargs[marg]{liste-mixte}, \tsargs[arg]{mot-clé}
%     \tsobj[key]{limits*}=\tsargs[marg]{liste-mixte}, \tsargs[arg]{mot-clé}
%   \end{codesyntax}
%   Cette clé détermine les bornes d'intégration à utiliser en suivant la convention édictée dans le résumé. Sous sa forme la plus simple, la valeur de la clé prend comme argument une liste d'éléments séparés par une virgule (\emph{comma-separated values} ou \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}
% 
% L'avantage notable de la clé \tsobj[key]{limits} est qu'on peut lui spécifier les bornes d'intégration de plusieurs intégrales, et le package compose automatiquement les symboles correspondants. Pour séparer les paires de bornes, il faut utiliser le point-virgule (\emph{semicolon-separated values} ou \tsobj[meta]{ssv-list}\footnotemark[1]).
% 
% \footnotetext[1]{On entend donc par \tsobj[meta]{liste-mixte} le fait que \tsobj[key]{limits} puisse accepter un ensemble de \tsobj[meta]{csv-list} dans une \tsobj[meta]{ssv-list} plus globale.}
% 
% \begin{codestore}[3]
%   \begin{equation}
%     \integral[limits={1, 2; 3, 4}, variables={x, y}]{f(x, y)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{3}
% 
% Il est également possible de renseigner des bornes prédéfinies à l'aide de mots-clés (voir \cref{subsec:limits}). Enfin, la variante étoilée permet d'exprimer les bornes de l'intégrale sous forme d'intervalle. Le cas échéant, le sens des crochets s'adapte automatiquement à la présence de $\pm$\verb|\infty|
% 
% \begin{codestore}[4]
%   \begin{equation}
%     \integral[limits*={1, 10}]{f(x)}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{4}
% 
% \subsection{Modes d'affichage}
% 
% \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{Uniquement} lorsque la clé \tsobj[key]{limits} est employée, il est possible d'alterner entre trois styles d'affichage distincts. Chacun d'entre eux est entièrement compatible avec l'option \tsobj[key]{invert-diff}.
%   \begin{describelist*}{option}
%     \describe{default}{Compose l'ensemble des symboles, puis l'intégrande, puis les variables d'intégration. La macro opérant par défaut dans ce mode, il n'est donc pas nécessaire d'utiliser la clé avec cette valeur.}
%     \describe{nested}{Compose une intégrale \emph{imbriquée} où symbole et intégrande alternent avant que tous les variables d'intégrations soient écrits.}
%     \describe{product}{Compose un produit d'intégrales où symbole, intégrande et variables d'intégration alternent.}
%   \end{describelist*}
%   Bien sûr, rien ne vous empêche pour le mode produit d'utiliser plusieurs fois la macro \tsobj[macro]{\integral} d'affilée pour produire le même résultat que dans l'exemple ci-dessous. Pour celles et ceux qui préféreraient cependant obtenir le résultat avec une seule macro, cette méthode est permise.
%   \begin{tsremark}[\textcolor{RoyalRed}{Important:}]
%     pour les deux derniers modes, l'intégrande sera, d'une certaine manière, \emph{découpée}. Afin de correctement effectuer cette action, il faut avoir recours à la même méthode qu'avec \tsobj[key]{limits}, c'est-à-dire en employant le point-virgule.
%   \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}
% 
% Pour bien fonctionner, il est évident que les clés \tsobj[key]{limits} et \tsobj[key]{variables} (voir \ref{subsubsec:variables}), ainsi que l'intégrande, doivent avoir le même nombre d'éléments. Si ce n’est pas le cas, la compilation n’échouera pas, mais l’expression de l’intégrale risque de ne plus avoir aucun sens. De nombreux messages d’avertissement seront là pour vous en informer.
%
% \subsection{Symbole (et encore des bornes)}
% 
% Les clés \tsobj[key]{limits(*)} se révèlent très  utiles lorsque l'on souhaite composer une intégrale définie. Néanmoins, cela couvre seulement les expressions finales où les bornes de chaque variable ont été spécifiées. Pour des cas plus généraux --- les intégrales indéfinies donc \nobreak--- elles sont relativement malcommodes. Pour composer une intégrale double sur une surface $S$, on devrait écrire \verb|limits={,;S,}|. Il va sans dire que c'est assez mal adapté pour l'utilisateur et peu optimal pour le package. Par ailleurs, le glyphe ne serait pas correct. L'ensemble des clés à suivre propose donc une façon de facilement modifier le symbole ainsi que les bornes.
% 
% \subsubsection{Sélectionner le symbole}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{symbol}
%   \begin{codesyntax}[key]
%     \tsobj[key]{symbol}=\tsobj[meta]{séquence de contrôle}
%   \end{codesyntax}
%   Cette clé accepte une macro désignant un symbole d'intégration. Tout symbole préalablement défini par une séquence de contrôle est recevable. Si vous tentez d'en utiliser une qui n'est pas définie, elle sera substituée à \tsobj[macro]{\int} et un message d'avertissement sera émis.
%   \begin{tsremark}[\textcolor{RoyalGreen}{Remarque:}]
%     à part la vérification de l'exis tence de la macro, aucun contrôle particulier n'est effectué et la valeur de la clé est utilisée telle quelle pour composer le symbole. Ceci implique notamment deux choses. Tout d'abord, le symbole va dépendre de la façon dont il est défini. Par exemple, \tsobj[pkg]{amsmath} et \tsobj[pkg]{unicode-math} ne définissent pas \tsobj[macro]{\iint} de la même manière. Le résultat sera donc différent. De plus, si vous renseignez comme argument de la clé une macro \emph{définie} mais ne correspondant pas à un symbole intégral, le package n'en tiendra pas compte et utilisera quand même le symbole donné. Outre l'incohérence mathématique que cela peut représenter, il est susceptible que cela mène, sous certaines circonstances, à des erreurs de bas niveau.
%   \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{Générer beaucoup d'intégrales}
% 
% \begin{codedescribe}[key]{nint}
%   \begin{codesyntax}[key]
%     \tsobj[key]{nint}=\tsobj[meta]{entier}
%   \end{codesyntax}
%   Cette clé accepte un entier $n$ qui permet de composer $n$ intégrales. Il est conseillé d'avoir recours à cette clé seulement si le nombre de symboles dépasse 4 afin de privilégier les glyphes définis par la police mathématique utilisée.
% \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{Définir des bornes ponctuellement}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{llimit, ulimit}
%   \begin{codesyntax}[key]
%     \tsobj[key]{llimit}=\tsobj[meta]{borne inférieure}
%     \tsobj[key]{ulimit}=\tsobj[meta]{borne supérieure}
%   \end{codesyntax}
%   Ces deux clés permettent de spécifier les bornes inférieures et supérieures respectivement. Elles ne sont adaptées que si un seul symbole est affiché. Si vous avez besoin de spécifier les deux bornes, la clé \tsobj[key]{limits} devra être privilégiée.
% \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{Motifs récurrents de bornes}
% 
% Les bornes suivent parfois des schémas courants qui peuvent se généraliser avec des clés, évitant ainsi de surcharger l'argument de \tsobj[key]{llimit}.
% 
% \begin{codedescribe}[key, update={v3.0.0}]{domain, domain*}
%   \begin{codesyntax}[key]
%     \tsobj[key]{domain}=\tsargs[marg]{*-liste}
%     \tsobj[key]{domain*}=\tsargs[marg]{*-liste}
%   \end{codesyntax}
%   Ces clés acceptent une liste dont le délimiteur est un astérisque. Ensuite, chaque élément de la liste est analysé de la façon suivante:
%   \begin{itemize}[label=\textemdash]
%     \item Le premier token de l’item se voit passer \tsobj[macro]{\mathbb} (précédé d’\tsobj[macro]{\uppercase} au cas où la touche \textsc{shift} serait trop loin pour vos doigts).
%     \item Les tokens restants --- qui peuvent être vides --- sont placés comme exposant (ou en indice pour la variante étoilée de la clé).
%   \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]{borne inférieure}
%   \end{codesyntax}
%   Cette clé place simplement le symbole $\partial\,$ avant la borne inférieure.
% \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{Différentielles}
% 
% \subsubsection{Spécifier les variables d'intégration}\label{subsubsec:variables}
% 
% \begin{codedescribe}[key, update={v3.0.0}]{variables}
%   \begin{codesyntax}[key]
%     \tsobj[key]{variables}=\tsargs[marg]{liste-csv}, \tsobj[meta]{mot-clé}, \tsobj[option]{none}
%   \end{codesyntax}
%   Cette clé permet de définir les variables d'une intégrale sous forme d'une \tsobj[meta]{csv-list}. La clé peut, tout comme \tsobj[key]{limits}, accepter un mot-clé comme argument. Ce comportement est aussi expliqué plus tard (voir \cref{subsec:variablekey})
%   \begin{tsremark}[\textcolor{RoyalGreen}{Remarque:}]
%     si aucune variable d'intégration n'est renseignée, c'est-à-dire que \tsobj[key]{variables} n'est pas appelée, le package place automatiquement \enquote{$\odif{x}$} (ou \enquote{$\odif{\vec{r}}$} si \tsobj[key]{diff-vec} est actif). De plus, si \tsobj[option]{none} est passé comme valeur, aucune variable d'intégration ne sera affichée.
%   \end{tsremark}
% \end{codedescribe}
% 
% \begin{codestore}[13]
%   \begin{equation}
%     \integral[variables=t]{t^2}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{13}
%
% \subsubsection{Inclure le jacobien}
% 
% \begin{codedescribe}[key]{jacobian}
%   \begin{codesyntax}[key]
%     \tsobj[key]{jacobian}
%   \end{codesyntax}
%   Cette clé active l'affichage du jacobien lorsque défini par \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}
% 
% Comme évoqué plus tôt, \tsobj[pkg]{derivative} est utilisé par le package pour composer les différentielles. L'ensemble des clés à suivre, dont le nom portera le préfixe \enquote{\texttt{diff-}}\footnote{Quoique la clé \tsobj[key]{diff-vec} ne soit pas liée à \tsobj[pkg]{derivative}.}, vous permettent ainsi d'appliquer les fonctionnalités de la macro \tsobj[macro]{\odif}.
% 
% \subsubsection{Modifier le symbole des différentielles}
% 
% \begin{codedescribe}[key]{diff-symb}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-symb}=\tsargs[meta]{macro de différentielle}
%   \end{codesyntax}
%   Cette clé permet de modifier le style des différentielles parmi ceux définis par \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{Réaliser une intégrale curviligne}
% 
% \begin{codedescribe}[key]{diff-vec}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-vec}
%   \end{codesyntax}
%   Cette clé applique un vecteur à chaque variable d'intégration en plus d'un point médian. Elle n'est compatible qu'avec le mode \tsobj[option]{default}. 
% \end{codedescribe}
% 
% \begin{codestore}[16]
%   \begin{equation}
%     \integral[double=S, variables=S, diff-vec]{\vec F}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{16}
% 
% \subsubsection{Opter pour la variante étoilée}
% 
% \begin{codedescribe}[key]{diff-star}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-star}
%   \end{codesyntax}
%   Activer cette clé revient à utiliser \tsobj[macro]{\odif*} ou ses variantes.
% \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{Désigner des options}
% 
% \begin{codedescribe}[key]{diff-options}
%   \begin{codesyntax}[key]
%     \tsobj[key]{diff-options}=\tsargs[marg]{liste clé-valeur}
%   \end{codesyntax}
%   Cette clé accepte une liste de clés telle qu’elle aurait été écrite comme argument optionnel de \tsobj[macro]{\odif} ou ses variantes. Pour illustrer, \verb|diff-options={order={2, 3}, var=all}| sera interprété comme \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{Macros annexes}
% 
% En plus de la large gamme de clés définies par le package, quelques macros viennent également améliorer leurs usages.
% 
% \subsection{Emplacements personnalisés des différentielles}
% 
% \begin{codedescribe}[macro]{\differentials}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\differentials}
%   \end{codesyntax}
%   Bien que l’option \tsobj[key]{invert-diff} existe, il est souvent souhaitable de pouvoir placer les différentielles où l’on veut. Par exemple, il est fréquent de les voir au numérateur d'une fraction lorsque celui-ci vaut 1. Pour répondre à ce besoin, le package met à disposition la macro \tsobj[macro]{\differentials}. Pour les modes \tsobj[option]{default} et \tsobj[option]{nested}, la macro compose toutes les différentielles d'un coup. Avec \tsobj[option]{product}, il faudra répéter la macro entre chaque point-virgule.
% \end{codedescribe}
% 
% \begin{codestore}[19]
%   \begin{equation}
%     \integral{\frac{\differentials}{x}}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{19}
% 
% \subsection{Retour sur la clé \emph{limits}}\label{subsec:limits}
% 
% \begin{codedescribe}[macro]{\NewLimitsKeyword, \RenewLimitsKeyword, \ProvideLimitsKeyword, \DeclareLimitsKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewLimitsKeyword}\tsargs[marg]{mot-clé}\tsargs[marg]{bornes}
%   \end{codesyntax}
%   Il est courant de devoir renseigner les mêmes bornes dans une intégrale. Pour faciliter leur écriture, les clés \tsobj[key]{limits(*)} acceptent, en plus des bornes explicites, un mot-clé en désignant une paire prédéfinie par l’une de ces quatre macros:
%   \begin{describelist*}{macro}
%     \describe{\NewLimitsKeyword}{Crée un nouveau mot-clé et émet une erreur s’il existe déjà.}
%     \describe{\RenewLimitsKeyword}{Redéfinit un mot-clé et émet une erreur s’il n’existe pas déjà.}
%     \describe{\ProvideLimitsKeyword}{Ne crée un nouveau mot-clé que s’il n’existe pas déjà. Aucun message ne sera émis dans le cas échéant.}
%     \describe{\DeclareLimitsKeyword}{Crée un nouveau mot-clé quoi qu’il en soit, écrasant toute définition préalable.}
%   \end{describelist*}
%   Voici la liste des mots-clés déjà définis par le package et les bornes qu'ils contiennent:
%   \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}{Remarque:}]
%     les mots-clés contiennent les \emph{deux} bornes d'une intégrale en même temps. Ils doivent donc être précédés et/ou suivis de point-virgule.
%   \end{tsremark}
%   \begin{tsremark}[\textcolor{RoyalRed}{Important:}]
%     dû à l'implémentation de \tsobj[macro]{\NewLimitsKeyword} et ses variantes, l'utilisateur \emph{doit} suivre la convention d'ordre des bornes du package, même si \tsobj[key]{invert-limits} est fixé à \tsobj[option]{true}
%   \end{tsremark}
%   On pourrait donc modifier l’expression d'une l’intégrale de la façon suivante:
% \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}
% 
% Il est tout à fait possible de mélanger ces mots-clés avec la syntaxe plus explicite de \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{Retour sur la clé \emph{variables}}\label{subsec:variablekey}
% 
% \begin{codedescribe}[macro]{\NewVariableKeyword, \RenewVariableKeyword, \ProvideVariableKeyword, \DeclareVariableKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewVariableKeyword}\tsargs[marg]{mot-clé}\tsargs[marg]{variables}\tsargs[oarg]{jacobien}
%   \end{codesyntax}
%   De façon similaire, les mêmes groupes de variables réapparaissent souvent. On peut donc également définir des mots-clés contenant un ensemble de variables d'intégration préenregistrés. Les variantes de cette macro ont le même comportement que pour \tsobj[macro]{\NewLimitsKeyword}. La seule différence est qu'il est ici possible de définir un jacobien, sous forme d'une \tsobj[meta]{csv-list} si besoin. Son affichage est ensuite contrôlé par la clé \tsobj[key]{jacobian} expliquée précédemment. Voici la liste des mots-clés de variables déjà définis par le package, avec le jacobien pour certains:
%   \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{Retour sur la clé \emph{symbol}}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\NewSymbolKeyword, \RenewSymbolKeyword, \ProvideSymbolKeyword, \DeclareSymbolKeyword}
%   \begin{codesyntax}[macro]
%     \tsobj[macro]{\NewSymbolKeyword}\tsargs[marg]{clé}\tsargs[marg]{symbole}
%   \end{codesyntax}
%   Afin de composer des intégrales indéfinies, le package offre essentiellement deux clés: \tsobj[key]{symbol} et \tsobj[key]{llimit}. Bien qu'elles soient simples d'utilisation, il demeure toujours laborieux de les écrire toutes les deux avec leurs valeurs. C'est pourquoi \tsobj[pkg]{intexgral} met à disposition des clés dites \emph{raccourcies}, dont le but est de combiner l'action de sélection du symbole et des bornes. Contrairement aux deux macros précédentes, il s'agit ici de créer de toutes nouvelles clés, et non simplement des valeurs spécifiques attribuées à \tsobj[key]{symbol}. Toutes seules, ces clés modifient le symbole intégral. La valeur de ces clés correspondra elle à la borne inférieure. Voici la liste de l'ensemble des \emph{clé-symbole} définie par le package:
%   \begin{describelist*}{key}
%     \describe{single}{symbole utilisé = \tsobj[macro]{\int}}
%     \describe{double}{symbole utilisé = \tsobj[macro]{\iint}}
%     \describe{triple}{symbole utilisé = \tsobj[macro]{\iiint}}
%     \describe{quadruple}{symbole utilisé = \tsobj[macro]{\iiiint}}
%     \describe{contour}{symbole utilisé = \tsobj[macro]{\oint}}
%     \describe{surface}{symbole utilisé = \tsobj[macro]{\oiint}}
%     \describe{volume}{symbole utilisé = \tsobj[macro]{\oiiint}}
%   \end{describelist*}
%   \begin{tsremark}[\textcolor{RoyalRed}{Important:}]
%   offrir la possibilité de créer soi-même une clé à la macro \tsobj[macro]{\integral} représente un risque qui sera mieux expliqué dans la prochaine section. Retenez pour l'instant que toutes ces macros\footnote{À l'exception de \tsobj[macro]{\DeclareSymbolKeyword} qui suppose que l'utilisateur sait ce qu'il fait.} émettront un message d'avertissement si vous tentez de créer une nouvelle \emph{clé-symbole} portant le même nom qu'un groupe de bornes définies.
%   \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{Syntaxe \emph{spéciale}}
% 
% \subsection{Présentation de la syntaxe}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\integral}
%   \NoAutoSpacing
%   \begin{codesyntax}
%     \tsmacro{\integral}[limits:variables(+j):mode]{intégrande}
%   \end{codesyntax}
%   \AutoSpacing
%   En ce qui concerne les intégrales définies, l'utilisateur sera amené à employer au maximum quatre clés pour les composer: \tsobj[key]{limits}, \tsobj[key]{variables}, \tsobj[key]{mode} et \tsobj[key]{jacobian}. On peut néanmoins leur reprocher la même chose qu'avant; écrire ces quatre clés, pouvant recevoir des arguments assez longs, va à l'encontre de l'objectif principal de ce package. Ainsi, l'utilisateur peut désigner comme argument optionnel d'\tsobj[macro]{\integral}, une syntaxe dite \emph{spéciale} qui n'est propre qu'à \tsobj[pkg]{intexgral}. La logique est la suivante:
%   \begin{itemize}[label=\textemdash]
%     \item Vous spécifiez un argument \emph{valide} de la clé \tsobj[key]{limits}
%     \item Vous spécifiez un argument \emph{valide} de la clé \tsobj[key]{variables}
%     \item Vous spécifiez un argument \emph{valide} de la clé \tsobj[key]{mode}
%   \end{itemize}
%   Et vous séparez le tout d'un deux points. Voyons un exemple pour mieux comprendre.
% \end{codedescribe}
% 
% \begin{codestore}[24]
%   \begin{equation}
%     \integral[1, 2; 4, 5:y, x:nested]{x; y}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{24}
% 
% On entend par \emph{argument valide} le fait que toutes les formes de valeurs acceptées par les quatre clés peuvent être pareillement adoptées par la syntaxe spéciale. Cela comprend donc les mots-clés.
% 
% \begin{codestore}[25]
%   \begin{equation}
%     \integral[radius;circle;scircle:spherical:product]{r;\theta;\phi}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{25}
% 
% Afin d'inclure le jacobien, il suffit d'écrire \texttt{+j} après l'argument de \tsobj[key]{variables}. Le mode peut aussi être indiqué à l'aide d'une initiale seulement.
% 
% \begin{codestore}[26]
%   \begin{equation}
%     \integral[radius;circle;scircle:spherical+j:p]{;;}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{26}
% 
% Il est important de répéter que dans la configuration classique de l'argument optionnel, il n'est bien sûr pas obligatoire de renseigner les quatre clés citées. Il en va de même pour cette syntaxe. Puisque la clé \tsobj[key]{mode} n'est pas nécessaire pour \tsobj[option]{default}, cette partie peut être omise.
% 
% \begin{codestore}[27]
%   \begin{equation}
%     \integral[1, 2; 3, 4:x, y]{xy}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{27}
% 
% Vous pouvez aussi toujours profiter du placement automatique du \enquote{$\odif{x}$} avec cette syntaxe en faisant abstraction de \tsobj[key]{variables}.
% 
% \begin{codestore}[28]
%   \begin{equation}
%     \integral[1, 10]{x}
%   \end{equation}
% \end{codestore}
% 
% \tsdemo*[intexgral]{28}
% 
% \subsection{Fonctionnement de la syntaxe}
% 
% Du point de vue de l'utilisateur, il est relativement simple de choisir quelle syntaxe adopter. Toutefois, le package doit pouvoir distinguer les deux. Sans trop rentrer dans les détails\footnote{Les plus courageux d'entre vous sont tout de même invités à lire le code source.} de l'implémentation, il est porté à votre intention que le package tente d'extraire la première clé de l'argument optionnel\footnote{Ou du moins, le groupe de tokens qu'il pense correspondre à une clé.} et vérifie si elle existe. C'est pourquoi, si vous créez une clé avec \tsobj[macro]{\NewSymbolKeyword} dont le nom pourra probablement servir de bornes d'intégrations, \tsobj[pkg]{intexrgal} peut faussement évaluer la nature de l'argument optionnel.
% 
% \section{Paramètres annexes}
% 
% \begin{codedescribe}[macro, new={v3.0.0}]{\IntegralSetup}
%   \begin{codesyntax}[macro]
%   \tsmacro{\IntegralSetup}{liste de paramètres}
%   \end{codesyntax}
%   Cette macro permet, sous la syntaxe \tsobj[meta]{clé=valeur}, de modifier des paramètres liés à certaines clés. Toutes les assignations effectuées sont locales et la macro peut donc être placée dans un groupe si besoin. Voici un exemple de la macro avec les assignations par défaut du package:
% \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}
%   Cette clé modifie la variable d'intégration insérée automatiquement lorsque \tsobj[key]{variables} n'est pas utilisée. L'argument peut tout à fait correspondre à un mot clé défini par \tsobj[macro]{\NewVariableKeyword}. La variante étoilée de la clé contrôle la variable d'intégration à composer avec \tsobj[key]{diff-vec}.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{vectorstyle}
%   \begin{codesyntax}[key]
%     \tsobj[key]{vectorstyle}=\tsobj[meta]{séquence de contrôle}
%   \end{codesyntax}
%   Cette clé modifie la macro à appliquer aux variables quand \tsobj[key]{diff-vec} est en action. Il est donc possible d'altérer le style du vecteur: gras, souligné, ou même un autre style d'un package particulier, \tsobj[pkg]{esvect} par exemple.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{domainstyle}
%   \begin{codesyntax}[key]
%     \tsobj[key]{domainstyle}=\tsobj[meta]{séquence de contrôle}
%   \end{codesyntax}
%   Semblablement, on peut changer la macro à appliquer pour les clés \tsobj[key]{domain(*)}.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{symbolskip}
%   \begin{codesyntax}[key]
%     \tsobj[key]{symbolskip}=\tsobj[meta]{muexpr}
%   \end{codesyntax}
%   Lorsque le mode \tsobj[option]{default} est en vigueur, le package insère un crénage entre les symboles pour légèrement les rapprocher. La dimension par défaut ($-6$mu) peut ainsi être ajustée selon la police mathématique en vigueur.
% \end{codedescribe}
% 
% \begin{codedescribe}[key]{hide-diff}
%   \begin{codesyntax}[key]
%     \tsobj[key]{hide-diff}=\tsobj[option, meta or]{true,\uline{false}}
%   \end{codesyntax}
%   Lorsqu'une large partie du document nécessite de ne pas inclure les différentielles, il est possible de prolonger dans la durée l'action plus ponctuelle de \tsobj[key]{variables}\texttt{=}\tsobj[option]{none}.
% \end{codedescribe}
% 
% \newpage
% 
% \phantomsection
% \addcontentsline{toc}{section}{Historique des modifications}
% \begin{changelog}[sectioncmd=\section*]
%
% \begin{version}[v=3.0.1, date=02-01-2026]
% \fixed 
% \item Bug avec le jacobien dans la syntaxe spéciale (\href{https://github.com/ankaa3908/intexgral/issues/3}{problème \#3}).
% \item Documentation anglaise et française (\href{https://github.com/ankaa3908/intexgral/issues/4}{problème \#4}, \href{https://github.com/ankaa3908/intexgral/problèmes/6}{problème \#6} et \href{https://github.com/ankaa3908/intexgral/issues/7}{problème \#7}).
% \changed
% \item Les mots-clés \tsobj[option]{positive} et \tsobj[option]{real} contiennent  maintenant un signe $+$ (\href{https://github.com/ankaa3908/intexgral/issues/5}{problème \#5}).
% \end{version}
%
% \begin{version}[v=3.0.0, date=24-12-2025]
% \added
% \item Syntaxe spéciale.
% \item Clés \tsobj[key]{domain*} et \tsobj[key]{mode}.
% \item Macros \tsobj[macro]{\IntegralSetup} et \tsobj[macro]{\NewSymbolKeyword}.
% \removed 
% \item Macros \tsobj[macro]{\defaultdiff}, \tsobj[macro]{\defaultdiff}, \tsobj[macro]{\defaultvdiff} et \tsobj[macro]{\vdiffstyle} en faveur de \tsobj[macro]{\IntegralSetup}.
% \item Clés controlant symbole et borne, maintenant gérées à un plus haut niveau avec \tsobj[macro]{\NewSymbolKeyword}.
% \item Clé \tsobj[key]{int-split}, en faveur de \tsobj[key]{mode}.
% \item Macro \tsobj[macro]{\NewInegralSymbol}.
% \changed
% \item Les noms de quelques clés (\tsobj[key]{variable} en \tsobj[key]{variables}, \tsobj[key]{lower-lim} et \tsobj[key]{upper-lim} en \tsobj[key]{llimit} et \tsobj[key]{ulimit}, \tsobj[key]{int-symb} en \tsobj[key]{symbol}, \tsobj[key]{invert-differentials} et \tsobj[key]{hide-differentials} en \tsobj[key]{invert-diff} et \tsobj[key]{hide-diff}).
% \item \tsobj[key]{jacobian} et \tsobj[key]{diff-star} ne nécessitent plus de valeur booléenne. Il suffit maintenant de les écrire pour activer leurs fonctionnalités.
% \item \tsobj[key]{hide-diff} attribué à une option locale plutôt qu'à une option de package.
% \item \tsobj[key]{limits-mode} attribué à une option de package plutôt qu'à une clé de macro.
% \end{version}
% 
% \begin{version}[v=v2.0.1, date=13-09-2025]
% \fixed
% \item Problème de compatibilité entre \tsobj[pkg]{unicode-math} et \tsobj[pkg]{amssymb} selon l'ordre de chargement (\href{https://github.com/ankaa3908/intexgral/issues/2}{problème \#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} et \tsobj[macro]{\vdiffstyle}.
% \changed
% \item Messages d'avertissement liés aux symboles non-existants. Ils ne sont maintenant provoqués que lorsque l'intégrale est composée.  
% \removed
% \item Clé \tsobj[key]{diff-vec-style} en faveur de \tsobj[macro]{\vdiffstyle}.
% \item Message d'avertissement lié à la mauvaise utilisation des points-virgules en conjonction de la clé \tsobj[key]{int-split}.
% \fixed 
% \item Bug où l'intégrande n'était pas réinitialisée lorsque \tsobj[macro]{\integral} était employée successivement dans le même groupe \TeX\ (\href{https://tex.stackexchange.com/questions/749990/issue-with-integral-command-from-intexgral-package-in-math-mode}{détails ici}).
% \item Des restes de log \tsobj[pkg]{expl3} qui n'auraient pas dû être là.
% \end{version}
% 
% \begin{version}[v=1.1.0, date=29-07-2025]
% \added
% \item Variantes étoilées pour les clés controlant symbole et borne (clés \tsobj[key]{single}, \tsobj[key]{contour} etc).
% \end{version}
% 
% \shortversion{v=1.0.0, date=26-07-2025, changes=Version initiale.}
% 
% \end{changelog}
%
% \newpage
%
% \phantomsection
% \PrintIndex
%
% \newpage
%
% \section*{Implémentation}
% \phantomsection
% \addcontentsline{toc}{section}{Implémentation}
% \CodelineNumbered
% \NoAutoSpacing
% \hbadness=10000
%
% L'implémentation sera expliquée plus en détails dans une version ultérieure\dots
%
%    \begin{macrocode}
%<*package>
%<@@=intexgral>
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}[2025-05-14]
\RequirePackage{pkginfograb}

% Package declaration

\pkginfograbProvidesExplPackage{intexgral}
  {
    name         = {intexgral}   ,
    author       = {Valentin Dao},
    date         = {2026-01-02}  ,
    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
        \str_if_eq:eeTF
          { \seq_item:Nn \l_tmpa_seq { 2 } }
          { +j }
          {
            \exp_args:NNne \seq_set_item:Nnn \l_tmpa_seq { 2 } 
              { \l_@@_default_differential_tl+j }
          }
          {
            \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  .tl_set:N   = \l_@@_default_differential_tl,
    defaultvar* .tl_set:N   = \l_@@_default_vector_differential_tl,
    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}