TransWikia.com

How to ease writing of a (long) command

TeX - LaTeX Asked by PIC-Nico on August 6, 2020

I was asking myself how I can ease writing of long commands/phrases that are used very often in the exact same way.

Example: How can I write the following:

begin{mdframed}begin{lstlisting}[style=mystyle]
bla bla bla
end{lstlisting}end{mdframed}

In a shorter way like:

mycommand{
bla bla bla
}

Edit:
As requested I will add an update to my origin question below:

Here is the missing style definition:

lstdefinestyle{mystyle}{
    language = C,
    basicstyle=footnotesizettfamily,
    keywordstyle = {color{DarkGreen}bfseries},
    morekeywords = {Send,Receive},
    mathescape=true,
    columns=fullflexible,
    prebreak=raisebox{0ex}[0ex][0ex]{ensuremath{rhookswarrow}},
    breakindent=0
}

So as you can see I also want to have the option for mathescape inside in order to do stuff like:

mycommand{
bla bla bla $1+2=3$
}

Which should not result into text "$1+2=3$" but into 1+2=3 as math interpretation.

4 Answers

I'd not recommend making the mdframedlstlisting into a command with argument instead of a proper environment.

For one thing, line breaks cannot be preserved in the argument version.

I'd also suggest tcolorbox rather than mdframed, because it offers better integration with listings. Anyway, you can do

documentclass{article}
usepackage{listings,mdframed}

lstnewenvironment{mylisting}
   {mdframedlstset{}}
   {endmdframed}

begin{document}

begin{mylisting}
bla bla bla
end{mylisting}

end{document}

Note the auxiliary commands mdframed and endmdframed, otherwise the lstnewenvironment declaration would produce something that doesn't work at all. I removed style=mystyle because I have no idea of how the style is defined. Add all the necessary options you need in the argument of lstset.

Extended version with a style


documentclass{article}
usepackage{listings,mdframed}
usepackage[svgnames]{xcolor}

lstdefinestyle{tmstyle}{
  language = C,
  basicstyle=footnotesizettfamily,
  keywordstyle = {color{DarkGreen}bfseries},
  morekeywords = {Send,Receive},
  mathescape=true,
  columns=fullflexible,
  prebreak=raisebox{0ex}[0ex][0ex]{ensuremath{rhookswarrow}},
  breakindent=0,
}

lstnewenvironment{mylisting}
   {mdframedlstset{style=tmstyle}}
   {endmdframed}

begin{document}

begin{mylisting}
Send bla bla bla $1+2=3$
end{mylisting}

end{document}

enter image description here

Correct answer by egreg on August 6, 2020

In general, you can do something like this:

newcommand{mycommand}[1]{
  begin{environment}
   #1
  end{environment}
}

However, the lstlisting environment relies on changing category codes to work so the category codes won't be what they need to be when the argument is expanded.

Fortunately, this is something that was foreseen as an issue. Instead, you'll need to use the lstnewenvironment command so you could do something like:

lstnewenvironment{mylisting}
   {begin{mdframed}lstset{style=mystyle}}
   {end{mdframed}}

and then use it with

begin{mylisting}
bla bla bla
end{mylisting}

Answered by Don Hosek on August 6, 2020

With the upcoming LaTeX kernel, due to be released in October, you can add to 'hooks' to achieve this. For example

documentclass{article}
usepackage{listings}
usepackage{mdframed}
AddToHook{env/lstlisting/before}{begin{mdframed}}
AddToHook{env/lstlisting/after}{end{mdframed}}
begin{document}
begin{lstlisting}
bla bla bla
end{lstlisting}
end{document}

