Miscellaneous

Using Comments

We can add comments to our Asciidoc markup. The comments will not be added to generated output. We can add both single and multiline comments in the markup. Single line comments start with a double slash (//). Multiline comments are enclosed in a block of four forward slashes (////).

The following sample markup defines Asciidoc markup with comments:

= Asciidoctor comments

// Paragraph with some text.
Writing documentation is fun with Asciidoctor.

* Item A
* Item B

// Divide lists with a single line comment.
// Now we have two lists, otherwise it would
// be a single list with 4 items.

* Item 1
* Item 2

////
With four forward slashed we can
start a multiline comment.

And we close it with another
four forward slashes.
////

Asciidoc is really like _programming_ documentation.

When we generate HTML output we don't see any of the comments, not even in the HTML source:

Written with Asciidoctor 1.5.0.

Original post written on August 12, 2014

Which Asciidoctor Version is Used?

When we create documentation using Asciidoc and Asciidoctor we can access the built-in attribute asciidoctor-version to see which version of Asciidoctor is used to generate the documentation.

We can reference built-in attributes like any other attributes, so we enclose the name of the attributes with curly braces ({attributeName}). In the following sample we simply print out the Asciidoctor version that was used to generate the content:

.Use built-in attribute asciidoctor-version
Document generated with Asciidoctor {asciidoctor-version}.

And we get the following HTML content once we have generated HTML from our Asciidoc source code:

Code written Asciidoctor 0.1.4.

Original post written on June 4, 2014

Disable Last Updated Text in Footer

When we transform our Asciidoc source files to HTML Asciidoctor will print the date and time the document was last updated in the footer. If we want to disable the Last updated text we disable the document attribute last-update-label.

In the following example Asciidoc file we disable the Last update label in the footer:\

:last-update-label!:

= Change footer

To disable the _Last updated_ text
in the footer we disable the document
attribute `last-update-label`.

----
// Disable last updated text.
:last-update-label!:
----

When we transform this to HTML we get the following output:

Written with Asciidoctor 1.5.1.

Original post written on November 26, 2014

Adding Custom Content to Head and Footer

When we convert our Asciidoctor markup to HTML we automatically get a head and footer element. We can add custom content to the HTML head element and to the HTML div with id footer. We must set a document attribute and create the files that contain the HTML that needs to be added to the head or footer. We have three different document attributes we can set to include the custom content files:

  • :docinfo: include document specific content. Files to be included must be named <docname>-docinfo.html for head element and <docname>-docinfo-footer.html for footer content.\
  • :docinfo1: include general custom content. Files to be included must be named docinfo.html for head element and docinfo-footer.html for footer content.\
  • :docinfo2: include document specific and general custom content. Files to be included must be named <docname>-docinfo.html and docinfo.html for head element and <docname>-docinfo-footer.html and docinfo-footer.html for footer content.\

In this sample we create the files docinfo.html and docinfo-footer.html we want to include in the generated output from the following Asciidoctor source file:

= Asciidoctor custom header and footer
Hubert A. Klein Ikkink
// Document specific and general custom
// content files are used:
:docinfo2: 
// Include general custom content files:
//:docinfo1:
// Include document specific content files:
//:docinfo:
// In generated HTML this is transformed
// to <meta name="description" content="..."/>
:description: Sample document with custom header and footer parts.
// In generated HTML this is transformed
// to <meta name="keywords" content="..."/>
:keywords: Asciidoctor, header, footer, docinfo

Using the `docinfo` attributes we can include custom content
in the header and footer. Contents of the files 
named `docinfo.html` and `docinfo-footer.html` are included.

We can choose between general or document specific custom
header and footer content.

Our docinfo.html looks like this:

<!-- Change some CSS. -->
<style>
/* Change CSS overflow for table of contents. */
#toc.toc2, #toc { overflow: scroll; }

/* Change styling for footer text. */
.footer-text { color: rgba(255,255,255,.8); }
</style>

<!-- We could also include Javascript 
     for example in this document. -->

For the custom footer we create the file docinfo-footer.html:

<p class="footer-text">
<!-- We can use document attributes: -->
Generated with Asciidoctor v{asciidoctor-version}.
</p>

The following screenshot shows the generated HTML page:

And here is part of the generated head element:

<head>

...

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.2">
<meta name="description" content="Sample document with custom header and footer parts.">
<meta name="keywords" content="Asciidoctor, header, footer, docinfo">
<meta name="author" content="Hubert A. Klein Ikkink">
<title>Asciidoctor custom header and footer</title>

...

<!-- Change some CSS. -->
<style>
/* Change CSS overflow for table of contents. */
#toc.toc2, #toc { overflow: scroll; }

/* Change styling for footer text. */
.footer-text { color: rgba(255,255,255,.8); }
</style>

<!-- We could also include Javascript
     for example in this document. -->
</head>

Written with Asciidoctor 1.5.2.

Original post written on April 20, 2015

Include Raw HTML

If we use the HTML backend with Asciidoc we can use a passthrough block to include raw HTML in the output. The contents of a passthrough block is untouched and will be put literally in the generated output. A passthrough block is enclosed in four plus signs (++++).

In the following sample Asciidoc markup we include some Javascript:

++++
<p><span id="replaceMe">Sample content</span> replaced by Javascript</p>
<script>
document.getElementById('replaceMe').innerHTML = 'New content!'
</script>
++++

The generated HTML will execute the Javascript and we get the following output:

We can also add raw HTML inline in our Asciidoc markup. We can enclose the HTML in triple plus signs (+++) or use the pass:[] macro. The following sample shows the markup where both methods are used:

We can also use passthrough inline macros to have raw HTML in the output.

For example with three plus symbols we can +++<em>emphasize text</em>+++.

Or we can use the inline macro syntax with the +pass+ name to pass:[<strong>make text strong</strong>].

The generated HTML looks like this:

Code written with Asciidoctor 0.1.4.

Original post written on June 11, 2014

Use Inline Icons

Asciidoctor adds the icon: macro to the Asciidoc markup. With the macro we can insert an icon in our text. We specify the name of the icon after the macro name. If we use an HTML backend together with the document attribute icons set to the value font we can use Font Awesome Icons. If we want to use icon images the icon is looked up in the directory specified by the attribute iconsdir. For example the Docbook backend will use this to insert an icon.

In the following markup we use the icon macro to insert a comment and file icon:

:icons: font

icon:comment[] This is a comment icon

icon:file[] And a file icon

We get the following result:

And the following HTML is generated:

<div class="paragraph">
<p><span class="icon"><i class="icon-comment"></i></span> This is a comment icon</p>
</div>

<div class="paragraph">
<p><span class="icon"><i class="icon-file"></i></span> And a file icon</p>
</div>

We can specify CSS classes using the role attribute for the macro. But together with the HTML backend and font-based icons we can also use other attributes: size, rotate and flip. The size attribute can specified without the attribute name if we use it as the first attribute:

// Change icon size
icon:comment[4x] This is a comment icon
// Alternative icon:comment[size="4x"]
// Possible values: large, 2x, 3x, 4x, 5x

// Flip and rotate
icon:file[flip="vertical", rotate="180", role="lime"] And a file icon
// Possible flip values: vertical, horizontal
// Possible rotate values: 90, 180, 270

When we generate HTML we get the following result:

When we want to use an inline icon as a link we can use the attributes link and window:

// Use link attribute to specify link.
// Optional window attribute will be the target window.
icon:user[link="http://www.mrhaki.com/about", window="_blank"]

Image based icons have the following attributes, like an image: alt, width, height, title, role.

Code written and generated with Asciidoctor 0.1.4.

Original post written on June 19, 2014

Changing the FontAwesome CSS Location

To use font icons from FontAwesome we set the document attribute icons with the value font. The default link to the CSS location is https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome.min.css. We can change the location for the FontAwesome CSS with document attributes.

If we want to use a different CDN to serve the CSS we can set the document attribute iconfont-cdn and set the URI as a value:

:icons: font

// Set new URI for reference to FontAwesome CSS
:iconfont-cdn: //maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css

== Sample doc

To reference the FontAwesome CSS from a relative location from our generated HTML page we can first unset the attribute iconfont-remote and set the attribute iconfont-name:

:icons: font

// First unset attribute to remotely link FontAwesome CSS
:iconfont-remote!:

// Specify name of FontAwesome CSS.
:iconfont-name: fontawesome-4.1.0

// We can optionally set the directory where CSS is stored.
:stylesdir: css

== Sample doc

In the generated HTML source we see the following link element:

...
<link rel="stylesheet" href="css/fontawesome-4.1.0.css">
...

Written with Asciidoctor 1.5.0.

Original post written on August 15, 2014

Change URI Scheme for Assets

When we define the document attribute icons with the value font the FontAwesome fonts are loaded in the generated HTML page. In the head section of the HTML document a link element to the FontAwesome CSS on https://cdnjs.cloudflare.com/ajax/libs is added. Also when we use the highlight.js or Prettify source highlighter a link to the Javascript files on the cdnjs.cloudflare.com server is generated. We can change the value of the scheme from https to http by setting the attribute asset-uri-scheme to http. Or we can leave out the scheme so a scheme-less URI is generated for the links. A scheme-less URI provides the benefit that the same protocol of the origin HTML page is used to get the CSS or Javascript files from the cdnjs.cloudflare.com server. Remember this might provide a problem if the HTML page is opened locally.

In the next sample Asciidoc markup we change the scheme to http:

:asset-uri-scheme: http
:icons:font

== Asset URI Scheme

Sample document.

In the generated HTML we see the new scheme value:

<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome\
.min.css">

Now we leave the value of the asset-uri-scheme attribute empty:

:asset-uri-scheme: 
:icons:font

== Asset URI Scheme

Sample document.

The generated HTML now contains a link to the FontAwesome CSS with a scheme-less URI:

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome.min.\
css">

Written with Asciidoctor 1.5.0.

Original post written on August 15, 2014

Replacements For Text To Symbols

With Asciidoctor we can use text to describe a symbol in our markup. The text is automatically transformed to a Unicode replacement. For example if we use the text (C) it is converted to &#169; which is the copyright symbol: ©.

In the following sample we see all the symbol replacements:

Written with Asciidoctor 1.5.2.

Original post written on September 15, 2016

Turn Section Titles Into Links

When we use Asciidoctor to write and generate our documentation we can use the document attributes sectanchors or sectlinks to turn section titles into link references. This can be useful if we want for example to bookmark a section.

The sectanchors attribute will show a section icon in front of the section title when we hover over the title. The icon itself is the link to the section.

Section title in generated HTML output.

Hover over section title and icon is shown.

Section icon is link reference.

With the sectlinks attribute the section title itself is the link. So we don't get an icon if we hover of the title, but the title text itself is now the link.

The section title is now a link.

Original post written on May 23, 2014

Leave Section Titles Out of Table Of Contents

Section titles in our document (titles start with two or more equals signs) are part of the document hierarchy and therefore can be used in a generated table of contents. If we don't want to include a section title in the table of contents we must make the title discrete. The title is styled like a normal section title, but it is no longer part of the document structure as title. Therefore the section title will not be generated in the table of contents. To make a title discrete we must use the attribute discrete for the title.

In the following document we first have a simple document with two section titles. When we generate the HTML for this document we see both titles in the table of contents.

:toc:
= Section example

== Introduction

Simple introduction section.

== More

There is more information in this document.

Now we make the first section title discrete by applying the discrete attribute:

:toc:
= Section example

[discrete]
== Introduction

Simple introduction section.

== More

There is more information in this document.

We generate the document again as HTML and this time we see the section title is no longer in the table of contents:

Written with Asciidoctor 1.5.2.

Original post written on September 10, 2015

Change Level Offset For Included Documents

When we use the include directive to include another document we can must make sure the included document fits the levels of our main document. For example the included document shouldn't have level 0 headings if the main document already contains a level 0 heading. We can change the level offset in the main document before including another document. This will change the heading levels for the included document so all heading rules are okay.

To change the level offset we use the document attribute leveloffset. It is best to use a relative value, so if the included document also contains included document the output will still be okay and the heading rules still apply. Alternatively we can use the leveloffset attribute for the include directive. In the following sample document we include other files with a level 0 heading:

// File: book.adoc
= Include other files
// Include section numbers.
:sectnums:

// The file `chapter1.adoc` has a level 0 heading.
// To make sure it can be included we
// increase the level offset.
:leveloffset: +1

include::chapter1.adoc[]

// Reset level offset.
:leveloffset: -1
// Or use :leveloffset: 0

// We can also use the `leveloffset` attribute
// of the `include` directive. The level offset
// is then automatically reset.
include::chapter2.adoc[leveloffset=+2]

Here is the source for the included files:

// File: chapter1.adoc
= First chapter

Sample document to be included.
// File: chapter2.adoc
= Second chapter

Sample document to be included.

When we transform book.adoc to HTML with Asciidoctor we get the following result:

\

Written with Asciidoctor 1.5.4.

Original post written on September 20, 2016

Use Counters in Markup

In Asciidoctor we can create a document attribute as a counter attribute. The attribute is automatically incremented each time we use it in our markup. We can choose to use numbers or characters. Only latin characters from 'a' to 'z' or 'A' to 'Z' are allowed. By default the counter will start at 1, but we can define another start value when we use the counter attribute for the first time.

To define a counter attribute we must prefix the attribute name with counter:. Each time we use this syntax with the counter: prefix the value is incremented and displayed. To only display the current value, without incrementing, we simply refer to the document attribute without the counter: prefix. For example if we want to add a counter attribute with the name steps we would use the following markup in Asciidoctor: {counter:steps}.

To increment the counter without display it we must replace counter: with counter2:. The value of the attribute is incremented but not displayed. So to increment our steps attribute we would use the syntax: {counter2:steps}. To get the current value without incrementing we simply use {steps}.

To start with a different value than 1 we can suffix the attribute name with :<:start-value>. Let's look at how we would create the steps counter attribute starting from 100: {counter:steps:100}. To have a counter with letters we define the start value as a letter from which we want to count: {counter:steps:A}.

In the following example markup we see different usages of the counter support in Asciidoctor:

== Counters

In Asciidoctor we can use counters. To use them
we ({counter:usage}) use a document attribute
prefixed with `counter:` and ({counter:usage}) use it again
to increment the counter.

Instead of numbers we can use characters. To use them
we ({counter:usageChar:A}) use a document attribute
prefixed with `counter:` and suffix `:A` and ({counter:usageChar}) use it again
to increment the counter.

=== Current value

Current value for a counter can be obtained by just referring to document attribute name. 
Value counter is *{usage}*.

=== Increment

{counter2:usage} We can also increment the counter without displaying the value. 
On the next increment the value is *{counter:usage}*.

=== Start at

To start at another number than 1 we can specify the starting counter value as 
a suffix to the counter attribute as `:<start>`.

{counter:sample:10}. do something followed by {counter:sample}. something else.

When we transform this to HTML with Asciidoctor we get the following result:

\

Written with Asciidoctor 1.5.4.

Original post written on September 16, 2016

To make an image linkable in Asciidoctor when formatted to HTML we must use the link attribute when we use the image macro. The value of the link attribute is the address where the user goes when clicking on the image. We can also specify extra link attributes like window to specify the target window for the link to open in.

In the following example we use the link attribute for a block and inline image, with and without an extra window attribute:

= Image with link

== Simple link

Using the `link` attribute with `image:`

image::haki-logo.png[link="https://www.mrhaki.com"]
A block image.

image:haki-logo.png[link="https://www.mrhaki.com"]
As inline image.

== Link attributes

Set link attribute `window="_blank"` to open link in new browser window:

image::haki-logo.png[link="https://www.mrhaki.com",window="_blank"]

When we transform this markup to HTML we get the following HTML for the images:

...
<div class="paragraph">
<p>Using the <code>link</code> attribute with <code>image:</code></p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="https://www.mrhaki.com"><img src="./images/haki-logo.png" alt="haki logo"></a>
</div>
</div>
<div class="paragraph">
<p>A block image.</p>
</div>
<div class="paragraph">
<p><span class="image"><a class="image" href="https://www.mrhaki.com"><img src="./images/haki-logo.png\
" alt="haki logo"></a></span>
As inline image.</p>
</div>
</div>
...
<div class="imageblock logo">
<div class="content">
<a class="image" href="https://www.mrhaki.com" target="_blank" rel="noopener"><img src="./images/haki-\
logo.png" alt="haki logo"></a>
</div>
...

Written with Asciidoctor 2.0.9.

Original post written on April 23, 2020

Since Asciidoctor 1.5.0 we can use the document attribute hide-uri-scheme to turn URLs into links, where the link text is displayed without the URI scheme. This can save typing when we simply want to add a URL without any special description.

In the next Asciidoc syntax we first define URLs without the hide-uri-scheme attribute, followed by URLs after the attribute is set:

Reference to http://www.mrhaki.com is 
turned into link +
`+<a href="http://www.mrhaki.com">http://www.mrhaki.com</a>+`.

To loose URI scheme we could write the link
as http://www.mrhaki.com[www.mrhaki.com]. Or we 
can use the new attribute `hide-uri-scheme` which is
added to Asciidoctor 1.5.0.

:hide-uri-scheme:

After applying the `hide-uri-scheme` attribute
the URI scheme is removed from the text in links.
So a reference to http://www.mrhaki.com is
turned into the link +
`+<a href="http://www.mrhaki.com">www.mrhaki.com</a>+`

This also works for other URI schemes like `file`.
For example 
file:///Users/mrhaki/file.txt is translated to +
`+<a href="file:///Users/mrhaki/file.txt">/Users/mrhaki/file.txt</a>+`.

When we generate output using the HTML backend we see the following output:

Written with Asciidoctor 1.5.0.

Original post written on August 12, 2014

To define a link in Asciidoc markup we only have to type the URL followed by an optional text for the link in square brackets ([text link]). With Asciidoctor we can add extra attributes that can be used when the content is generated. We have to set the document attribute :linkattrs: to make sure Asciidoctor will process the attributes.

In the following sample Asciidoc markup we define links with attributes like window and role:

:linkattrs:

http://mrhaki.blogspot.com[Messages from mrhaki, window="_blank"]

// Because window=_blank is used often we can 
// use the shortcut ^.
http://mrhaki.blogspot.com[Messages from mrhaki^, role="ext-link"]

The following HTML is generated when we use Asciidoctor with the HTML backend:

<div class="paragraph">
<p><a href="http://mrhaki.blogspot.com" target="_blank">Messages from mrhaki</a></p>
</div>
<div class="paragraph">
<p><a href="http://mrhaki.blogspot.com" class="ext-link" target="_blank">Messages from mrhaki</a></p>
</div>

Code written with Asciidoctor 0.1.4.

Original post written on June 13, 2014

Prevent Transformation of URL to Hyperlink

Normally if we type an URL in Asciidoctor that starts with a scheme Asciidoctor knows about, the URL is turned into a hyperlink. The following schemes are recognized by Asciidoctor:

  • http
  • https
  • ftp
  • irc
  • mailto
  • email@email.com

If we want to keep our URL as text and not a link we must prepend our URL with a backslash (\). This way Asciidoctor will not transform the URL to a hyperlink in our output.

In the following example we have URL that is transformed to a link, followed by the same URL but with a backslash (\) before it, that is not transformed:

== URL not as a link

The URL http://www.asciidoctor.org  should
be turned into a hyperlink.

But now the URL \http://www.asciidoctor.org should
just be text and not a hyperlink.

If we transform our document to HTML with Asciidoctor we get the following result:

Written with Asciidoctor 1.5.6.1.

Original post written on October 12, 2017

Customize How Missing Attributes Are Handled

Document attributes are like variables for your Asciidoctor document. Normally when we reference an attribute that is not set in our Asciidoctor markup the reference is still in the output. This is very handy, because we immediately see that a document attribute is not set. But we can customize this behavior with the document attribute attribute-missing. We can use the default value skip, which leaves the reference in the output. Another option is drop, which means the reference is dropped from the output. Finally we can set the value to drop-line, where the complete line with the attribute reference is dropped from the output.

In the following sample Asciidoctor markup we set the three values for the attribute attribute-missing:

== Handle Missing Attributes

:attribute-missing: skip

.`:attribute-missing: skip`
Line with attribute {sample-attr}, should show attribute reference.

:attribute-missing: drop

.`:attribute-missing: drop`
Line with attribute {sample-attr}, drops attribute reference.

:attribute-missing: drop-line

.`:attribute-missing: drop-line`
Line with attribute {sample-attr}, is completely dropped.

When we transform this to HTML5 we get the following output:

Written with Asciidoctor 1.5.2.

Original post written on February 25, 2015

Substitute Attribute in Listing Block

To write a listing block where the contents of the block is generated in a monospace font and line breaks are preserved is easy with Asciidoc. We can use ---- or [listing] or indent the paragraph with one space to define a listing block. All content in a listing block is processed as is, but special characters and callouts are processed. This means if we have an attribute in our block the attribute is not substituted with the actual value. To enable the replacement of the attribute with the attribute value we must set the subs attribute for our listing block.

Suppose we have the following listing block in our documentation with the attribute grailsVersion in the content:

:grailsVersion: 2.3.8

----
$ grails -version
Grails version: {grailsVersion}
----

When we generate HTML output we get the following result:

We add now the subs attribute to our listing and use the value attributes+ to instruct Asciidoctor to replace attributes with their values:

:grailsVersion: 2.3.8

[subs="attributes+"]
----
$ grails -version
Grails version: {grailsVersion}
----

The generated HTML now shows that the attribute value is used:

Alternative ways to define the listing block with the subs attribute. These will render the same result:

[listing,subs="attributes+"]
$ grails -version
Grails version: {grailsVersion}

[subs="attributes+"]
 $ grails -version
 Grails version: {grailsVersion}

Written with Asciidoctor 0.1.4.

Original post written on May 23, 2014

Escape Attribute References

One of the many cool features of Asciidoc is attribute substitution. We can define attributes with values and in our Asciidoc markup we reference those attributes between curly braces. For example we could include the value of the attribute customAttr like this in Asciidoc: {customAttr}. But sometimes we simply want to include some text between curly braces without any attribute value substitution. We need to put an escape character (\) before the first brace and Asciidoc will not replace the attribute with a value.

Suppose we have the following Asciidoc, where we want to explain some Groovy syntax ("${sampleValue}"). Asciidoc will try to substitute the attribute sampleValue with a value if set.

This is a sample where we include +"${}"+ as a Groovy GString sample. 
The sample +"${attrValue}"+ should be unchanged in the output.

If we generate HTML with Asciidoctor we get the following output and notice that attrValue is changed to attrvalue (lower case v):

If we add the escape character no attribute substitution will take place, even if we assign a value to the attribute attrValue:

:attrValue: sample

This is a sample where we include +"${}"+ as a Groovy GString sample. 
The sample +"$\{attrValue}"+ should be unchanged in the output.

Now we get the output we expect:

Written with Asciidoctor 0.1.4.

Original post written on July 3, 2014

Document Attributes With Styling

Document attributes in Asciidoctor are very powerful. We can assign values to a document attributes and reference the attribute name in our document enclosed between curly braces. Asciidoctor will fill in the value when the document is transformed. Instead of a plain value we can also use styling markup in the document attribute definition. We must use the passthrough macro and allow for quote substitution.

In the following example document we define three document attributes: cl-added, cl-updated and cl-changed. We use the passthrough macro, quotes substation to assign CSS classes:

= Attributes with styles
// Include contents of docinfo.html
// in HTML head with CSS style
// definitions for .label.added,
// .label.changed and .label.updated
// used in the document attributes
// cl-added, cl-changed and cl-updated.
:docinfo1:

// Document attribues with styling,
// using the passthrough macro
// and quotes subsitution.
// We can use quotes or the short-hand q.
:cl-added: pass:quotes[[.label.added]#Added:#]
:cl-changed: pass:q[[.label.changed]#Changed:#]
:cl-updated: pass:q[[.label.updated]#Updated:#]


== Sample section

* {cl-added} Document attributes for document.
* {cl-changed} Definition of attributes to include
 more options.
* {cl-updated} New version of Asciidoctor.

Notice we need a file docinfo.html with the CSS style definitions:

<style>
.label {
    color: #fff;
    padding: .2em .6em .3em;
    font-weight: 700;
    border-radius: .25em;
    font-size: 90%;
}

.added {background-color: #007700;}
.changed {background-color: #088;}
.updated {background-color: #3344bb;}
</style>

When run Asciidoctor to get HTML output we see the following:

Written with Aciidoctor 1.5.7.1.

Original post written on September 2, 2018

Using Conditional Directives

In Asciidoc markup we can include or exclude text based on the existence of document attributes or based on the value of a document attribute. Therefore we use the macros ifdef, ifndef and ifeval. If we want to include some content if the document attribute sample is set we can use the following syntax:

ifdef::sample[Content is shown when sample attribute is set]

ifdef::sample[]
Content is shown when sample attribute is set
endif::sample[]

If we want to include some content if the attribute is not set we use ifndef:

ifndef::sample[Content is shown when sample attribute is NOT set]

ifndef::sample[]
Content is shown when sample attribute is NOT set
endif::sample[]

We can even use multiple attributes for these macros. If the attribute names are , separated only one of the attributes need to be set to include the content. If we use the + separator all attributes must be set to include the content.

In the following sample Asciidoc markup we see several usages of the ifdef and ifndef macros:

|===
| Attributes

|
ifdef::intermediate[:intermediate:]
ifndef::intermediate[:intermediate!:]

|
ifdef::advanced[:advanced:]
ifndef::advanced[:advanced!:]

|===


ifdef::advanced[]
This is only visible if we 
set the advanced attribute.
endif::advanced[]

ifdef::intermediate,advanced[]
Here is some content for the
intermediate or advanced readers,
which is visible if the attributes
intermediate or advanced are set.
endif::intermediate,advanced[]

ifdef::intermediate+advanced[]
Here is some content for the
intermediate and advanced readers,
which is visible if the attributes
intermediate AND advanced are set.
endif::intermediate+advanced[]

If we generate HTML output and set and unset the intermediate and advanced document attributes we see that content is included or not:

\

Finally with Asciidoctor we can use the ifeval macro to evaluate the value of attributes. If the expression evaluates to true the content is included otherwise it is skipped. The following sample evaluate the version document attribute and shows different content based on the value:

|===
| Attributes

|
:version: {version}

|===


ifeval::[{version} >= 1]
We are live!
endif::[]


ifeval::[{version} < 1]
Still developing...
endif::[]

Let's generate HTML with different values for the version attribute:

Written with Asciidoctor 0.1.4.

Original post written on August 5, 2014

Conditional Directive to Check If Document is On GitHub

In a previous blog post we learned about the conditional directives in Asciidoctor. Dan Allen mentioned a conditional directive that we can use to see if the document is used on GitHub. The conditional directive is called env-github.

We have the following Asciidoc markup for a document stored on GitHub:

:blogpost: http://mrhaki.blogspot.com/2014/08/awesome-asciidoc-check-if-document-is.html

= Asciidoc on GitHub

Sample document for {blogpost}[Aweseome Asciidoc blog post].

ifdef::env-github[]
This line is only visible if the document is on GitHub.
GitHub is using Asciidoctor {asciidoctor-version}.
endif::env-github[]

ifndef::env-github[This line is visible if not rendered on GitHub.]

To see what is rendered we can view the document on GitHub.

Written with Asciidoctor 1.5.0.

Original post written on August 26, 2014

Using Document Fragments

Normally all Asciidoc files are processed and transformed to output files by Asciidoctor. But if we start the file name with an underscore (_) the file is not transformed to an output file. This is very useful, because we can define some Asciidoc document fragments and include them in other Asciidoc files, but in the output directory the document fragment is not generated.

Let's create two Asciidoc files. One is _attrs.adoc which is a document fragment file that is used in sample.doc:

// File: _attrs.adoc
:blogger_url: http://mrhaki.blogspot.com
:blogger_tag: Aweseome Asciidoctor
:author: mrhaki
// File: sample.adoc
include::_attrs.adoc[]

== Sample

Asciidoctor handles files starting
with an underscore (`_`) differently. The file is
not processed, but can be used in other Asciidoc
documents.

More {blogger_url}[blog posts] about
{blogger_tag} available written by {author}.

From the command line we can invoke the asciidoctor command. We also check the directory and see there is only the file sample.html:

$ asciidoctor sample.adoc
$ ls
_attrs.adoc sample.adoc sample.html
$

The following screenshot shows how the sample.html looks like in a web browser:

Written with Asciidoctor 1.5.1.

Original post written on November 25, 2014

Keep Line Breaks in Paragraphs

Normally when we write a paragraph in Asciidoc markup the line breaks are not preserved. Multiple lines are combined into a paragraph until an empty line is found to separate paragraphs. If we want to keep line breaks we must add the plus sign (+) at the end of the line. If we generate HTML from the Asciidoc markup a line break is inserted with a <br> tag. We can also use the hardbreaks document attribute to enable or disable line breaks in paragraphs without the addition of the + symbols.

In the following Asciidoc sample we use the + sign to keep line breaks in a paragraph:

// Use + to keep line breaks in paragraph.
A sample paragraph +
with line breaks +
applied using the _+_ symbol.

A sample paragraph 
without line breaks,
because the _+_ symbol 
is not used.

We get the following result if we use the HTML backend:

We can also use the hardbreaks attribute:

:hardbreaks:

A sample paragraph 
with line breaks.
Although the _+_ symbol 
is not used, but the
document attribute 
*:hardbreaks:* is set.

// Disable hardbreaks for reminder of document.
:!hardbreaks:

If we generate HTML we get the following result:

Samples written with Asciidoctor 0.1.4.

Original post written on June 25, 2014

Auto Number Callouts

In a previous post we learned about callouts in Asciidoctor to add explanation to source code. While surfing the Internet I came upon the following blog post by Alex Soto: Auto-numbered Callouts in Asciidoctor. I turns out that since Asciidoctor 1.5.8 we can use a dot (.) instead of explicit numbers to have automatic increasing numbering for the callouts.

Let's take our example from the earlier blog post and now use auto numbered callouts:

= Callout sample
:source-highlighter: prettify
:icons: font

[source,groovy]
----
package com.mrhaki.adoc

class Sample {
    String username // <.>

    String toString() {
        "${username?.toUpperCase() ?: 'not-defined'}" // <.>
    }
}
----
<.> Simple property definition where Groovy will generate the `setUsername` and `getUsername` methods.
<.> Return username in upper case if set, otherwise return `not-defined`.

When we convert this markup to HTML we get the following result:

This makes it very easy to add new callouts without having to change all numbers we first typed by hand.

Written with Asciidoctor 2.0.9

Original post written on December 10, 2019

Apply Custom Styling to Blocks

To define a listing block to display for example source code in Asciidoc is easy. We can use ---- delimiter or explicitly use [listing] and include the source code. If we use the HTML backend to generate HTML the result will be a pre block enclosed in some div sections with a couple CSS classes applied. If we want to add our own CSS classes to the generated output we can apply so-called roles to our block.

In the following Asciidoc markup we apply a role with the name console to a listing block. Remember we can use the same syntax for other types of blocks as well.

[source,role="console"]
----
$ ls
index.adoc
$
----

If we generate HTML we get the following HTML code. Notice the class attribute of the first div contains console:

<div class="listingblock console">
<div class="content">
<pre class="prettyprint"><code>$ ls
index.adoc
$</code></pre>
</div>
</div>

We can use an alternate syntax which resembles CSS classes closely. We can use dot (.) followed by the role name.

[source.console]
----
$ ls
index.adoc
$
----

If we want to apply multiple roles (CSS classes) we can specify the names separated by spaces in the role attribute or chain the names with .:

[source.console.shell]
----
$ ls
index.adoc
$
----

// Or use role attribute:
[source,role="console shell"]
----
$ ls
index.adoc
$
----

// If we don't apply the source attribute,
// we can still set roles:
[.console]  // Or [role="console"]
----
$ ls
index.adoc
$
----

// If we do not use the delimiter, 
// but specify block type:
[listing.console] // Or [listing,role="console"]
$ ls
index.adoc
$

By specifying role values we can customize how the output looks with different implementation for the CSS classes that we want.

Code generated by Asciidoctor 0.1.4.

Original post written on June 16, 2014

Customize the Figure Captions

With Asciidoctor we can use images in our documents with the image directive. When the document is converted each image gets a caption. By default the caption label is Figure followed a number for the position of the image in the document. So the first image has a caption Figure 1.. If we add a block title (text prefixed with a .) to the image then that text is used in the caption as well. We can customize the caption label, figure counter, caption text or disable the figure caption using a combination of document and image attributes.

We have the following Asciidoctor markup. We include several images and customize the figure caption settings. To change the caption label (Figure) we set a different value for the document attribute figure-caption. In our example we use the value Logo. Any captions following this definition will have the label Logo.

To use a separate counter we can use a counter attribute inside the caption attribute for our image. In our example we use this for the Gradle logo. If we want to use another caption text instead of the block title we can use the title attribute for an image.

Finally to disable all figure captions we negate the figure-caption document attribute.

= Figure caption

// Default the figure caption
// label is Figure.
.SDKMAN!
image::./sdkman-logo.png[]

// Set caption for figures
// for the rest of the document
// to the value Logo.
:figure-caption: Logo

// The figure caption label is Logo.
.Groovy
image::./groovy-logo.png[]

// Custom caption label for this image
// where we can still use a counter.
.Gradle
image::./gradle-logo.png[caption="Logo 1-{counter:logo}"]

// Instead of using the image block
// title in the caption we define
// our own caption text with the title
// attribute.
.Ratpack
image::./ratpack-logo.png[title="Ratpack library"]

// Disable all captions for figures.
:!figure-caption:

.Grails
image::./grails-logo.png[]

When we transform this markup to HTML we get the following output:

\

Written with Asciidoctor 1.5.4.

Original post written on September 26, 2016

Grouping Floating Images

With Asciidoctor markup we can position images in our document. We can even float images, so text can next to an image, inside only below or about the image. We can also define multiple images to float, so the images are displayed on the same line next to each other. Any text that follows these images is also displayed next to the images. If we want only to have floating images, but the text starting under the images we can place the images inside an open block and assign the block the role float-group.

In the next example we first define three images that all have roles to float left. In the second part we group these images using the role float-group, so the text will not be displayed next to the images, but under the images:

:imagesdir: images/

= Grouping floats

// Images in open block to indicate 
// they belong together.
--
image::groovy.png[float="left"]
image::gradle.png[float="left"]
// Define float role, instead of attribute.
[.left]
image::grails.png[]
--

The images are all on one line,
but the text is next to the images.

If we want the images to be on one line,
but the text underneath them, we must use
a _float-group_ role, like in the
following example.

[.float-group]
--
image::groovy.png[float="left"]
image::gradle.png[float="left"]
// Define float role, instead of attribute.
[.left]
image::grails.png[]
--

The images above are all grouped together
to appear on one line.

And the text is not next to the images, but
underneath the images, like we wanted.

When we create a HTML document from the Asciidoctor markup we get the following result:

Written with Asciidoctor 1.5.6.1.

Original post written on October 4, 2017

Trick To Use Caption Labels And Numbers In References

In Asciidoctor we can add an anchor with an ID to a section or title and then reference it in a link. The title of the section is used as link text. We can alter that when we define the link, but if we rely on the default behaviour we create a title for our section including the caption label and number. This way the created link points to the correct section and the text contains the caption text and number for that section.

In the following example markup we can see how we can use the caption label and section counter as attributes in the title. We do this with the title attribute of a section. By using the single quotes we tell Asciidoctor to interpret the attributes. We must also make sure we set the caption attribute to an empty string value. This disables the default caption creation of Asciidoctor for our section. Finally we need to provide an ID for the section using the #ID syntax:

= Code examples
// Enable the captions for listing blocks.
:listing-caption: Listing

== Creating an application

To create a simple Ratpack application we write
the following code:

// Our listing block has an id of SimpleJavaApp,
// so we can reference it as a link.
// The link text is the title of this listing block.
// We use the listing caption support of Asciidoctor
// in our title with the attributes listing-caption
// and counter:refnum. The value of listing-caption
// is defined with a document attribute (Listing)
// and counter:refnum contains the counter value
// for listing blocks.
// Finally we empty the caption attribute, otherwise
// the default caption rule is used to show Level {counter}.
[#SimpleJavaApp,source,java,caption='',title='{listing-caption} {counter:refnum}. Simple Java Ratpack \
application']
----
package com.mrhaki;

import ratpack.server.RatpackServer;

public class Main {
    public static void main(String... args) throws Exception {
        RatpackServer.start(server ->
            server
                .handlers(chain ->
                    chain
                        .get(ctx -> ctx.render("Hello World!"))));
    }
}
----

// A second section also with an ID 
// and custom caption and title attributes.
[#SimpleGroovyApp,source,groovy,caption='',title='{listing-caption} {counter:refnum}. Simple Groovy Ra\
tpack application']
----
package com.mrhaki

import static ratpack.groovy.Groovy.ratpack

ratpack {
    handlers {
        get {
            render "Hello World!"
        }
    }
}
----

// In these paragraphs we create a link to the sections with
// id's SimpleJavaApp and SimpleGroovyApp. The text of the links
// will be Listing 1. Simple Java Ratpack application and
// Listing 2. Simple Groovy Ratpack application.
As we can see in <<SimpleJavaApp>> the code is simple. The configuration
of the Ratpack application is done using a series of methods.

With the Groovy code in <<SimpleGroovyApp>> we can use a DSL to define
the application. This results in even better readable code.

When we generate a HTML version of this markup we get the following result:

Written with Asciidoctor 1.5.4.

Original post written on September 26, 2016

Changing Values for Default Captions

Asciidoctor has several captions and labels that can be overridden with document attributes. We need to define a document attribute and assign a new value to override a default caption or label. We can use UTF-8 characters as the value. The following list shows captions and labels we can override:

  • :appendix-caption:
  • :caution-caption:
  • :example-caption:
  • :figure-caption:
  • :important-caption:
  • :last-update-label:
  • :manname-title:
  • :note-caption:
  • :table-caption:
  • :tip-caption:
  • :toc-title:
  • :untitled-label:
  • :version-label:
  • :warning-caption:

In the next example Asciidoctor document we override caution-caption and last-update-label:

= Change default captions

:caution-caption: Watch out!
:last-update-label: I was created on

== Sample

CAUTION: Simple caution message to show changed caption.

We get the following HTML output:

This mechanism can be used to provide messages for other languages than English. The Asciidoctor Github repository contains a file with already translated values for a lot of languages. We include this document in our own Asciidoctor markup and we set the document attribute lang with the value we want, eg. nl. In the following example document we include the file https://raw.githubusercontent.com/asciidoctor/asciidoctor/v1.5.5/data/locale/attributes.adoc.

= Asciidoctor
// Set lang document attribute.
// This attribute is used in the
// included document attributes.adoc.
:lang: nl

// Include translations for built-in captions and labels.
// To make the inclusion with a URI work we must
// run Asciidoctor with attribute allow-uri-read:
// $ asciidoctor -a allow-uri-read sample.adoc
:i18n-labels-uri: https://raw.githubusercontent.com/asciidoctor/asciidoctor/v1.5.5/data/locale
include::{i18n-labels-uri}/attributes.adoc[]

// Simple caution block, where caption
// should be replaced by Dutch text.
CAUTION: Simpel bericht met `lang` document attribuut: {lang}.

// Labels for example blocks are also
// translated.
.Titel
====
Bijvoorbeeld label voor voorbeelden is ook aangepast.
====

When we invoke Asciidoctor via the command line we must add the option -a allow-uri-read to the remote document is included. The following screenshot shows the output:

Written with Asciidoctor 1.5.5.

Original post written on October 11, 2016

Display Keyboard Shortcuts

When we want to explain in our documentation which keys a user must press to get to a function we can use the keyboard macro in Asciidoctor. The macro will output the key nicely formatted as a real key on the keyboard. The syntax of the macro is kbd:[key]. To get the desired output we must set the document attribute experimental otherwise the macro is not used.

In the next Asciidoctor example file we use the keyboard macro:

= Keyboard macro

With the keyboard macro `kbd:[shortcut]`
we can include nicely formatted keyboard
shortcuts.

// We must enable experimental attribute.
:experimental:

// Define unicode for Apple Command key.
:commandkey: &#8984;

Press kbd:[{commandkey} + 1] or kbd:[Ctrl + 1] 
to access the _Project_ view.

To zoom out press kbd:[Ctrl + -].

Find files with kbd:[Ctrl + Alt + N] or kbd:[{commandkey} + Shift + N].

When we transform this to HTML with the built-in HTML5 templates we get the following output:

Written with Asciidoctor 1.5.2.

Original post written on April 22, 2015

Exclude Parts From Included Files

In a previous post we learned how to include parts of a document in the generated output. The included parts are defined using tags. The start of a tag is defined in a comment with the format tag::tagName[] and the end has the format end::tagName[]. Next we must use the tags attribute for the include macro followed by the tagName. If we don't want to include a tag we must prefix it with an exclamation mark (!).

Suppose we have an external Java source we want to include in our Asciidoctor document.

package mrhaki;

// tag::singletonAnnotation[]
@Singleton
// end::singletonAnnotation[]
public class Sample {
    public String greeting() {
        return "Hello Asciidoctor";
    }
}

In the following sample Asciidoctor document we include Sample.java, but we don't want to include the text enclosed with the singletonAnnotation tag. So we use tags=!singletonAnnotaion with the include macro:

= Sample

To NOT include sections enclosed with tags we must use `tags=!<tagName>` in the `include` directive.

[source,java]
----
include::Sample.java[tags=!singletonAnnotation]
----

When we transform our Asciidoctor markup to HTML we get the following result:

Written with Asciidoctor 1.5.6.1.

Original post written on January 29, 2019

Using Asciidoctor In Javadoc Comments

Asciidoctor is a great tool for writing technical documentation. The documentation to our Java source is what we write in Javadoc comments. Wouldn't it be nice if we could use Asciidoctor in our Javadoc comments? Of course! We can achieve this with the Asciidoclet Javadoc doclet. The doclet processes the Javadoc comments as Asciidoctor source and generates HTML in the final Javadoc documentation. We can use all of Asciidoc syntax like tables, lists, include directives, styling and more. We can even use Asciidoctor extensions like asciidoctor-diagram.

In the following Java source code we have Javadoc comments with Asciidoctor syntax. We have document attributes, list, styling, include macro, table and asciidoctor-diagram code in our Javadoc. Notice that we don't have the clutter of HTML tags we normally we would have if we write Javadoc.

package com.mrhaki.sample;

/**
 * = Application
 *
 * Project version: {projectVersion}.
 *
 * Sample Java application in project {projectName}
 * to show Asciidoclet as replacement for the
 * default Javadoclet.
 *
 * We can apply Asciidoc syntax in our Javadoclet
 * comments, like:
 *
 *  - `code`
 *  - **bold**
 *  - _italics_
 *
 * include::./src/main/javadoc/usage.adoc[]
 *
 * [plantuml]
 * ....
 * hide footbox
 *
 * actor Client
 * Client -> Application : main()
 * ....
 *
 * @author mrhaki
 * @version 1.0
 */
public class Application {

    /**
     * Main method to start the application.
     *
     * The following arguments are allowed
     * (easy Asciidoc table syntax):
     *
     * |===
     * | Name | Description
     *
     * | --help
     * | Getting more help about the application.
     *
     * | --info
     * | Show extra logging information
     *
     * |===
     *
     */
    public static void main(final String... arguments) {
        System.out.println("Application started...");
    }

}

Next we create a Gradle build file and configure the javadoc task to use the Asciidoclet Javadoc doclet. In our Java class we also used the asciidoctor-diagram support and therefore we also need to set up the Gradle jruby plugin.

plugins {
    // jruby plugin needed for asciidoctor-diagram gem.
    id 'com.github.jruby-gradle.base' version '0.1.5'
}
apply plugin: 'java'

version = '1.2.1'

ext {
    asciidoctorDocletVersion = '1.5.2'
}

configurations {
    // Extra configuration to assign Asciidoclet dependencies to.
    // This way the dependency will not interfer with oterh configurations.
    asciidoctorDoclet
}

repositories.jcenter()

dependencies {
    // Define dependencies for Asciidoclet.
    asciidoctorDoclet group: 'org.asciidoctor',
                 name: 'asciidoclet',
                 version: project.asciidoctorDocletVersion

    // Define dependency on asciidoctor-diagram Ruby gem.
    // Only needed when we want to use asciidoctor-diagram in our Javadoc.
    gems 'rubygems:asciidoctor-diagram:1.2.0'
}

// Download required gems. Only when we need gems in our Javadoc.
javadoc.dependsOn jrubyPrepareGems

javadoc {
    // Configure Javadoc options.
    options.with {
        // Configure Asciidoclet class path and class name
        // for the Javadoc task.
        docletpath = configurations.asciidoctorDoclet.files.asType(List)
        doclet = 'org.asciidoctor.Asciidoclet'

        // Set base dir. E.g. used for include directives.
        // Asciidoclet attributes need to be prefixed with -.
        // - is turned into -- when Javadoc tool is executed.
        addStringOption '-base-dir', projectDir.toString()

        // We can add Asciidoc document attributes and use them
        // in our Javadoc comments. E.g. {projectName}.
        def attributes = [projectName: project.name,
                          projectVersion: project.version]

        // Configure Asciidoclet to use asciidoctor-diagram gem.
        addStringOption '-require', 'asciidoctor-diagram'
        addStringOption '-gem-path', jrubyPrepareGems.outputDir.absolutePath
        // Include generated diagram inline.
        attributes['data-uri'] = ''

        // Combine document attributes with key/value pairs separated
        // by a comma. These are the document attributes passed
        // on to Asciidoctor.
        addStringOption '-attribute', attributes*.toString().join(',')

        // Overview document can also be a Asciidoctor document.
        overview = 'src/main/javadoc/overview.adoc'

        // Show version and author tags.
        // Normal Javadoc tags are correctly processed.
        version = true
        author = true
    }
}

When we run the javadoc task we get the generated output. For example part of the generated documentation for our Application class looks like this:

Documentation for the main method:

Remember this only applies to Javadoc. If we write Groovy code and use Groovydoc to generate documentation we cannot use Asciidoclet.

Written with Asciidoclet 1.5.2 and Gradle 2.7.

Original post written on October 12, 2015