There's an active character *
(can be anything, asterisk just used for demonstration purposes).
If the character following *
is a space, write \marginpar{foo}
, otherwise write \marginpar{bar}
. This works.
The active character may have an optional argument. The optional argument must immediately follow the active character, otherwise it is not to be considered a macro argument, e.g. *[wut] bla
or *[but]yum
, but not * [noo]
where [noo]
is not interpreted as a macro argument as it's separated with a space. This also works.
I considered this to be an easy task but kept getting errors when the token following the active char is a formatting macro, e.g. *[flut]\textbf{...}
.
I stole^Wborrowed some LaTeX2e macros to fit my needs, and after hours of trial and error, the best I could come up with was this:
\documentclass{book}
\usepackage{lipsum}
\makeatletter
% Do not skip space in contrast to \@ifnextchar.
\long\def\@ifonlynextchar#1#2#3{%
\let\reserved@d=#1%
\def\reserved@a{#2}%
\def\reserved@b{#3}%
\futurelet\@let@token\@ifonch}
\def\@ifonch{%
\ifx\@let@token\reserved@d
\let\reserved@c\reserved@a
\else
\let\reserved@c\reserved@b
\fi
\reserved@c}
% Check for trailing space
\long\def\@ifspace#1#2{%
\def\reserved@a{#1}%
\def\reserved@b{#2}%
\futurelet\@let@token\@ifspc}
\def\@ifspc{%
\if\@let@token\@sptoken
\let\reserved@c\reserved@a
\else
\let\reserved@c\reserved@b
\fi
\reserved@c}
\def\foobar{%
\@ifonlynextchar[{\foobar@opt}%
{\foobar@{}}%
}
\def\foobar@opt[#1]{\foobar@{#1}}
\def\foobar@#1{%
{\scriptsize #1}%
\@ifspace{\foo}{\bar}%
}
\def\foo{\marginpar{foo}}
\def\bar{\marginpar{bar}}
\catcode`\*=13
\let*\foobar
\makeatother
\begin{document}
\lipsum[2][2] There is a trailing space* here should write \emph{foo} in margin.
There is a trailing space*[xy] should write \emph{foo} in margin and \emph{xy} before space. \lipsum[3][4]
There is a space between asterisk and bracket,* [za] should write \emph{foo} in margin and [za] as a literal (shall not be part of the macro argument).
\lipsum[1][3] There is no trailing space *should write \emph{bar}. Then, there is no trailing space but an optional argument so should *[bc]write \emph{bar} in margin and \emph{bc} before ``write.''
Macro after active char *\textbf{shall} detect no space and write \emph{bar} in margin. Then, with an optional argument *[de]\textbf{shall} write \emph{bar} in margin and emit \emph{de} before ``shall.''
\end{document}
Expected results:
- First occurrence in last paragraph prints bar in margin and does not emit error.
- Second occurrence in last paragraph prints de before shall, and bar in margin without emitting an error.
Actual results:
- Error on first occurrence
! Undefined control sequence.
\reserved@c ->\@nil
l.60 Macro after active char *\textbf
{shall} emit no space and write \emph{b...
- Error on second occurrence
! Undefined control sequence.
\reserved@c ->\@nil
l.60 ...en, with an optional argument *[de]\textbf
{shall} write \emph{bar} i...
I'm stuck here. As a workaround, I can issue a TeX primitive to make the error go away, e.g. bla bla *\relax\textbf{even more bla}
but that goes against the intent of using an active character.
The active character should be smart enough to detect any token that is not a space without needing manual intervention. Does anybody spot the error in the minimal working example above? Could somebody suggest a working solution? I'd be very grateful for that.
*{\textbf{shall}}
would also work