(You'll need to run e.g. pdflatex-dev at present for this to work: that uses the pre-release version of the kernel.)

Answered by Joseph Wright on August 6, 2020

As long as mycommand is used on document-level only, not from within arguments of other macros, not from within definition-texts of other macros, not from within token-registers, not as part of a a moving argument, you can have LaTeX read things as verbatim-arguments and pass these to scantokens.

But I cannot recommend this because indenting the code that is to be displayed will definitely not be easier this way:

documentclass{article}
usepackage{xparse}
usepackage{listings}
usepackage{mdframed}

lstdefinestyle{mystyle}{%
    language = C,
    basicstyle=footnotesizettfamily,
    keywordstyle = {color{DarkGreen}bfseries},
    morekeywords = {Send,Receive},
    mathescape=true,
    columns=fullflexible,
    prebreak=raisebox{0ex}[0ex][0ex]{ensuremath{rhookswarrow}},
    breakindent=0
}


newcommandmycommand{%
  begingroup
  catcode`^^I=12 %
  newlinechar=endlinechar
  MyReadVerbatimArgument
}%
begingroup
NewDocumentCommandMyReadVerbatimArgument{+v +v}{%
  endgroup
  NewDocumentCommandMyReadVerbatimArgument{+v}{%
    scantokens{endgroup#1##1#2}%
  }%
}%
MyReadVerbatimArgument|begin{mdframed}
begin{lstlisting}[style=mystyle]
||
end{lstlisting}
end{mdframed}
%|

begin{document}

mycommand{bla bla bla
           bla bla bla
bla bla bla}

end{document}

enter image description here



If you wish, this can be extended to remove a leading endline-character from the entire verbatim-argument if present and a trailing endline-character from the entire verbatim-argument if present.

This way

mycommand{
           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla
}

and

mycommand{           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla
}

and

mycommand{
           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla}

and

mycommand{           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla}

will all yield the same output.

The tricks for removing a leading/trailing endline-character, i.e., a leading/trailing ^^M-character of category code 12(other)=a leading/trailing return-character of category code 12(other) are the same as the tricks for a removing leading/trailing space-token from a macro-argument.
With the helper-macros just don't use space-tokens as argument-delimiters but use explicit return-character-tokens of category code 12(other).

The latter (removal of a leading/trailing space) is discussed in Exercise 15 of Michael Downes' "Around the Bend"-collection of TeX challenges.

A pdf-file by Peter Wilson containing all challenges/exercises and all solutions/answers belonging to the "Around the Bend"-collection of TeX challenges can be found at:
http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf

The original text of the challenge/exercise can be found at:
http://mirrors.ctan.org/info/challenges/aro-bend/exercise.015

The original text of the discussion of submitted solutions/answers can be found at:
http://mirrors.ctan.org/info/challenges/aro-bend/answer.015

documentclass{article}
usepackage{xparse}
usepackage{listings}
usepackage{mdframed}


%%/////////////////////////////////////////////////////////////////////////////
%% Begin of code for  UDRemoveLeadingNTrailingEndl
%%/////////////////////////////////////////////////////////////////////////////
makeatletter
%%=============================================================================
%% 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>}%
newcommandUD@CheckWhetherNull[1]{%
  romannumeral0ifrelaxdetokenize{#1}relax
  expandafter@firstoftwoelseexpandafter@secondoftwofi
  {@firstoftwo{expandafter}{} @firstoftwo}%
  {@firstoftwo{expandafter}{} @secondoftwo}%
}%
%%=============================================================================
%% Exchange arguments
%%=============================================================================
newcommandUDExchange[2]{#2#1}%
begingroup
% Dummy-definition, will be overridden. Is used only to get ^^M of 
% category code 12(other) as #1 into subsequent definition-texts:
NewDocumentCommandUD@CheckWhetherLeadingEndl{+m}{%
  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>}%
  newcommandUD@CheckWhetherLeadingEndl[1]{%
    UD@@CheckWhetherLeadingEndlUD@SelDom##1UD@SelDom#1UD@@SelDom
  }%
  @ifdefinableUD@@CheckWhetherLeadingEndl{%
    longdefUD@@CheckWhetherLeadingEndl##1UD@SelDom#1##2UD@@SelDom{%
      UD@CheckWhetherNull{##2}{@secondoftwo}{@firstoftwo}%
    }%
  }%
  %%===========================================================================
  %% Remove one leading endline-character from _verbatimized_ argument
  %%===========================================================================
  @ifdefinableUD@@TrimLeadingEndl{longdefUD@@TrimLeadingEndl#1{}}%
  %%===========================================================================
  %% 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>}%
  newcommandUD@CheckWhetherTrailingEndl[1]{%
    UD@@CheckWhetherTrailingEndl##1UD@SelDom#1UD@SelDomUD@@SelDom
  }%
  @ifdefinableUD@@CheckWhetherTrailingEndl{%
    longdefUD@@CheckWhetherTrailingEndl##1#1UD@SelDom##2UD@@SelDom{%
      UD@CheckWhetherNull{##2}{@secondoftwo}{@firstoftwo}%
    }%
  }%
  %%===========================================================================
  %% Remove one trailing endline-character from _verbatimized_ argument
  %%===========================================================================
  newcommandUD@TrimTrailingEndl[1]{UD@@TrimTrailingEndl##1UD@SelDom}%
  @ifdefinableUD@@TrimTrailingEndl{%
    longdefUD@@TrimTrailingEndl##1#1UD@SelDom{##1}%
  }%
  %%===========================================================================
  %% Remove one leading and one trailing endline-character from _verbatimized_ 
  %% argument if present. Due to romannumeral0-expansion the result is
  %% delivered in 2 expansion-steps:
  %%===========================================================================
  newcommandUDRemoveLeadingNTrailingEndl[1]{%
    romannumeral0%
    UD@CheckWhetherLeadingEndl{##1}{%
      UD@CheckWhetherTrailingEndl{##1}{%
         UDExchange{ }{%
           expandafterexpandafterexpandafterexpandafter
           expandafterexpandafterexpandafter
         }%
         expandafterUD@TrimTrailingEndlexpandafter{UD@@TrimLeadingEndl##1}%
       }{%
         UDExchange{ }{expandafter}%
         UD@@TrimLeadingEndl##1%
       }%
    }{%
      UD@CheckWhetherTrailingEndl{##1}{%
         UDExchange{ }{expandafterexpandafterexpandafter}%
         UD@TrimTrailingEndl{##1}%
      }{ ##1}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% 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,
%% close the group, override itself and define all those macros where that
%% catcode-12-^^M  is needed:
catcode`^^M=12 %
UD@CheckWhetherLeadingEndl{^^M}%
makeatother
%%/////////////////////////////////////////////////////////////////////////////
%% End of code for  UDRemoveLeadingNTrailingEndl
%%/////////////////////////////////////////////////////////////////////////////


lstdefinestyle{mystyle}{
    language = C,
    basicstyle=footnotesizettfamily,
    keywordstyle = {color{DarkGreen}bfseries},
    morekeywords = {Send,Receive},
    mathescape=true,
    columns=fullflexible,
    prebreak=raisebox{0ex}[0ex][0ex]{ensuremath{rhookswarrow}},
    breakindent=0
}

newcommandmycommand{%
  begingroup
  catcode`^^I=12 %
  newlinechar=endlinechar
  MyReadVerbatimArgument
}%
begingroup
NewDocumentCommandMyReadVerbatimArgument{+v +v}{%
  endgroup
  NewDocumentCommandMyReadVerbatimArgument{+v}{%
    scantokensexpandafter{romannumeral0%
     expandafterexpandafterexpandafterUDExchange
     expandafterexpandafterexpandafter{%
       UDRemoveLeadingNTrailingEndl{##1}%
     }{ endgroup#1}#2}%
  }%
}%
MyReadVerbatimArgument|begin{mdframed}
begin{lstlisting}[style=mystyle]
||
end{lstlisting}
end{mdframed}
%|

begin{document}

mycommand{
           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla
}


mycommand{           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla
}


mycommand{
           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla}


mycommand{           bla bla bla
           bla bla bla
This line is not indented.
           bla bla bla
           bla bla bla}

end{document}

enter image description here

Some remarks about subtleties with the ways in which TeX works:

TeX's mechanism for reading and tokenizing input in any case discards all space-characters at the end of a line of .tex-input and then adds a character whose coding-point-number in the TeX-engine's internal character-encoding scheme (which either is ASCII with traditional engines or is UTF‑8/Unicode with engines based on XeTeX/LuaTeX; ASCII can be considered a strict subset of Unicode) equals the value of the integer-parameter endlinechar before starting to tokenize that line. Usually the value of the endlinechar-parameter is 13, denoting the return-character which in TeX's ^^-notation is also accessible as ^^M. (M is the 13th letter in the latin alphabet.)

This implies that .tex-input-lines containing space-characters (ASCII 32(dec)/Unicode 32(dec)) only will in any case be treated as empty lines.

This also implies that with .tex-input-lines ending with space-characters (ASCII 32(dec)/Unicode 32(dec)) these space-characters will be discarded.
You can test this by putting lines of text that end with a sequence of space-characters into the verbatim*-environment.

Answered by Ulrich Diez on August 6, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP