diff --git a/lib/ES/Util.pm b/lib/ES/Util.pm
index 906d1a83d93f7..3f3a3abaacf12 100644
--- a/lib/ES/Util.pm
+++ b/lib/ES/Util.pm
@@ -93,6 +93,7 @@ sub build_chunked {
# '-a' => 'attribute-missing=warn',
'-a' => 'asciidoc-dir=' . $asciidoc_dir,
$resources ? ( '-a' => 'resources=' . join(',', @$resources)) : (),
+ '-a' => 'inline-callouts',
'--destination-dir=' . $dest,
docinfo($index),
$index
@@ -211,6 +212,7 @@ sub build_single {
$private ? () : ( '-a' => "edit_url=$edit_url" ),
'-a' => 'asciidoc-dir=' . $asciidoc_dir,
$resources ? ( '-a' => 'resources=' . join(',', @$resources)) : (),
+ '-a' => 'inline-callouts',
# Disable warning on missing attributes because we have
# missing attributes!
# '-a' => 'attribute-missing=warn',
diff --git a/resources/asciidoctor/lib/extensions.rb b/resources/asciidoctor/lib/extensions.rb
index b7eaa25ee5445..b579a22712ac6 100644
--- a/resources/asciidoctor/lib/extensions.rb
+++ b/resources/asciidoctor/lib/extensions.rb
@@ -6,6 +6,9 @@
require_relative 'elastic_compat_preprocessor/extension'
require_relative 'elastic_include_tagged/extension'
+# This extensions is special because it is evil - just loading it is enough
+require_relative 'inline_callout/extension'
+
Extensions.register Added
Extensions.register do
# Enable storing the source locations so we can look at them. This is required
diff --git a/resources/asciidoctor/lib/inline_callout/extension.rb b/resources/asciidoctor/lib/inline_callout/extension.rb
new file mode 100644
index 0000000000000..208d27f9d2ac7
--- /dev/null
+++ b/resources/asciidoctor/lib/inline_callout/extension.rb
@@ -0,0 +1,69 @@
+require 'asciidoctor'
+
+include Asciidoctor
+
+##
+# Enables inline callouts which asciidoc supports but asciidoctor doesn't.
+# Filed as enhancement request at
+# https://github.com/asciidoctor/asciidoctor/issues/3037
+#
+# Usage
+#
+# POST <1> /_search/scroll <2>
+#
+# NOTE: This isn't an asciidoctor extension so much as a hack. Just including
+# the file causes us to monkey patch its code into asciidoctor. By default we
+# don't change asciidoctor, but if you set the `inline-callouts` attribute so
+# you need to *ask* for the change in behavior.
+#
+module InlineCallout
+ InlineCalloutScanRx = /\\?/
+ InlineCalloutSourceRx = %r(((?://|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\3>)
+ InlineCalloutSourceRxt = "(\\\\)?<()(\\d+|\\.)>"
+ InlineCalloutSourceRxMap = ::Hash.new {|h, k| h[k] = /(#{::Regexp.escape k} ?)?#{InlineCalloutSourceRxt}/ }
+
+ # Disable VERBOSE so we don't log any warnings. It really isn't great to
+ # have to patch these in like this but it gets the job done and we're looking
+ # to get this into Asciidoctor proper. These methods are basically the same
+ # as the methods in asciidoctor but with new regexes.
+ old_verbose = $VERBOSE
+ $VERBOSE = false
+ Parser.class_eval do
+ def self.catalog_callouts(text, document)
+ found = false
+ autonum = 0
+ callout_rx = (document.attr? 'inline-callouts') ? InlineCalloutScanRx : CalloutScanRx
+ text.scan(callout_rx) {
+ captured, num = $&, $2
+ document.callouts.register num == '.' ? (autonum += 1).to_s : num unless captured.start_with? '\\'
+ # we have to mark as found even if it's escaped so it can be unescaped
+ found = true
+ } if text.include? '<'
+ found
+ end
+ end
+
+ Substitutors.module_eval do
+ def sub_callouts(text)
+ autonum = 0
+ text.gsub(callout_rx) {
+ # honor the escape
+ if $2
+ # use sub since it might be behind a line comment
+ $&.sub(RS, '')
+ else
+ Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, :id => @document.callouts.read_next_id, :attributes => { 'guard' => $1 }).convert
+ end
+ }
+ end
+
+ def callout_rx
+ if attr? 'line-comment'
+ ((attr? 'inline-callouts') ? InlineCalloutSourceRxMap : CalloutSourceRxMap)[attr 'line-comment']
+ else
+ (attr? 'inline-callouts') ? InlineCalloutSourceRx : CalloutSourceRx
+ end
+ end
+ end
+ $VERBOSE = old_verbose
+end
diff --git a/resources/asciidoctor/spec/inline_callout_spec.rb b/resources/asciidoctor/spec/inline_callout_spec.rb
new file mode 100644
index 0000000000000..071cae1c8202d
--- /dev/null
+++ b/resources/asciidoctor/spec/inline_callout_spec.rb
@@ -0,0 +1,57 @@
+require 'inline_callout/extension'
+
+RSpec.describe InlineCallout do
+ it "enables support for inline callouts if requested" do
+ attributes = {
+ 'inline-callouts' => '',
+ }
+ input = <<~ASCIIDOC
+ ----
+ POST <1> /_search/scroll <2>
+ ----
+ <1> words
+ <2> other words
+ ASCIIDOC
+ expected = <<~DOCBOOK
+
+
+ POST /_search/scroll
+
+
+ words
+
+
+ other words
+
+
+
+ DOCBOOK
+ expect(convert(input, attributes)).to eq(expected.strip)
+ end
+
+ it "does not enable support for inline callouts by default" do
+ input = <<~ASCIIDOC
+ ----
+ POST <1> /_search/scroll <2>
+ ----
+ <1> words
+ <2> other words
+ ASCIIDOC
+ expected = <<~DOCBOOK
+
+
+ POST <1> /_search/scroll
+
+
+ words
+
+
+ other words
+
+
+
+ DOCBOOK
+ actual = convert input, {}, eq('WARN: : line 4: no callout found for <1>')
+ expect(actual).to eq(expected.strip)
+ end
+end
\ No newline at end of file