Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion lib/rdoc/markup/attribute_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ def initialize
add_html "b", :BOLD, true
add_html "tt", :TT, true
add_html "code", :TT, true

@word_pair_chars = @matching_word_pairs.keys.join

# Matches a word pair delimiter (*, _, +) that is NOT already protected.
# Used by #protect_code_markup to escape delimiters inside <code>/<tt> tags.
@unprotected_word_pair_regexp = /([#{@word_pair_chars}])(?!#{PROTECT_ATTR})/
end

##
Expand Down Expand Up @@ -164,7 +170,7 @@ def convert_attrs_matching_word_pairs(str, attrs, exclusive)
}.keys
return if tags.empty?
tags = "[#{tags.join("")}](?!#{PROTECT_ATTR})"
all_tags = "[#{@matching_word_pairs.keys.join("")}](?!#{PROTECT_ATTR})"
all_tags = "[#{@word_pair_chars}](?!#{PROTECT_ATTR})"

re = /(?:^|\W|#{all_tags})\K(#{tags})(\1*[#\\]?[\w:#{PROTECT_ATTR}.\/\[\]-]+?\S?)\1(?!\1)(?=#{all_tags}|\W|$)/

Expand Down Expand Up @@ -245,6 +251,20 @@ def mask_protected_sequences
@str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of repeated regexp creation like this in this file. I think most of them can be extracted into ivars.

end

##
# Protects word pair delimiters (*, _, +) inside
# <code> and <tt> tags from being processed as inline formatting.
# For example, *bold* in +*bold*+ will NOT be rendered as bold.

def protect_code_markup
@str.gsub!(/<(code|tt)>(.*?)<\/\1>/im) do
tag = $1
content = $2
escaped = content.gsub(@unprotected_word_pair_regexp, "\\1#{PROTECT_ATTR}")
"<#{tag}>#{escaped}</#{tag}>"
end
end

##
# Unescapes regexp handling sequences of text

Expand Down Expand Up @@ -308,6 +328,7 @@ def flow(str)
@str = str.dup

mask_protected_sequences
protect_code_markup

@attrs = RDoc::Markup::AttrSpan.new @str.length, @exclusive_bitmap

Expand Down
24 changes: 24 additions & 0 deletions test/rdoc/markup/attribute_manager_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,30 @@ def test_convert_attrs_ignores_code
assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <code>__send__</code> bar')
end

def test_convert_attrs_ignores_bold_inside_code
assert_equal 'foo <CODE>*bold*</CODE> bar', output('foo <code>*bold*</code> bar')
end

def test_convert_attrs_ignores_em_inside_code
assert_equal 'foo <CODE>_em_</CODE> bar', output('foo <code>_em_</code> bar')
end

def test_convert_attrs_ignores_tt_inside_code
assert_equal 'foo <CODE>+tt+</CODE> bar', output('foo <code>+tt+</code> bar')
end

def test_convert_attrs_ignores_bold_inside_tt
assert_equal 'foo <CODE>*bold*</CODE> bar', output('foo <tt>*bold*</tt> bar')
end

def test_convert_attrs_ignores_em_inside_tt
assert_equal 'foo <CODE>_em_</CODE> bar', output('foo <tt>_em_</tt> bar')
end

def test_convert_attrs_ignores_tt_inside_tt
assert_equal 'foo <CODE>+tt+</CODE> bar', output('foo <tt>+tt+</tt> bar')
end

def test_convert_attrs_ignores_tt
assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <tt>__send__</tt> bar')
end
Expand Down
10 changes: 10 additions & 0 deletions test/rdoc/rdoc_markdown_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,16 @@ def test_markdown_link_with_styled_label
assert_includes html, '<a href="https://example.com">Link to <code>Foo</code> and <code>Bar</code> and <code>Baz</code></a>'
end

def test_code_span_preserves_inline_formatting_chars
# Code spans should display formatting characters literally, not as styling
doc = parse "Code: `*bold*` and `_em_` and `+tt+`"
html = @to_html.convert doc

assert_includes html, '<code>*bold*</code>'
assert_includes html, '<code>_em_</code>'
assert_includes html, '<code>+tt+</code>'
end

def parse(text)
@parser.parse text
end
Expand Down
Loading