- 1. Introduction
- 2. Installation
- 3. Asciidoc-LaTeX
- 4. Converting to LaTeX
- 4.1. Inline mathematics
- 4.2. Display mathematics
- 4.3. Currency
- 4.4. Environments
- 4.5. Vanilla environments
- 4.6. Special environments
- 4.7. Sections
- 4.8. Lists
- 4.9. Tables
- 4.10. Bold, italic, and monospaced text
- 4.11. Quotations
- 4.12. Footnotes
- 4.13. References and labels
- 4.14. Hyperlinks
- 4.15. Line breaks
- 4.16. Images
- 4.17. Listing
- 4.18. Open blocks
- 4.19. Literal
- 4.20. Page break
- 4.21. Pass
- 5. Design of the Asciidoctor-LaTeX processor
- 6. Design of the HTML Backend
- 7. Design of the LaTeX Backend
Asciidoc-LaTeX defines an extended mathematical syntax for the Asciidoc markup language that closely parallels LaTeX. To render documents written in Asciidoc-LaTeX into HTML or LaTeX, one uses the Asciidoctor-LaTeX processor. It is used in the same way that the Asciidoctor processor is used to render Asciidoc documents into HTML.
You will find an on-line copy of this report at Noteshare.io. (The table of contents for this report is not displayed on GitHub, but is in the online copy.) roughly increasing order of size and technical complexity.
-
A guide to the installation and use of Asciidoctor-LaTeX.
-
An introduction to the Asciidoc-LaTeX markup language. Here we give a few examples and principles. For more examples and more detail, see the Asciidoctor-LaTeX Manual.
-
A description of the mapping given by Asciidoctor-LaTeX.
At this writing, the mapping is (quite) incomplete. It is nonetheless suffcient to translate most of the material on Noteshare.io into LaTeX, e.g, this article.
-
Overviews of the design of the Design of the Asciidoctor-LaTeX processor. This will be helpful to anyone who wishes to fork or maintain the code.
This report is a work-in-progress. I will extend its coverage of the above topics as time permits.
Asciidoctor-LaTeX is developed by James Carlson, Jakub Jirutka, and Dan Allen.
There is a development release at RubyGems.org Beta alert!
If you would like to install a development version from the repository, use:
$ git clone https://github.com/asciidoctor/asciidoctor-latex.git $ cd asciidoctor-latex $ gem build asciidoctor-latex.gemspec $ gem install *.gem
Asciidoc math files can be rendered
-
as HTML. Use
$ asciidoctor-latex -b html foo.adoc
to producefoo.html
. With this command the Asciidoc-LaTeX syntax and extensions will be rendered. -
as LaTeX. Use
$ asciidoctor-latex foo.adoc
to producefoo.tex
.
Asciidoctor-LaTeX supports two closely-related
math formats, Asciidoc-LaTeX
and AsciiMath.
In Asciidoc-LaTeX,
one can write $ a^2 + b^2 = c^2 $
and
\[ e^{2\pi \sqrt{-1}} = 1, \]
for in-line and display mathematial
text, respectively.
You will need to express dollar-denominated
currency using
escaped dollar signs, as
in the sentence, "He paid \$100 for that
theore.m" In AsciiMath, one writes
stem:[ a^2 + b^2 = c^2 ]
and
[stem] ++++ e^{2\pi \sqrt{-1}} = 1. ++++
Asciidoc-LaTeX supports an env
construct that maps to LaTeX environments.
Thus
[env.theorem] -- There exist infinitely many prime numbers. --
renders as an automatically numbered theorem. Environments can contain in-line and display mathematics, e.g.,
[env.theorem] -- A two-by-two matrix is invertible if its determinant is nonzero, i.e., if \[ \left|\begin{matrix} a & b \\ c & d \end{matrix}\right| \ne 0 \] This result extends to $n\times n$ matrices. --
There is complete freedom in parameter NAME
of [env.NAME]
, Thus,one can write
[env.definition] -- An integer $n$ is *prime* if (a) it is not $\pm 1$ and (b) it has no divisors other than $\pm 1$ and $\pm n$. --
or
[env.joke] -- A mathematician, a philosopher, and a lawyer met at the local bar for a drink. The lawyer said ... --
One can make cross references by labeling the environment as in
[env.joke#mathjoke1] -- A mathematician, a philosopher, and a lawyer met at the local bar for a drink. The lawyer said ... --
then referencing it later as [mathjoke1]
.
Certain environments receive special treatment.
For numbered equations, use [env.equation]
like this
[env.equation] -- a^{p-1} \equiv 1\ \text{mod}\ p --
For sets of equations, use [env,equationalign]
:
[env.equationalign] -- A & = 4\pi r^2 \\ V & = \frac{4}{3} \pi r^3 --
Click blocks are similar to [env]
blocks exceptiipoo that the body of
the block is not displayed until the user clicks on the heading.
The heading of a click block is displayed in blue. Once a click
block is "opened", it can be closed by clicking again on the heading.
[click.comment] -- It is sometimes useful to "hide" a comment in a click block so as not to unduly disturb the flow of the prose. Click blocks are also useful for problem sets, since one can make hints, solutions, etc. clickable.
The default for click blocks is not to number them.
See the file click.adoc
in the exampless
directory
for more information.
The text
\[ \int_0^1 x^n dx = \frac{1}{n+1} \]
is rendered as
\[ \int_0^1 x^n dx = \frac{1}{n+1} \]
The source text
Some finance: that theorem costs \$100!
maps to
Some finance: that theorem costs \$100!
The [env.FOO]
construct in Asciidoc-LaTeX gives us
a way to mimic the
\begin{FOO} ... whatever ... \end{FOO}
construct in LaTeX. The variable FOO can
be something familiar — theorem
, lemma
,
definition
, etc. Asciidoctor-LaTeX provides
default LaTeX definitions for the
most common of these. You can override
them with your own defintions and you
can you can define environments for special
needs, e.g., [env.joke]
, [env.objection]
,
etc.
This said, there are special environments built in to Asciidoc-LaTeX which receive special treatment. We thus distinguish two classes of environments, Vanilla and Special.
The [env.theorem]
environment
is a typical vanilla environemet.
Thus, the source text
[env.theorem] -- The equation $a^2 + b^2 = c^2$ has infinitely many non-proportional integer solutions. --
renders as
\begin{theorem} The equation $a^2 + b^2 = c^2$ has infinitely many non-proportional integer solutions. \end{theorem}
Vanilla environments can contain display as well as inline mathematics. Thus, the source text
[env.theorem] -- \[ e^{2\pi\sqrt{-1}} = 1 \] --
renders as
\begin{theorem} \[ e^{2\pi\sqrt{-1}} = 1 \] \end{theorem}
Vanilla environments can take a title, as in this example.
.Euler [env.theorem] -- \[ e^{2\pi\sqrt{-1}} = 1 \] --
It renders as
\begin{theorem}{\rm (Euler) } \[ e^{2\pi\sqrt{-1}} = 1 \] \end{theorem}
To label a vanilla environment for cross-referencing, do this:
[env.theorem#euler] -- \[ e^{2\pi\sqrt{-1}} = 1 \] --
To refer to this theorem, say
[euler]
.
For equations we have the special
environment [env.equation]
. The
source text
[env.equation] -- \sum_{k=1}^\infty \frac{1}{n} --
renders as
\begin{equation} \sum_{k=1}^\infty \frac{1}{n} \end{equation}
The fictitious derivation
[env.equationalign] -- a &= b + c \\ a &= (c + d) + d \\ &= c + 2d --
renders as
\begin{equation} \begin{split} a &= b + c \\ a &= (c + d) + d \\ &= c + 2d \end{split} \end{equation}
The source text
== Section === Going down farther -- subsection ==== And farther still ... ===== Yikes! We have hit bottom!!
is rendered as
\section*{Section} \subsection*{Going down farther — subsection} \subsubsection*{And farther still …} \paragraph*{Yikes! We have hit bottom!!}
If we precede the source text by the code
:numbered:
we turn on automatic numbering and get this instead:
\section{Section} \subsection{Going down farther — subsection} \subsubsection{And farther still …} \paragraph{Yikes! We have hit bottom!!}
To turn automatic numbering off, insert this code:
:!numbered:
the Asciidoc source
* Pay Bills * Get Groceries ** Milk ** Bread ** Orange Juice * Change Oil Filter on Car
is mapped to the LaTeX
\begin{itemize} \item Pay Bills \item Get Groceries \begin{itemize} \item Milk \item Bread \item Orange Juice \end{itemize} \item Change Oil Filter on Car \end{itemize}
The Asciidoc
. Pay Bills . Get Groceries .. Milk .. Bread .. Orange Juice . Change Oil Filter on Car
is mapped to the LaTeX
\begin{enumerate} \item Pay Bills \item Get Groceries \begin{enumerate} \item Milk \item Bread \item Orange Juice \end{enumerate} \item Change Oil Filter on Car \end{enumerate}
The Asciidoc text
Foo:: a lambda expession of the first kind Bar:: a lambda expressi of the second kind
is mapped to the LaTeX
\begin{description} \item[Foo]a lambda expession of the first kind \item[Bar]a lambda expressi of the second kind \end{description}
The Asciidoc text
|=== | Eggs | one dozen | Potatoes | nine pounds | Milks | three quarts |===
is mapped to the LaTeX
\begin{center} \begin{tabular}{|c|c|} \hline Eggs & one dozen \\ Potatoes & nine pounds \\ Milks & three quarts \\ \hline \end{tabular} \end{center}
The text "She said potatoes but he said potaatoes", written in Asciidoc as
She said _potatoes_ but he said *potaatoes*
is mapped to
She said \emph{potatoes} but he said \textbf{potaatoes}
The text
`monospaced`
is mapped to
{\tt monospaced}
The text
[quote, Abraham Lincoln, Soldiers' National Cemetery Dedication] ____ Four score and seven years ago our fathers brought forth on this continent a new nation ____
is mapped to
\begin{quote} Four score and seven years ago our fathers brought forth on this continent a new nation \end{quote}
Text like this
Ho hum.footnote:[An expression of boredom]
is mapped to
Ho hum\footnote{An expression of boredom}
The label
Ho hum[[foo]]
is mapped to
Ho hum\label{foo}
The cross-reference
Please see <<foo>>
is mapped to
Please see \ref{foo}
Labels can also be constructed directly in Asciidoc-LaTeX environments. Consider the source text below.
[env.theorem#pythagoras] -- Let $a$ an $b$ denote the altitue and base of a right triangle. Let $c$ denote its hypotenuse. Then $c^2= a + b$. --
The code #pythagoras
creates
a label pythagoras
.
The hyperlink
http://nytimes.com[All the news that is fit to print]
is mapped to
\href{http://nytimes.com}{All the news that is fit to print}
The source text
Roses are red, + Daisies are white, + But all need the light.
is mapped to
Roses are red, \\ Daisies are white, \\ But all need the light.
Images can be rendered in both the
HTML produced by Asciidoctor-LaTeX and in the
PDF files generated by LaTeX. Typical
source text for including an image
in an .adoc
file is
image::foo.png[width=200]
This is rendered in LaTeX as follows.
\begin{figure}[h]{} \includegraphics[width=2.0truein]{foo.png} \caption{} \end{figure}
In both LaTeX and Asciidoc-LaTeX, the default is
to keep all images in the directory images
ad the root of your document directory.
The source text
[listing] .... sum = 0 k = 1 100.times do sum += 1.0/k k += 1 end puts sum ....
is mapped to
\begin{verbatim} sum = 0 k = 1 100.times do sum += 1.0/k k += 1 end puts sum \end{verbatim}
Here is an open block:
-- This is an anonymous open block. End of story. --
It is rendered as-is in LaTeX:
This is an anonymous open block. End of story.
Here is an open block masquerading as a listing block:
[listing] -- This is an anonymous open block masquerading a listing block. End of story. --
And here is how it is rendered in LaTeX:
\begin{verbatim} This is an anonymous open block masquerading a listing block. End of story. \end{verbatim
The text
[literal] This is a test of whether it realy works!
is rendered as
\begin{verbatim} This is a test of whether it realy works! \end{verbatim}
Note that in the source text there are no blank lines. If there are blank lines, there is an alternate construction:
.... This is also a test of whether it realy works! ....
It is rendered as
\begin{verbatim} This is also a test of whether it realy works! \end{verbatim}
The text
Fee, fie <<< fo, fum!
will render in TeX las
Fee, fie \vfill\eject fo, fum!
Asciidoctor-LaTeX adds new behavior to the
existing Html5Converter for Asciidoctor. It does
this via Ruby 2.0’s prepend
method:
class Asciidoctor::Converter::Html5Converter
# inject our custom code into the
# existing Html5Converter class
prepend Asciidoctor::LaTeX::Html5ConverterExtensions
end
This code ensures that methods of module
Asciidoctor::LaTeX:Html5ConverterExtensions
are executed
in preference to methods of module
Asciidoctor::LaTeX:
.
The new behavior itself is defined
in the module
Asciidoctor::LaTeX:Html5ConverterExtensions
.
There we find, for example, a new method,
environment(node)
which handles a new
type of block, the environment block.
One also finds the method inline_anchor(node)
,
which already exists in
Asciidoctor::LaTeX:Html5Converter
and which
processes inline anchors such as
http://asciidoctor.org[Asciidoctor]
At its highest level, module Asciidoctor::LaTeX
has two components, module Html5ConverterExtensions
and class Converter
. Let us examine these
in ever greater detail.
module Asciidoctor::LaTeX
module Html5ConverterExtensions
end
class Converter
end
end
The Html5ConverterExtensions
module
contains handlers for nodes, e.g, the
environment_block
node, which is new,
and the inline_anchor
node, which
has new behavior.
module Asciidoctor::LaTeX
module Html5ConverterExtensions
#
# Node handlers ...
#
end
end
module Html5ConverterExtensions
def environment node
attrs = node.attributes
case attrs['role']
when 'equation'
handle_equation(node)
when 'equationalign'
handle_equation_align(node)
###### etc ######
end
node.attributes['roles'] = (node.roles + ['environment']) * ' '
self.open node
end
def click node
node.lines = [ENV_CSS] + node.lines + [DIV_END]
node.attributes['roles'] = (node.roles + ['click']) * ' '
self.open node
end
def handle_equation(node)
end
###### etc ######
end
def handle_equation(node)
options = node.attributes['options']
node.title = nil
number_part = '<td style="text-align:right">' + "(#{node.caption}) </td>"
number_part = ["+++ #{number_part} +++"]
equation_part = ['+++<td style="width:100%";>+++'] + ['\\['] + node.lines + ['\\]'] + ['+++</td>+++']
table_style='style="width:100%; border-collapse:collapse;border:0" class="zero" '
row_style='style="border-collapse: collapse; border:0; font-size: 12pt; "'
if options['numbered']
node.lines = ["+++<table #{table_style}><tr #{row_style}>+++"] + equation_part + number_part + [TABLE_ROW_END]
else
node.lines = ["+++<table #{table_style}><tr #{row_style}>+++"] + equation_part + [TABLE_ROW_END]
end
end
In the Converter
class, preprocessors,
postprocessors, etc., are registered, the backend
is initialized, and converter method is defined.
Asciidoctor-LaTeX calls the converter on AST (abstract syntax
tree) that the parser has produced, and proceeds
to walk through it node by node. The converter
dispatches each node to its processor. The handler
is determined by the node, e.g., by its name
and role. In so doing, the converter looks in
an array of node types to
see if it knows about that kind of node. If
it does, the node is dispatched to its processor.
If it does not, it issues a warning which can be used
to add the needed behavior to the converter.
class Converter
include Asciidoctor::Converter
# Register processors ...
# def initialize backend, opts ...
# def convert node, transform = nil ...
end
class Converter
include Asciidoctor::Converter
register_for 'latex'
Asciidoctor::Extensions.register do
preprocessor TeXPreprocessor
preprocessor MacroInsert if File.exist? 'macros.tex' and document.basebackend? 'html'
block EnvironmentBlock
block ClickBlock
inline_macro ChemInlineMacro
# preprocessor ClickStyleInsert if document.attributes['click_extras'] == 'include2'
postprocessor InjectHTML unless document.attributes['noteshare'] == 'yes'
postprocessor EntToUni if document.basebackend? 'tex' unless document.attributes['unicode'] == 'no'
postprocessor Chem if document.basebackend? 'html'
postprocessor HTMLPostprocessor if document.basebackend? 'html'
postprocessor TexPostprocessor if document.basebackend? 'tex'
end
Asciidoctor::Extensions.register :latex do
# EnvironmentBlock
end
# TYPES ...
# def initialize
# def convert
end
class Converter
# Registration
# TYPES ...
def initialize backend, opts
super
basebackend 'tex'
outfilesuffix '.tex'
end
def convert node, transform = nil
if NODE_TYPES.include? node.node_name
node.tex_process
else
warn %(Node to implement: #{node.node_name}, class = #{node.class}).magenta if $VERBOSE
# This warning should not be switched off by $VERBOSE
end
end
end