2

I want to define a macro that behaves like \ttfamily, i.e. it should read everything until } (or \endgroup?) as a parameter.

I.e. this

{\mynewmacro lorem ipsum
 dolores
}

should be equivalent to this

\mymacro{lorem ipsum
 dolores
}

Is this possible?

13
  • your two requests are somewhat incompatible, \ttfamily does not read ahead to the end of the group, it is not equivalent to a macro with argument in the way you suggest with \mymacro Jan 22 '18 at 22:28
  • 4
    Perhaps it would be better to show your use-case of \mymacro.
    – Werner
    Jan 22 '18 at 22:31
  • 2
    This looks like an “X-Y problem” (that is, you actually want to do Y, and you find out that you could do it, if only you were able to do X—which, unfortunately, you are not; so you ask how to do X, but what you actually want to achieve is Y). If so, please tell us what Y is: perhaps, we could suggest a different way to achieve it that doesn’t require going through X.
    – GuM
    Jan 22 '18 at 23:55
  • @GuM: The issue I actually have is that when using \texttt you sometimes get overfull boxes, because hyphenation doesn't work properly. That's a known issue. I want to insert a \linebreak[1] after every character so as mentioned here: tex.stackexchange.com/questions/324042. I want a new command that replaces \texttt and ideally I also want a command that replaces \ttfamily to have that functionality. But it appears that \ttfamily is special in that sense.
    – Volker
    Jan 23 '18 at 7:17
  • 1
    @Volker There are so many places where such a \mynewmacro could go wrong that's better to give up with it. Since you want to process text in a special way, a command with argument is what you need.
    – egreg
    Jan 23 '18 at 7:40
6

The macro \ttfamily does not read up to }: it is a declaration that sets (locally) the current font and its action continues until the current group ends.

You can do this, but it's conceptually wrong to begin with.

\long\def\mymacro#1{--#1--}
\long\def\mynewmacro{\egroup\iftrue\expandafter\mymacro\expandafter{\else}\fi}

\mymacro{lorem ipsum
 dolores
}

{\mynewmacro lorem ipsum
 dolores
}

\bye

