diff options
author | Karl Berry <karl@freefriends.org> | 2014-02-03 23:52:26 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2014-02-03 23:52:26 +0000 |
commit | d852feb864bd3edda9a7023a00a1415a8bbcee0d (patch) | |
tree | f997826c516aa1bfe698ab18568296d2afd8073c /Master/texmf-dist | |
parent | 8ad58f29ed0930ae433d45971bbd0362555bd26d (diff) |
pkgloader (3feb14)
git-svn-id: svn://tug.org/texlive/trunk@32864 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
16 files changed, 1943 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/latex/pkgloader/README b/Master/texmf-dist/doc/latex/pkgloader/README new file mode 100644 index 00000000000..0fccd0a2173 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/README @@ -0,0 +1,51 @@ +latex-pkgloader +=============== + +LaTeX Package : latex-pkgloader 0.1.0 + +Last Modified : 2014-01-29 + +Author : Michiel Helvensteijn (www.mhelvens.net) + + +Summary +------- + +A LaTeX package for managing the options and loading order of other packages + + +Prerequisites +------------- + +To use this package, you need the following packages: + +* `lt3graph` + +To generate the documentation some additional packages are needed. + + +Installation +------------- + +`pkgloader.sty` is provided directly in the package archive. Put +it in a place where your LaTeX distribution can find it. +(`pkgloader.sty` is not generated, but manually maintained; you + may use docstrip to remove the documentation, but you don't + have to; it will just work the way it is) + + +Documentation +------------- + +`pkgloader.pdf` is provided directly in the package archive. To +generate the documentation yourself, run LaTeX on pkgloader.tex. +(`pkgloader.tex` does not contain the package code itself; it inputs + `pkgloader.sty` directly to document the implementation) + + +License +------- + +This material is subject to the LaTeX Project Public License. See +http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html +for the details of that license.
\ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/pkgloader/pkgloader-packagedoc.cls b/Master/texmf-dist/doc/latex/pkgloader/pkgloader-packagedoc.cls new file mode 100644 index 00000000000..25cc215c359 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/pkgloader-packagedoc.cls @@ -0,0 +1,390 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% Copyright (c) 2013 - Michiel Helvensteijn - www.mhelvens.net % +% % +% https://github.com/mhelvens/latex-lt3graph % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status 'maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\let\packagename\jobname + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Document Class % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\LoadClassWithOptions{l3doc} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Importing The Main Package % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\RequirePackage{pkgloader} + \RequirePackage{array} + \RequirePackage{etoolbox} + \RequirePackage[table]{xcolor} + \RequirePackage[xcolor]{mdframed} + \RequirePackage{marginnote} + \RequirePackage{listings} + \RequirePackage{textcomp} + \RequirePackage{hyperref} + \RequirePackage{needspace} + \RequirePackage{noindentafter} + \RequirePackage{pkgloader-dry} +\LoadPackagesNow + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Documentation Options % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\verbatimchar{"} % because the macro \& is being indexed + +\EnableCrossrefs +\CodelineIndex +\RecordChanges + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% File Info % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\extratitlenote{} + +\GetFileInfo{\packagename.sty} + +\title{ + The \textsf{\packagename} package\thanks{% + This document corresponds to + \textsf{\packagename}~\fileversion, + dated \filedate. + } + \ifdefempty{\extratitlenote}{}{\thanks{\extratitlenote}} +} + +\author{ + Michiel Helvensteijn\\ + \href{mailto:mhelvens+latex@gmail.com}{mhelvens+latex@gmail.com} +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Development Info % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newmdenv[ + leftline = false, + rightline = false +]{bannerframe} + +\apptocmd{\maketitle}{ + \begin{bannerframe} + \small + \begin{center} + Development of this package is organized at + \href{https://github.com/mhelvens/latex-\packagename} + {github.com/mhelvens/latex-\packagename}.\\ + I am happy to receive feedback there! + \end{center} + \end{bannerframe} +}{}{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Example Environment Setup % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\renewcommand{\ttdefault}{pcr} + +\lstdefinelanguage{latex}{ + language=[LaTeX]tex, + alsoletter={_,:}, + morekeywords={before,after,late,early,if, + error,always,because,loaded}, + moretexcs={RequirePackage,RequirePackageWithOptions,Load,LoadPackagesNow}, + mathescape, + texcsstyle=*\bfseries +} + +\lstset{ + language=latex, + escapechar=|, + basicstyle=\ttfamily\upshape, + keywordstyle=\ttfamily\upshape\bfseries, + keywordstyle=[2]\color{green!40!black}, + keywordstyle=[3]\itshape, + commentstyle=\color{gray}, + numbers=left, + numberstyle=\footnotesize, + frame=none, + columns=fixed, + literate={[} {\bfseries[} 1 + {]} {\bfseries]} 1 + {\{} {\bfseries\{} 1 + {\}} {\bfseries\}} 1 + {(} {\bfseries(} 1 + {)} {\bfseries)} 1 + {\&\&} {\bfseries\&\&} 2 + {||} {\bfseries||} 2 + {!} {\bfseries!} 1 + {,} {\bfseries,} 1 +} + +%%% Environments + +\lstnewenvironment{latex}[1][]{ + \lstset{language=latex, #1} +}{} +\NoIndentAfterEnv{latex} + +%%% File Input Command + +\NewDocumentCommand\inputlatexcode{ O{} m }{% + \lstinputlisting[% + language=latex, + literate={[} {\bfseries[} 1 + {]} {\bfseries]} 1 + {\{} {\bfseries\{} 1 + {\}} {\bfseries\}} 1 + {(} {\bfseries(} 1 + {)} {\bfseries)} 1 + {\&\&} {\bfseries\&\&} 2 + {||} {\bfseries||} 2 + {!} {\bfseries!} 1 + {,} {\bfseries,} 1, #1 + ]{#2}% + \NoIndentAfterThis% +} + + +%%% Code formatting + +\lstdefinestyle{examplecode}{% + language=latex,% + basicstyle=\ttfamily\small,% + texcsstyle=*\bfseries,% + keywordstyle=\bfseries% +} + +%%% Setting up example code block + +\definecolor{examplecodelinecolor}{rgb}{0,0,0} +\definecolor{examplecodebackgroundcolor}{rgb}{.9,.9,.9} +\newmdenv[ + linecolor = examplecodelinecolor, + backgroundcolor = examplecodebackgroundcolor, + skipabove = 0bp, + skipbelow = 0bp, + innertopmargin = -3bp, + innerrightmargin = 4bp, + innerbottommargin = -3bp, + innerleftmargin = 4bp +]{examplecodeframe} + +%%% Defining example output block + +\definecolor{exampleoutputbackgroundcolor}{rgb}{1,1,1} +\newmdenv[ + linecolor = examplecodelinecolor, + backgroundcolor = exampleoutputbackgroundcolor, + skipabove = 0bp, + skipbelow = 0bp, + innertopmargin = 4bp, + innerrightmargin = 4bp, + innerbottommargin = 4bp, + innerleftmargin = 4bp +]{exampleoutputframe} + +%%% Macros for counting lines in file, adapted from +%%% http://andreas.scherbaum.la/blog/archives/ +%%% 670-Read-number-lines-in-a-file-in-LaTeX.html +% +\RequirePackage{ifthen} +\newboolean{packagedoc@restfile} +\newcommand*{\packagedoc@fileline}{} +\newread\packagedoc@file +\newcommand*{\packagedoc@readnextline}[1]{% + \ifthenelse{\boolean{packagedoc@restfile}}{% + \read#1 to \packagedoc@fileline% + \ifeof#1\setboolean{packagedoc@restfile}{false}% + \else\fi% + }{}% +} +\newcommand*{\countlinesinfile}[2]{% + \setboolean{packagedoc@restfile}{true}% + \setcounter{packagedoc@linecount}{0}% + \openin\packagedoc@file=#1% + \whiledo{\boolean{packagedoc@restfile}}{% + \packagedoc@readnextline{\packagedoc@file}% + \ifthenelse{\boolean{packagedoc@restfile}}{% + \stepcounter{packagedoc@linecount}% + }{}% + }% + \closein\packagedoc@file% + \edef#2{\thepackagedoc@linecount}% +} + +\newcounter{packagedoc@linecount} +\newlength{\packagedoc@spacetoreserve} + +%%% DRYer without output +% +\NewDRYer{latex-example}{% + \addvspace{4bp}% + {% + \ttfamily\small% + \countlinesinfile{#1}{\countedlines}% + \setlength{\packagedoc@spacetoreserve}{\countedlines\baselineskip}% + \setlength{\packagedoc@spacetoreserve}{1.7\packagedoc@spacetoreserve}% + \addtolength{\packagedoc@spacetoreserve}{-4bp}% + \needspace{\packagedoc@spacetoreserve}% + }% + \begin{examplecodeframe}% + \renewcommand{\ttdefault}{pcr}% + \lstinputlisting[style=examplecode]{#1}% + \end{examplecodeframe}% + #2% + \addvspace{4bp}% +} +\NoIndentAfterEnv{latex-example} + +%%% DRYer WITH output but WITHOUT side-effects +% +\NewDRYer{latex-example-show}{% + \addvspace{4bp}% + {% + \ttfamily\small% + \countlinesinfile{#1}{\countedlines}% + \setlength{\packagedoc@spacetoreserve}{\countedlines\baselineskip}% + \setlength{\packagedoc@spacetoreserve}{1.7\packagedoc@spacetoreserve}% + \addtolength{\packagedoc@spacetoreserve}{\baselineskip}% + \needspace{\packagedoc@spacetoreserve}% + }% + \begin{examplecodeframe}% + \renewcommand{\ttdefault}{pcr}% + \lstinputlisting[style=examplecode]{#1}% + \end{examplecodeframe}\vspace{-4bp}% + \begin{exampleoutputframe}% + #2% + \end{exampleoutputframe}% + \addvspace{4bp}% +} +\NoIndentAfterEnv{latex-example-show} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Implementation Code Box Setup % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% Saving old implementation code block font +% +\AtBeginDocument{\let\old@macro@font\macro@font} + +%%% Setup for 'interesting' implementation code blocks +% +\definecolor{interestingcodebackgroundcolor}{rgb}{.9,.9,.9} +\definecolor{interestingcodelinecolor}{rgb}{0,0,0} +\mdfdefinestyle{interestingcode}{ + linecolor = interestingcodelinecolor, + backgroundcolor = interestingcodebackgroundcolor +} +\newcommand*{\interesting}{% + \def\codestyle{interestingcode}% + \let\macro@font\old@macro@font% +} + +%%% Setup for 'UNinteresting' implementation code blocks +% +\definecolor{uninterestingcodebackgroundcolor}{rgb}{.97,.97,.97} +\definecolor{uninterestingcodelinecolor}{rgb}{.5,.5,.5} +\definecolor{uninterestingcodecolor}{rgb}{.4,.4,.4} +\mdfdefinestyle{uninterestingcode}{ + linecolor = uninterestingcodelinecolor, + backgroundcolor = uninterestingcodebackgroundcolor, +} +\newcommand*{\uninteresting}{% + \def\codestyle{uninterestingcode}% + \def\macro@font{\color{uninterestingcodecolor}\old@macro@font}% + \vskip-\belowdisplayskip% + \vskip-1.05\abovedisplayskip% +} + +\BeforeBeginEnvironment{macrocode}{\vskip.2\abovedisplayskip} + +%%% Actually surround 'macrocode' with the frame +% +\surroundwithmdframed[ + style = \codestyle, + skipabove = 0bp, + skipbelow = 0bp, + splitbottomskip = 4bp, + innertopmargin =-3bp, + innerrightmargin = 1bp, + innerbottommargin = 4bp, + innerleftmargin = 1bp +]{macrocode} + +%%% Start out with 'interesting' code status and +%%% always go back to it after one code block +% +\interesting +\AfterEndEnvironment{macrocode}{\vskip\belowdisplayskip\interesting\NoIndentAfterThis} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Argument Specifiers and such % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand*{\movarg}[1]{[ \texttt{#1} ]} +\newcommand*{\momarg}[1]{[ \meta{#1} ]} + +\newcommand{\describemacro}[2]{% + \needspace{3\baselineskip}% + \noindent\\\DescribeMacro{#1} #2\\\NoIndentAfterThis% +} + +\newcommand{\describeanymacro}[2]{% + \needspace{3\baselineskip}% + \noindent\\\marginnote{#1} #2\\\NoIndentAfterThis% +} + +\newcommand{\describemetamacro}[2]{% + \describeanymacro{\meta{#1}}{#2}% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Other Stuff % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\NoIndentAfterEnv{description} +\NoIndentAfterEnv{itemize} +\NoIndentAfterEnv{enumerate} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Automatic Implementation Docs % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\AtEndDocument{ + \pagebreak + + \renewcommand{\ttdefault}{cmtt} + + \section{Implementation} \label{sec:implementation} + + \StopEventually {\PrintChanges} + + We now show and explain the entire implementation from \texttt{\packagename.sty}. + + \DocInput{\packagename.sty} + + \Finale + + \PrintIndex +} diff --git a/Master/texmf-dist/doc/latex/pkgloader/pkgloader.pdf b/Master/texmf-dist/doc/latex/pkgloader/pkgloader.pdf Binary files differnew file mode 100644 index 00000000000..0d788800559 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/pkgloader.pdf diff --git a/Master/texmf-dist/doc/latex/pkgloader/pkgloader.tex b/Master/texmf-dist/doc/latex/pkgloader/pkgloader.tex new file mode 100644 index 00000000000..1e186cf1ce1 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/pkgloader.tex @@ -0,0 +1,331 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% + +\documentclass[a4paper]{pkgloader-packagedoc} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Setup % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\nt#1{\ensuremath{\hbox{\footnotesize$\langle$}\mathit{#1}\hbox{\footnotesize$\rangle$}}} +\def\|{\ \mid\ } + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global Changes % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\changes{0.1.0}{2014/01/29} + {initial version} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{document} % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\maketitle + +\section {Introduction} % % % % % % % % % % % % % % % % % % % % % % % % % % % % + +\LaTeX\ can be extended by loading packages +using a \lstinline+\usepackage+, \lstinline+\RequirePackage+ or \lstinline+\RequirePackageWithOptions+ command. +Packages can add definitions, change existing ones, or otherwise extend functionality of the language. + +While the Turing-complete power of the \TeX\ family is quite useful at times, it does +make it all too easy for independent package authors to step on each others +toes. CTAN is full of conceptually independent packages that cannot be +loaded together, or break if they are not loaded in a specific order. + +Yet, until now, there has been no automated package management to speak of. +Document authors are usually told to avoid certain package combinations, +or to load packages in some specific order. +Occasionally, package authors patch their code to be aware of specific +other packages, circumventing known conflicts. +But this makes maintenance more difficult, because these package authors +are `mixing concerns'; they put code related to other packages into their +own package. And it is all done in an ad-hoc fashion. + +Enter \lstinline+pkgloader+. + + + +\subsection {Package Description} % % % % % % % % % % % % % % % % % % % % % % + +Here is an example of main file for a \LaTeX\ document +which uses \lstinline+pkgloader+: + +\begin{latex} +\documentclass{article} + +\RequirePackage{pkgloader} + \usepackage{xltxtra} + \usepackage[xetex]{graphicx} + $\smash{\raisebox{-1pt}{\small\vdots}}$ +\LoadPackagesNow + +\begin{document} $\ldots$ \end{document} +\end{latex} + +The idea is to load \lstinline+pkgloader+ before loading any other package. +It can then intercept all package loading requests, analyze them +and load them properly, taking this burden off the shoulders of +the average document author. + +Between the second and sixth lines, the loading of all packages +is postponed. The \lstinline+\LoadPackagesNow+ command then +loads the packages in some valid order. During this process, +`conflict resolving' code may also be run, meant specifically to make +other packages work together properly. If the above code were +compiled without \lstinline+pkgloader+ (using the \XeTeX\ engine, as of this writing), +the given order between \lstinline+xltxtra+ and \lstinline+graphicx+ would +cause an error. +%% +The main advantage to this approach is that the complexity of dealing +with package conflicts is moved to the \lstinline+pkgloader+ package and handled +in a systematic manner. + +If you are a document author, this may be all you need to know to use +\lstinline+pkgloader+. If you are interested in more advanced functionality, +read on! + + +\subsection {The \texttt{pkgloader} Area} % % % % % % % % + +\describeanymacro + {\ttfamily\bfseries\textbackslash RequirePackage\!\!\!\!\!} + {{\ttfamily{\bfseries\{}pkgloader{\bfseries\}}\quad\ldots\quad{\bfseries\textbackslash LoadPackagesNow}}} + +The \lstinline+pkgloader+ area is the area between +\lstinline+\RequirePackage{pkgloader}+ and +\lstinline+\LoadPackagesNow+. +Within it, the three traditional package-loading commands +are `hijacked', recording information rather than loading +packages directly. Also, a \lstinline+\Load+ command is +available, which offers more flexibility in regulating +package loading behavior. + +|pkgloader| accepts sets of rules coming from outside +packages, though support is still somewhat limited. +Any |pkgloader-|\nt{something}|.sty| file can be loaded +within the |pkgloader| area by passing \nt{something} +as a package option. The file |pkgloader-recommended.sty| +is loaded this way by default. You can overwrite this by +passing |recommended=false| as an option. For example: + +\begin{latex} +\RequirePackage[recommended=false, my-better-rules]{pkgloader} + $\smash{\raisebox{-1pt}{\small\vdots}}$ +\LoadPackagesNow +\end{latex} + +This area does not play by the recommended package loading +rules, but uses the rules in |pkgloader-my-better-rules.sty| +instead. + + + +\subsection {Package Loading Requests} % % % % % % % % + + +\marginnote{\ttfamily\bfseries\textbackslash usepackage\\ + \textbackslash RequirePackage\\ + \textbackslash RequirePackageW{\ldots}s}\noindent +For requesting specific packages inside the |pkgloader| area, +just use the three commands always used +for this purpose: \lstinline+\usepackage+, \lstinline+\RequirePackage+ and +\lstinline+\RequirePackageWithOptions+. Their syntax and effective semantics +are the same as they have always been. Their effects are just delayed, +reordered and perhaps modified by the active rules. + + + +\subsection {Package Loading Rules} % % % % % % % % + +\marginnote{\ttfamily\bfseries\textbackslash Load}\noindent +Each invocation if the \lstinline+\Load+ command sets up a rule about +a package or packages, which are not necessarily ever loaded. +These rules can come from any number of different sources. +A central registry will be maintained together with \lstinline+pkgloader+ itself +in the form of |pkgloader-recommended.sty|, +specifying well-known conflicts and resolutions. +Individual package authors, however, can supply their own rules, +as can document authors. Though ideally, for the +average document author, things should `just work'. + +The \lstinline+\Load+ command expects the following syntax: + +\vskip\abovedisplayskip +\begingroup +\centering +\begin{tabular}{r@{\ \ \ \ }r@{\ \ \ \ }l} + \nt{load} &$::=$& \lstinline+\Load+$\ \nt{package}\ \ \nt{clause}_1\ \ldots\ \nt{clause}_i$ \\ + &$ \|$& \lstinline+\Load error+ $\ \ \ \,\nt{clause}_1\ \ldots\ \nt{clause}_i$ \\[2mm] + + \nt{package} &$::=$& \lstinline+[+$\;\nt{options}\;$\lstinline+] {+$\;\nt{pkg}\;$\lstinline+} [+$\;\nt{version}\;$\lstinline+]+ \\[2mm] + + \nt{clause} &$::=$& $\nt{order}\ \ \|\ \ \nt{condition}\ \ \|\ \ \nt{reason}$ \\[2mm] + + \nt{order} &$::=$& \lstinline+before {+ $\nt{pkg}_1\,$\lstinline+, +$\ldots\,$\lstinline+, +$\nt{pkg}_j$ \lstinline+}+ \\ + &$ \|$& \lstinline+after {+ $\nt{pkg}_1\,$\lstinline+, +$\ldots\,$\lstinline+, +$\nt{pkg}_j$ \lstinline+}+ \\ + &$ \|$& \lstinline+early+ \\ + &$ \|$& \lstinline+late+ \\[2mm] + + \nt{condition} &$::=$& \lstinline+always+ $\ \ \|\ \ $ + \lstinline+if loaded+ $\ \ \|\ \ $ + \lstinline+if {+ $\nt{\phi}$ \lstinline+}+ \\[2mm] + + \nt{\phi} &$::=$& $\nt{pkg}$ $\ \ \|\ \ $ + $\nt{\phi}\ $\lstinline+&&+$\ \nt{\phi}$ $\ \ \|\ \ $ + $\nt{\phi}\ $\lstinline+||+$\ \nt{\phi}$ $\ \ \|\ \ $ + \lstinline+!+$\;\nt{\phi}$ $\ \ \|\ \ $ + \lstinline+(+$\;\nt{\phi}\;$\lstinline+)+ \\[2mm] + + \nt{reason} &$::=$& \lstinline+because {+ $\nt{token{-}list}$ \lstinline+}+ +\end{tabular} +\endgroup +\vskip\belowdisplayskip + +\noindent +\nt{pkg} represents a package name. +\nt{token{-}list} should expand to a human-readable text without formatting. + +\marginnote{\ttfamily\bfseries if}\noindent +The \( \nt{condition} \) clause determines under which package loading +conditions any and all parts of a rule are invoked. +Here is an example of the use of the \( \nt{condition} \) clause: +\begin{latex} +\Load {res-ie-lst} if {inputenc && listings} +\Load {fixltx2e} always +\end{latex} + +\lstinline+res-ie-lst+ (a fictional package built specifically to resolve the +conflict between \lstinline+inputenc+ and \lstinline+listings+) will be loaded if requested +specifically, or if both \lstinline+inputenc+ and \lstinline+listings+ are loaded. The \lstinline+fixltx2e+ package is +always loaded, as it was created to smooth over some mistakes in the +\LaTeXe\ core. + +\marginnote{\ttfamily\bfseries always\\ if loaded} +The \lstinline+always+ keyword makes a rule unconditional. The \lstinline+if loaded+ +directive makes a rule conditional on its package already being loaded anyway. +This can be used to order two packages only when they are being loaded by other +means, and is actually the default behavior (in other words, \lstinline+if loaded+ +really does nothing). + +\marginnote{\ttfamily\bfseries before\\ after} +The \lstinline+before+ and \lstinline+after+ keywords should be pretty straightforward. They +can be used for things like: +\begin{latex} +\Load {xltxtra} after {graphicx} +\end{latex} +which fixes the loading order between these two packages when they are both loaded. + +\marginnote{\ttfamily\bfseries early\\ late} +But the set of \LaTeX\ packages is constantly growing, and it appears that +some big packages should almost always be loaded early in the process, +and others should almost always be loaded late. Therefore the \lstinline+early+ +and \lstinline+late+ stages are provided as a fallback mechanism. If two packages +are not related by an explicit application order, their loading order +may still be decided by their relative stages: \lstinline+early+ before `normal' before \lstinline+late+. +That way, conflicts may be avoided in a majority of cases. +This is implemented with |pkgloader-early| and |pkgloader-late| stubs in +the loading order graph. + +The following example uses the \( \nt{order} \) clause +in addition to the \( \nt{condition} \) clause: +\begin{latex} +\Load {res-ie-lst} if {inputenc && listings} + after {inputenc , listings} +\Load {fixltx2e} always early +\end{latex} +An important observation about the loading order is that it +might form a cycle when contradictory ordering rules are specified: +\begin{latex} +\Load {pkg1} after {pkg2} +\Load {pkg2} after {pkg1} +\end{latex} +In practice this could happen if the authors of \lstinline+pkg1+ and \lstinline+pkg2+ +independently discover a conflict, and both try to solve it by patching +their code and having their own package be loaded last. \lstinline+pkgloader+ +can provide a clear error message when this happens, allowing the +two package authors to seek contact and collaborate on a solution. + +\marginnote{\ttfamily\bfseries error} +Now, about the \lstinline+error+ keyword. +Initially all package combinations are valid. But if two packages +are irredeemably incompatible, their combination can be made to trigger +an error message by a command such as the following: +\begin{latex} +\Load error if {algorithms && pseudocode} +\end{latex} +These two packages provide almost identical functionality and conflict +on many command-names. It was generally agreed upon that they should +never be loaded together. Document authors should simply choose one +or the other. + +\marginnote{\ttfamily\bfseries because} +Finally, the \( \nt{reason} \) clause can be used to supply a +human-readable explanation of a rule. +We finish the above examples by providing reasons: +\begin{latex}[basewidth=.598em] +\Load {res-ie-lst} if {inputenc && listings} + after {inputenc , listings} + because {it allows the use of 1 byte unicode + characters in code listings} + +\Load {fixltx2e} always early + because {it fixes some imperfections in LaTeX2e} + +\Load error when {algorithms && pseudocode} + because {they provide almost identical functionality + and conflict on many command names} +\end{latex} +In the future, reasons will be extracted automatically to +generate documentation. For now, they are displayed with error +messages related to the rule in question. + + +\subsection {Status} % % % % % % % % + +So far, \lstinline+pkgloader+ seems to work as expected, but has not +yet been tested as extensively as it should be. Therefore, bug-reports +on the |pkgloader| issue tracker on Github would be most welcome. +Also, lots more recommended package loading rules are needed. + +I nonetheless decided to publish the package now, because I've been +promising to do so for a while now: + +\begin{center} + \url{http://tex.stackexchange.com/questions/123174} +\end{center} + +\noindent +I hope that, with feedback and community collaboration, +use of this package will become widespread and package +authors will be able to work in a more modular fashion. + +\emph{Future versions} of |pkgloader| will be able to deal with +document classes, to intelligently merge package options +and to track packages loaded by other packages in order +to better inform the user --- perhaps even fix problems +by carrying information into the next run through auxiliary files. +But most of this will depend on feedback. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{document} % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/doc/latex/pkgloader/test1.sty b/Master/texmf-dist/doc/latex/pkgloader/test1.sty new file mode 100644 index 00000000000..2a01c6236e4 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/test1.sty @@ -0,0 +1,3 @@ +\xdef\PackageOrderLog{\PackageOrderLog\quad test1[\csname opt@test1.sty\endcsname]} +\DeclareOption*{} +\ProcessOptions\relax diff --git a/Master/texmf-dist/doc/latex/pkgloader/test2.sty b/Master/texmf-dist/doc/latex/pkgloader/test2.sty new file mode 100644 index 00000000000..b817cf49be9 --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/test2.sty @@ -0,0 +1,3 @@ +\xdef\PackageOrderLog{\PackageOrderLog\quad test2[\csname opt@test2.sty\endcsname]} +\DeclareOption*{} +\ProcessOptions\relax diff --git a/Master/texmf-dist/doc/latex/pkgloader/test3.sty b/Master/texmf-dist/doc/latex/pkgloader/test3.sty new file mode 100644 index 00000000000..933106879fe --- /dev/null +++ b/Master/texmf-dist/doc/latex/pkgloader/test3.sty @@ -0,0 +1,3 @@ +\xdef\PackageOrderLog{\PackageOrderLog\quad test3[\csname opt@test3.sty\endcsname]} +\DeclareOption*{} +\ProcessOptions\relax diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-dry.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-dry.sty new file mode 100644 index 00000000000..bcb21ea2e3d --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-dry.sty @@ -0,0 +1,54 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2013 - Michiel Helvensteijn - www.mhelvens.net % +% % +% https://github.com/mhelvens/latex-lt3graph % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status 'maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% + +% I will 'officially' release this file at some point in the future. For +% now I'm just using it to document a couple of packages. Still, it's +% released under LPPL, so use it as you will. +% +% -- Michiel Helvensteijn + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{dry} + [2013/10/11 convenience macros for reusing LaTeX code] + +\RequirePackage{filecontents} +\RequirePackage{xparse} +\RequirePackage{etoolbox} +\RequirePackage{withargs} + +\newcommand\minput[1]{% + \input{#1}\unskip% +} + +\NewDocumentCommand{\NewDRYer}{m +m}{% + \withargs [\uniquecsname] [#2] {% + \newenvironment{#1}{% + \begingroup% + \@tempswafalse\filec@ntents{##1.tmp}% + }{% + \endfilecontents% + \endgroup% + }% + \AfterEndEnvironment{#1}{% + \withargs (xn) [##1.tmp] [\minput{##1.tmp}] {% + ##2% + }% + }% + }% +} diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-early.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-early.sty new file mode 100644 index 00000000000..c698a494835 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-early.sty @@ -0,0 +1,24 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% +% % +% This file is always loaded after the 'early' % +% packages but before every other package. It's % +% really just a stub in the dependency graph. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-error.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-error.sty new file mode 100644 index 00000000000..f685e7bcb39 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-error.sty @@ -0,0 +1,60 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% +% % +% This file is loaded whenever a combination of packages is % +% requested that has been marked as illegal. Loading this % +% file always results in the termination of the LaTeX run. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%% Back to expl3 syntax +% +\ExplSyntaxOn + + +%%% Add an empty line to the log before the errors are printed +% +\typeout{} + + +%%% Initialization for the error-message loop +% +\cs_generate_variant:Nn \int_step_inline:nnnn {nnvn} +\cs_generate_variant:Nn \int_compare:nNnTF {nNvTF} +\cs_generate_variant:Nn \msg_error:nnnn {nnvv} + + +%%% The loop issues one error message for each reason the +%%% package combination is illegal. None of them are +%%% critical or fatal errors; we terminate the run manually. +% +\int_step_inline:nnvn {1} {1} {g__pkgloader_count_(pkgloader-error)_int} { + \bool_if:cT {g__pkgloader_used_(pkgloader-error)_(#1)_bool} { + \msg_error:nnvv + {pkgloader} {illegal-combination} + {g__pkgloader_condition_(pkgloader-error)_(#1)_tl} + {g__pkgloader_reason_ (pkgloader-error)_(#1)_tl} + } +} + + +%%% Terminate the LaTeX run +% +\stop\bye diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-false.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-false.sty new file mode 100644 index 00000000000..0112ef148e8 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-false.sty @@ -0,0 +1,24 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% +% % +% This file is never loaded by pkgloader, and that's its % +% only function: to be 'false' in loading conditions. % +% Basically, it reserves the name 'pkgloader-false'. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-late.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-late.sty new file mode 100644 index 00000000000..745a4e9aac5 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-late.sty @@ -0,0 +1,24 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% +% % +% This file is always loaded before the 'late' % +% packages but after every other package. It's % +% really just a stub in the dependency graph. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-recommended.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-recommended.sty new file mode 100644 index 00000000000..f557f91ee59 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-recommended.sty @@ -0,0 +1,38 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `author-maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% \begin{macrocode} +\Load {fixltx2e} early always +\Load {fancyhdr} before {hyperref} if loaded +\Load {fncychap} before {hyperref} if loaded +\Load {float} before {hyperref} if loaded +\Load {hyperref} before {algorithm} if loaded +\Load {amssymb} before {xunicode} if loaded +\Load {amssymb} before {xltxtra} if loaded +\Load {graphicx} before {xltxtra} if loaded +\Load {graphicx} before {fontspec} if loaded +\Load {caption} before {subfig} if loaded +\Load {amsmath} before {wasysym} if loaded +\Load {todonotes} before {program} if loaded +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-test-rules.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-test-rules.sty new file mode 100644 index 00000000000..842d73a4679 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-test-rules.sty @@ -0,0 +1,22 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `author-maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% + + +\Load [option=true] {test2} if {test1} before {test1} +\Load error if {test1 && test3} because {I don't like this combination} diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader-true.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-true.sty new file mode 100644 index 00000000000..2db6b108209 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader-true.sty @@ -0,0 +1,23 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% +% % +% This file is always loaded by pkgloader, and that's its % +% only function: to be 'true' in loading conditions. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Master/texmf-dist/tex/latex/pkgloader/pkgloader.sty b/Master/texmf-dist/tex/latex/pkgloader/pkgloader.sty new file mode 100644 index 00000000000..593e8d9c987 --- /dev/null +++ b/Master/texmf-dist/tex/latex/pkgloader/pkgloader.sty @@ -0,0 +1,893 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% +% % +% Copyright (c) 2014 - Michiel Helvensteijn (www.mhelvens.net) % +% % +% https://github.com/mhelvens/latex-pkgloader % +% % +% This work 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.3 or later is part of all distributions of LaTeX % +% version 2005/12/01 or later. % +% % +% This work has the LPPL maintenance status `maintained'. % +% % +% The Current Maintainer of this work is Michiel Helvensteijn. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% + +% \CheckSum{414} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \subsection{Package Info} % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% First, the mandatory package meta-information: +% +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\RequirePackage{expl3} +\ProvidesExplPackage{pkgloader}{2014/01/29}{0.1.0} + {managing the options and loading order of LaTeX packages} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \subsection{Required Packages} % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The following packages are required. Three standard |expl3|-related +% packages, one experimental package in |l3regex| and one user-contributed +% |expl3| package in |lt3graph|: +% +% \begin{macrocode} +\RequirePackage{xparse} +\RequirePackage{l3prop} +\RequirePackage{l3keys2e} +\RequirePackage{l3regex} +\RequirePackage{lt3graph} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \subsection{Package Code} % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% We need two global data-structures. One to keep track of all packages +% that are known, one to keep track of the packages that are actually +% going to be loaded, and their order: +% +% \begin{macrocode} +\prop_new:N \g__pkgloader_known_pkg_prop +\graph_new:N \g__pkgloader_pkg_graph +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% We store pristine versions of the three package loading +% commands: +% +% \begin{macrocode} +\cs_gset_eq:NN \__pkgloader_usepkg:wnw \usepackage +\cs_gset_eq:NN \__pkgloader_RPkg:wnw \RequirePackage +\cs_gset_eq:NN \__pkgloader_RPkgWithOptions:wnw \RequirePackageWithOptions +% \end{macrocode} +% +% And we define a command to restore the commands back to +% their pristine versions: +% +% \begin{macrocode} +\cs_new_protected:Nn \__pkgloader_restore_commands: { + \cs_gset_eq:NN \usepackage \__pkgloader_usepkg:wnw + \cs_gset_eq:NN \RequirePackage \__pkgloader_RPkg:wnw + \cs_gset_eq:NN \RequirePackageWithOptions \__pkgloader_RPkgWithOptions:wnw +} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This function globally registers a package loading rule, +% which can be created with either the |\Load| command or +% any of the three hijacked |\usepackage| commands: +% +% \begin{macrocode} +\cs_new_protected:Nn \__pkgloader_register_rule:nnnnnnnnn { + % #1: package name + % #2: options + % #3: version + % #4: condition + % #5: compiled condition + % #6: packages to load before this one + % #7: packages to load after this one + % #8: reason + % #9: command +% \end{macrocode} +% +% If this package hasn't been seen before, register +% it and create a rule-counter for it: +% +% \begin{macrocode} + \prop_if_in:NnF \g__pkgloader_known_pkg_prop {#1} { + \prop_gput:Nnn \g__pkgloader_known_pkg_prop {#1} {} + \int_new:c {g__pkgloader_count_(#1)_int} + } +% \end{macrocode} +% +% Increment the rule-counter: +% +% \begin{macrocode} + \int_incr:c {g__pkgloader_count_(#1)_int} +% \end{macrocode} +% +% Then, we set all properties of the +% +% \begin{macrocode} + \tl_set:Nf \l_tmpa_tl {\int_use:c {g__pkgloader_count_(#1)_int}} + \tl_set:cn {g__pkgloader_options_ (#1)_(\l_tmpa_tl)_tl} {#2} + \tl_set:cn {g__pkgloader_version_ (#1)_(\l_tmpa_tl)_tl} {#3} + \tl_set:cn {g__pkgloader_condition_ (#1)_(\l_tmpa_tl)_tl} {#4} + \tl_set:cn {g__pkgloader_compiled_condition_(#1)_(\l_tmpa_tl)_tl} {#5} + \tl_set:cn {g__pkgloader_predecessors_ (#1)_(\l_tmpa_tl)_tl} {#6} + \tl_set:cn {g__pkgloader_successors_ (#1)_(\l_tmpa_tl)_tl} {#7} + \tl_set:cn {g__pkgloader_reason_ (#1)_(\l_tmpa_tl)_tl} {#8} + \tl_set:cn {g__pkgloader_command_ (#1)_(\l_tmpa_tl)_tl} {#9} + \bool_new:c {g__pkgloader_used_ (#1)_(\l_tmpa_tl)_bool} +% \end{macrocode} +% \uninteresting\begin{macrocode} +} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% These three functions are redefined to just register +% the package loading information rather than load the +% package immediately: +% +% \begin{macrocode} +\RenewDocumentCommand {\usepackage} { o m o } + { \__pkgloader_usepackage_cmd:nnnn + {\__pkgloader_usepkg:wnw} {#1} {#2} {#3} } +\RenewDocumentCommand {\RequirePackage} { o m o } + { \__pkgloader_usepackage_cmd:nnnn + {\__pkgloader_RPkg:wnw} {#1} {#2} {#3} } +\RenewDocumentCommand {\RequirePackageWithOptions} { o m o } + { \__pkgloader_usepackage_cmd:nnnn + {\__pkgloader_RPkgWithOptions:wnw} {#1} {#2} {#3} } +% \end{macrocode} +% +% Storing this information is delegated to the +% |\__pkgloader_register_rule:nnnnnnnnn| function: +% +% \begin{macrocode} +\cs_new:Nn \__pkgloader_usepackage_cmd:nnnn { + \__pkgloader_register_rule:nnnnnnnnn + {#3} {#2} {#4} % package name, options, version + {pkgloader-true} % condition + {\c_true_bool} % compiled condition + {} {} % predecessors, successors + {it~is~loaded~by~the~user} % reason + {#1} % command +} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This is a sophisticated user-level command for manipulating +% package loading order and conditions. It has a `non-standard' +% but convenient syntax, not showing any standard- +% +% \begin{macrocode} +\NewDocumentCommand {\Load} {} { +% \end{macrocode} +% +% Initialize the variables used for storing given data: +% +% \begin{macrocode} + \tl_clear:N \l__pkgloader_load_options_tl + \tl_clear:N \l__pkgloader_load_name_tl + \tl_clear:N \l__pkgloader_load_version_tl + \clist_clear:N \l__pkgloader_load_pred_clist + \clist_clear:N \l__pkgloader_load_succ_clist + \tl_clear:N \l__pkgloader_load_cond_tl + \tl_clear:N \l__pkgloader_load_because_tl + \bool_set_false:N \l__pkgloader_early_late_used_bool +% \end{macrocode} +% +% Start scanning for input: +% +% \begin{macrocode} + \__pkgloader_load_scan_pkg_:w +% \end{macrocode} +% \uninteresting\begin{macrocode} +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This function starts scanning for the name of the package +% central to this rule, as well as the options and minimum +% version proposed for it. +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_pkg_:w { + \peek_charcode_remove_ignore_spaces:NTF e {% % % error + \__pkgloader_load_scan_pkg_e:w + }{\peek_charcode_remove_ignore_spaces:NTF [ {% % package options + \__pkgloader_load_scan_pkg_options:nw + }{ % % % % % % % % % % % % % % % % % % % % % % % package name + \__pkgloader_load_scan_pkg_:nw + }} +} +% \end{macrocode} +% +% %%%%%%%%% +% +% The |error| keyword can take the place of a package name, +% options and version. It is shorthand for the |pkgloader-error| +% file, and then jumps ahead to scanning clauses: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_pkg_e:w rror { + \tl_set:Nn \l__pkgloader_load_name_tl {pkgloader-error} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This scans the options and goes ahead to scan the package name: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_pkg_options:nw #1 ] { + \tl_set:Nn \l__pkgloader_load_options_tl {#1} + \__pkgloader_load_scan_pkg_:nw +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This scans the package name, peeks ahead for a minimum +% version, and otherwise goes on to scanning for clauses: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_pkg_:nw #1 { + \tl_set:Nn \l__pkgloader_load_name_tl {#1} + \peek_charcode_remove_ignore_spaces:NTF [ {% % % % package version + \__pkgloader_load_scan_version:nw + }{ % % % % % % % % % % % % % % % % % % % % % % % % clauses + \__pkgloader_load_scan_clause_:w + } +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This scans the version, and then goes ahead to scan for clauses: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_version:nw #1 ] { + \tl_set:Nn \l__pkgloader_load_version_tl {#1} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This is the starting- and return-point used to scan +% for (additional) |\Load| clauses: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_:w { + \peek_charcode_remove_ignore_spaces:NTF a { + \peek_charcode_remove:NTF l { % % % % % % % % % always + \__pkgloader_load_scan_clause_al:w + }{\peek_charcode_remove:NTF f { % % % % % % % % after + \__pkgloader_load_scan_clause_af:w + }{ + \__pkgloader_load_end: a + }} + }{\peek_charcode_remove_ignore_spaces:NTF b { % + \peek_charcode_remove:NTF e { + \peek_charcode_remove:NTF c { % % % % % % % because + \__pkgloader_load_scan_clause_bec:w + }{\peek_charcode_remove:NTF f { % % % % % % before + \__pkgloader_load_scan_clause_bef:w + }{ + \__pkgloader_load_end: be + }} + }{ + \__pkgloader_load_end: b + } + }{\peek_charcode_remove_ignore_spaces:NTF e { % % % early + \__pkgloader_load_scan_clause_e:w + }{\peek_charcode_remove_ignore_spaces:NTF i { % % % if + \__pkgloader_load_scan_clause_i:w + }{\peek_charcode_remove_ignore_spaces:NTF l { % % % late + \__pkgloader_load_scan_clause_l:w + }{ + \__pkgloader_load_end: + }}}}} +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|always|'' clause: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_al:w ways { + \tl_put_right:Nn \l__pkgloader_load_cond_tl {~||~pkgloader-true} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|after|'' clause: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_af:w ter #1 { + \clist_put_right:Nn \l__pkgloader_load_pred_clist {#1} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|because|'' clause: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_bec:w ause #1 { + \tl_set:Nn \l__pkgloader_load_because_tl {#1} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|before|'' clause: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_bef:w ore #1 { + \clist_put_right:Nn \l__pkgloader_load_succ_clist {#1} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|early|'' clause, which orders +% this package before the ``|pkgloader-early|'' stub: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_e:w arly { + \bool_set_true:N \l__pkgloader_early_late_used_bool + \clist_put_right:Nn \l__pkgloader_load_succ_clist {pkgloader-early} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|if|'' clause, which may still be +% a manual condition or the ``|loaded|'' keyword: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_i:w f { + \peek_charcode_remove_ignore_spaces:NTF l { + \__pkgloader_load_scan_clause_if_l:w + }{ + \__pkgloader_load_scan_clause_if_:nw + } +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|if loaded|'' clause, which uses +% this package being loaded as the condition for the rule being used: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_if_l:w oaded { + \tl_put_right:Nn \l__pkgloader_load_cond_tl {~||~} + \tl_put_right:NV \l__pkgloader_load_cond_tl \l__pkgloader_load_name_tl + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|always|'' clause, which loads this +% package conditional on the ``|pkgloader-true|'' package being +% loaded (which always is): +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_if_:nw #1 { + \tl_put_right:Nn \l__pkgloader_load_cond_tl {~||~#1} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This processes the ``|late|'' clause, which orders +% this package after the ``|pkgloader-late|'' stub: +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \__pkgloader_load_scan_clause_l:w ate { + \bool_set_true:N \l__pkgloader_early_late_used_bool + \clist_put_right:Nn \l__pkgloader_load_pred_clist {pkgloader-late} + \__pkgloader_load_scan_clause_:w +} +% \end{macrocode} +% +% %%%%%%%%% +% +% This function processes the collected data and registers it: +% +% \begin{macrocode} +\cs_new_protected_nopar:Nn \__pkgloader_load_end: { +% \end{macrocode} +% +% If this package should not specifically go early or late, +% it goes inbetween the two: +% +% \begin{macrocode} + \bool_if:NF \l__pkgloader_early_late_used_bool { + \tl_if_eq:VnF \l__pkgloader_load_name_tl {pkgloader-early} { + \tl_if_eq:VnF \l__pkgloader_load_name_tl {pkgloader-late} { + \clist_put_right:Nn \l__pkgloader_load_pred_clist {pkgloader-early} + \clist_put_right:Nn \l__pkgloader_load_succ_clist {pkgloader-late } + } + } + } +% \end{macrocode} +% +% We remove the leading ``\texttt{\ \textbar\textbar\ }'' from the condition: +% +% \begin{macrocode} + \tl_remove_once:Nn \l__pkgloader_load_cond_tl {~||~} +% \end{macrocode} +% +% If no condition is given at all, the default is: ``|if loaded|'' +% +% \begin{macrocode} + \tl_if_empty:NT \l__pkgloader_load_cond_tl + { \tl_set_eq:NN \l__pkgloader_load_cond_tl \l__pkgloader_load_name_tl } +% \end{macrocode} +% +% We now take the condition and compile it to a |\bool_if:| +% kind of syntax. The user-syntax is preserved to use in +% error messages and such: +% +% \begin{macrocode} + \tl_set_eq:NN \l__pkgloader_load_compd_cond_tl \l__pkgloader_load_cond_tl + \regex_replace_all:nnN + { [^\&\|\(\)\!\s]+ } + { (\c{graph_if_vertex_exist_p:Nn} + \c{g__pkgloader_pkg_graph}\cB\{\0\cE\}) } + \l__pkgloader_load_compd_cond_tl +% \end{macrocode} +% +% If no reason was given for this rule, it was obviously +% still because of reasons: +% +% \begin{macrocode} + \tl_if_empty:NT \l__pkgloader_load_because_tl + { \tl_set:Nn \l__pkgloader_load_because_tl {of~reasons} } +% \end{macrocode} +% +% Having gathered and processed the data, the rule is +% registered: +% +% \begin{macrocode} + \__pkgloader_register_rule:VVVVVVVVn + \l__pkgloader_load_name_tl + \l__pkgloader_load_options_tl + \l__pkgloader_load_version_tl + \l__pkgloader_load_cond_tl + \l__pkgloader_load_compd_cond_tl + \l__pkgloader_load_pred_clist + \l__pkgloader_load_succ_clist + \l__pkgloader_load_because_tl + \__pkgloader_RPkg:wnw % TODO: make configurable +% \end{macrocode} +% \uninteresting\begin{macrocode} +} +% \end{macrocode} +% +% The scanning functions need the following variants: +% +% \begin{macrocode} +\cs_generate_variant:Nn \tl_if_eq:nnF {VnF} +\cs_generate_variant:Nn \graph_gput_vertex:Nn {NV} +\cs_generate_variant:Nn \graph_gput_edge:Nnn {NnV,NVn} +\cs_generate_variant:Nn \seq_gput_right:Nn {NV} +\cs_generate_variant:Nn \__pkgloader_register_rule:nnnnnnnnn {VVVVVVVVn} +% \end{macrocode} +% +% And they need the following local variables: +% +% \begin{macrocode} +\tl_new:N \l__pkgloader_load_options_tl +\tl_new:N \l__pkgloader_load_name_tl +\tl_new:N \l__pkgloader_load_version_tl +\clist_new:N \l__pkgloader_load_pred_clist +\clist_new:N \l__pkgloader_load_succ_clist +\tl_new:N \l__pkgloader_load_cond_tl +\tl_new:N \l__pkgloader_load_because_tl +\bool_new:N \l__pkgloader_early_late_used_bool +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This function decides, based on all loaded rules and package +% requests, which packages, options and versions end up being +% loaded, and in which order. +% +% \begin{macrocode} +\cs_new_protected:Nn \__pkgloader_select_packages: { +% \end{macrocode} +% +% We first set up a graph to record accepted orderings: +% +% \begin{macrocode} + \graph_clear:N \l__pkgloader_order_graph +% \end{macrocode} +% +% We then start a loop that runs at least once, then repeats +% while additional package configurations are still being added +% to the set. Eventually the loop reaches a fixed point and terminates. +% +% \begin{macrocode} + \bool_do_while:Nn \l__pkgloader_selection_changed_bool { + \bool_set_false:N \l__pkgloader_selection_changed_bool +% \end{macrocode} +% +% Then first, for all possible package configurations (a nested +% loop, but not doubly indented because it feels like one loop): +% +% \begin{macrocode} + \prop_map_inline:Nn \g__pkgloader_known_pkg_prop {%%%%%%%%%%%%%% ##1 + \int_step_inline:nncn {1} {1} {g__pkgloader_count_(##1)_int} {%% ####1 +% \end{macrocode} +% +% If the current configuration should be loaded but still +% isn't selected (nested conditional; but again, not indented): +% +% \begin{macrocode} + \bool_if:cF {g__pkgloader_used_(##1)_(####1)_bool} { + \bool_if:vT {g__pkgloader_compiled_condition_(##1)_(####1)_tl} { +% \end{macrocode} +% +% We mark the package configuration as being used: +% +% \begin{macrocode} + \bool_set_true:c {g__pkgloader_used_(##1)_(####1)_bool} +% \end{macrocode} +% +% We record the configuration in the main package graph, which maps +% each package to a clist of selected configurations: +% +% \begin{macrocode} + \graph_get_vertex:NnNTF \g__pkgloader_pkg_graph {##1} + \l__pkgloader_used_configs_tl { + \tl_if_empty:NTF \l__pkgloader_used_configs_tl + { \graph_gput_vertex:Nnf \g__pkgloader_pkg_graph {##1} {####1} } + { \graph_gput_vertex:Nnf \g__pkgloader_pkg_graph {##1} + {\l__pkgloader_used_configs_tl, ####1} } + } { \graph_gput_vertex:Nnf \g__pkgloader_pkg_graph {##1} {####1} } +% \end{macrocode} +% +% In a separate graph, we record the associated (now activated) +% package loading orders. We don't do this in the main graph, +% because it may involve packages that are themselves not yet +% selected. These edges are later filtered and added to the main graph: +% +% \begin{macrocode} + \graph_put_vertex:Nn \l__pkgloader_order_graph {##1} + \clist_map_inline:cn {g__pkgloader_predecessors_(##1)_(####1)_tl} { + \graph_put_vertex:Nn \l__pkgloader_order_graph {########1} + \graph_get_edge:NnnNTF \l__pkgloader_order_graph + {########1} {##1} \l__pkgloader_used_configs_tl + { \graph_put_edge:Nnnn \l__pkgloader_order_graph + {########1} {##1} {\l__pkgloader_used_configs_tl,####1} } + { \graph_put_edge:Nnnn \l__pkgloader_order_graph + {########1} {##1} {####1} } + } + \clist_map_inline:cn {g__pkgloader_successors_(##1)_(####1)_tl} { + \graph_put_vertex:Nn \l__pkgloader_order_graph {########1} + \graph_get_edge:NnnNTF \l__pkgloader_order_graph + {##1} {########1} \l__pkgloader_used_configs_tl + { \graph_put_edge:Nnnn \l__pkgloader_order_graph + {##1} {########1} {\l__pkgloader_used_configs_tl,####1} } + { \graph_put_edge:Nnnn \l__pkgloader_order_graph + {##1} {########1} {####1} } + } +% \end{macrocode} +% +% We then mark the change, so a next iteration will be entered: +% +% \begin{macrocode} + \bool_set_true:N \l__pkgloader_selection_changed_bool +% \end{macrocode} +% \uninteresting\begin{macrocode} + }} + }} + } +% \end{macrocode} +% +% Finally, we put the applicable proposed orderings into the +% graph of selected packages: +% +% \begin{macrocode} + \graph_gput_edges_from:NN \g__pkgloader_pkg_graph \l__pkgloader_order_graph +% \end{macrocode} +% \uninteresting\begin{macrocode} +} +% \end{macrocode} +% +% This function needs the following variations: +% +% \begin{macrocode} +\cs_generate_variant:Nn \int_step_inline:nnnn {nncn} +\cs_generate_variant:Nn \bool_if:nT {vT} +\cs_generate_variant:Nn \withargs:nnn {vvn} +\cs_generate_variant:Nn \graph_gput_vertex:Nnn {Nnf} +% \end{macrocode} +% +% And it needs the following local variables: +% +% \begin{macrocode} +\graph_new:N \l__pkgloader_order_graph +\tl_new:N \l__pkgloader_used_configs_tl +\bool_new:N \l__pkgloader_selection_changed_bool +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Now follows the user command to consolidate all package loading +% requests and do the `right thing' (tm). +% +% \begin{macrocode} +\NewDocumentCommand {\LoadPackagesNow} {} { +% \end{macrocode} +% +% We first select package configurations by their loading conditions: +% +% \begin{macrocode} + \__pkgloader_select_packages: +% \end{macrocode} +% +% We then restore |\usepackage|, |\RequirePackage| and +% |\RequirePackageWithOptions| to their normal definitions. +% +% \begin{macrocode} + \__pkgloader_restore_commands: +% \end{macrocode} +% +% Now, if there is a cycle in the derived package loading order: ERROR +% +% \begin{macrocode} + \graph_if_cyclic:NT \g__pkgloader_pkg_graph + { \msg_fatal:nn {pkgloader} {cyclic-order} } +% \end{macrocode} +% +% Then, for all used packages, in topological order\ldots +% +% \begin{macrocode} + \graph_map_topological_order_inline:Nn \g__pkgloader_pkg_graph { +% \end{macrocode} +% +% \ldots load that package. Though note that this code is still quite +% incomplete, because it loads the first viable configuration. It should: +% \begin{enumerate} +% \item use |\RequirePackageWithOptions| if necessary, +% |\RequirePackage| otherwise, +% \item allow custom merging schemes for options, and +% \item use the latest required version. +% \end{enumerate} +% \begin{macrocode} + \withargs:xn { \clist_item:nn{##2}{1} } { + \withargs:vvnvn {g__pkgloader_command_(##1)_(####1)_tl} + {g__pkgloader_options_(##1)_(####1)_tl} + {##1} + {g__pkgloader_version_(##1)_(####1)_tl} { + \IfValueTF {########2} + { \IfValueTF {########4} + { ########1 [########2] {########3} [########4] } + { ########1 [########2] {########3} } } + { \IfValueTF {########4} + { ########1 {########3} [########4] } + { ########1 {########3} } } +% \end{macrocode} +% \uninteresting\begin{macrocode} + } + } + } +} +% \end{macrocode} +% +% The above function needs the following function variations: +% +% \begin{macrocode} +\cs_generate_variant:Nn \withargs:nn {xn} +\cs_generate_variant:Nn \withargs:nnnnn {vvnvn} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Bootstrap |pkgloader| by inserting |pkgloader-true| in +% the graph directly, so all other packages can be inserted +% with rules, possibly using the |always| clause. +% +% \begin{macrocode} +\graph_gput_vertex:Nn \g__pkgloader_pkg_graph {pkgloader-true} +% \end{macrocode} +% +% We then register the core logical rules of |pkgloader|, +% regarding such basics as |pkgmanager-false|, +% |pkgloader-error|, |pkgloader-early| and |pkgloader-late|. +% +% \begin{macrocode} +\withargs:nn {of~the~mandatory~core~rules~of~pkgloader} { + \Load error if {pkgloader-false} because {#1} + \Load {pkgloader-true} always because {#1} + \Load {pkgloader-early} always because {#1} + \Load {pkgloader-late} always because {#1} + \Load {pkgloader-early} before {pkgloader-late} because {#1} +} +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% We process the options passed to |pkgloader| as |.sty| files +% to be loaded before pkgloader does its thing. This +% should be used to define new |pkgloader| rules. Note, +% particularly, that any |\usepackage|-like command inside +% those |.sty| files is registered and processed by +% |pkgloader|; not loaded directly. +% +% First, we define the functions used to handle an option. +% +% \begin{macrocode} +\cs_new:Nn \__pkgloader_process_option:n + { \__pkgloader_process_option:nn {#1} {true} } +\cs_new:Nn \__pkgloader_process_option:nn + { \tl_if_eq:nnTF {#2} {true} + { \seq_put_right:Nn \l__pkgloader_rule_packages_seq {#1} } + { \seq_remove_all:Nn \l__pkgloader_rule_packages_seq {#1} } } +% \end{macrocode} +% +% The |recommended| rules are loaded unless explicitly turned off. +% +% \begin{macrocode} +\seq_new:N \l__pkgloader_rule_packages_seq +\seq_put_right:Nn \l__pkgloader_rule_packages_seq {recommended} +% \end{macrocode} +% +% Process the options to populate |\l__pkgloader_rule_packages_seq|. +% +% \begin{macrocode} +\cs_generate_variant:Nn \keyval_parse:NNn {NNv} +\keyval_parse:NNv + \__pkgloader_process_option:n + \__pkgloader_process_option:nn + {opt@pkgloader.sty} +\seq_remove_duplicates:N \l__pkgloader_rule_packages_seq +% \end{macrocode} +% +% Actually load the |.sty| files in |\l__pkgloader_rule_packages_seq|. +% Note that the actual file needs the |pkgloader-| prefix. +% +% \begin{macrocode} +\seq_map_inline:Nn \l__pkgloader_rule_packages_seq + { \__pkgloader_RPkg:wnw {pkgloader-#1} } +% \end{macrocode} +% +% Finally, we make a show of using the proper macros for \LaTeX's +% benefit. If we don't, a \LaTeX\ error is issued. +% +% \begin{macrocode} +\DeclareOption*{} +\ProcessOptions\relax +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Finally, here are the error messages this package can generate. +% First a simple error for cycles, which should be improved to +% show the cause of the cycle. +% +% \begin{macrocode} +\msg_new:nnn {pkgloader} {cyclic-order} + { There~is~a~cycle~in~the~requested~package~loading~order. } +% \end{macrocode} +% +% And the following is the error reported for certain package +% combinations that have been forbidden through an |error| rule. +% +% \begin{macrocode} +\msg_new:nnnn {pkgloader} {illegal-combination} + { A~combination~of~packages~fitting~the~following~condition~ + was~requested: + \\\\\ \ \ \ #1\\\\ + This~is~an~error~because~#2. } + { A~pkgloader~rule~was~requested~that~prohibits~the~logical~ + combination~above~for~the~specified~reason.~It~is~probably~ + a~good~reason. } +% \end{macrocode} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + |