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.)

TRiG
  • 213
  • 1
  • 12
Gaussler
  • 12,801
  • 3
    on the side question, usually none but the \ form is more general, to see the difference try it with % instead of * :-) – David Carlisle Apr 02 '15 at 07:49
  • 5
    Maybe you could write your document in Markdown and use pandoc for conversion to LaTeX. – Habi Apr 02 '15 at 07:50
  • 3
    http://tex.stackexchange.com/questions/101717/converting-markdown-to-latex-in-latex – Joseph Wright Apr 02 '15 at 07:56
  • 1
    See also http://tex.stackexchange.com/a/15374/4427 – egreg Apr 02 '15 at 10:02
  • 1
    There is no difference between \catcode`*\active and \catcode`\*\active; there would be in case we'd like to use % as the character to activate. – egreg Apr 02 '15 at 10:07
  • 8
    Making * active will destroy any star form of macros and environments in LaTeX. – Heiko Oberdiek Apr 02 '15 at 11:56
  • @HeikoOberdiek - As my answer (which sets up a Lua function, and hence doesn't make * active) shows, it's quite possible to have starred macros and environments along with asterisk-based markdown, as long as the lines of input that feature the starred macros and environments contain no further asterisks. – Mico Apr 08 '15 at 01:58
  • @DavidCarlisle and @egreg, what does the apostrophe in \catcode`*\active do? – Gaussler Apr 25 '15 at 08:14
  • @Gaussler backtick not apostophe, it's tex number syntax 65, "41 and \Aand`\A` all denote 65 (decimal, hex and ascii code) – David Carlisle Apr 25 '15 at 09:50
  • @DavidCarlisle, yes, I chose the term "apostrophe" because I didn't know its real name. But what does the "backtick" do? Why not just \catcode*\active? – Gaussler Apr 25 '15 at 09:53
  • @Gaussler try it, you'll find it is a syntax error, the argument of \catcode is a number not a character. as I said it is number syntax \*` is another way of writing 42 – David Carlisle Apr 25 '15 at 10:01
  • Okay, so `* returns some kind of TeX number? – Gaussler Apr 25 '15 at 10:02
  • @Gaussler not some kind, a usual kind \catcode\*\activeis same as\catcode42=13` – David Carlisle Apr 25 '15 at 10:03
  • 1
    @Gaussler \setlength\textwith{\*cm}sets\textwidthto42cm` – David Carlisle Apr 25 '15 at 10:05
  • Then in the code A `quote` from Knuth, why is the q not replaced by the TeX number (or whatever it is called) of the letter q? – Gaussler Apr 25 '15 at 10:21

3 Answers3

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}
Mico
  • 506,678
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}
Fran
  • 80,769