diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb index c5e4f62c97..dab486aaae 100644 --- a/lib/rdoc/markup/to_html_crossref.rb +++ b/lib/rdoc/markup/to_html_crossref.rb @@ -184,38 +184,35 @@ def link(name, text, code = true, rdoc_ref: false) end end - def convert_flow(flow) + def convert_flow(flow_items, &block) res = [] i = 0 - while i < flow.size - item = flow[i] - i += 1 + while i < flow_items.size + item = flow_items[i] + case item - when RDoc::Markup::AttrChanger then - # Make "+Class#method+" a cross reference - if tt_tag?(item.turn_on) and - String === (str = flow[i]) and - RDoc::Markup::AttrChanger === flow[i+1] and - tt_tag?(flow[i+1].turn_off, true) and - (@options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP).match?(str) and - (text = cross_reference str) != str - then - text = yield text, res if defined?(yield) + when RDoc::Markup::AttrChanger + if (text = convert_tt_crossref(flow_items, i)) + text = block.call(text, res) if block res << text - i += 2 + i += 3 next end + off_tags res, item - on_tags res, item - when String then + on_tags res, item + i += 1 + when String text = convert_string(item) - text = yield text, res if defined?(yield) + text = block.call(text, res) if block res << text - when RDoc::Markup::RegexpHandling then + i += 1 + when RDoc::Markup::RegexpHandling text = convert_regexp_handling(item) - text = yield text, res if defined?(yield) + text = block.call(text, res) if block res << text + i += 1 else raise "Unknown flow element: #{item.inspect}" end @@ -223,4 +220,37 @@ def convert_flow(flow) res.join('') end + + private + + ## + # Detects ... spans that contain a single cross-reference candidate. + # When the candidate occupies the whole span (aside from trailing + # punctuation), the tt markup is replaced by the resolved cross-reference. + + def convert_tt_crossref(flow_items, index) + opener = flow_items[index] + return unless tt_tag?(opener.turn_on) + + string = flow_items[index + 1] + closer = flow_items[index + 2] + + return unless String === string + return unless RDoc::Markup::AttrChanger === closer + return unless tt_tag?(closer.turn_off, true) + + crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP + match = crossref_regexp.match(string) + return unless match + return unless match.begin(1).zero? + + trailing = match.post_match + # Only convert when the remainder is punctuation/whitespace so other tt text stays literal. + return unless trailing.match?(/\A[[:punct:]\s]*\z/) + + text = cross_reference(string) + return if text == string + + text + end end diff --git a/test/rdoc/rdoc_markup_to_html_crossref_test.rb b/test/rdoc/rdoc_markup_to_html_crossref_test.rb index a52c7f1506..e6836ea4c2 100644 --- a/test/rdoc/rdoc_markup_to_html_crossref_test.rb +++ b/test/rdoc/rdoc_markup_to_html_crossref_test.rb @@ -33,6 +33,24 @@ def test_convert_CROSSREF assert_equal para("# :stopdoc::"), result end + def test_convert_CROSSREF_backslash_in_tt + @options.hyperlink_all = false + + formatter = RDoc::Markup::ToHtmlCrossref.new(@options, 'C9.html', @c9_b) + + result = formatter.convert 'C1' + assert_equal para('C1'), result + + result = formatter.convert '.bar.hello()' + assert_equal para('.bar.hello()'), result + + result = formatter.convert '.bar.hello(\)' + assert_equal para('.bar.hello(\)'), result + + result = formatter.convert '.bar.hello(\\\\)' + assert_equal para('.bar.hello(\\)'), result + end + def test_convert_CROSSREF_ignored_excluded_words @options.autolink_excluded_words = ['C1']