4

In TeX, starting and ending math mode is done with the same symbol, namely $. Suppose I would like to start and end an environment like this, perhaps with the text italic, using the character *, as follows. The code *this is italic* would typeset this text is italic. I have attempted the following solution but it does not work.

\catcode`*\active
\def*#1{\bgroup\it#1\egroup}
*this is italic*
\bye

I have also tried

\catcode`*\active
\newif\ifitalic
\def*#1{\ifitalic\egroup\italicfalse\else\italictrue\bgroup\it#1\fi}
*this is italic*
\bye

But they both throw the error

Runaway argument?
! Paragraph ended before * was complete.

What am I doing wrong?

btshepard
  • 680
  • You might have noticed that they are trying to replace $...$ with \(...\), since keeping track of even-odd occurrences of $ is difficult (some editors change the font color with each occurrence). – John Kormylo Jun 21 '22 at 19:53
  • The purpose of this question is to be able to type italics and bold fonts like in markdown or another? Because in first case, exist the markdown package ... – Fran Jun 22 '22 at 01:40
  • 1
    It woudn’t be the most robust solution, but why not do \def*#1*{...}? – Gaussler Jun 22 '22 at 06:55

3 Answers3

3

Here's a “plainification” of Bruno Le Floch's code in https://tex.stackexchange.com/a/15374/4427

\font\bfit=cmbxti10

\catcode`@=11

% boilerplate \long\def@gobble#1{} \long\def@firstofone#1{#1}

\def\star@out{% \star@ifnext{\bgroup\bf\let\star@current\star@inbf@gobble}% {\bgroup\it\let\star@current\star@init}% } \def\star@inbf{% \star@ifnext{\egroup@gobble}{\bgroup\bfit\let\star@current\star@initbf}% } \def\star@init{% \star@ifnext{\bgroup\bf\let\star@current\star@initbf}{\egroup}% } \def\star@initbf{\star@ifnext{\egroup@gobble}{\egroup}} \let\star@current\star@out

\def\star@ifnext#1#2{% \def \reserved@a {#1}% \def \reserved@b {#2}% \futurelet @let@token \star@ifnext@aux } \begingroup \catcode\*=13 \@firstofone{\endgroup \def*{\star@current} \def\star@ifnext@aux{% \ifx \@let@token *\let \reserved@c \reserved@a \else \let \reserved@c \reserved@b \fi \reserved@c } } \catcode@=12

\catcode`*=\active

Hello, this is a test, to see whether it works.

\bye

enter image description here

egreg
  • 1,121,712
2

Use the character * as a parameter delimeter.

\catcode`\*=\active
    \def*#1*{\bgroup\it#1\egroup}
    *this is italic*, but this isn't
\bye
  • Your second code doesnt work because the macro tries to use \bye as argument, what generate an error. Try to define without the parameter #1: \def*{\ifitalic\egroup\italicfalse\else\italictrue\bgroup\it\fi}. – Felipe Math Jun 21 '22 at 20:02
2

Your problem is that your macro * reads only single following token (after ignoring spaces) because you say \def*#1{...}, i.e. the #1 is unseparated parameter. The first usage of * gets t to the #1 and the second usage (at the end of the phrase) gets \par to the #1 (if empty line follows) and the result is "paragraph ended before \par" because * isn't defined as \long. If there is \bye without empty line (this is exactly in your example) then \bye is scanned to #1 and the result is "Forbidden control sequence" because \bye is defined as \outer in plain TeX.

You can define "switching macro" \startit without parameter as follows:

\def\startit{\bgroup \let\startit=\egroup \it}

\catcode`=13 \def{\startit}

Test this is italic \bye

The first usage of * starts the group, selects italic font and redefines \startit to \egroup. The second usage of * (at the end of the phrase) runs \startit in the meaning \egroup and closes the group (the italic font is not selected now). Moreover, the \startit gets its original meaning after \egroup, so next possible * opens italic text again.

Egreg showed an example how to combine * with italic meaning and ** with bold meaning. Moreower, ** in italic does nothing and * in bold selects bold italic. The same behavior can be achieved by following seven lines:

\font\bi=cmbxti10

\catcode`*=13 \def{\activeast} \def\activeast{\futurelet\next\aastA} \def\aastA{\ifx\next \expandafter \startbf \else \startit \fi} \def\startit{\bgroup \def\startbf{}\let\startit=\egroup \it} \def\startbf{\bgroup \let\it=\bi \def\startbf*{\egroup}\bf}

Hello, this is a test, to see whether it works.

\bye

Note that the code is much more compact than egreg's code at 34 lines.

wipet
  • 74,238