github asciidoctor/asciidoctor v2.0.0


Now this is a major version. The big 2.0!

This release is a major step forward for Asciidoctor. Not only does it get us over the pitfall of second version syndrome, it marks a switch to semantic versioning and a faster release cycle. It also goes a long way towards modernizing the codebase by dropping unsupported versions of Ruby (Ruby < 2.3 and JRuby < 9.1), switching to modern Ruby syntax and IO / encoding operations, dumping workarounds for older versions of Ruby, removing load path manipulation and string mutation, clarifying the boundaries of the API, tightening the extension DSL, testing on newer Ruby platforms such as TruffleRuby, beginning to apply consistent formatting to the source code, and applying substantial cleanups to the test suite. We're also working on rolling out a brand new documentation site powered by Antora (Asciidoctor's documentation site builder) that brings substantial content updates (soon to be available at And, as always, there's a measurable boost in performance, with roughly a 7% improvement in processing speed on CRuby and a 20% improvement on JRuby!

But this release is about more than just the versioning strategy, refactoring, and performance. There are a number of notable features for you to explore that further the extensibility of the platform.


The main feature highlight of the 2.0 release is the pluggable syntax highlighter. Prior to 2.0, the syntax highlighting integration was baked directly into the core processor, only offering the option to use CodeRay, Pygments, highlight.js, and prettify. These integrations are all still supported out of the box, along with a new integration with Rouge (>= 2.1), but they're all now implementations of the syntax highlighter extension. And having been given a fresh look, all of these integrations have been polished and improved. (For example, you can specify additional languages for highlight.js to load using the highlightjs-languages attribute and dark Pygments styles are fully supported).

Like with custom converters, you can register a new or replacement syntax highlighter. The adapter receives callbacks for all the strategic points at which the syntax highlighter needs to contribute to the conversion process, including highlighting the source code and contributing external resources to the output. You can publish your syntax highlighting adapter as a RubyGem to share with other users.

The converter API has been completely redesigned based on the work done for the syntax highlighter API. But don't worry, existing converters are expected to continue to work as the old APIs have been bridged to the new ones. A custom converter can now be registered in just a few lines of code. It's even possible to access and extend the built-in converters (which now use the same API) using Converter.for, making it easier than ever to develop your own converter. If you extended from the provided base converter, all convert handler methods are prefixed with convert_ to prevent them from colliding with built-in and helper methods (and an adapter is included to ensure compatibility with existing converters). To top it off, converter registration is now thread-safe out of the box. As you dive deep into the new API, you're sure to discover even more added value.

In Asciidoctor 2.0, we say goodbye to the DocBook 4.5 converter. DocBook 4.5 was superceded by DocBook 5 nearly a decade ago and there's no reason anyone should be using it anymore. But, if for some reason, you still rely on DocBook 4.5 output, it wouldn't be hard to take the code from 1.5.8 and develop a custom converter to produce it.

As a heads up, source document files must be encoded in UTF-8 or have a BOM (magic encoding hint). Asciidoctor does not accept documents encoded any other way. In short, when reading a file, Asciidoctor either honors the BOM or assumes the encoding is UTF-8. When using the API, on the other hand, you can pass a string with a different encoding and Asciidoctor will automatically reencode it to UTF-8 (using Ruby's String#encode method).

There are some nice enhancements and shorthands when creating content. If you set the collapsible option on an example block, it will be converted to a details/summary tag set (and the requisite styles have been added to the default stylesheet to support this block type). If the source language is set on a listing block or on the document, the block is automatically promoted to a source block. When defining index terms, you can now specifiy the see or see also relationship. If for some reason the AsciiDoc syntax escaping you, a handy cheatsheet is always at your fingertips using the command asciidoctor --help syntax.

Other highights of this release are as follows:

  • fixed a number of crashes and one hang in parser due to unexpected or malformed content
  • substitutions in section and block titles are now applied in normal substitution order
  • block attributes no longer inherit from document attributes by default (a feature now reserved for specific cases only)
  • processor substitutes footnotes after all other macros
  • processor substitutes custom inline macros before all other macros
  • attribute-missing setting respected when processing include directives and block macros
  • log dropped lines at info level when attribute-missing=drop-line (including include directives)
  • enhanced find_by to locate table cells and blocks inside AsciiDoc table cells
  • renamed find_by directives to better aligns with NodeFilter from DOM (:reject instead of :skip, :prune instead of :skip_children, :stop to short-circuit)
  • added parse_attributes helper to base extension processor class
  • separated the functionality of the -w (enable script warnings) and -v (enable verbose logging) CLI flags
  • allow failure level of CLI to be set to info
  • renamed header_footer option to standalone and add the -e, --embedded CLI flag as an alias for -s, --no-header-footer
  • can now delegate to a registered backend using the syntax synthetic:delegate when using custom templates with an unregistered backend name
  • if the target of a formal xref macro has a file extension, assume it's a path reference
  • added a docinfo insertion slot in the header location of a standalone output document and moving the footer insertion slot below built-in docinfo content
  • log debug message instead of a warning when the block style is unknown to further promote the use of block extensions
  • log warning message at info level if inline macro processor returns a String value
  • always store the section numeral as a string; compute part numeral at assignment
  • allow the ID and role properties to be set on the API for ordered and unordered list items
  • inline anchors at the start of callout list items get cataloged (and thus valid xref targets)
  • always use :refs table in the document catalog to look for registered IDs and stop populating the deprecated :ids table
  • modified the Table::Cell class to extend from AbstractBlock instead of AbstractNode
  • apply subs to Inline node returned by inline macro processor if specified
  • dropped the verse table cell and the 2-character quote block syntax
  • renamed hardbreaks document attribute to hardbreaks-option
  • substitute replacements in author values used in document header
  • extend TLD for implicit e-mail addresses to 5 characters; allow ampersand in address part
  • drop legacy LaTeX math delimiters if present (for compatibility with pandoc output)
  • only promote indexterms automatically if indexterm-promotion option is set (DocBook output)
  • drop indexterms table from document catalog in preparation for new model to be introduced in 2.x


Asciidoctor is also packaged for Fedora, Debian, Ubuntu, Alpine Linux, OpenSUSE, and Homebrew. You can use the system's package manager to install the package named asciidoctor.

Release meta

Released on: 2019-03-22
Released by: @mojavelinux
Release beer: A selection of beers from Collaboration Fest 2019 and the FireStone Walker 22nd Anniversary Ale

Logs: resolved issues | full diff


We'd like to give a big shout out to @mogztter, who provided critical technical assistance and advice to help get this release finished and to make it what it is today.

Thanks to the following people who contributed to this release:

@mogztter, @graphitefriction, @zelivans, @nik9000, @robertpanzer, @aerostitch, @andrewcarver, @vmj, @owenh000, @Hentaro1989, @eskwayrd, @apnadkarni, @benhourigan, @lordofthejars, @miltador, @oncletom, @farleylai, @bimlas, @rahmanusta, @taqtiqa-mark, @chrylis, @nfrankel, @fiech, @gdamore, @rkratky, @jghub, @zaxebo1, @andorchen, @obilodeau, @schauder, @mafritsch, @plaindocs, @dmalan, @michael-o, @alexanderzobkov, @jods4, @jtkorb, @sbrannen, @razrfalcon, @paulofrancalacerda, @andrewcarver, @sums801, @sandmann1, @jxxcarlson, @janicesignalfx, @abelsromero, @jirutka, @elextr, @danyill, @ulehnerhs, @5pacetoast, @anidotnet, @lodestone, @phlow, @jaredmorgs, @stephenhay, @chickenkiller, @foadsf, @skycaptain

Additional thanks to the following people for updating translations of the built-in attributes: @deining, @bnogent.

The push to Asciidoctor 2.0 was fueled by our former Change Maker sponsor, Okta. We want to thank Okta for their support, as well as our other generous sponsors, without whose support Asciidoctor would not be possible. Thank you sponsors for your dedication to improving the state of technical documentation!

You can support this project by becoming a sponsor on OpenCollective. For those still contributing via BountySource, we kindly ask that you switch your donations over to OpenCollective because it's a nicer system and better aligns with our values.

A very special thanks to all our awesome supporters on OpenCollective. Their support provided critical funding for the development of this release and the ongoing development of the project.


Enhancements / Compliance

  • drop support for Ruby < 2.3 and JRuby < 9.1 and remove workarounds (#2764)
  • drop support for Slim < 3 (#2998)
  • drop the converter for the docbook45 backend (#3005)
  • apply substitutions to section and block titles in normal substitution order (#1173)
  • make syntax highlighter pluggable; extract all logic into adapter classes (#2106)
  • add syntax highlighter adapter for Rouge (>= 2.1) (#1040)
  • redesign Converter API based on SyntaxHighlighter API; remap deprecated API to new API to ensure compatibility (#2891)
  • repurpose built-in converters as regular converters (#2891)
  • make registration and resolution of global converters thread-safe (#2891)
  • fold the default converter factory into the Converter module (#2891)
  • add a default implementation for Converter#convert in the Base converter (#2891)
  • rename Converter::BackendInfo to Converter::BackendTraits; map backend_info to new backend_traits method (#2891)
  • allow built-in converter classes to be resolved using Converter#for and instantiated using Converter#create (#2891)
  • allow converter factory to be passed using :converter_factory API option (#2891)
  • honor htmlsyntax if defined on converter (#2891)
  • add backend_traits_source keyword argument to CompositeConverter constructor (#2891)
  • add support for start attribute when using prettify to highlight source blocks with line numbering enabled
  • use String#encode to encode String as UTF-8 instead of using String#force_encoding (#2764)
  • add FILE_READ_MODE, URI_READ_MODE, and FILE_WRITE_MODE constants to control open mode when reading files and URIs and writing files (#2764)
  • set visibility of private and protected methods (#2764)
  • always run docinfo processor extensions regardless of safe mode (gives control to extension) (#2966)
  • use infinitive verb form for extension DSL method names; map deprecated method names where appropriate
  • add docinfo insertion slot for header location to built-in converters (#1720)
  • add support for the muted option on vimeo videos (allows autoplay to work in Chrome) (#3014)
  • use value of prettify-theme attribute as is if it starts with http:// or https:// (#3020)
  • allow icontype to be set using icons attribute (#2953)
  • when using a server-side syntax highlighter, highlight content of source block even if source language is not set (#3027)
  • automatically promote a listing block without an explicit style to a source block if language is set (#1117)
  • remove the 2-character (i.e., "") quote block syntax
  • don't allow block role to inherit from document attribute; only look for role in block attributes (#1944)
  • split out functionality of -w CLI flag (script warnings) from -v CLI flag (verbose logging) (#3030)
  • log possible invalid references at info level (#3030)
  • log dropped lines at info level when attribute-missing=drop-line (#2861)
  • honor attribute-missing setting when processing include directives and block macros (#2855)
  • log warning when include directive is not resolved due to missing attribute or blank target; always include warning in output document (#2868)
  • use the third argument of AbstractNode#attr / AbstractNode#attr? to set the name of a fallback attribute to look for on the document (#1934)
  • change default value of third argument to Abstractnode#attr / AbstractNode#attr? to nil so attribute doesn't inherit by default (#3059)
  • look for table-frame, table-grid, and table-stripes attributes on document as fallback for frame, grid, and stripes attributes on table (#3059)
  • always assume the target of a shorthand interdocument xref is a reference to an AsciiDoc document (source-to-source) (#3021)
  • if the target of a formal xref macro has a file extension, assume it's a path reference (#3021)
  • never assume target of a formal xref macro is a path reference unless a file extension or fragment is present (#3021)
  • encode characters in URI to comply with RFC-3986
  • implement full support for styled xreftext in manpage converter (#3077)
  • allow the ID and role properties to be set on a list item of ordered and unordered lists via the API (#2840)
  • yield processor instance to registration block for document processor if block has non-zero arity (i.e., has parameters)
  • add Document#parsed? method to check whether document has been parsed
  • modify Cell class to extend from AbstractBlock instead of AbstractNode (#2963)
  • implement block? and inline? methods on Column, both which return false (#2963)
  • drop verse table cell style (treat as normal table cell) (#3111)
  • allow negated subs to be specified on inline pass macro (#2191)
  • log warning if footnoteref macro is found and compat mode is not enabled (#3114)
  • log info message if inline macro processor returns a String value (#3176)
  • apply subs to Inline node returned by inline macro processor if subs attribute is specified (#3178)
  • add create_inline_pass helper method to base extension processor class (#3178)
  • log debug message instead of warning if block style is unknown (#3092)
  • allow backend to delegate to a registered backend using the syntax synthetic:delegate when using custom templates (e.g., slides:html) (#891)
  • AbstractBlock#find_by looks inside AsciiDoc table cells if traverse_documents selector option is true (#3101)
  • AbstractBlock#find_by finds table cells, which can be selected using the :table_cell context in the selector (#2524)
  • allow ampersand to be used in e-mail address (#2553)
  • propogate ID assigned to inline passthrough (#2912)
  • rename control keywords in find_by to better align with the standard NodeFilter terminology
  • stop find_by iteration if filter block returns :stop directive
  • rename header_footer option to standalone (while still honoring header_footer for backwards compatibility) (#1444)
  • replace anchors and xrefs before footnotes (replace footnotes last in macros substitution group)
  • apply substitution for custom inline macro before all other macros
  • only promote index terms automatically (A, B, C becomes A > B > C + B > C + C) if indexterm-promotion option is set on document (#1487)
  • add support for see and see-also on index terms; parse attributes on indexterm macros if text contains = (#2047)
  • drop :indexterms table from document catalog (in preparation for solution to #450 in a 2.x release)
  • load additional languages for highlight.js as defined in the comma-separated highlightjs-languages attribute (#3036)
  • log warning if conditional expression in ifeval directive is invalid (#3161)
  • drop lines that contain an invalid preprocessor directive (#3161)
  • rename AbstractBlock#find_by directives; use :prune in place of :skip_children and :reject in place of :skip
  • convert example block into details/summary tag set if collapsible option is set; open by default if open option is set (#1699)
  • substitute replacements in author values used in document header (#2441)
  • require space after semi-colon that separates multiple authors (#2441)
  • catalog inline anchors at start of callout list items (#2818) (@owenh000)
  • add parse_attributes helper method to base extension Processor class (#2134)


  • propagate document ID to DocBook output (#3011)
  • always store section numeral as string; compute roman numeral for part at assignment time (@vmj)
  • refactor code to use modern Hash syntax
  • define LIB_DIR constant; rename *_PATH constants to *_DIR constants to be consistent with RubyGems terminology (#2764)
  • only define ROOT_DIR if not already defined (for compatibility with Asciidoctor.js)
  • move custom docinfo content in footer below built-in docinfo content in footer in HTML converter (#3017)
  • read and write files using File methods instead of IO methods (#2995)
  • value comparison in AbstractNode#attr? is only performed if expected value is truthy
  • align default CodeRay style with style for other syntax highlighters (#2106)
  • ensure linenos class is added to linenos column when source highlighter is pygments and pygments-css=style
  • rename CSS class of Pygments line numbering table to linenotable (to align with Rouge) (#1040)
  • remove unused Converter#convert_with_options method (#2891)
  • add -e, --embedded CLI flag as alias for -s, --no-header-footer (require long option to specify eRuby impl) (#1444)
  • don't store the options attribute on the block once the options are parsed (#3051)
  • add an options method on AbstractNode to retrieve the set of option names (#3051)
  • pass :input_mtime option to Document constructor; let Document constructor assign docdate/time/year attributes (#3029)
  • never mutate strings; add a frozen_string_literal: true magic comment to top of all Ruby source files (#3054)
  • always use docdate and doctime to compute docyear and docdatetime (#3064)
  • rename PreprocessorReader#exceeded_max_depth? to PreprocessorReader#exceeds_max_depth? and return nil if includes are disabled
  • stop populating :ids table in document catalog (#3084)
  • always use :refs table in document catalog to look for registered IDs (#3084)
  • don't compute and store reference text in document catalog (#3084)
  • populate reference text table lazily for resolving ID by reference text (#3084)
  • don't store fallback reference text on :bibref node (#3085)
  • call AbstractNode#reftext instead of AbstractNode#text to retrieve reference text for bibref node (#3085)
  • only map unparsed attrlist of inline macro to target when format is short
  • add clearer exception message when source data is binary or has invalid encoding (#2884)
  • rename context for table cell and table column to :table_cell and :table_column, respectively
  • rename hardbreaks document attribute to hardbreaks-option; retain hardbreaks as a deprecated alias (#3123)
  • extend TLD for implicit e-mail addresses to 5 characters (#3154)
  • truncate with precision (instead of rounding) when computing absolute width for columns in DocBook output (#3131)
  • drop legacy LaTeX math delimiters (e.g, $..$) if present (#1339)
  • use proper terminology in warning message about mismatched preprocessor directive (#3165)
  • rename low-level extension attribute name :pos_attrs to :positional_attrs
  • mark default_attrs extension DSL method deprecated in favor of default_attributes
  • upgrade MathJax to 2.7.5

Bug Fixes

  • fix crash caused by inline passthrough macro with the macros sub clearing the remaining passthrough placeholders (#3089)
  • fix crash if ifeval directive is missing expression (#3164)
  • prevent relative leveloffset from making section level negative and causing hang (#3152)
  • don't fail to parse Markdown-style quote block that only contains attribution line (#2989)
  • enforce rule that Setext section title must have at least one alphanumeric character; fixes problem w/ block nested inside quote block (#3060)
  • apply header subs to doctitle value when assigning it back to the doctitle document attribute (#3106)
  • don't fail if value of pygments-style attribute is not recognized; gracefully fallback to default style (#2106)
  • do not alter the $LOAD_PATH (#2764)
  • fix crash if stem block is empty (#3118)
  • remove conditional comment for IE in output of built-in HTML converter; fixes sidebar table of contents (#2983)
  • fix styling of source blocks with linenums enabled when using prettify as syntax highlighter (#640)
  • update default stylesheet to support prettify themes (#3020)
  • remove hard-coded color values on source blocks in default stylesheet (#3020)
  • add fallback if relative path cannot be computed because the paths are located on different drives (#2944)
  • ignore explicit section level style (#1852)
  • don't eat space before callout number in source block if line-comment attribute is empty (#3121)
  • check if type is defined in a way that's compatible with autoload
  • fix invalid check for DSL in extension class (previously always returned true)
  • scope constant lookups (#2764)
  • use byteslice instead of slice to remove BOM from string (#2764)
  • don't fail if value of -a CLI option is empty string or equals sign (#2997)
  • allow failure level of CLI to be set to info
  • Reader#push_include should not fail if data is nil
  • fix deprecated ERB trim mode that was causing warning (#3006)
  • move time anchor after query string on vimeo video to avoid dropping options
  • allow color for generic text, line numbers, and line number border to inherit from Pygments style (#2106)
  • enforce and report relative include depth properly (depth=0 rather than depth=1 disables nested includes)
  • allow outfilesuffix to be soft set from API (#2640)
  • don't split paragraphs in table cell at line that resolves to blank if adjacent to other non-blank lines (#2963)
  • initialize the level to WARN when instantiating the NullLogger
  • next_adjacent_block should not fail when called on dlist item (#3133)
  • don't suppress browser styles for summary tag; add pointer cursor and panel margin bottom (#3155)
  • only consider TLDs in e-mail address that have ASCII alpha characters
  • allow underscore in domain of e-mail address

Build / Infrastructure

  • clear SOURCE_DATE_EPOCH env var when testing timezones (PR #2969) (@aerostitch)
  • remove compat folder (removes the AsciiDoc Python config file that provides pseudo-compliance with Asciidoctor and a stylesheet for an old Font Awesome migration)
  • add Ruby 2.6.0 to build matrix
  • stop running CI job on unsupported versions of Ruby
  • exclude test suite, build script, and Gemfile from gem (#3044)
  • split build tasks out into individual files
latest releases: v2.0.16, v2.0.15, v2.0.14...
2 years ago