Skip to content

Commit

Permalink
resolves #3788 allow closing square bracket in reftext of inline anch…
Browse files Browse the repository at this point in the history
…or shorthand to be escaped
  • Loading branch information
mojavelinux committed Oct 27, 2020
1 parent 882cc24 commit 95e7b1e
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Expand Up @@ -44,6 +44,7 @@ Bug Fixes::
* Use custom init function for highlight.js to select the correct `code` elements (#3761)
* Fix resolved value of :to_dir when both :to_file and :to_dir options are set to absolute paths (#3778)
* Restore label in front of each bibliography entry in DocBook output that was dropped by fix for #3085 (#3782)
* Allow closing square bracket in reftext of inline anchor shorthand to be escaped (#3788)

Compliance::

Expand Down
6 changes: 5 additions & 1 deletion lib/asciidoctor/parser.rb
Expand Up @@ -1131,7 +1131,10 @@ def self.catalog_callouts(text, document)
#
# Returns nothing
def self.catalog_inline_anchor id, reftext, node, location, doc = node.document
reftext = doc.sub_attributes reftext if reftext && (reftext.include? ATTR_REF_HEAD)
if reftext
reftext = reftext.gsub '\]', ']' if reftext.include? ']'
reftext = doc.sub_attributes reftext if reftext.include? ATTR_REF_HEAD
end
unless doc.register :refs, [id, (Inline.new node, :anchor, reftext, type: :ref, id: id)]
location = location.cursor if Reader === location
logger.warn message_with_context %(id assigned to anchor already in use: #{id}), source_location: location
Expand All @@ -1150,6 +1153,7 @@ def self.catalog_inline_anchors text, block, document, reader
text.scan InlineAnchorScanRx do
if (id = $1)
if (reftext = $2)
reftext = reftext.gsub '\]', ']' if reftext.include? ']'
next if (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
end
else
Expand Down
6 changes: 3 additions & 3 deletions lib/asciidoctor/rx.rb
Expand Up @@ -438,13 +438,13 @@ module Rx; end
# anchor:idname[]
# anchor:idname[Reference Text]
#
InlineAnchorRx = /(\\)?(?:\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]|anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\]))/
InlineAnchorRx = /(\\)?(?:\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}*?[^\\]))?\]\]|anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\]))/

# Scans for a non-escaped anchor (i.e., id + optional reference text) in the flow of text.
InlineAnchorScanRx = /(?:^|[^\\\[])\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]|(?:^|[^\\])anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\])/
InlineAnchorScanRx = /(?:^|[^\\\[])\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}*?[^\\]))?\]\]|(?:^|[^\\])anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\])/

# Scans for a leading, non-escaped anchor (i.e., id + optional reference text).
LeadingInlineAnchorRx = /^\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]/
LeadingInlineAnchorRx = /^\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}*?[^\\]))?\]\]/

# Matches a bibliography anchor at the start of the list item text (in a bibliography list).
#
Expand Down
4 changes: 3 additions & 1 deletion lib/asciidoctor/substitutors.rb
Expand Up @@ -719,7 +719,9 @@ def sub_macros text

# NOTE reftext is only relevant for DocBook output; used as value of xreflabel attribute
if (id = $2)
reftext = $3
if (reftext = $3) && (reftext.include? R_SB)
reftext = reftext.gsub ESC_R_SB, R_SB
end
else
id = $4
if (reftext = $5) && (reftext.include? R_SB)
Expand Down
38 changes: 27 additions & 11 deletions test/links_test.rb
Expand Up @@ -396,20 +396,36 @@
end
end

test 'unescapes square bracket in reftext of anchor macro' do
input = <<~'EOS'
see <<foo>>
test 'unescapes square bracket at end of reftext in inline anchor' do
%w([[foo,ba[r\]]] anchor:foo[ba[r\]]).each do |variation|
input = <<~EOS
see <<foo>>
anchor:foo[b[a\]r]tex'
EOS
result = convert_string_to_embedded input
assert_includes result, 'see <a href="#foo">b[a]r</a>'
#{variation}content
EOS
result = convert_string_to_embedded input
assert_includes result, 'see <a href="#foo">ba[r]</a>'
end
end

test 'unescapes square bracket in reftext of anchor macro in DocBook output' do
input = 'anchor:foo[b[a\]r]'
result = convert_inline_string input, backend: :docbook
assert_equal '<anchor xml:id="foo" xreflabel="b[a]r"/>', result
test 'unescapes square bracket in middle of reftext in inline anchor' do
%w([[foo,b[a\]r]] anchor:foo[b[a\]r]).each do |variation|
input = <<~EOS
see <<foo>>
#{variation}content
EOS
result = convert_string_to_embedded input
assert_includes result, 'see <a href="#foo">b[a]r</a>'
end
end

