23

I rather like the system here where *...* is italic, **...** is bold, and ***...*** is bold italic. Is it possible to do that in (La)TeX?

A MWE that implements the first one:

\documentclass{article}

\begin{document}

\begingroup

\catcode`*\active
\def*#1*{\emph{#1}}

*italic text*

\endgroup
\end{document}

But how about the other two? There are questions about making two characters active, but using two characters both at the beginning and at the end of a command sounds more difficult. And don't get me started about three characters.

A side question: I have been wondering for some time: What is the difference between \catcode`*\active and \catcode`\*\active? (Note the \ in the second example.)

15

3 Answers 3

32

The nice thing here is that you can turn the feature on with \starON and turn it off with \starOFF (the default condition).

Here is the MWE.

\documentclass{article}
\makeatletter
\def\starparse{\@ifnextchar*{\bfstarx}{\itstar}}
\def\bfstarx#1{\@ifnextchar*{\bfitstar\@gobble}{\bfstar}}
\makeatother
\def\itstar#1*{\textit{#1}\starON}
\def\bfstar#1**{\textbf{#1}\starON}
\def\bfitstar#1***{\textbf{\textit{#1}}\starON}
\def\starON{\catcode`\*=\active}
\def\starOFF{\catcode`\*=12}
\starON
\def*{\starOFF \starparse}
\starOFF
\begin{document}
\starON Turn feature on:\par
This is a test of *italic*, and **bold**, as well as ***bold, italic*** text.

\starOFF Turn feature off:\par
This is a test of *italic*, and **bold**, as well as ***bold, italic*** text.
\end{document}

enter image description here

11

The following solution uses LuaLaTeX's capabilities to define a function, called allstars, which converts instances of pairs of groups of asterisks -- ***...***, **...**, and *...* -- into "traditional" LaTeX code: {\bfseries\itshape ...}, {\bfseries ...}, and {\itshape ...}, respectively. The code assumes that asterisk-based markdown does not span linebreaks. The code does not make the * "active" (in the TeX sense of the word). Thus, various complications caused by * being active do not arise.

Using starred LaTeX macros (e.g., \section*) and starred LaTeX environments (e.g., equation*) is OK -- i.e., they will not crash the compilation -- if there are no other asterisks on the respective input lines. For extra generality, the code provides two macros -- named \markdownoff and \markdownon -- that turn the operation of the allstars function off and on. The allstars function is not activated by default -- it has to be turned on by executing \markdownon.

The markdown directives can be nested, in the sense that an italic string can contain a bold italic substring and also that a bold string can contain a bold italic substring.


The allstars function is assigned to LuaTeX's process_input_buffer callback, making it operate during a very early stage of compilation (before TeX's "eyes" get to do any work). The function allstars performs three "sweeps" or "passes" over each line of input with Lua's string.gsub function. During the first pass, it searches for pairs of *** characters; during the second, it looks for pairs of ** characters; and during the third and final pass, it looks for pairs of * characters.

To fully understand how the allstars function works, it is instructive to examine what happens if an input line contains instances of four or more consecutive asterisks (even though "regular" markdown shouldn't contain such instances). For instance, if an input line contains the seven-asterisk sequence

a*******b 

and no further asterisks anywhere else on the input line, the output will be "ab": a single "" character between "a" and "b", but no italic or bold characters. What's going on? The first six asterisks in ******* are interpreted by the allstars function as a pair of *** strings, and ******* therefore gets converted to {\bfseries\itshape}; they thus end up doing nothing at all, at least as far as TeX is concerned. The seventh asterisk, though, is not modified by the allstars function and therefore gets typeset by TeX.

Or, consider the string

a*******b********c

(seven asterisks between "a" and "b" and eight asterisks between "b" and "c"). During the first string.gsub pass, the input line is converted to

a{\bfseries\itshape}*b{\bfseries\itshape}**c

which is equivalent (for our purposes) to

a*b**c

The function's second pass does nothing because no pair of ** characters is present in the input line. The function's third pass finds a pair of * characters and therefore converts the input line to

a{\itshape b}*c

and that's what gets typeset by the (Lua)TeX engine.

Finally, consider what happens if and input line consists of

\section*{A New* Hope}

(and no further asterisks). The third pass of the allstars function finds a pair of single asterisks in this line of input and therefore converts it to

\section{\itshape {A New} Hope}

which is equivalent to

\section{\itshape A New Hope}

Thus, we get a numbered section, and the section header -- but not the section number -- is typeset in bold italics. Probably not what was expected, or intended... If you really need to typeset * directly, you should issue \markdownoff to suspend the operation of the allstars function.


enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amsmath}   % for 'equation*' environment

\usepackage{luacode,luatexbase}
\begin{luacode}
   -- Use Lua captures to extract material affected by markdown
   function allstars (line) 
      line = string.gsub( line, "(%*%*%*)(.-)(%*%*%*)", "{\\bfseries\\itshape %2}")
      line = string.gsub( line, "(%*%*)(.-)(%*%*)", "{\\bfseries %2}" )
      line = string.gsub( line, "(%*)(.-)(%*)", "{\\itshape %2}" )
      return line
   end
\end{luacode}

\newcommand\markdownon{%
   \directlua{luatexbase.add_to_callback( "process_input_buffer", allstars, "allstars" )}}
\newcommand\markdownoff{%
   \directlua{luatexbase.remove_from_callback( "process_input_buffer", "allstars" )}}

\begin{document}

\markdownon
normal

*italic*, **bold**, normal, *more italic*

**bold**, *italic*, **more bold**

***bold italic***, normal, ***more bold italic text***,

**bold text containing a *bold italic* substring**

*italic text with **bold italic** substring*

normal again

\markdownoff % not actually required, as each of the following lines contains exactly one asterisk
\medskip
an \texttt{equation*} environment:
\begin{equation*}
a = b
\end{equation*}

\markdownon
more **bold text with a *bold italic* substring**
\end{document}
5

If you have not objection to use ' instead of *, then the wiki package is the easy solution.

This way there are not collision with starred macros. Moreover, it use the common Wikipedia syntax and on the other mand, the bolds and italics can be nested and even overlapped:

MWE

\documentclass[border=1cm]{standalone}
\usepackage{wiki}
\begin{document}
\wikimarkup
normal, 
'''bold''', 
''italic'', 
'''''bold italic''''' 
and 
''over'''lap''ping''' 
style.
\end{document}

You must log in to answer this question.

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