3

I want to create a command that display a given LaTeX code and its formatted output. So far I've noticed that the showexpl packages does a good job, since you can use those styles that have been defined through the \lstdefinestyle{} command from the listings package and some other reasons.

The problem

Now, drawing on the accepted answers from the following questions

I have created the following command

\usepackage{showexpl}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\LTXIO}{+v}{
  \exp_args:Nx \scantokens
  {
        \string\LTXexample[\unexpanded{pos=b, numbers=none, basicstyle=\ttfamily}]
            #1
    \string\endLTXexample
  }
}
\ExplSyntaxOff

which can be used as it follows

\LTXIO
{
    \Huge{another}
    \\\scriptsize{another}
}

enter image description here

However, the created command shows a compilation error when the command to be tested is written into a single line (e.g. \LTXIO{\Huge{another}}). The compilation error that is showed is

Package Listings Warning: Text dropped after begin of listing on input line 1.

So, the question is How can I make the LTXIO command to process single and multiple lines?

  • 1
    not really related to the question but the example is showing misused size commands, which do not take an argument. – David Carlisle Dec 11 '19 at 18:28
3

The problem has three aspects:

Aspect 1:

\scantokens pretends to write things unexpanded to external text file and then to input that external text file whereby the content of that external text file gets tokenized under the current category-code-régime.

+v-arguments encode line-endings as ^^M-characters of category-code 12(other)=carriage-return-characters of category-code 12(other) while at the time of carrying out \scantokens the value of the integer-parameter \newlinechar still denotes the character ^^J=the linefeed-character.

You need to make sure that \newlinechar's value denotes the ^^M-character=the carriage-return-character at the time when \scantokens does its faking of unexpanded-writing things to external file.

Aspect 2:

In case code is in a single line, there must be a linebreak between the call to \begin{LTXexample}[...] and the first line of code.
There must also be a linebreak between the last line of code and \end{LTXexample}.

So you need a routine for detecting whether the code sequence is enclosed by linebreaks or not.

This can be implemented in the same way as checks for leading and trailing spaces. Instead about space-tokens it is about ^^M-character-tokens of category-code 12(other)=carriage-return-character-tokens of category-code 12(other), that's all.

Detecting leading and trailing spaces is discussed in Michael Downes' Around-the-Bend-answer 15. (Exercise 15 is about writing macros for trimming leading and trailing spaces from macro arguments.)

Peter Wilson created a nicely formatted pdf-file with all Around-the-Bend-exercises and -answers.

Aspect 3:

The treatment of indenting of lines.

The argument of \LTXIO can contain several lines of code.

How shall indenting of such code be treated?

In the example below, such indenting is left as is.

\documentclass{article}
\usepackage{xparse}
\usepackage{showexpl}