test 'unescapes square bracket in reftext of inline anchor in DocBook output' do
%w([[foo,b[a\]r]] anchor:foo[b[a\]r]).each do |variation|
input = %(#{variation}text)
result = convert_inline_string input, backend: :docbook
assert_equal '<anchor xml:id="foo" xreflabel="b[a]r"/>text', result
end
end

test 'xref using angled bracket syntax' do
Expand Down
38 changes: 38 additions & 0 deletions test/lists_test.rb
Expand Up @@ -839,6 +839,24 @@
assert_xpath '(//p)[1]/a[@href="#mount-evans"][text()="Mount Evans"]', output, 1
end

test 'should allow closing square bracket in anchor at start of unordered list item text to be escaped' do
input = <<~'EOS'
The highest peak in the Front Range is <<grays-peak>>, which tops <<mount-evans>> by just a few feet.
* [[mount-evans,[Mount\] Evans]]At 14,271 feet, Mount Evans is the highest summit of the Chicago Peaks in the Front Range of the Rocky Mountains.
* [[grays-peak,Grays [Peak\]]]
Grays Peak rises to 14,278 feet, making it the highest summit in the Front Range of the Rocky Mountains.
EOS

doc = document_from_string input
refs = doc.catalog[:refs]
assert refs.key?('mount-evans')
assert refs.key?('grays-peak')
output = doc.convert standalone: false
assert_xpath '(//p)[1]/a[@href="#grays-peak"][text()="Grays [Peak]"]', output, 1
assert_xpath '(//p)[1]/a[@href="#mount-evans"][text()="[Mount] Evans"]', output, 1
end

test 'should discover anchor at start of ordered list item text and register it as a reference' do
input = <<~'EOS'
This is a cross-reference to <<step-2>>.
Expand All @@ -859,6 +877,26 @@
assert_xpath '(//p)[1]/a[@href="#step-4"][text()="Step 4"]', output, 1
end

test 'should allow closing square bracket in anchor at start of ordered list item text to be escaped' do
input = <<~'EOS'
This is a cross-reference to <<step-2>>.
This is a cross-reference to <<step-3b>>.
. Ordered list, item 1, without anchor
. [[step-2,Step [2\]]]Ordered list, item 2, with anchor
. Ordered list, item 3, without anchor
.. [[step-3b,Step [3\]b]]Ordered list, item 3b, with anchor
EOS

doc = document_from_string input
refs = doc.catalog[:refs]
assert refs.key?('step-2')
assert refs.key?('step-3b')
output = doc.convert standalone: false
assert_xpath '(//p)[1]/a[@href="#step-2"][text()="Step [2]"]', output, 1
assert_xpath '(//p)[1]/a[@href="#step-3b"][text()="Step [3]b"]', output, 1
end

test 'should discover anchor at start of callout list item text and register it as a reference' do
input = <<~'EOS'
This is a cross-reference to <<url-mapping>>.
Expand Down
23 changes: 23 additions & 0 deletions test/tables_test.rb
Expand Up @@ -1398,6 +1398,29 @@
assert_xpath '(//table/tbody/tr)[2]//th//a[@id="grays-peak"]', output, 1
end

test 'should allow closing square bracket in anchor at start of table cell to be escaped' do
input = <<~'EOS'
The highest peak in the Front Range is <<grays-peak>>, which tops <<mount-evans>> by just a few feet.
[cols="1s,1"]
|===
|[[mount-evans,[Mount\] Evans]]Mount Evans
|14,271 feet
h|[[grays-peak,Grays [Peak\]]]
Grays Peak
|14,278 feet
|===
EOS
doc = document_from_string input
refs = doc.catalog[:refs]
assert refs.key?('mount-evans')
assert refs.key?('grays-peak')
output = doc.convert standalone: false
assert_xpath '(//p)[1]/a[@href="#grays-peak"][text()="Grays [Peak]"]', output, 1
assert_xpath '(//p)[1]/a[@href="#mount-evans"][text()="[Mount] Evans"]', output, 1
end

test 'footnotes should not be shared between an AsciiDoc table cell and the main document' do
input = <<~'EOS'
|===
Expand Down

0 comments on commit 95e7b1e

Please sign in to comment.