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")
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
12 changes: 4 additions & 8 deletions lib/rdoc/token_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,7 @@ def self.to_html(token_stream)
then 'ruby-identifier'
end

comment_with_nl = false
if :on_comment == t[:kind] or :on_embdoc == t[:kind] or :on_heredoc_end == t[:kind]
comment_with_nl = true if "\n" == t[:text][-1]
text = t[:text].rstrip
else
text = t[:text]
end
text = t[:text]

if :on_ident == t[:kind] && starting_title
starting_title = false
Expand All @@ -65,7 +59,9 @@ def self.to_html(token_stream)
text = CGI.escapeHTML text

if style then
"<span class=\"#{style}\">#{text}</span>#{"\n" if comment_with_nl}"
end_with_newline = text.end_with?("\n")
text = text.chomp if end_with_newline
"<span class=\"#{style}\">#{text}</span>#{"\n" if end_with_newline}"
else
text
end
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