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 Commented Jan 22, 2018 at 22:28
  • 4
    Perhaps it would be better to show your use-case of \mymacro.
    – Werner
    Commented Jan 22, 2018 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
    Commented Jan 22, 2018 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
    Commented Jan 23, 2018 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
    Commented Jan 23, 2018 at 7:40

2 Answers 2

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 Commented Jan 22, 2018 at 22:37
  • 1
    @DavidCarlisle The OP wanted braces. ;-)
    – egreg
    Commented Jan 22, 2018 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. Commented Jan 22, 2018 at 22:54
  • 3
    A classic alternative, if I remember correctly, \def\mynewmacro{\aftergroup\mymacro\aftergroup{}}.
    – Manuel
    Commented Jan 22, 2018 at 23:00
  • 1
    @Manuel: Why don’t you turn your comment into an answer?
    – GuM
    Commented Jan 22, 2018 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

You must log in to answer this question.

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