Skip to content

Commit a81ec9b

Browse files
committed
Preserve inline styling inside tidy link labels
1 parent 88db613 commit a81ec9b

File tree

3 files changed

+148
-11
lines changed

3 files changed

+148
-11
lines changed

lib/rdoc/markup/to_html.rb

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,19 +158,16 @@ def handle_regexp_RDOCLINK(target)
158158
def handle_regexp_TIDYLINK(target)
159159
text = target.text
160160

161-
return text unless
162-
text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/
163-
164-
label = $1
165-
url = CGI.escapeHTML($2)
161+
if tidy_link_capturing?
162+
return finish_tidy_link(text)
163+
end
166164

167-
if /^rdoc-image:/ =~ label
168-
label = handle_RDOCLINK(label)
169-
else
170-
label = CGI.escapeHTML(label)
165+
if text.start_with?('{') && !text.include?('}')
166+
start_tidy_link text
167+
return ''
171168
end
172169

173-
gen_url url, label
170+
convert_complete_tidy_link(text)
174171
end
175172

176173
# :section: Visitor
@@ -359,7 +356,14 @@ def accept_table(header, body, aligns)
359356
# CGI-escapes +text+
360357

361358
def convert_string(text)
362-
CGI.escapeHTML text
359+
html = CGI.escapeHTML text
360+
361+
if tidy_link_capturing?
362+
append_to_tidy_label html
363+
''
364+
else
365+
html
366+
end
363367
end
364368

365369
##
@@ -458,4 +462,104 @@ def to_html(item)
458462
super convert_flow @am.flow item
459463
end
460464

465+
private
466+
467+
def append_to_tidy_label(fragment)
468+
return unless @tidy_link_buffer
469+
470+
@tidy_link_buffer << fragment
471+
end
472+
473+
def convert_complete_tidy_link(text)
474+
return text unless
475+
text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/
476+
477+
label = $1
478+
url = CGI.escapeHTML($2)
479+
480+
label_html = if /^rdoc-image:/ =~ label
481+
handle_RDOCLINK(label)
482+
else
483+
render_tidy_link_label(label)
484+
end
485+
486+
gen_url url, label_html
487+
end
488+
489+
def emit_tidy_link_fragment(res, fragment)
490+
if tidy_link_capturing?
491+
append_to_tidy_label fragment
492+
else
493+
res << fragment
494+
end
495+
end
496+
497+
def finish_tidy_link(text)
498+
label_tail, url, trailing = extract_tidy_link_parts(text)
499+
500+
append_to_tidy_label CGI.escapeHTML(label_tail) unless label_tail.empty?
501+
502+
return '' unless url
503+
504+
label_html = @tidy_link_buffer
505+
506+
@tidy_link_buffer = nil
507+
508+
link = gen_url(url, label_html)
509+
510+
return link if trailing.empty?
511+
512+
link + CGI.escapeHTML(trailing)
513+
end
514+
515+
def extract_tidy_link_parts(text)
516+
if text =~ /^(.*?)\}\[(.*?)\](.*)$/
517+
[$1, CGI.escapeHTML($2), $3]
518+
else
519+
[text, nil, '']
520+
end
521+
end
522+
523+
def on_tags(res, item)
524+
each_attr_tag(item.turn_on) do |tag|
525+
emit_tidy_link_fragment(res, annotate(tag.on))
526+
@in_tt += 1 if tt? tag
527+
end
528+
end
529+
530+
def off_tags(res, item)
531+
each_attr_tag(item.turn_off, true) do |tag|
532+
emit_tidy_link_fragment(res, annotate(tag.off))
533+
@in_tt -= 1 if tt? tag
534+
end
535+
end
536+
537+
def start_tidy_link(text)
538+
@tidy_link_buffer = String.new
539+
append_to_tidy_label CGI.escapeHTML(text.delete_prefix('{'))
540+
end
541+
542+
def tidy_link_capturing?
543+
!!@tidy_link_buffer
544+
end
545+
546+
def render_tidy_link_label(label)
547+
RDoc::Markup::LinkLabelToHtml.render(label, @options, @from_path)
548+
end
549+
end
550+
551+
##
552+
# Formatter dedicated to rendering tidy link labels without mutating the
553+
# calling formatter's state.
554+
555+
class RDoc::Markup::LinkLabelToHtml < RDoc::Markup::ToHtml
556+
def self.render(label, options, from_path)
557+
new(options, from_path).to_html(label)
558+
end
559+
560+
def initialize(options, from_path = nil)
561+
super(options)
562+
563+
self.from_path = from_path if from_path
564+
end
461565
end

test/rdoc/rdoc_markdown_test.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,23 @@ def test_gfm_table_with_backslashes_in_code_spans
12631263
assert_equal expected, doc
12641264
end
12651265

1266+
def test_markdown_link_with_styled_label
1267+
markdown = <<~MD
1268+
[Link to Foo](https://example.com)
1269+
1270+
[Link to `Foo`](https://example.com)
1271+
1272+
[Link to **Foo**](https://example.com)
1273+
MD
1274+
1275+
doc = parse markdown
1276+
html = @to_html.convert doc
1277+
1278+
assert_includes html, '<a href="https://example.com">Link to Foo</a>'
1279+
assert_includes html, '<a href="https://example.com">Link to <code>Foo</code></a>'
1280+
assert_includes html, '<a href="https://example.com">Link to <strong>Foo</strong></a>'
1281+
end
1282+
12661283
def parse(text)
12671284
@parser.parse text
12681285
end

test/rdoc/rdoc_markup_to_html_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,22 @@ def test_convert_TIDYLINK_multiple
734734
assert_equal expected, result
735735
end
736736

737+
def test_convert_TIDYLINK_with_code_label
738+
result = @to.convert '{Link to +Foo+}[https://example.com]'
739+
740+
expected = "\n<p><a href=\"https://example.com\">Link to <code>Foo</code></a></p>\n"
741+
742+
assert_equal expected, result
743+
end
744+
745+
def test_convert_TIDYLINK_with_bold_label
746+
result = @to.convert '{Link to *Foo*}[https://example.com]'
747+
748+
expected = "\n<p><a href=\"https://example.com\">Link to <strong>Foo</strong></a></p>\n"
749+
750+
assert_equal expected, result
751+
end
752+
737753
def test_convert_TIDYLINK_image
738754
result =
739755
@to.convert '{rdoc-image:path/to/image.jpg}[http://example.com]'

0 commit comments

Comments
 (0)