The \egroup balances the initial {; then we have the problem to make \mymacro into seeing an explicit { and to get rid of the necessary } (because \def wouldn't accept an unbalanced list of tokens). The \iftrue test follows the true branch; actually what it does is simply disappearing, leaving

\expandafter\mymacro\expandafter{\else}\fi

on the input stream, but with TeX knowing it should ignore the \else part. With \expandafter we reach this \else, whose expansion removes everything up to \fi. So at the end we remain with

\mymacro{\fi

so by general rule \mymacro will read up to the matching }. The remaining \fi will expand leaving nothing at all.

Note, however, that you can't call this as \begingroup\mynewmacro ...\endgroup nor use \bgroup and \egroup.

12
  • 1
    \begingroup \mynewmacro hello egreg\endgroup Jan 22 '18 at 22:37
  • 1
    @DavidCarlisle The OP wanted braces. ;-)
    – egreg
    Jan 22 '18 at 22:38
  • 1
    @Fran basically your bgroup example fails as you asked that it acts like a macro with arguments and you can not (for any macro taking an argument) use \mymacro \bgroup ...\egroup the argument of the macro is just \bgroup not the whole group. Jan 22 '18 at 22:54
  • 3
    A classic alternative, if I remember correctly, \def\mynewmacro{\aftergroup\mymacro\aftergroup{}}.
    – Manuel
    Jan 22 '18 at 23:00
  • 1
    @Manuel: Why don’t you turn your comment into an answer?
    – GuM
    Jan 22 '18 at 23:50
0

With the following example

  • the macro \FetchTillCloseBrace{\macro} fetches everything till the next unmatched closing brace and passes that as undelimited argument to \macro, re-inserting that unmatched closing brace.

  • the macro \CopyBehindCloseBrace is an example of how to put/copy tokens from inside a pair of braces forming a local scope behind the closing brace of that scope.

Be aware that processing via macros/macro arguments breaks things that rely on reading and tokenizing things under different catcode-régime, e.g., \verb and the like.

\documentclass{article}

\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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% \UD@PullOutFirstUndelimitedArgument{<action>}%
%%                                    {{<e_k>}{<e_(k+1)>}..{<e_n>}}%
%% yields
%%  <action>{<e_k>}{{<e_(k+1)>}..{<e_n>}}
%% It must be ensured that list is not empty!
%%......................................................................
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@KeepFirstTillSelDOM{}%
\long\def\UD@KeepFirstTillSelDOM#1#2\UD@SelDOM{{#1}}%
\newcommand\UD@PullOutFirstUndelimitedArgument[2]{%
    \expandafter\UD@Exchange
    \expandafter{%
    \expandafter{%
    \@firstoftwo{}#2}}{\UD@ExtractFirstListElementLoop{#2\UD@SelDOM}{#1}}%
}%
\newcommand\UD@ExtractFirstListElementLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
  {\UD@Exchange{#1}}%
  {%
    \expandafter\UD@ExtractFirstListElementLoop
    \expandafter{%
    \UD@KeepFirstTillSelDOM#1}%
  }%
}%
%%----------------------------------------------------------------------
%% \CopyBehindCloseBrace
%%
%%   {<token sequence A>\CopyBehindCloseBrace{<tokens to appear only behind closing brace}<tokens to be copied behind closing brace>}
%% yields:
%%   {<token sequence A><tokens to be copied behind closing brace>}<tokens to appear only behind closing brace>{<tokens to be copied behind closing brace>}
%%......................................................................
\newcommand\FetchTillCloseBraceStart[2]{%
  \expandafter\expandafter\expandafter\UD@PullOutFirstUndelimitedArgument
  \expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter{%
  \expandafter\@secondoftwo\string}{}%
  {#2}%
}%
\newcommand\CopyBehindCloseBrace{%
  \romannumeral0%
  \FetchTillCloseBraceStart{\@CopyBehindCloseBrace}%
}%
\newcommand\@CopyBehindCloseBrace[2]{%
   \expandafter\@secondoftwo\string{{ }#2}#1{#2}%
}%
%%----------------------------------------------------------------------
%% \FetchTillCloseBrace{\macro}
%%
%%   {<token sequence A>\FetchTillCloseBrace{\macro}<remaining tokens in brace group>}
%% yields:
%%   {<token sequence A>\macro{<remaining tokens in brace group>}}
%%......................................................................
\newcommand\FetchTillCloseBrace{%
  \romannumeral0%
  \FetchTillCloseBraceStart{\@PassToMacroInsideScope}%
}%
\newcommand\@PassToMacroInsideScope[2]{%
   \expandafter\@secondoftwo\string{{ }#1{#2}}%
}%
%%----------------------------------------------------------------------
%%
%% {ABC \LowercaseTillCloseBrace DEF}
%%   -> {ABC \lowercase{DEF}}
%%
%%......................................................................
\newcommand\LowercaseTillCloseBrace{%
   \FetchTillCloseBrace{\lowercase}%
}%

\makeatother

\begin{document}

\frenchspacing

{This is rmfamily. \FetchTillCloseBrace{\textsf}This is sffamily.}
This is rmfamily.

\bigskip

{ABC \LowercaseTillCloseBrace DEF}
GHI

\bigskip

{%<--This starts the boldface-group
 \bfseries This is boldface.
 \CopyBehindCloseBrace{This is to appear only outside the boldface-group. \textit}%
 This is to be copied outside the boldface-group.
}%<--This ends the boldface-group

\bigskip

\def\tempa{This is tempa outside the local scope. }%
{%
  \def\tempa{This is tempa inside the local scope. }%

  \CopyBehindCloseBrace{}\tempa
}

% This does _not(!) work:
% {Text\CopyBehindCloseBrace{Bla}\verb$verbatim text?$}
%
% Nor does this work:
%
% {Text \FetchTillCloseBrace{\textbf}\verb&verbatim \TeX t&}
%
% While this works:
% {Text \bfseries\selectfont \verb&verbatim \TeX t&}

\end{document}

enter image description here

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.