From 0c9f0e3c20d7b39baa0fdbdc1563c13349ad108a Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 29 Apr 2018 21:46:58 +0000 Subject: exercisebank (29apr18) git-svn-id: svn://tug.org/texlive/trunk@47483 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/latex/exercisebank/exercisebank.sty | 350 +++++++++++++++------ 1 file changed, 254 insertions(+), 96 deletions(-) (limited to 'Master/texmf-dist/tex/latex/exercisebank/exercisebank.sty') diff --git a/Master/texmf-dist/tex/latex/exercisebank/exercisebank.sty b/Master/texmf-dist/tex/latex/exercisebank/exercisebank.sty index 059c4e1973b..6d32887e413 100644 --- a/Master/texmf-dist/tex/latex/exercisebank/exercisebank.sty +++ b/Master/texmf-dist/tex/latex/exercisebank/exercisebank.sty @@ -1,5 +1,5 @@ -% Source (with comments) can be found at https://github.com/Strauman/exerciseBank -%% The LaTeX package exercisebank - version v0.1.0 (2018/04/08) - build 55 +% Source (with comments) can be found at https://github.com/Strauman/exercisebank/ +%% The LaTeX package exercisebank - version v0.1.4 (2018/04/28) - build 74 %% exercisebank.sty: Exercise bank %% ------------------------------------------------------------------------------------------- %% Copyright (c) 2018 by Andreas Storvik Strauman @@ -13,9 +13,10 @@ %% version 2008/05/04 or later. %% This work has the LPPL maintenance status `author-maintained'. %% This work consists of all files listed in README -\ProvidesPackage{exercisebank}[2018/04/08 v0.1.0 Creates a setup that gives freedom in making sets and exercises.] -\PackageWarningNoLine{exercisebank-v0.1.0}{This package is in the alpha stage, and if something unexpected happens please, oh pretty please, report it to https://github.com/Strauman/exerciseBank. Thank you!} -\@ifundefined{ownLineNoSpacesGotIt}{\@latex@warning{Compilation wont work unless \string\end{problem} and \string\end{solution} are on their own lines and without any spaces. This warning can be removed by doing \string\def\string\ownLineNoSpacesGotIt{} before \@backslashchar usepackage{exbank}} +\ProvidesPackage{exercisebank}[2018/04/28 v0.1.4 Creates a setup that gives freedom in making sets and exercises.] +\xdef\exbank@quiet{1} +\PackageWarningNoLine{exercisebank-v0.1.4}{This package is in the alpha stage, and if something unexpected happens please, oh pretty please, report it to https://github.com/Strauman/exerciseBank. Thank you!} +\@ifundefined{ownLineNoSpacesGotIt}{\@latex@warning{Compilation wont work unless \string\end{problem} and \string\end{solution} are on their own lines and without any spaces. This warning can be removed by doing \string\def\string\ownLineNoSpacesGotIt{} before \@backslashchar usepackage{exercisebank}} }{} \gdef\setExercisesDir#1{\@latex@error{\string\setExercisesDir is deprecated. Use \string\exercisebanksetup{exercise directory=#1} instead}{}\stop\bye } @@ -29,8 +30,59 @@ \usepackage{calc} \usepackage{pgfpages} \usepackage{geometry} +\usepackage{listofitems} +\usepackage{trimspaces} \edef\@isTrue{1} \edef\@isFalse{0} +\gdef\isin#1#2#3#4{ \def\needle{#2} + \def\haystack{#1} + \def\isFalse{0} + \let\isInList = \isFalse + \IfInteger{\needle}{}{\@latex@error{ISIN: Can't look for part problem that is not numeric!}{}\bye\stop} + \IfInteger{\haystack}{ \ifnum\haystack=\needle\relax + #3 + \else + #4 + \fi +}{ \foreach\pp in #1{ \ifnum\pp=\needle\relax% + \gdef\isInList{1} + #3 + \fi +} + \if\isInList\isFalse + #4 + \fi +} +} +\gdef\strif#1#2{% + \ifnum\pdfstrcmp{#1}{#2}=\z@\relax% +} +\let\ea = \expandafter +\begingroup\lccode`\|=`\\ +\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}} +\gdef\exbank@macroname#1{\expandafter\removebs\string#1} +\gdef\@noneofone#1{} +\gdef\@noneoftwo#1#2{} +\@ifundefined{exbank@quiet}{ \global\let\@dlog\@latex@warning +}{ \global\let\@dlog\@noneofone +} +\newcommand\ex@before[2]{\edef #1{\unexpanded{#2}\unexpanded\expandafter{#1}} +} +\newcommand{\exb@lmargin}[2]{\strut\vadjust{\exb@domark{#1}{#2}}} +\newcommand{\exb@domark}[2]{% + \hbox to #2{ \vbox to 0pt{ \kern-\dp\strutbox + \smash{\llap{#1}} + \vss +}% +} +} +\edef\@isTrue{1} +\edef\@isFalse{0} +\gdef\ShowNumbers{\gdef\@displayMetaCounter{\isTrue}} +\gdef\@DisplaySolutions{\@isFalse} +\gdef\DisplaySolutions{\xdef\@DisplaySolutions{\isTrue}\@latex@warning{Showing solutions}} +\gdef\@SolutionsOnly{\@isFalse} +\gdef\SolutionsOnly{\xdef\@SolutionsOnly{\@isTrue}\DisplaySolutions} \pgfkeys{/exbanksetup/.is family, /exbanksetup, default/.style = { part problems = On, tighten paragraphs = True, @@ -38,8 +90,10 @@ default/.style = { part problems = On, part problem header={\large\textbf{(\theproblemcounter\alph{partproblemcounter})}}, solution header={\large{\textbf{\@tr{Solution}:}}}, exercise directory=., + figure root directory=\@exercisesDir, }, exercise directory/.estore in = \@exercisesDir, % +figure root directory/.estore in = \@figrootDir, % problem header/.store in = \exbank@opt@problemHeader, part problem header/.store in = \exbank@opt@partProblemHeader, solution header/.store in = \exbank@opt@solutionHeader, @@ -56,6 +110,30 @@ switches/.cd, \newcommand\exercisebanksetup[1]{ \pgfkeys{/exbanksetup, #1}% } \exercisebanksetup{default} +\AtBeginDocument{\xdef\tpd{\the\prevdepth}} +\gdef\tighten@paragraph{% +\if\exbank@opt@tightenparagraphs\@isTrue\relax% + \if\@SolutionsOnly\@isFalse + \if\@DisplaySolutions\@isFalse + \filbreak% + \fi + \fi +\fi% +} +\gdef\tighten@paragraph@solutions{% +\if\exbank@opt@tightenparagraphs\@isTrue\relax% + \if\@SolutionsOnly\@isFalse + \if\@DisplaySolutions\@isTrue + \filbreak% + \fi + \fi +\fi% +} +\gdef\tighten@paragraph@always{% +\if\exbank@opt@tightenparagraphs\@isTrue\relax% +\filbreak% +\fi% +} \pgfkeys{ /exbanki18n/.is family, /exbanki18n, default/.style = {Problem = Problem, Solution = Solution}, Problem/.estore in = \@tr@Problem, @@ -68,18 +146,35 @@ switches/.cd, } } \let\ea = \expandafter -\def\removebs#1{\if#1\@backslashchar\else#1\fi} -\newcommand{\At}[2]{ \def\macname{\expandafter\removebs\detokenize{#1}} - \let\mname = \macname +\begingroup\lccode`\|=`\\ +\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}} +\newcommand{\At}[2]{ \edef\mname{\exbank@macroname{#1}} \ifcsname At@\mname\endcsname \ea\g@addto@macro\csname At@\mname\endcsname{#2} \else \ea\gdef\csname At@\mname\endcsname{#2} + \AtEndDocument{ \expandafter\let\csname At@\mname\endcsname\relax +} \fi } -\newcommand{\Trigger}[1]{ \def\macname{\expandafter\removebs\detokenize{#1}} - \let\mname = \macname - \@ifundefined{At@\mname}{}{\csname At@\mname\endcsname} +\newcommand{\Trigger}[1]{ \edef\mname{\exbank@macroname{#1}} + \ea\@ifundefined{At@\mname}{}{% + \csname At@\mname\endcsname% +}% +} +\xdef\figuresPath{\@figrootDir/} +\gdef\fileInputPath{} +\gdef\fileInputBase{} +\providecommand*{\input@path}{} +\g@addto@macro\input@path{{\fileInputBase}{\fileInputPath}} +\At\PathControl{ \xdef\figuresPath{\@figrootDir/} + \edef\exfile{\exerciseFile} + \expandafter\filename@parse{\exfile} + \xdef\fileInputPath{\figuresPath\filename@area} + \xdef\fileInputBase{\figuresPath\filename@area\filename@base/} + \graphicspath{{\fileInputBase}{\fileInputPath}} + \@dlog{\fileInputBase} + \@ifundefined{input@path}{\gdef\input@path{{\fileInputBase}{\fileInputPath}}}{} } \newlength{\ppLeading} \newlength{\pMarginBelow} @@ -111,17 +206,21 @@ switches/.cd, \end{addmargin} \vspace*{\pMarginBelow} } -\At\EndProblem{ \if\exbank@opt@tightenparagraphs\isTrue\filbreak\fi +\At\EndProblem{\tighten@paragraph } \At\VeryBeginPartproblem{% \stepcounter{partproblemcounter}% + \bgroup + \if\@displayMetaCounter\isTrue\relax% + \ex@before\exbank@opt@partProblemHeader{{\Large\themetacounter}:} + \fi \begin{addmargin}{\ppMargin} - \if\exbank@opt@tightenparagraphs\isTrue\filbreak\fi \begin{itemize} \item[\exbank@opt@partProblemHeader] } \At\EndPartproblem{ \end{itemize} \end{addmargin} + \egroup\tighten@paragraph \vspace*{\pMarginBelow}% } \At\BeginSolution{ \vspace*{1em} @@ -132,36 +231,43 @@ switches/.cd, \At\EndSolution{ \end{itemize} \end{addmargin} } +\At\EndProblem{% +\if\exbank@opt@tightenparagraphs\@isTrue\relax% + \if\@SolutionsOnly\@isFalse% + \if\@DisplaySolutions\@isTrue% + \penalty-300% + \fi% + \fi% +\fi% +} +\@ifundefined{figure}{}{\edef\figure{\unexpanded{\tighten@paragraph@always}\unexpanded\expandafter{\figure}} +} +\@ifundefined{endfigure}{}{\g@addto@macro\endfigure{\tighten@paragraph@always} +} \gdef\isFalse{0} \gdef\isTrue{1} \gdef\DisplayProblem{\isTrue} \gdef\@displayMetaCounter{\isFalse} -\gdef\ShowNumbers{\gdef\@displayMetaCounter{\isTrue}} -\gdef\@DisplaySolutions{\isFalse} -\gdef\DisplaySolutions{\xdef\@DisplaySolutions{\isTrue}\@latex@warning{Showing solutions}} \AtBeginDocument{ \if\@DisplaySolutions\isFalse \@latex@warning{Hiding solutions. Show them with \string\DisplaySolutions} \fi } \global\let\do@ProcessCutFile = \ProcessCutFile \gdef\showhideproblem#1{% - \if\@displayMetaCounter\isTrue% - {P:\Large\themetacounter} - \Trigger\BeginPartproblem - \Trigger\VeryBeginPartproblem - \gdef\DisplayProblem{\isTrue} + \if\DisplayProblem\isFalse + \def\ProcessCutFile{} \else - \if\DisplayProblem\isFalse - \def\ProcessCutFile{} - \else - #1 - \fi + \if\@SolutionsOnly\@isTrue\relax% + \def\ProcessCutFile{}\fi% + #1 \fi } \generalcomment{problem}{ \edef\DisplaySolution{\@DisplaySolutions} + \stepcounter{metacounter} \Trigger\DecideProblemDisplay \begingroup - \showhideproblem{ \if\exbank@opt@partProblems\isTrue + \showhideproblem{% + \if\exbank@opt@partProblems\isTrue \Trigger\BeginPartproblem \Trigger\VeryBeginPartproblem \else @@ -169,9 +275,10 @@ switches/.cd, \Trigger\VeryBeginProblem \fi } -}{ \if\DisplayProblem\isFalse\else +}{ \if\DisplayProblem\@isFalse\relax\else \if\exbank@opt@partProblems\isTrue \Trigger\EndPartproblem + \tighten@paragraph \else \Trigger\EndProblem \fi @@ -193,14 +300,28 @@ switches/.cd, \fi }{\if\DisplaySolution\isTrue \Trigger\EndSolution +\tighten@paragraph@solutions +\vspace*{0.5em} \fi -\Trigger\EndSolutionHard \endgroup +\Trigger\EndSolutionHard% } \generalcomment{intro}{ \if\@countIntros\isTrue + \stepcounter{metacounter} \Trigger\DecideProblemDisplay \begingroup - \showhideproblem{\Trigger\BeginIntro} + \if\@displayMetaCounter\isTrue\relax% + {\exb@lmargin{{\Large\themetacounter}}{\pMarginLeft}} + \fi + \if\@spriteMode\isTrue + \if\introarg\isTrue + \stepcounter{partproblemcounter} + \fi + \fi + \showhideproblem{% + \tighten@paragraph% + \Trigger\BeginIntro% +} \fi }{ \if\@countIntros\isTrue \Trigger\EndIntro @@ -208,25 +329,6 @@ switches/.cd, \fi \vspace*{1em} } -\gdef\isin#1#2#3#4{ \def\needle{#2} - \def\haystack{#1} - \def\isFalse{0} - \let\isInList = \isFalse - \IfInteger{\haystack}{ \if\haystack\needle - #3 - \else - #4 - \fi -}{ \foreach\pp in #1{ \if\pp\needle - \gdef\isInList{1} - #3 - \fi -} - \if\isInList\isFalse - #4 - \fi -} -} \def\squeeze{ \newlength{\marginw} \setlength{\marginw}{1.5cm} \newgeometry{margin=\marginw} @@ -259,20 +361,16 @@ switches/.cd, } \let\ea = \expandafter \newcounter{metacounter} -\def\emptyList{-1} -\begingroup\lccode`\|=`\\ -\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}} -\newcommand{\macroname}[1]{\expandafter\removebs\string#1} -\gdef\ifppMode#1{ \def\mname{\macroname{#1}} - \if\mname\ppMode +\setcounter{metacounter}{0} +\gdef\emptyList{0} +\gdef\ifppMode#1{ \def\mname{\exbank@macroname{#1}} + \strif\mname\ppMode } -\gdef\isppMode#1#2{ \edef\mname{\macroname{#1}} - \if{\macroname{#1}}\ppMode#2\fi +\gdef\isppMode#1#2{ \edef\mname{\exbank@macroname{#1}} + \strif{\exbank@macroname{#1}}{\ppMode}\relax#2\fi } -\gdef\@noneofone#1{} -\gdef\@noneOfTwo#1#2{} \gdef\@ifppMode#1{% -\ifnum\pdfstrcmp{\macroname{#1}}{\ppMode}=\z@% +\ifnum\pdfstrcmp{\exbank@macroname{#1}}{\ppMode}=\z@% \expandafter\@firstofone% \else% \expandafter\@noneofone% @@ -280,17 +378,18 @@ switches/.cd, }% \def\pm@Exclude{exclude} \def\pm@Select{select} +\def\pm@Normal{normal} \let\ipm\@ifppMode \let\T@\isTrue \let\F@\isFalse -\At\DecideProblemDisplay{ \if\ppList\emptyList - \xdef\DisplayProblem{\ipm\exclude\T@\ipm\select\F@} - \else - \isin{\ppList}{\themetacounter}{ \xdef\DisplayProblem{\ipm\exclude\F@\ipm\select\T@\ipm\normal\T@} -}{ \xdef\DisplayProblem{\ipm\exclude\T@\ipm\select\F@\ipm\normal\T@} +\At\DecideProblemDisplay{% + \ifnum\pdfstrcmp{\ppList}{\emptyList}=\z@\relax% + \xdef\DisplayProblem{\ipm\exclude\T@\ipm\select\F@} + \else + \isin{\ppList}{\themetacounter}{ \xdef\DisplayProblem{\ipm\exclude\F@\ipm\select\T@\ipm\normal\T@} +}{ \xdef\DisplayProblem{\ipm\exclude\T@\ipm\select\F@\ipm\normal\T@} } - \fi - \stepcounter{metacounter} + \fi } \pgfkeys{ /makeset/.is family, /makeset, default/.style = {noheadarg=\isFalse, introarg=\isFalse}, @@ -301,69 +400,125 @@ switches/.cd, } \gdef\@listOfSets{} \gdef\@spriteMode{\isFalse} +\gdef\exbank@spriteSets{\emptyList} +\long\gdef\spritesets#1{ \gdef\exbank@spriteSets{#1} +} +\global\let\exlist@protect\noexpand \newcommand\makeset[3][]{ \pgfkeys{/makeset, default, #1}% \if\introarg\isTrue% + \gdef\introarg{\isTrue} \ea\gdef\csname setlist@#2@intro\endcsname{\isTrue} \fi \if\noheadarg\isTrue% \ea\gdef\csname setlist@#2@nohead\endcsname{\isTrue} \fi - \ea\gdef\csname setlist@#2\endcsname{#3} + \ea\gdef\csname setlist@#2\endcsname{\exlist@protect{#3}} \def\setmacro{\unexpanded\expandafter{\csname setlist@#2\endcsname}} - \g@addto@macro\@listOfSets{#2} + \g@addto@macro\@listOfSets{,#2} } \long\gdef\about#1{} \newcommand\sprite[1][4]{\squeeze \gdef\@spriteMode{\isTrue} \long\def\about##1{{\Large\textbf{About}:\\[1.1em]##1\\[1.5em]}} \pgfpagesuselayout{#1 on 1}[a4paper,border shrink=5mm] - \foreach\set in \@listOfSets{ \buildset{\set} +\ifnum\pdfstrcmp{\exbank@spriteSets}{\emptyList}=\z@\relax% + \edef\sprite@setlist{\ea\@secondoftwo\@listOfSets} + \readlist*\list@sprite@setlist\sprite@setlist + \foreachitem\set\in\list@sprite@setlist{ \edef\theset{{\set}} + \if\theset\empty\relax\else% + \buildset{\set}% + \fi% +} +\else + \edef\sprite@setlist{\exbank@spriteSets} + \readlist*\list@sprite@setlist\sprite@setlist + \foreachitem\set\in\list@sprite@setlist{ \edef\theset{{\set}} + \if\theset\empty\relax\else% + \buildex{\set}% + \fi% } +\fi +} +\gdef\exbank@setEnv@normal#1{\exbank@setEnv{#1}{normal} } -\newcommand{\redef}[3][{-1}]{ \if\@spriteMode\isFalse% +\newcommand{\exbank@setEnv}[3][{-1}]{ \if\@spriteMode\isFalse% \gdef\ppList{#1} \gdef\exerciseFile{#2} \gdef\ppMode{#3} \else - \gdef\ppList{} + \gdef\ppList{\emptyList} \gdef\exerciseFile{#2} - \gdef\ppMode{exclude} -\fi + \gdef\ppMode{\pm@Normal} + \fi } \newcommand{\exclude}[2]{[{#2}]{#1}{exclude}} \newcommand{\select}[2]{[{#2}]{#1}{select}} \gdef\buildex#1{ \makeset{#1}{#1} \buildset{#1} } +\gdef\exbank@def@makeset@command#1#2{% + \edef\macroname{\exbank@macroname{#1}}% + \xdef#1{?{@\macroname}}% + \ea\gdef\csname @\macroname\endcsname{#2}% +} +\let\exbank@isFirstProblem\isTrue +\exbank@def@makeset@command{\phead}{ \if\exbank@isFirstProblem\isTrue% + \let\exbank@isFirstProblem\isFalse% + \else% + \Trigger\EndProblem% + \fi% + \Trigger\BeginProblem% + \Trigger\VeryBeginProblem% +} +\exbank@def@makeset@command{\pbreak}{\clearpage} +\let\DeclareExerciseCommand\exbank@def@makeset@command +\global\let\ex@protect\noexpand +\gdef\exec#1{:\ex@protect{#1}} \gdef\@countIntros{\isFalse} -\gdef\phead{?\noexpand\Trigger\noexpand\VeryBeginProblem} \newcommand\buildset[2][]{ \def\oarg{#1} - \@ifundefined{setlist@#2@intro}{\gdef\@countIntros{\isFalse}}{\gdef\@countIntros{\isTrue}\@latex@warning{Counting intros}} + \@ifundefined{setlist@#2@intro}{\gdef\@countIntros{\isFalse}}{\gdef\@countIntros{\isTrue}\@dlog{Counting intros}} \@ifundefined{setlist@#2@nohead}{\gdef\nohead{\isFalse}}{\gdef\nohead{\isTrue}} \xdef\setName{#2} \@ifundefined{setlist@#2}{ \@latex@error{Couldn't find set #2. Did you remember to do \string\makeset{#2}{}?} \stop\bye }{} - \edef\setlist{\csname setlist@#2\endcsname} + \let\exlist@protect\unexpanded + \edef\exbank@setlist{\csname setlist@#2\endcsname} + \let\exlist@protect\noexpand \if\@spriteMode\isFalse \Trigger\StartBuildset \fi - \foreach\exerciseFileInfo in \setlist{ \def\continueLoop{\isTrue} - \gdef\ppList{-1} - \setcounter{metacounter}{1} - \StrLeft{\exerciseFileInfo}{1}[\firstchar]% - \if[\firstchar - \ea\redef\exerciseFileInfo\relax - \def\continueLoop{\isTrue} - \else\if?\firstchar - \expandafter\@secondoftwo\exerciseFileInfo - \def\continueLoop{\isFalse} - \else - \redef{\exerciseFileInfo}{normal} - \def\continueLoop{\isTrue} - \fi\fi - \if\continueLoop\isTrue + \gdef\@delegateFileInfo{\@ifnextchar?\@execute@makeset@command\@is@exec} + \def\@is@exec{\@ifnextchar:\@execute@exec\@is@file} + \gdef\@is@file{\@ifnextchar[\exb@setEnv@withOptargs\X@exb@setEnv} + \gdef\X@exb@setEnv##1{% + \def\continueLoop{\isTrue}% + \@dlog{Processing normal file "\exerciseFileInfo.tex"}% + \exbank@setEnv@normal{\exerciseFileInfo}\bgroup\nullfont% +} + \gdef\exb@setEnv@withOptargs{% + \def\continueLoop{\isTrue}\ea\exbank@setEnv\exerciseFileInfo\bgroup\nullfont% +} + \gdef\@execute@makeset@command ?##1{% + \edef\inner{\@firstofone##1} + \@dlog{Executing macro \@backslashchar\@gobble##1} + \csname\inner\endcsname + #1\def\continueLoop{\isFalse}\ea\bgroup +} + \def\@execute@exec:{% + \def\continueLoop{\isFalse}\@dlog{Executing custom command}\bgroup +} + \readlist*\setlist\exbank@setlist + \foreachitem\exerciseFileInfo\in\setlist{ \def\continueLoop{\isTrue} + \gdef\ppList{\emptyList} + \setcounter{metacounter}{0} + \let\ex@protect\unexpanded + \edef\exerciseFileInfo{\exerciseFileInfo} + \ea\@delegateFileInfo\exerciseFileInfo\egroup \Trigger\InputExercise + \if\continueLoop\isTrue + \let\ex@protect\noexpand + \Trigger\PathControl \if\nohead\isFalse \if\@spriteMode\isFalse \Trigger\BeginProblem @@ -372,11 +527,14 @@ switches/.cd, \if\nohead\isFalse\Trigger\VeryBeginProblem\fi \if\@spriteMode\isTrue\textbf{\exerciseFile.tex\\}\fi \IfFileExists{\@exercisesDir/\exerciseFile}{ \incl{\@exercisesDir/\exerciseFile} + \if\@spriteMode\isTrue + \setcounter{partproblemcounter}{0}% + \fi }{ \@latex@error{Could not find \@exercisesDir/\exerciseFile. Maybe it is because the default exercise directory is now changed to the same directory that your main file is in. To set default exercise directory to exercises, do \string\exercisebanksetup{exercise directory=exercises}}{} \stop\bye } \if\nohead\isFalse\Trigger\EndProblem\fi - \fi + \fi% } \if\@spriteMode\isFalse \Trigger\EndBuildset @@ -385,14 +543,14 @@ switches/.cd, \newcommand\refcounter[1]{\edef\@currentlabel{#1}% } \DeclareRobustCommand{\pplabel}[1]{ \refcounter{\theproblemcounter}\label{pr:\exerciseFile:#1} - \refcounter{\thepartproblemcounter}\label{pp:\exerciseFile:#1} + \refcounter{\alph{partproblemcounter}}\label{pp:\exerciseFile:#1} } \let\pptag = \pplabel \newcommand\pppref[1]{% -(\ref{pp:\exerciseFile:#1})\relax% +(\ea\@alph\ref{pp:\exerciseFile:#1})\relax% } \newcommand\ppref[1]{% -\ref{pr:\exerciseFile:#1}\ref{pp:\exerciseFile:#1}\relax% +(\ref{pr:\exerciseFile:#1}\ref{pp:\exerciseFile:#1})\relax% } \newcommand\pref[1]{% \ref{pr:\exerciseFile:#1}\relax% -- cgit v1.2.3