2

Following up this answer to my previous question, I have the following problems to fix:

1- If the answers option is disabled, I need setting twofilestrue to generate only the exam without the solution.

2- When using lualatex (i.e. \latexmkiffalse) and the option answers is enabled, I can't generate any pdf file. It goes into an endless compilation loop.

\documentclass{exam}
\usepackage{expl3}

\newif\iftwofiles
\twofilesfalse% false to print one file , true for both at a time

\newif\iflatexmkif
\latexmkiffalse% true to use latexmk , false to use lualatex

\ExplSyntaxOn

\str_new:N \g__diaa_solved_jobname_str

\iflatexmkif
    \str_new:N \l__diaa_latexmk_engine_str
    \str_const:Nn \l__diaa_latexmk { latexmk }
\else
    \str_const:Nn \l__diaa_latex_cmd { lualatex }
    \str_const:Nn \l__diaa_latex_options { -synctex=1 ~ -interaction=nonstopmode ~ -shell-escape }
\fi

\cs_new:Nn \__diaa_build_solved_jobname:
{
\str_gset:Nx \g__diaa_solved_jobname_str { \c_sys_jobname_str }
\str_gremove_all:Nn \g__diaa_solved_jobname_str { " }
\str_gput_left:Nn \g__diaa_solved_jobname_str { "[solved]~ }
\str_gput_right:Nn \g__diaa_solved_jobname_str { " }
}

\sys_if_shell_unrestricted:T
{
    \iflatexmkif

        \sys_if_engine_luatex:T
        { \str_set:Nn \l__diaa_latexmk_engine_str { -lualatex ~ -g ~ -interaction=nonstopmode } }
        \sys_if_engine_pdftex:T
        { \str_set:Nn \l__diaa_latexmk_engine_str { -pdf } }
        \sys_if_engine_xetex:T
        { \str_set:Nn \l__diaa_latexmk_engine_str { -xelatex } }

        \iftwofiles

            \__diaa_build_solved_jobname:
            \sys_shell_now:x
            {% printing the solution
                \l__diaa_latexmk \c_space_tl
                \l__diaa_latexmk_engine_str \c_space_tl
                -usepretex="\string\AtBeginDocument{\string\printanswerstrue}" \c_space_tl
                -jobname=\g__diaa_solved_jobname_str \c_space_tl
                \c_sys_jobname_str
            }
            \sys_shell_now:x
            {% printing the exam
                \l__diaa_latexmk \c_space_tl
                \l__diaa_latexmk_engine_str \c_space_tl
                -usepretex="\string\AtBeginDocument{\string\printanswersfalse}" \c_space_tl
                \c_sys_jobname_str
            }
            \stop

        \else % one file

            \legacy_if:nT { printanswers }
            {
                \__diaa_build_solved_jobname:
                \sys_shell_now:x
                {
                    \l__diaa_latexmk \c_space_tl
                    \l__diaa_latexmk_engine_str \c_space_tl
                    -jobname=\g__diaa_solved_jobname_str \c_space_tl
                    \c_sys_jobname_str
                }
                \stop
            }
        \fi

    \else % lualatex

        \iftwofiles

            \__diaa_build_solved_jobname:
            \sys_shell_now:x
            {% printing the solution
                \l__diaa_latex_cmd \c_space_tl
                -jobname=\g__diaa_solved_jobname_str \c_space_tl
                \l__diaa_latex_options \c_space_tl
                "\string\AtBeginDocument{\string\printanswerstrue}" \c_space_tl
                "\string\input{\c_sys_jobname_str}"
            }
            \sys_shell_now:x
            {% printing the exam
                \l__diaa_latex_cmd \c_space_tl
                -jobname=\c_sys_jobname_str \c_space_tl
                \l__diaa_latex_options \c_space_tl
                "\string\AtBeginDocument{\string\printanswersfalse}" \c_space_tl
                "\string\input{\c_sys_jobname_str}"
            }
            \stop

        \else % one file

            \legacy_if:nT { printanswers } % if answers is enabled
            {
                \__diaa_build_solved_jobname:
                \sys_shell_now:x
                {
                    \l__diaa_latex_cmd \c_space_tl
                    \l__diaa_latex_options \c_space_tl
                    -jobname=\g__diaa_solved_jobname_str \c_space_tl
                    \c_sys_jobname_str
                }
                \stop
            }
        \fi
    \fi
}

\ExplSyntaxOff

\begin{document}
    \begin{questions}
        \question some question
        \begin{solution}
            the solution
        \end{solution}
    \end{questions}
\end{document}
1
  • For future readers, you may need to check this if you would like to know how to create a TeXStudio command that opens the output PDF file with different name from that of the original tex file (i.e. \jobname).
    – Diaa
    May 29, 2020 at 4:39

1 Answer 1

1

You got an infinite loop because you passed -shell-escape to lualatex when building through \sys_shell_now:x. So the \sys_if_shell_unrestricted:T test passes and you again run lualatex.

If I understand you right the following MWE will do what you want.

If the class answers option is not specified, then only the questions are produced, regardless of whether you call the initial build with -shell-escape. You can override this by uncommenting \bool_gset_true:N \g__diaa_build_two_files_bool, in which case questions and answers will always be produced.

When compiling with -shell-escape, the build will use whatever engine you initiate the compile with (pdflatex, lualatex, xelatex).

You can use latexmk for the build by uncommenting \bool_gset_true:N \g__diaa_use_latexmk_bool (assuming you also initiate the build with with the -shell-escape flag).

Update

You can now:

  • control output of questions using \g__diaa_build_questions_bool.
  • control output of answers using \g__diaa_build_solved_bool.
  • specify options for both LaTeX and Latexmk using \g__diaa_latex_options_str and \g__diaa_latexmk_options_str respectively.
  • control whether Latexmk is used using \g__diaa_use_latexmk_bool.

To ensure that synctex data is correctly written you will need the options -synctex=1 -output-directory=out. This ensures that files are not overwritten by the main compiling process.

MWE

\documentclass[answers]{exam}

\usepackage{expl3}

\ExplSyntaxOn

% Flag to enable Latexmk
\bool_new:N \g__diaa_use_latexmk_bool

% Uncomment the following line to use Latexmk
%\bool_gset_true:N \g__diaa_use_latexmk_bool


% Flag to output questions and/or answers
\bool_new:N \g__diaa_build_questions_bool
\bool_new:N \g__diaa_build_solved_bool

% Always build questions
\bool_gset_true:N \g__diaa_build_questions_bool

% Build answers if class answers option is set
\legacy_if:nT { printanswers }
  {
    \bool_gset_true:N \g__diaa_build_solved_bool
  }

% Uncomment the following line to not build questions
%\bool_gset_false:N \g__diaa_build_questions_bool

% Uncomment the following line to always build answers even if class answers option is not set
%\bool_gset_true:N \g__diaa_build_solved_bool


% Answers jobname variable
\str_new:N \g__diaa_solved_jobname_str

% LaTeX engine and options variables
\str_new:N \g__diaa_latex_cmd_str
\str_const:Nn \g__diaa_latex_options_str { -synctex=1 ~ -output-directory=out ~ -interaction=nonstopmode }

% Latexmk engine and options variables
\str_const:Nn \g__diaa_latexmk_str { latexmk }
\str_const:Nn \g__diaa_latexmk_options_str { -synctex=1 ~ -output-directory=out }
\str_new:N \g__diaa_latexmk_engine_str

% Final build commands
\str_new:N \g__diaa_cmd_questions_str
\str_new:N \g__diaa_cmd_solved_str


% Build the answer jobname
\cs_new:Nn \__diaa_build_solved_jobname:
  {
    \str_gset:Nx \g__diaa_solved_jobname_str { \c_sys_jobname_str }
    \str_gremove_all:Nn \g__diaa_solved_jobname_str { " }
    \str_gput_left:Nn \g__diaa_solved_jobname_str { " }
    \str_gput_right:Nn \g__diaa_solved_jobname_str { ~[solved]" }
  }

% Set engines based on current engine
\cs_new:Nn \__diaa_set_engine:
  {
    \sys_if_engine_luatex:T
      {
        \str_gset:Nn \g__diaa_latex_cmd_str { lualatex }
        \str_gset:Nn \g__diaa_latexmk_engine_str { -lualatex }
      }
    \sys_if_engine_pdftex:T
      {
        \str_gset:Nn \g__diaa_latex_cmd_str { pdflatex }
        \str_gset:Nn \g__diaa_latexmk_engine_str { -pdf }
      }
    \sys_if_engine_xetex:T
      {
        \str_gset:Nn \g__diaa_latex_cmd_str { xelatex }
        \str_gset:Nn \g__diaa_latexmk_engine_str { -xelatex }
      }
  }

% Build LaTeX questions command
\cs_new:Nn \__diaa_build_latex_questions_cmd:
  {
    \str_gset:Nx \g__diaa_cmd_questions_str
      {
        \g__diaa_latex_cmd_str \c_space_tl
        -jobname=\c_sys_jobname_str \c_space_tl
        \g__diaa_latex_options_str \c_space_tl
        "\string\AtBeginDocument{\string\printanswersfalse}" \c_space_tl
        "\string\input{\c_sys_jobname_str}"
      }
  }

% Build LaTeX answers command
\cs_new:Nn \__diaa_build_latex_solved_cmd:
  {
    \str_gset:Nx \g__diaa_cmd_solved_str
      {
        \g__diaa_latex_cmd_str \c_space_tl
        -jobname=\g__diaa_solved_jobname_str \c_space_tl
        \g__diaa_latex_options_str \c_space_tl
        "\string\AtBeginDocument{\string\printanswerstrue}" \c_space_tl
        "\string\input{\c_sys_jobname_str}"
      }
  }

% Build Latexmk questions command
\cs_new:Nn \__diaa_build_latexmk_questions_cmd:
  {
    \str_gset:Nx \g__diaa_cmd_questions_str
      {
        \g__diaa_latexmk_str \c_space_tl
        \g__diaa_latexmk_engine_str \c_space_tl
        \g__diaa_latexmk_options_str \c_space_tl
        -usepretex="\string\AtBeginDocument{\string\printanswersfalse}" \c_space_tl
        \c_sys_jobname_str
      }
  }

% Build Latexmk answers command
\cs_new:Nn \__diaa_build_latexmk_solved_cmd:
  {
    \str_gset:Nx \g__diaa_cmd_solved_str
      {
        \g__diaa_latexmk_str \c_space_tl
        \g__diaa_latexmk_engine_str \c_space_tl
        \g__diaa_latexmk_options_str \c_space_tl
        -usepretex="\string\AtBeginDocument{\string\printanswerstrue}" \c_space_tl
        -jobname=\g__diaa_solved_jobname_str \c_space_tl
        \c_sys_jobname_str
      }
  }


% Build the files
\sys_if_shell_unrestricted:T
  {
    % Set up engines
    \__diaa_set_engine:

    % Build answers jobname
    \__diaa_build_solved_jobname:

    % Set up compile commands
    \bool_if:NTF \g__diaa_use_latexmk_bool
      {
        \__diaa_build_latexmk_questions_cmd:
        \__diaa_build_latexmk_solved_cmd:
      }
      {
        \__diaa_build_latex_questions_cmd:
        \__diaa_build_latex_solved_cmd:
      }

    % Build questions
    \bool_if:NT \g__diaa_build_questions_bool
      {
        \sys_shell_now:x
          {
            \str_use:N \g__diaa_cmd_questions_str
          }
      }

    % Build answers
    \bool_if:NT \g__diaa_build_solved_bool
      {
        \sys_shell_now:x
          {
            \str_use:N \g__diaa_cmd_solved_str
          }
      }
    \stop
  }

\ExplSyntaxOff

\begin{document}
\begin{questions}
  \question One of these things is not like the others; one of these things is
  not the same. Which one is different?
  \begin{oneparchoices}
    \choice John
    \choice Paul
    \choice George
    \choice Ringo
    \CorrectChoice Socrates
  \end{oneparchoices}
\end{questions}
\end{document}
21
  • I highly appreciate the effort you put into making such a well constructed and informative answer. Thanks again for your time and consideration.
    – Diaa
    Apr 22, 2020 at 10:35
  • How can I make this document print only the solution without the questions-only file? and I need this behavior for both latexmk and lualatex. Thanks in advance.
    – Diaa
    Apr 22, 2020 at 11:04
  • Another issue; when setting \g__diaa_latex_options {-synctex=1} and \g__diaa_latexmk_engine_str { -lualatex ~ -synctex=1}, I have an error SyncTeX: Can't rename <file name>.synctex(busy) to <file name>.synctex.gz since I appended to the compiler command (e.g. lualatex) the option -synctex=1 in my texstudio settings. So, is there a way to keep my texstudio command as it is and avoid this conflict of applying synctex?
    – Diaa
    Apr 22, 2020 at 11:12
  • 1
    Let us continue this discussion in chat. Apr 23, 2020 at 5:35
  • 1
    Sorry, I use Linux not windows. You would be better asking a new question. Oct 9, 2020 at 22:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.