\makeatletter
%%=============================================================================
%% Work around showexpl's weird overriding of xleftmargim/xrightmargin in case
%% of having no codeline-numbers -- that weirdness is in \SX@codeInput.
%%=============================================================================
\lst@Key{nocodelinenumbers}{false}[true]{%
    \lstKV@SwitchCases{#1}{%
       false:\\%
       true:\long\def\lst@PlaceNumber{}%
     }{\PackageError{Listings}{nocodelinenumbers #1 unknown}\@ehc}%
}%
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\if\relax\detokenize{#1}\relax
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\@firstoftwo{\expandafter}{} \@firstoftwo}%
  {\@firstoftwo{\expandafter}{} \@secondoftwo}%
}%
%%=============================================================================
%% Exchange arguments
%%=============================================================================
\newcommand\UD@Exchange[2]{#2#1}%
\begingroup
% Dummy-definition, will be overridden. Is used only to get ^^M of 
% category code 12(other) as #1 and verbatimized calls as #2 and #3
% into subsequent definition-texts:
\NewDocumentCommand\UD@CheckWhetherLeadingEndl{+m+v+v}{%
  \endgroup
  %%===========================================================================
  %% Check whether_verbatimized_ argument starts with a endline-character
  %%===========================================================================
  %% \UD@CheckWhetherLeadingEndl{<Argument which is to be checked>}%
  %%                            {<Tokens to be delivered in case <argument
  %%                              which is to be checked>'s 1st token is a
  %%                              endline-charactern>}%
  %%                            {<Tokens to be delivered in case <argument
  %%                              which is to be checked>'s 1st token is not
  %%                              a endline-character>}%
  \newcommand\UD@CheckWhetherLeadingEndl[1]{%
    \UD@@CheckWhetherLeadingEndl\UD@SelDom##1\UD@SelDom#1\UD@@SelDom
  }%
  \@ifdefinable\UD@@CheckWhetherLeadingEndl{%
    \long\def\UD@@CheckWhetherLeadingEndl##1\UD@SelDom#1##2\UD@@SelDom{%
      \UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
    }%
  }%
  %%===========================================================================
  %% Check whether _verbatimized_ argument ends with a endline-character
  %%===========================================================================
  %% \UD@CheckWhetherTrailingEndl{<Argument which is to be checked>}%
  %%                             {<Tokens to be delivered in case <argument
  %%                               which is to be checked>'s last token is a
  %%                               endline-charactern>}%
  %%                             {<Tokens to be delivered in case <argument
  %%                               which is to be checked>'s last token is not
  %%                               a endline-character>}%
  \newcommand\UD@CheckWhetherTrailingEndl[1]{%
    \UD@@CheckWhetherTrailingEndl##1\UD@SelDom#1\UD@SelDom\UD@@SelDom
  }%
  \@ifdefinable\UD@@CheckWhetherTrailingEndl{%
    \long\def\UD@@CheckWhetherTrailingEndl##1#1\UD@SelDom##2\UD@@SelDom{%
      \UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
    }%
  }%
  %%===========================================================================
  %%  \LTXIO
  %%===========================================================================
  \newcommand*\LTXIO{%
    \begingroup
    % Make sure endline-chars yield linebreaks when \scantokens
    % does its fake-writing-part:
    \newlinechar=`\^^M %
    % Make sure horizontal tabs won't cause problems when LTXIO reads its
    % +v-argument:
    \@makeother\^^I%
    \InnerLTXIO
  }%
  \NewDocumentCommand{\InnerLTXIO}{+v}{%
    \scantokens\expandafter{%
        \romannumeral0%
        \UD@CheckWhetherLeadingEndl{##1}{%
          \UD@CheckWhetherTrailingEndl{##1}{%
            \UD@Exchange{##1}%
          }{%
            \UD@Exchange{##1#1}%
          }%
        }{%
          \UD@CheckWhetherTrailingEndl{##1}{%
            \UD@Exchange{#1##1}%
          }{%
            \UD@Exchange{#1##1#1}%
          }%
        }%
        { \endgroup#2}%
        #3%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% Now let's change the catcode of ^^M and then call the dummy-definition
%% of \UD@CheckWhetherLeadingEndl so that it can fetch the catcode-12-^^M
%% and the verbatim-phrases for closing the group and overriding itself
%% and defining all those macros where that catcode-12-^^M and those
%% verbatimized phrases are needed:
\catcode`\^^M=12 %
\UD@CheckWhetherLeadingEndl%
  {^^M}%
  {\begin{LTXexample}[pos=b, frame=single, linewidth=\textwidth, xleftmargin=3.4pt, 
   xrightmargin=3.4pt, basicstyle=\ttfamily, nocodelinenumbers, showspaces=true,
   showtabs=true]}%
  {\end{LTXexample}}%
\makeatother

\begin{document}

\noindent\textbf{The input}

\begin{verbatim*}
\LTXIO
{
  {%
    \Huge
    another
    piece
    of
    text%
  }\\
  {\scriptsize another piece of text}
}
\end{verbatim*}

\noindent\textbf{yields:}\vspace*{\partopsep}\vspace*{\topsep}

\LTXIO
{
  {%
    \Huge
    another
    piece
    of
    text%
  }\\
  {\scriptsize another piece of text}
}

\bigskip

\noindent\null\hrule height 2pt\hfill\null

\bigskip

\noindent\textbf{The input}

\begin{verbatim*}
\LTXIO{{\Huge another piece of text}}
\end{verbatim*}

\noindent\textbf{yields:}\vspace*{\partopsep}\vspace*{\topsep}

\LTXIO{{\Huge another piece of text}}

\end{document}

enter image description here

| improve this answer | |

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.