2

I am trying to create a mechanism to know whether or not the number of times a command is repeated in an enumerate environment is present.

As an example, using the \dummy command, this would be a valid entry:

\begin{enumerate}
  \item Level 1 \dummy{1} OK
  \item Level 1 \dummy{2} OK
\end{enumerate}

And an invalid entry would be:

\begin{enumerate}
  \item Level 1 \dummy{1} OK
  \item Level 1 NO dummy here.
\end{enumerate}

As the environment can be nested, a valid entry can take the following form:

\begin{enumerate}
  \item Level 1 \dummy{1} OK
  \item Level 1 NO dummy here, dummy in next level
    \begin{enumerate}
      % Start level 2
      \item Level 2 \dummy{2} OK
      \item Level 2 NO dummy here, dummy in next level
        \begin{enumerate}
          % Start level 3
          \item Level 3 \dummy{3} OK
          \item Level 3 NO dummy here, dummy in next level
            \begin{enumerate}
              % Start level 4
              \item Level 4 \dummy{4} OK
              \item Level 4 \dummy{5} OK
            \end{enumerate}
          \item Level 3 \dummy{6} OK
        \end{enumerate}
      \item Level 2 \dummy{7} OK
    \end{enumerate}
  \item Level 1 \dummy{8} OK
\end{enumerate}

With the next MWE I would expect the final output to be { TRUE }

\documentclass{article}
\ExplSyntaxOn
% Copy macros
\cs_new_eq:NN \_enumerate_start: \enumerate
\cs_new_eq:NN \_enumerate_stop: \endenumerate
\NewCommandCopy{ \_item_std }{ \item }

% Vars
\int_new:N \g_enumerate_level_int
\int_new:N \g_enumerate_item_int

% Redefine enumerate
\RenewDocumentEnvironment{enumerate}{ }
  {
    \int_gincr:N \g_enumerate_level_int
    \_redefine_item:
    \_enumerate_start:
  }
  {
    \_enumerate_stop:
    \int_compare:nTF { \g_enumerate_level_int = \g_enumerate_item_int }
      { TRUE }{ FALSE }
  }

% Redefine \item
\cs_new_protected:Npn \_redefine_item:
  {
    \RenewDocumentCommand\item{ o }
      {
        \int_gincr:N \g_enumerate_item_int
        %\int_compare:nT { \g_enumerate_level_int > 1 }
          %{
            %\int_gsub:Nn \g_enumerate_item_int { 1 }
          %}
        \tl_if_novalue:nTF {##1}
          {
            \_item_std%[Item ~ \int_use:N \g_enumerate_item_int]
          }
          { \_item_std[##1] }
      }
  }

\NewDocumentCommand\dummy{ m }
  {
    \int_gincr:N \g_tmpb_int
    \texttt{dummy~#1~=~\int_use:N \g_tmpb_int}
  }
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
  \item Level 1 \dummy{1} OK % \g_enumerate_item_int = 1
  \item Level 1 NO dummy here, dummy in next level
    \begin{enumerate}
      % Start level 2
      \item Level 2 \dummy{2} OK % \g_enumerate_item_int = 2
      \item Level 2 NO dummy here, dummy in next level
        \begin{enumerate}
          % Start level 3
          \item Level 3 \dummy{3} OK % \g_enumerate_item_int = 3
          \item Level 3 NO dummy here, dummy in next level
            \begin{enumerate}
              % Start level 4
              \item Level 4 \dummy{4} OK % \g_enumerate_item_int = 4
              \item Level 4 \dummy{5} OK % \g_enumerate_item_int = 5
            \end{enumerate}
          \item Level 3 \dummy{6} OK % \g_enumerate_item_int = 6
        \end{enumerate}
      \item Level 2 \dummy{7} OK % \g_enumerate_item_int = 7
    \end{enumerate}
  \item Level 1 \dummy{8} OK % \g_enumerate_item_int = 8
\end{enumerate}
\end{document}

How can I achieve this?

The real context is a question/answer list and the idea is to check that each question has an answer.

If the line starts with an \item and does not open a nested environment it must have a \dummy, if the line starts with an \item and opens a nested environment, each \item in the nested environment must have a \dummy.

0

2 Answers 2

1

Here is a tokcycle approach, where you wrap your outer environment in \needdummytrue\tokencyclexpress...\endtokencyclexpress. It analyzes the ... in advance before executing it, and inserts (MISSING) into the environment if a \dummy was supposed to have appeared on that \item but didn't, or an (XTRA) if a \dummy appeared where it was not expected.

By removing the wrapper, the test goes away and the environment executes normally.

While this MWE does not analyze the "valid form" provided by the OP, this approach was run with that input and does not detect any errors, as expected.

\documentclass{article}
\usepackage{tokcycle}
\def\dummy{DD}
\newif\ifneeddummy
\Macrodirective{%
  \ifx\item#1\ifneeddummy\addcytoks{(MISSING)}\else\needdummytrue\fi\fi
  \ifx\end#1\ifneeddummy\addcytoks{(MISSING)}\fi\fi
  \ifx\dummy#1\ifneeddummy\needdummyfalse\else\addcytoks{(XTRA)}\fi\fi
  \ifx\begin#1\ifneeddummy\needdummyfalse\else\addcytoks{(XTRA)}\fi\fi
  \addcytoks{#1}%
}
\begin{document}
\needdummytrue\tokencyclexpress
\begin{itemize}
\item \dummy
\item no dummy
  \begin{enumerate}
  \item \dummy
  \item no dummy
  \item \dummy
  \end{enumerate}
\item \dummy \dummy
\item \dummy
  \begin{enumerate}
  \item \dummy
  \end{enumerate}
\end{itemize}
\endtokencyclexpress
\end{document}

enter image description here

If I comment out the wrapper lines, I get the same output with the diagnostic messages removed. Of course, the output may contain errors, if the warnings of running the diagnostic were not heeded.

enter image description here

0

Possible solution (has not failed my tests) and fits what I need :)

\documentclass{article}
\ExplSyntaxOn
% Copy macros
\cs_new_eq:NN \_enumerate_start: \enumerate
\cs_new_eq:NN \_enumerate_stop: \endenumerate
\NewCommandCopy{ \_item_std }{ \item }

% Vars
\int_new:N \g_enumerate_tempa_int
\int_new:N \g_enumerate_tempb_int
\int_new:N \g_enumerate_tempc_int
\int_new:N \l_enumerate_level_int
\int_new:N \g_enumerate_count_item_all_int

% Redefine enumerate
\RenewDocumentEnvironment{enumerate}{ }
  {
    \int_incr:N \l_enumerate_level_int
    \_enumerate_start:
    \_redefine_item:
    \int_case:nn{ \l_enumerate_level_int }
      {
        { 2 }{ \int_gincr:N \g_enumerate_tempa_int }
        { 3 }{ \int_gincr:N \g_enumerate_tempb_int }
        { 4 }{ \int_gincr:N \g_enumerate_tempc_int }
      }
  }
  { \_enumerate_stop: }

% Redefine \item
\cs_new_protected:Npn \_redefine_item:
  {
    \RenewDocumentCommand\item{ o }
      {
        \int_gincr:N \g_enumerate_count_item_all_int
        \tl_if_novalue:nTF {##1} { \_item_std } { \_item_std[##1] }
      }
  }

\NewDocumentCommand\dummy{ m }
  {
    \int_gincr:N \g_tmpb_int
    \texttt{dummy~#1~=~\int_use:N \g_tmpb_int}
  }
\NewDocumentCommand\test{ }
  {
   \int_gset:Nn \g_tmpa_int
     {
        \g_enumerate_count_item_all_int - \g_enumerate_tempa_int
      - \g_enumerate_tempb_int - \g_enumerate_tempc_int
     }
   % \int_show:N \g_tmpa_int
    \int_compare:nTF { \g_tmpa_int = \g_tmpb_int }
      { \typeout{TRUE}  }{ \typeout{FALSE} }
  }
\ExplSyntaxOff
\begin{document}

\begin{enumerate}
  \item Level 1 \dummy{1}
  \item Level 1 NO dummy
    \begin{enumerate}
      \item Level 2 \dummy{2}
      \item Level 2 NO dummy
        \begin{enumerate}
          \item Level 3 \dummy{3}
          \item Level 3 NO dummy
            \begin{enumerate}
              \item Level 4 \dummy{4}
              \item Level 4 \dummy{5}
            \end{enumerate}
          \item Level 3 \dummy{6}
        \end{enumerate}
      \item Level 2 NO dummy
        \begin{enumerate}
          \item Level 3 \dummy{7}
          \item Level 3 NO dummy
            \begin{enumerate}
              \item Level 4 \dummy{8}
              \item Level 4 \dummy{9}
            \end{enumerate}
          \item Level 3 \dummy{10}
        \end{enumerate}
      \item Level 2 \dummy{11}
    \end{enumerate}
  \item Level 1 \dummy{12}
  \item Level 1 \dummy{13}
  \item Level 1 NO dummy
    \begin{enumerate}
      \item Level 2 \dummy{14}
      \item Level 2 NO dummy
         \begin{enumerate}
           \item Level 3 \dummy{15}
          \end{enumerate}
       \item Level 2 \dummy{16}
     \end{enumerate}
\end{enumerate}

% TRUE
\test

\end{document}

You must log in to answer this question.

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