4

I'm working on a document which lists actions to expected results, in enumerated lists. Some of the actions are noteworthy, as are some of the results. I'd like the noteworthy actions' and results' labels to be listed, where noteworthyness is determined by using the starred action/result macro used when defining the actions and results, to avoid manually typesetting them. Current MWE:

\documentclass{article}

\usepackage{enumitem}
\newlist{actions}{enumerate}{1}
\setlist[actions, 1]{label=A\arabic*}
\newlist{checks}{enumerate}{1}
\setlist[checks, 1]{label=R\arabic*}

\usepackage{xparse}
\NewDocumentCommand{\action}{s m}{\IfBooleanTF #1 {\item\emph{#2}}{\item #2}}
\NewDocumentCommand{\result}{s m}{\IfBooleanTF #1 {\item\emph{#2}}{\item #2}}

\begin{document}

\subsection{First of many}

\noindent
Special actions: \textbf{A2}.\\
Special results: \textbf{A1R2, A3R2}. 

\begin{actions}
 \action{Make list references to `special' items automatically.}
 \begin{checks}
  \result{First attempt fails}
  \result*{All other attempts fail}
 \end{checks}
 \action*{Turn to google\ldots}
 \begin{checks}
  \result{Still fails, can't find the right search terms}
 \end{checks}
 \action{Post a MWE to \TeX{} SE.}
 \begin{checks}
  \result{Someone produces automagic? There's a package for that\ldots}
  \result*{Re-write the original document. Again.}
  \result{Job done}
 \end{checks}
\end{actions}
\end{document}

which produces (bold text to become automagic) : Output

What is the best approach here? My current failures involve generating labels and producing a list of them, use of imakeidx and maintaining a list of enumi/enumii as text.

A complication is that the document will contain many of these sections (~50), each subsection should only list it's own noteworthy items.

3
  • Another possibility is to create a new float type using newfloat or float, add entries to the corresponding file extension with \addcontentsline and use the provided \listof variant. Jul 27, 2020 at 12:35
  • Are the special actions/results printed at the start of every subsection, at the start of every section, or at the start of the document? It wouldn't be that hard to create a LaTeX3 sequence of actions and results, save them in the aux file and then read them back in. It's just a question of how often you need to save the data.
    – user30471
    Jul 27, 2020 at 12:58
  • @Andrew In the full document, these specials are printed in their own subsubsection, before the subsubsection that contains the full list. The full doc is strictly structured, as its put together with macros, so there are already places where additional setup/teardown could be done. Any examples/tips on where to start with LaTeX3?
    – aejh
    Jul 27, 2020 at 13:13

2 Answers 2

2

Here is a prototype. The idea is to save the special actions and results into LaTeX3 sequences \g_actions_seq and \g_results_seq and each time a subsection starts these are saved to the aux file as entries of the form

\SetActionResult{actions}{0.1}{{{A2}}}
\SetActionResult{results}{0.1}{{{A1}}{{R2}},{{A3}}{{R2}}}

When the aux file is read in, the \SetActionResult command stores this data into two property lists, \g_special_actions_prop and \g_special_results_prop for actions and results. At the start of each subsection if the property lists contain keys for the current subsection then this information is automatically printed. With this in place, your MWE produces:

enter image description here

I left the hard-coded lists of special actions and results in the file for comparison.

Here is the code:

\documentclass{article}

\usepackage{enumitem}
\newlist{actions}{enumerate}{1}
\setlist[actions, 1]{label=A\arabic*}
\newlist{checks}{enumerate}{1}
\setlist[checks, 1]{label=R\arabic*}

\usepackage{xparse}
\usepackage{expl3}
\ExplSyntaxOn
\prop_new:N \g_special_actions_prop
\prop_new:N \g_special_results_prop
\seq_new:N \g_actions_seq
\seq_new:N \g_results_seq

\NewDocumentCommand\action{ sm }
{
\item 
  \IfBooleanTF{#1}
    { \emph{#2}\seq_gput_right:Nx \g_actions_seq {\theactionsi} }
    { #2 }
}

\NewDocumentCommand\result{ sm }
{
\item 
  \IfBooleanTF{#1}
    { \emph{#2}
      \seq_gput_right:Nx \g_results_seq {\theactionsi\thechecksi} }
    { #2 }
}

\NewDocumentCommand\SetActionResult{mmm}
{ 
   \prop_gput:cnn {g_special_#1_prop} {#2} {#3} 
}

\NewDocumentCommand\SaveActionsResults{}{
  % save special actions and results to the aux file
  \seq_if_empty:NF \g_actions_seq
  {
    \iow_now:cx { @auxout }
    {
      \token_to_str:N\SetActionResult {actions} 
        { \thesubsection }{\seq_use:Nn \g_actions_seq {,~}}
    }
    \seq_gclear:N \g_actions_seq
  }
  \seq_if_empty:NF \g_results_seq
  {
    \iow_now:cx { @auxout }
    {
      \token_to_str:N\SetActionResult {results} 
         { \thesubsection }{\seq_use:Nn \g_results_seq {,~}}
    }
    \seq_gclear:N \g_results_seq
  }
}

\NewDocumentCommand\Subsection{ m }
{
  \SaveActionsResults
  \subsection{ #1 }
  % print all known special results and actions
  \prop_if_in:NxT \g_special_actions_prop {\thesubsection} {
    \prop_get:NxN \g_special_actions_prop {\thesubsection} \l_tmpa_tl
    \noindent Special~actions:~\tl_use:N \l_tmpa_tl.
    \newline
    }
  \prop_if_in:NxT \g_special_results_prop {\thesubsection} {
    \prop_get:NxN \g_special_results_prop {\thesubsection} \l_tmpa_tl
    \noindent Special~results:~\tl_use:N \l_tmpa_tl.
    \newline
  }
}
\cs_generate_variant:Nn \prop_if_in:NnT {NxT}
\cs_generate_variant:Nn \prop_get:NnN {NxN}
\ExplSyntaxOff

\begin{document}

\Subsection{First of many}

\noindent
Special actions: \textbf{A2}.\\
Special results: \textbf{A1R2, A3R2}.

\begin{actions}
 \action{Make list references to `special' items automatically.}
 \begin{checks}
  \result{First attempt fails}
  \result*{All other attempts fail}
 \end{checks}
 \action*{Turn to google\ldots}
 \begin{checks}
  \result{Still fails, can't find the right search terms}
 \end{checks}
 \action{Post a MWE to \TeX{} SE.}
 \begin{checks}
  \result{Someone produces automagic? There's a package for that\ldots}
  \result*{Re-write the original document. Again.}
  \result{Job done}
 \end{checks}
\end{actions}

% save the data from the last subsection
\SaveActionsResults
\end{document}

At the risk of obfuscation, the code could be rationalised slightly because the actions and results are treated in almost exactly the same way. For example, the \SetActionResult command shows how to combine the action and result code branches into one function.

LaTeX3 takes a little bit of getting used to but after a while you grow to like it as it is very powerful. The best place that I have found to learn about it is by typing texdoc interface3.

1
  • Thanks for this - very useful. It has integrated well into the existing document. For anyone doing similar, the after option to setlist can be used to call \SaveActionResults. Hyperlinks, as provided by the Ulrich's answer, can be added with \seq_gput_right:Nx \g_actions_seq {\exp_not:N \hyperlink {\@currentHref}{\theactionsi}}.
    – aejh
    Jul 30, 2020 at 15:54
2

You can use the datatool-package for maintaining a database with your special things.

Then you can use datatool-macros for iterating the database and "filtering" entries for "spitting out" desired lists.

In the example below actually two databases are used.

One database is written to. That database at the end of the LaTeX-run gets saved to external file. That database is named specialthingsinterim.

The other database stems from the previous LaTeX-run/from the external file saved in the previous LaTeX-run and is used for iterating and printing lists etc. That database is named specialthings.

This way you can both write to database and use the database at the same time.

But you need to compile the document at least twice.

\documentclass{article}
\usepackage{hyperref}
\usepackage{datatool}
\usepackage{atveryend}

\makeatletter
\newcommand\DATABASEFILECreateIfNotExistent[1]{%
  \DTLifdbexists{#1}{}{%
    \IfFileExists{\jobname.#1}{%
      \DTLloaddb{#1}{\jobname.#1}%
    }{%
      \DTLnewdb{#1}%
    }%
  }%
  \DTLifdbexists{#1interim}{}{%
    \DTLnewdb{#1interim}%
    \AtEndDocument{%
      % This will save the interim-database to file with
      % the last \shipout. The last \shipout is triggered
      % by \end{document}/\enddocument.
      \DTLsavedb{#1interim}{\jobname.#1}%
    }%
    \AfterLastShipout{%
      % Check if content of database-token-register stemming from
      % database-file of previous LaTeX-run differs from content of
      % database-token-register stemming from database-file of 
      % the current LaTeX-run.
      % If so, something changed and you need to re-run LaTeX.
      % Probably this should be omitted with large databases.
      \begingroup
      \DTLgdeletedb{#1interim}%
      \DTLloaddb{#1interim}{\jobname.#1}%
      \edef\tempa{\the\csname dtldb@#1\endcsname}%
      \edef\tempb{\the\csname dtldb@#1interim\endcsname}%
      \ifx\tempa\tempb
        \endgroup
      \else
        \endgroup
        \@latex@warning@no@line{%
           Database `#1' may have changed.
           Rerun to get listings of entries etc right%
         }%
      \fi
    }%
  }%
}%
%-------------------------------------------------------------------------
\newcommand\SpecialThingsCount{0}%
\newcommand\AddSpecialThingToDatabase{%
  \@bsphack
  \xdef\SpecialThingsCount{\number\numexpr\SpecialThingsCount+1\relax}%
  \DATABASEFILECreateIfNotExistent{specialthings}%
  \DTLnewrow{specialthingsinterim}%
  {%
    \dtlexpandnewvalue
    \DTLnewdbentry{specialthingsinterim}{PrimaryKey}{\SpecialThingsCount}%
    \DTLnewdbentry{specialthingsinterim}{Subsection}{\thesubsection}%
    \DTLnewdbentry{specialthingsinterim}{HSubsection}{\theHsubsection}%
    \DTLnewdbentry{specialthingsinterim}{Environment}{\@currenvir}%
    \DTLnewdbentry{specialthingsinterim}{Itemnumber}{\@currentlabel}%
    \DTLnewdbentry{specialthingsinterim}{Superordinateitemnumber}{\previouscurrentlabel}%
    \DTLnewdbentry{specialthingsinterim}{Destinationname}{\@currentHref}%
  }%
  \@esphack
}%

\newcommand\exchange[2]{#2#1}%
\newcommand\previouscurrentlabel{}%

\newcommand\ListOfSpecialThingsSeparator{}%
\newcommand\ListOfSpecialThings[2]{%
  \xdef\ListOfSpecialThingsSeparator{}%
  \DATABASEFILECreateIfNotExistent{specialthings}%
  \DTLforeach{specialthings}{%
    \PrimaryKeyField=PrimaryKey,
    \SubsectionField=Subsection,
    \HSubsectionField=HSubsection,
    \EnvironmentField=Environment,
    \ItemnumberField=Itemnumber,
    \SuperordinateitemnumberField=Superordinateitemnumber,
    \Destinationnamefield=Destinationname%
  }{%
    \begingroup
    \edef\@tempa{\HSubsectionField}%
    \edef\@tempb{#2}%
    \ifx\@tempa\@tempb\expandafter\@firstofone\else\expandafter\@secondoftwo\fi
    {%
      \edef\@tempa{\EnvironmentField}%
      \def\@tempb{#1}%
      \ifx\@tempa\@tempb\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
      {%
        \def\@tempa{checks}%
        \ifx\@tempa\@tempb\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
        {\exchange{\hyperlink{\Destinationnamefield}{\textbf{\SuperordinateitemnumberField\ItemnumberField}}}}%
        {\exchange{\hyperlink{\Destinationnamefield}{\textbf{\ItemnumberField}}}}%
        {%
          \endgroup
          \ListOfSpecialThingsSeparator
        }%
        \xdef\ListOfSpecialThingsSeparator{, }%
      }%
    }%
    {\endgroup}%
   }%
}%
\newcommand\ListOfSpecialActions{\ListOfSpecialThings{actions}{\theHsubsection}}%
\newcommand\ListOfSpecialChecks{\ListOfSpecialThings{checks}{\theHsubsection}}%


\usepackage{enumitem}
\newlist{actions}{enumerate}{1}
\setlist[actions, 1]{label=A\arabic*, before*={\def\previouscurrentlabel{}}}
\newlist{checks}{enumerate}{1}
\setlist[checks, 1]{label=R\arabic*,  before*={\let\previouscurrentlabel=\@currentlabel}}

\newcommand*{\SpecialThingItem}{\item\@ifstar{\AddSpecialThingToDatabase\emph}{}}

\newcommand*{\action}{\SpecialThingItem}
\newcommand*{\result}{\SpecialThingItem}

\makeatother

\begin{document}

\subsection{First of many}

\noindent
Special actions: \ListOfSpecialActions.\\
Special results: \ListOfSpecialChecks. 

\begin{actions}
 \action{Make list references to `special' items automatically.}
 \begin{checks}
  \result{First attempt fails}
  \result*{All other attempts fail}
 \end{checks}
 \action*{Turn to google\ldots}
 \begin{checks}
  \result{Still fails, can't find the right search terms}
 \end{checks}
 \action{Post a MWE to \TeX{} SE.}
 \begin{checks}
  \result{Someone produces automagic? There's a package for that\ldots}
  \result*{Re-write the original document. Again.}
  \result{Job done}
 \end{checks}
\end{actions}


\subsection{Second of many}

\noindent
Special actions: \ListOfSpecialActions.\\
Special results: \ListOfSpecialChecks. 

\begin{actions}
 \action*{Make list references to `special' items automatically.}
 \begin{checks}
  \result{First attempt fails}
  \result{Second attempt fails}
  \result{Third attempt fails}
  \result*{All other attempts fail}
 \end{checks}
 \action{Turn to google\ldots}
 \begin{checks}
  \result*{Still fails, can't find the right search terms}
 \end{checks}
 \action*{Post a MWE to \TeX{} SE.}
 \begin{checks}
  \result{Someone produces automagic? There's a package for that\ldots}
  \result{Re-write the original document. Again.}
  \result*{Job done}
 \end{checks}
\end{actions}

\end{document}

enter image description here

2
  • Thanks for this tip on the datatool package, and how to use \@currentHref.
    – aejh
    Jul 30, 2020 at 15:58
  • You are welcome. ;-) (Usually \@currentHref holds the name of the destination which was placed into the .pdf-file as the last one so far due to \refstepcounter... \item also triggers placement of a destination and updating of \@currentHref...) Jul 30, 2020 at 15:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .