diff options
Diffstat (limited to 'macros/latex/contrib/stex/source/extensions/problem.dtx')
-rw-r--r-- | macros/latex/contrib/stex/source/extensions/problem.dtx | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/macros/latex/contrib/stex/source/extensions/problem.dtx b/macros/latex/contrib/stex/source/extensions/problem.dtx new file mode 100644 index 0000000000..b21b1c493d --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/problem.dtx @@ -0,0 +1,910 @@ +% \iffalse meta-comment +% An Infrastructure for Problems +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% \fi +% +% \iffalse +% +%<*driver> +\def\bibfolder{../../lib/bib} +\input{../../doc/docheader} +\RequirePackage[hints,solutions,notes]{problem} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \iffalse\CheckSum{318}\fi +% +% ^^A\changes{v0.9}{2006/09/18}{First Version with Documentation} +% +% \GetFileInfo{problem.sty} +% +% \MakeShortVerb{\|} +% +% \title{\texttt{problem.sty}: An Infrastructure for formatting Problems\thanks{Version {\fileversion} (last revised +% {\filedate})}} +% \author{Michael Kohlhase\\ +% FAU Erlangen-N\"urnberg\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{problem} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/problem} +% \fi +% +% \begin{documentation} +% The |problem| package supplies an infrastructure that allows specify problems and to +% reuse them efficiently in multiple environments. +% +%\section{Introduction}\label{sec:intro} +% +% The |problem| package supplies an infrastructure that allows specify problem. Problems +% are text fragments that come with auxiliary functions: hints, notes, and +% solutions\footnote{for the moment multiple choice problems are not supported, but may +% well be in a future version}. Furthermore, we can specify how long the solution to a +% given problem is estimated to take and how many points will be awarded for a perfect +% solution. +% +% Finally, the |problem| package facilitates the management of problems in small files, +% so that problems can be re-used in multiple environment. +% +% \section{The User Interface}\label{sec:ui} +% +% \subsection{Package Options} +% The |problem| package takes the options \DescribeMacro{solutions}|solutions| (should +% solutions be output?), \DescribeMacro{notes}|notes| (should the problem notes be +% presented?), \DescribeMacro{hints}|hints| (do we give the hints?), +% \DescribeMacro{gnotes}|gnotes| (do we show grading notes?), \DescribeMacro{pts}|pts| (do +% we display the points awarded for solving the problem?), \DescribeMacro{min}|min| (do we +% display the estimated minutes for problem soling). If theses are specified, then the +% corresponding auxiliary parts of the problems are output, otherwise, they remain +% invisible. +% +% The \DescribeMacro{boxed}|boxed| option specifies that problems should be formatted in +% framed boxes so that they are more visible in the text. Finally, the +% \DescribeMacro{test}|test| option signifies that we are in a test situation, so this +% option does not show the solutions (of course), but leaves space for the students to +% solve them. +% +% The \DescribeMacro{mh}|mh| option turns on MathHub support; see \cite{Kohlhase:mss}. +% +% Finally, if the \DescribeMacro{showmeta}|showmeta| is set, then the metadata keys are +% shown (see~\cite{Kohlhase:metakeys} for details and customization options). +% +% \subsection{Problems and Solutions}\label{sec:user:probsols} +% +% \DescribeEnv{problem} The main environment provided by the |problem| package is +% (surprise surprise) the |problem| environment. It is used to mark up problems and +% exercises. The environment takes an optional KeyVal argument with the keys +% \DescribeMacro{id}|id| as an identifier that can be reference later, +% \DescribeMacro{pts}|pts| for the points to be gained from this exercise in homework or +% quiz situations, \DescribeMacro{min}|min| for the estimated minutes needed to solve the +% problem, and finally \DescribeMacro{title}|title| for an informative title of the +% problem. For an example of a marked up problem see Figure~\ref{fig:problem} and the +% resulting markup see Figure~\ref{fig:result}. +% +%\begin{exfig} +% \begin{verbatim} +% \usepackage[solutions,hints,pts,min]{problem} +% \begin{document} +% \begin{sproblem}[id=elefants,pts=10,min=2,title=Fitting Elefants] +% How many Elefants can you fit into a Volkswagen beetle? +% \begin{hint} +% Think positively, this is simple! +% \end{hint} +% \begin{exnote} +% Justify your answer +% \end{exnote} +% \begin{solution}[for=elefants,height=3cm] +% Four, two in the front seats, and two in the back. +% \begin{gnote} +% if they do not give the justification deduct 5 pts +% \end{gnote} +% \end{solution} +% \end{sproblem} +% \end{document} +% \end{verbatim} +% \caption{A marked up Problem}\label{fig:problem} +% \end{exfig} +% +% \DescribeEnv{solution} The |solution| environment can be to specify a solution to a +% problem. If the \DescribeMacro{solutions}|solutions| option is set or |\solutionstrue| +% is set in the text, then the solution will be presented in the output. The |solution| +% environment takes an optional KeyVal argument with the keys \DescribeMacro{id}|id| for +% an identifier that can be reference \DescribeMacro{for}|for| to specify which problem +% this is a solution for, and \DescribeMacro{height}|height| that allows to specify the +% amount of space to be left in test situations (i.e. if the \DescribeMacro{test}|test| +% option is set in the |\usepackage| statement). +% +%\begin{exfig} +% \begin{minipage}{.9\linewidth} +% \begin{sproblem}[id=elefants.prob,title=Fitting Elefants] +% How many Elefants can you fit into a Volkswagen beetle? +% \begin{hint} +% Think positively, this is simple! +% \end{hint} +% \begin{exnote} +% Justify your answer +% \end{exnote} +% \smallskip\noindent\hrule\textbf{Solution:} +% Four, two in the front seats, and two in the back. +% \hrule +% \end{sproblem} +% \end{minipage} +% \caption{The Formatted Problem from Figure~\ref{fig:problem}}\label{fig:result} +% \end{exfig} +% +% \DescribeEnv{hint}\DescribeEnv{exnote} The |hint| and |exnote| environments can be used +% in a |problem| environment to give hints and to make notes that elaborate certain +% aspects of the problem. +% +% \DescribeEnv{gnote} The |gnote| (grading notes) environment can be used to document +% situtations that may arise in grading. +% +% Sometimes we would like to locally override the |solutions| option we have given to the +% package. To turn on solutions we use the +% \DescribeMacro{\startsolutions}|\startsolutions|, to turn them off, +% \DescribeMacro{\stopsolutions}|\stopsolutions|. These two can be used at any point in +% the documents. +% +% Also, sometimes, we want content (e.g. in an exam with master solutions) conditional on +% whether solutions are shown. This can be done with the +% \DescribeMacro{\ifsolutions}|\ifsolutions| conditional. +% +% \subsection{Multiple Choice Blocks}\label{sec:user:mcq} +% +% Multiple choice blocks can be formatted using the \DescribeMacro{mcb}|mcb| environment, +% in which single choices are marked up with +% \DescribeMacro{\mcc}|\mcc[|\meta{keyvals}|]{|\meta{text}|}| macro, which takes an +% optional key/value argument \meta{keyvals} for choice metadata and a required argument +% \meta{text} for the proposed answer text. The following keys are supported +% \begin{itemize} +% \item \DescribeMacro{T}|T| for true answers, \DescribeMacro{F}|F| for false ones, +% \item \DescribeMacro{Ttext}|Ttext| the verdict for true answers, +% \DescribeMacro{Ftext}|Ftext| for false ones, and +% \item \DescribeMacro{feedback}|feedback| for a short feedback text given to the student. +% \end{itemize} +% See Figure~\ref{fig: mcq} for an example +%\begin{exfig} +% \begin{verbatim} +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \end{verbatim} +% \solutionsfalse\hrule +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \solutionstrue\hrule +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \caption{A Problem with a multiple choice block}\label{fig:mcq} +% \end{exfig} +% +% \subsection{Including Problems}\label{sec:user:includeproblem} +% +% The \DescribeMacro{\includeproblem}|\includeproblem| macro can be used to include a +% problem from another file. It takes an optional KeyVal argument and a second argument +% which is a path to the file containing the problem (the macro assumes that there is only +% one problem in the include file). The keys \DescribeMacro{title}|title|, +% \DescribeMacro{min}|min|, and \DescribeMacro{pts}|pts| specify the problem title, the +% estimated minutes for solving the problem and the points to be gained, and their values +% (if given) overwrite the ones specified in the |problem| environment in the included +% file. +% +% \subsection{Reporting Metadata}\label{sec:user:reporting} +% +% The sum of the points and estimated minutes (that we specified in the |pts| and |min| +% keys to the |problem| environment or the |\includeproblem| macro) to the log file and +% the screen after each run. This is useful in preparing exams, where we want to make sure +% that the students can indeed solve the problems in an allotted time period. +% +% The |\min| and |\pts| macros allow to specify (i.e. to print to the margin) the +% distribution of time and reward to parts of a problem, if the |pts| and |pts| package +% options are set. This allows to give students hints about the estimated time and the +% points to be awarded. +% +% \section{Limitations}\label{sec:limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX GitHub repository~\cite{sTeX:github:on}. +% \begin{enumerate} +% \item none reported yet +% \end{enumerate} +% +% \end{documentation} +% \begin{implementation} +% +% \section{The Implementation}\label{sec:implementation} +% +% \subsection{Package Options}\label{sec:impl:options} +% +% The first step is to declare (a few) package options that handle whether certain +% information is printed or not. They all come with their own conditionals that are set by +% the options. +% +% \begin{macrocode} +%<*package> +%<@@=problems> +\ProvidesExplPackage{problem}{2022/02/24}{3.0.0}{Semantic Markup for Problems} +\RequirePackage{l3keys2e} + +\keys_define:nn { problem / pkg }{ + notes .default:n = { true }, + notes .bool_set:N = \c_@@_notes_bool, + gnotes .default:n = { true }, + gnotes .bool_set:N = \c_@@_gnotes_bool, + hints .default:n = { true }, + hints .bool_set:N = \c_@@_hints_bool, + solutions .default:n = { true }, + solutions .bool_set:N = \c_@@_solutions_bool, + pts .default:n = { true }, + pts .bool_set:N = \c_@@_pts_bool, + min .default:n = { true }, + min .bool_set:N = \c_@@_min_bool, + boxed .default:n = { true }, + boxed .bool_set:N = \c_@@_boxed_bool, + unknown .code:n = {} +} +\newif\ifsolutions + +\ProcessKeysOptions{ problem / pkg } +\bool_if:NTF \c_@@_solutions_bool { + \solutionstrue +}{ + \solutionsfalse +} +% \end{macrocode} +% +% Then we make sure that the necessary packages are loaded (in the right versions). +% \begin{macrocode} +\RequirePackage{comment} +% \end{macrocode} +% +% The next package relies on the \LaTeX3 kernel, which \latexml only partially +% supports. As it is purely presentational, we only load it when the |boxed| option is +% given and we run {\latexml}. +% +% \begin{macrocode} +\bool_if:NT \c_@@_boxed_bool { \RequirePackage{mdframed} } +% \end{macrocode} +% +% \begin{macro}{\prob@*@kw} +% For multilinguality, we define internal macros for keywords that can be specialized in +% |*.ldf| files. +% \begin{macrocode} +\def\prob@problem@kw{Problem} +\def\prob@solution@kw{Solution} +\def\prob@hint@kw{Hint} +\def\prob@note@kw{Note} +\def\prob@gnote@kw{Grading} +\def\prob@pt@kw{pt} +\def\prob@min@kw{min} +% \end{macrocode} +% \end{macro} +% +% For the other languages, we set up triggers +% \begin{macrocode} +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{babel}{ + \makeatletter + \clist_set:Nx \l_tmpa_clist {\bbl@loaded} + \clist_if_in:NnT \l_tmpa_clist {ngerman}{ + \input{problem-ngerman.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {finnish}{ + \input{problem-finnish.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {french}{ + \input{problem-french.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {russian}{ + \input{problem-russian.ldf} + } + \makeatother + }{} +} +% \end{macrocode} +% +% \subsection{Problems and Solutions}\label{sec:impl:probsols} +% +% We now prepare the KeyVal support for problems. The key macros just set appropriate +% internal macros. +% +% \begin{macrocode} +\keys_define:nn{ problem / problem }{ + id .str_set_x:N = \l_@@_prob_id_str, + pts .tl_set:N = \l_@@_prob_pts_tl, + min .tl_set:N = \l_@@_prob_min_tl, + title .tl_set:N = \l_@@_prob_title_tl, + type .tl_set:N = \l_@@_prob_type_tl, + refnum .int_set:N = \l_@@_prob_refnum_int +} +\cs_new_protected:Nn \_@@_prob_args:n { + \str_clear:N \l_@@_prob_id_str + \tl_clear:N \l_@@_prob_pts_tl + \tl_clear:N \l_@@_prob_min_tl + \tl_clear:N \l_@@_prob_title_tl + \tl_clear:N \l_@@_prob_type_tl + \int_zero_new:N \l_@@_prob_refnum_int + \keys_set:nn { problem / problem }{ #1 } + \int_compare:nNnT \l_@@_prob_refnum_int = 0 { + \let\l_@@_prob_refnum_int\undefined + } +} +% \end{macrocode} +% +% Then we set up a counter for problems. +% \begin{macro}{\numberproblemsin} +% \begin{macrocode} +\newcounter{problem} +\newcommand\numberproblemsin[1]{\@addtoreset{problem}{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@label} +% We provide the macro |\prob@label| to redefine later to get context involved. +% \begin{macrocode} +\newcommand\prob@label[1]{#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@number} +% We consolidate the problem number into a reusable internal macro +% \begin{macrocode} +\newcommand\prob@number{ + \int_if_exist:NTF \l_@@_inclprob_refnum_int { + \prob@label{\int_use:N \l_@@_inclprob_refnum_int } + }{ + \int_if_exist:NTF \l_@@_prob_refnum_int { + \prob@label{\int_use:N \l_@@_prob_refnum_int } + }{ + \prob@label\theproblem + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@title} +% We consolidate the problem title into a reusable internal macro as well. |\prob@title| +% takes three arguments the first is the fallback when no title is given at all, the +% second and third go around the title, if one is given. +% \begin{macrocode} +\newcommand\prob@title[3]{% + \tl_if_exist:NTF \l_@@_inclprob_title_tl { + #2 \l_@@_inclprob_title_tl #3 + }{ + \tl_if_exist:NTF \l_@@_prob_title_tl { + #2 \l_@@_prob_title_tl #3 + }{ + #1 + } + } +} +% \end{macrocode} +% \end{macro} +% +% With these the problem header is a one-liner +% +% \begin{macro}{\prob@heading} +% We consolidate the problem header line into a separate internal macro that can be +% reused in various settings. +% \begin{macrocode} +\def\prob@heading{ + {\prob@problem@kw}\ \prob@number\prob@title{~}{~(}{)\strut} + %\sref@label@id{\prob@problem@kw~\prob@number}{} +} +% \end{macrocode} +% \end{macro} +% +% With this in place, we can now define the |problem| environment. It comes in two shapes, +% depending on whether we are in boxed mode or not. In both cases we increment the problem +% number and output the points and minutes (depending) on whether the respective options +% are set. +% \begin{environment}{sproblem} +% \begin{macrocode} +\newenvironment{sproblem}[1][]{ + \_@@_prob_args:n{#1}%\sref@target% + \@in@omtexttrue% we are in a statement (for inline definitions) + \stepcounter{problem}\record@problem + \def\current@section@level{\prob@problem@kw} + \tl_if_exist:NTF \l_@@_inclprob_type_tl { + \tl_set_eq:NN \sproblemtype \l_@@_inclprob_type_tl + }{ + \tl_set_eq:NN \sproblemtype \l_@@_prob_type_tl + } + \str_if_exist:NTF \l_@@_inclprob_id_str { + \str_set_eq:NN \sproblemid \l_@@_inclprob_id_str + }{ + \str_set_eq:NN \sproblemid \l_@@_prob_id_str + } + + + \clist_set:No \l_tmpa_clist \sproblemtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproblem_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproblem_start: + }{ + \l_tmpa_tl + } + \stex_ref_new_doc_target:n \sproblemid +}{ + \clist_set:No \l_tmpa_clist \sproblemtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproblem_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproblem_end: + }{ + \l_tmpa_tl + } + + + \smallskip +} + + +\cs_new_protected:Nn \_@@_sproblem_start: { + \par\noindent\textbf\prob@heading\show@pts\show@min\\\ignorespacesandpars +} +\cs_new_protected:Nn \_@@_sproblem_end: {\par\smallskip} + +\newcommand\stexpatchproblem[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sproblem_start: { #2 } + \tl_set:Nn \_@@_sproblem_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_end:\endcsname{ #3 } + } +} + + +\bool_if:NT \c_@@_boxed_bool { + \surroundwithmdframed{problem} +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\record@problem} +% This macro records information about the problems in the |*.aux| file. +% \begin{macrocode} +\def\record@problem{ + \protected@write\@auxout{} + { + \string\@problem{\prob@number} + { + \tl_if_exist:NTF \l_@@_inclprob_pts_tl { + \l_@@_inclprob_pts_tl + }{ + \l_@@_prob_pts_tl + } + }% + { + \tl_if_exist:NTF \l_@@_inclprob_min_tl { + \l_@@_inclprob_min_tl + }{ + \l_@@_prob_min_tl + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@problem} +% This macro acts on a problem's record in the |*.aux| file. It does not have any +% functionality here, but can be redefined elsewhere (e.g. in the |assignment| +% package). +% \begin{macrocode} +\def\@problem#1#2#3{} +% \end{macrocode} +% \end{macro} +% +% The \DescribeEnv{solution}|solution| environment is similar to the |problem| +% environment, only that it is independent of the boxed mode. It also has it's own keys +% that we need to define first. +% +% \begin{macrocode} +\keys_define:nn { problem / solution }{ + id .str_set_x:N = \l_@@_solution_id_str , + for .tl_set:N = \l_@@_solution_for_tl , + height .dim_set:N = \l_@@_solution_height_dim , + creators .clist_set:N = \l_@@_solution_creators_clist , + contributors .clist_set:N = \l_@@_solution_contributors_clist , + srccite .tl_set:N = \l_@@_solution_srccite_tl +} +\cs_new_protected:Nn \_@@_solution_args:n { + \str_clear:N \l_@@_solution_id_str + \tl_clear:N \l_@@_solution_for_tl + \tl_clear:N \l_@@_solution_srccite_tl + \clist_clear:N \l_@@_solution_creators_clist + \clist_clear:N \l_@@_solution_contributors_clist + \dim_zero:N \l_@@_solution_height_dim + \keys_set:nn { problem / solution }{ #1 } +} +% \end{macrocode} +% the next step is to define a helper macro that does what is needed to start a solution. +% \begin{macrocode} +\newcommand\@startsolution[1][]{ + \_@@_solution_args:n { #1 } + \@in@omtexttrue% we are in a statement. + \bool_if:NF \c_@@_boxed_bool { \hrule } + \smallskip\noindent + {\textbf\prob@solution@kw :\enspace} + \begin{small} + \def\current@section@level{\prob@solution@kw} + \ignorespacesandpars +} +% \end{macrocode} +% +% \begin{macro}{\startsolutions} +% for the |\startsolutions| macro we use the |\specialcomment| macro from the |comment| +% package. Note that we use the |\@startsolution| macro in the start codes, that parses +% the optional argument. +% \begin{macrocode} +\newcommand\startsolutions{ + \specialcomment{solution}{\@startsolution}{ + \bool_if:NF \c_@@_boxed_bool { + \hrule\medskip + } + \end{small}% + } + \bool_if:NT \c_@@_boxed_bool { + \surroundwithmdframed{solution} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stopsolutions} +% \begin{macrocode} +\newcommand\stopsolutions{\excludecomment{solution}} +% \end{macrocode} +% \end{macro} +% +% so it only remains to start/stop solutions depending on what option was specified. +% +% \begin{macrocode} +\ifsolutions + \startsolutions +\else + \stopsolutions +\fi +% \end{macrocode} +% +% \begin{environment}{exnote} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{exnote}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@note@kw : }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{exnote} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{hint} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{hint}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@hint@kw :~ }\small + }{ + \smallskip\hrule + } + \newenvironment{exhint}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@hint@kw :~ }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{hint} + \excludecomment{exhint} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{gnote} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{gnote}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@gnote@kw : }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{gnote} +} +% \end{macrocode} +% \end{environment} +% +% \subsection{Multiple Choice Blocks}\label{sec:impl:mcq} +% +% \begin{environment}{mcb} +% \ednote{MK: maybe import something better here from a dedicated MC package} +% \begin{macrocode} +\newenvironment{mcb}{ + \begin{enumerate} +}{ + \end{enumerate} +} +% \end{macrocode} +% \end{environment} +% we define the keys for the |mcc| macro +% \begin{macrocode} +\cs_new_protected:Nn \_@@_do_yes_param:Nn { + \exp_args:Nx \str_if_eq:nnTF { \str_lowercase:n{ #2 } }{ yes }{ + \bool_set_true:N #1 + }{ + \bool_set_false:N #1 + } +} +\keys_define:nn { problem / mcc }{ + id .str_set_x:N = \l_@@_mcc_id_str , + feedback .tl_set:N = \l_@@_mcc_feedback_tl , + T .default:n = { true } , + T .bool_set:N = \l_@@_mcc_t_bool , + F .default:n = { true } , + F .bool_set:N = \l_@@_mcc_f_bool , + Ttext .code:n = { + \_@@_do_yes_param:Nn \l_@@_mcc_Ttext_bool { #1 } + } , + Ftext .code:n = { + \_@@_do_yes_param:Nn \l_@@_mcc_Ftext_bool { #1 } + } +} +\cs_new_protected:Nn \l_@@_mcc_args:n { + \str_clear:N \l_@@_mcc_id_str + \tl_clear:N \l_@@_mcc_feedback_tl + \bool_set_true:N \l_@@_mcc_t_bool + \bool_set_true:N \l_@@_mcc_f_bool + \bool_set_true:N \l_@@_mcc_Ttext_bool + \bool_set_false:N \l_@@_mcc_Ftext_bool + \keys_set:nn { problem / mcc }{ #1 } +} +% \end{macrocode} +% +% \begin{macro}{\mcc} +% \begin{macrocode} +\newcommand\mcc[2][]{ + \l_@@_mcc_args:n{ #1 } + \item #2 + \ifsolutions + \\ + \bool_if:NT \l_@@_mcc_t_bool { + % TODO! + % \ifcsstring{mcc@T}{T}{}{\mcc@Ttext}% + } + \bool_if:NT \l_@@_mcc_f_bool { + % TODO! + % \ifcsstring{mcc@F}{F}{}{\mcc@Ftext}% + } + \tl_if_empty:NTF \l_@@_mcc_feedback_tl { + ! + }{ + \l_@@_mcc_feedback_tl + } + \fi +} %solutions +% \end{macrocode} +% \end{macro} +% +% \subsection{Including Problems}\label{sec:impl:includeproblem} +% +% \begin{macro}{\includeproblem} +% The |\includeproblem| command is essentially a glorified |\input| statement, it sets +% some internal macros first that overwrite the local points. Importantly, it resets the +% |inclprob| keys after the input. +% \begin{macrocode} + +\keys_define:nn{ problem / inclproblem }{ + id .str_set_x:N = \l_@@_inclprob_id_str, + pts .tl_set:N = \l_@@_inclprob_pts_tl, + min .tl_set:N = \l_@@_inclprob_min_tl, + title .tl_set:N = \l_@@_inclprob_title_tl, + refnum .int_set:N = \l_@@_inclprob_refnum_int, + type .tl_set:N = \l_@@_inclprob_type_tl, + mhrepos .str_set_x:N = \l_@@_inclprob_mhrepos_str +} +\cs_new_protected:Nn \_@@_inclprob_args:n { + \str_clear:N \l_@@_prob_id_str + \tl_clear:N \l_@@_inclprob_pts_tl + \tl_clear:N \l_@@_inclprob_min_tl + \tl_clear:N \l_@@_inclprob_title_tl + \tl_clear:N \l_@@_inclprob_type_tl + \int_zero_new:N \l_@@_inclprob_refnum_int + \str_clear:N \l_@@_inclprob_mhrepos_str + \keys_set:nn { problem / inclproblem }{ #1 } + \tl_if_empty:NT \l_@@_inclprob_pts_tl { + \let\l_@@_inclprob_pts_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_min_tl { + \let\l_@@_inclprob_min_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_title_tl { + \let\l_@@_inclprob_title_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_type_tl { + \let\l_@@_inclprob_type_tl\undefined + } + \int_compare:nNnT \l_@@_inclprob_refnum_int = 0 { + \let\l_@@_inclprob_refnum_int\undefined + } +} + +\cs_new_protected:Nn \_@@_inclprob_clear: { + \let\l_@@_inclprob_id_str\undefined + \let\l_@@_inclprob_pts_tl\undefined + \let\l_@@_inclprob_min_tl\undefined + \let\l_@@_inclprob_title_tl\undefined + \let\l_@@_inclprob_type_tl\undefined + \let\l_@@_inclprob_refnum_int\undefined + \let\l_@@_inclprob_mhrepos_str\undefined +} +\_@@_inclprob_clear: + +\newcommand\includeproblem[2][]{ + \_@@_inclprob_args:n{ #1 } + \str_if_empty:NTF \l_@@_inclprob_mhrepos_str { + \input{#2} + }{ + \stex_in_repository:nn{\l_@@_inclprob_mhrepos_str}{ + \input{\mhpath{\l_@@_inclprob_mhrepos_str}{#2}} + } + } + \_@@_inclprob_clear: +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Reporting Metadata} +% +% For messages it is OK to have them in English as the whole documentation is, and we can +% therefore assume authors can deal with it. +% +% \begin{macrocode} +\AddToHook{enddocument}{ + \bool_if:NT \c_@@_pts_bool { + \message{Total:~\arabic{pts}~points} + } + \bool_if:NT \c_@@_min_bool { + \message{Total:~\arabic{min}~minutes} + } +} +% \end{macrocode} +% +% The margin pars are reader-visible, so we need to translate +% +% \begin{macrocode} +\def\pts#1{ + \bool_if:NT \c_@@_pts_bool { + \marginpar{#1~\prob@pt@kw} + } +} +\def\min#1{ + \bool_if:NT \c_@@_min_bool { + \marginpar{#1~\prob@min@kw} + } +} +% \end{macrocode} +% +% \begin{macro}{\show@pts} +% The |\show@pts| shows the points: if no points are given from the outside and also no +% points are given locally do nothing, else show and add. If there are outside points +% then we show them in the margin. +% \begin{macrocode} +\newcounter{pts} +\def\show@pts{ + \tl_if_exist:NTF \l_@@_inclprob_pts_tl { + \bool_if:NT \c_@@_pts_bool { + \marginpar{\l_@@_inclprob_pts_tl\ \prob@pt@kw\smallskip} + \addtocounter{pts}{\l_@@_inclprob_pts_tl} + } + }{ + \tl_if_exist:NT \l_@@_prob_pts_tl { + \bool_if:NT \c_@@_pts_bool { + \marginpar{\l_@@_prob_pts_tl\ \prob@pt@kw\smallskip} + \addtocounter{pts}{\l_@@_prob_pts_tl} + } + } + } +} +% \end{macrocode} +% \end{macro} +% and now the same for the minutes +% \begin{macro}{\show@min} +% \begin{macrocode} +\newcounter{min} +\def\show@min{ + \tl_if_exist:NTF \l_@@_inclprob_min_tl { + \bool_if:NT \c_@@_min_bool { + \marginpar{\l_@@_inclprob_pts_tl\ min} + \addtocounter{min}{\l_@@_inclprob_min_tl} + } + }{ + \tl_if_exist:NT \l_@@_prob_min_tl { + \bool_if:NT \c_@@_min_bool { + \marginpar{\l_@@_prob_min_tl\ min} + \addtocounter{min}{\l_@@_prob_min_tl} + } + } + } +} +%</package> +% \end{macrocode} +% \end{macro} +% \end{implementation} +\endinput +% LocalWords: GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal iffalse +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% \fi +% LocalWords: RequirePackage Semiverbatim DefEnvironment OptionalKeyVals soln texttt baz +% LocalWords: exnote DefConstructor inclprob NeedsTeXFormat omd.sty textbackslash exfig +% LocalWords: stopsolution fileversion filedate maketitle setcounter tocdepth newpage +% LocalWords: tableofcontents showmeta showmeta solutionstrue usepackage minipage hrule +% LocalWords: linewidth elefants.prob Elefants smallskip noindent textbf startsolutions +% LocalWords: startsolutions stopsolutions stopsolutions includeproblem includeproblem +% LocalWords: textsf HorIacJuc cscpnrr11 includemhproblem includemhproblem importmodule +% LocalWords: importmhmodule foobar ldots latexml mhcurrentrepos mh-variants mh-variant +% LocalWords: compactenum langle rangle langle rangle ltxml metakeys newif ifexnotes rm +% LocalWords: exnotesfalse exnotestrue ifhints hintsfalse hintstrue ifsolutions ifpts +% LocalWords: solutionsfalse ptsfalse ptstrue ifmin minfalse mintrue ifboxed boxedfalse +% LocalWords: boxedtrue sref mdframed marginpar prob srefaddidkey addmetakey refnum kv +% LocalWords: newcounter ifx thesection theproblem hfill newenvironment metasetkeys ltx +% LocalWords: stepcounter currentsectionlevel xspace ignorespaces surroundwithmdframed +% LocalWords: omdoc autoopen autoclose solvedinminutes kvi qw vals newcommand exhint +% LocalWords: specialcomment excludecomment mhrepos xref marginpar addtocounter doctex +% LocalWords: mh@currentrepos endinput + |