rdoc 7.0.3 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -4
- data/doc/markup_reference/markdown.md +558 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/lib/rdoc/code_object/attr.rb +2 -1
- data/lib/rdoc/code_object/class_module.rb +24 -3
- data/lib/rdoc/code_object/context/section.rb +46 -9
- data/lib/rdoc/code_object/context.rb +15 -4
- data/lib/rdoc/code_object/mixin.rb +3 -0
- data/lib/rdoc/code_object/top_level.rb +2 -0
- data/lib/rdoc/comment.rb +1 -1
- data/lib/rdoc/cross_reference.rb +31 -24
- data/lib/rdoc/generator/template/aliki/_head.rhtml +5 -0
- data/lib/rdoc/generator/template/aliki/class.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +48 -36
- data/lib/rdoc/generator/template/aliki/js/aliki.js +8 -2
- data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
- data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +1 -1
- data/lib/rdoc/generator/template/aliki/js/search_controller.js +1 -1
- data/lib/rdoc/generator/template/darkfish/class.rhtml +2 -0
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -0
- data/lib/rdoc/markdown.kpeg +22 -12
- data/lib/rdoc/markdown.rb +36 -26
- data/lib/rdoc/markup/formatter.rb +129 -106
- data/lib/rdoc/markup/heading.rb +101 -29
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/parser.rb +1 -1
- data/lib/rdoc/markup/to_ansi.rb +51 -4
- data/lib/rdoc/markup/to_bs.rb +22 -42
- data/lib/rdoc/markup/to_html.rb +178 -183
- data/lib/rdoc/markup/to_html_crossref.rb +58 -79
- data/lib/rdoc/markup/to_html_snippet.rb +62 -62
- data/lib/rdoc/markup/to_label.rb +29 -20
- data/lib/rdoc/markup/to_markdown.rb +61 -37
- data/lib/rdoc/markup/to_rdoc.rb +86 -26
- data/lib/rdoc/markup/to_test.rb +9 -1
- data/lib/rdoc/markup/to_tt_only.rb +10 -16
- data/lib/rdoc/markup/verbatim.rb +1 -1
- data/lib/rdoc/markup.rb +10 -32
- data/lib/rdoc/parser/changelog.rb +29 -0
- data/lib/rdoc/parser/prism_ruby.rb +44 -32
- data/lib/rdoc/parser/ruby.rb +1 -1
- data/lib/rdoc/text.rb +44 -5
- data/lib/rdoc/token_stream.rb +4 -8
- data/lib/rdoc/version.rb +1 -1
- data/rdoc.gemspec +2 -2
- metadata +7 -12
- data/ExampleMarkdown.md +0 -39
- data/ExampleRDoc.rdoc +0 -210
- data/lib/rdoc/markup/attr_changer.rb +0 -22
- data/lib/rdoc/markup/attr_span.rb +0 -35
- data/lib/rdoc/markup/attribute_manager.rb +0 -405
- data/lib/rdoc/markup/attributes.rb +0 -70
- data/lib/rdoc/markup/regexp_handling.rb +0 -40
data/lib/rdoc/markup/to_html.rb
CHANGED
|
@@ -51,11 +51,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
51
51
|
@in_list_entry = nil
|
|
52
52
|
@list = nil
|
|
53
53
|
@th = nil
|
|
54
|
+
@in_tidylink_label = false
|
|
54
55
|
@hard_break = "<br>\n"
|
|
55
56
|
|
|
56
57
|
init_regexp_handlings
|
|
57
|
-
|
|
58
|
-
init_tags
|
|
59
58
|
end
|
|
60
59
|
|
|
61
60
|
# :section: Regexp Handling
|
|
@@ -72,6 +71,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
72
71
|
# external links
|
|
73
72
|
@markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)#{URL_CHARACTERS_REGEXP_STR}+\w/,
|
|
74
73
|
:HYPERLINK)
|
|
74
|
+
|
|
75
|
+
# suppress crossref: \#method \::method \ClassName \method_with_underscores
|
|
76
|
+
@markup.add_regexp_handling(/\\(?:[#:A-Z]|[a-z]+_[a-z0-9])/, :SUPPRESSED_CROSSREF)
|
|
77
|
+
|
|
75
78
|
init_link_notation_regexp_handlings
|
|
76
79
|
end
|
|
77
80
|
|
|
@@ -80,7 +83,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
80
83
|
|
|
81
84
|
def init_link_notation_regexp_handlings
|
|
82
85
|
add_regexp_handling_RDOCLINK
|
|
83
|
-
add_regexp_handling_TIDYLINK
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
def handle_RDOCLINK(url) # :nodoc:
|
|
@@ -88,6 +90,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
88
90
|
when /^rdoc-ref:/
|
|
89
91
|
CGI.escapeHTML($')
|
|
90
92
|
when /^rdoc-label:/
|
|
93
|
+
return CGI.escapeHTML(url) if in_tidylink_label?
|
|
91
94
|
text = $'
|
|
92
95
|
|
|
93
96
|
text = case text
|
|
@@ -113,11 +116,127 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
113
116
|
end
|
|
114
117
|
end
|
|
115
118
|
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
def handle_PLAIN_TEXT(text)
|
|
120
|
+
emit_inline(convert_string(text))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def handle_REGEXP_HANDLING_TEXT(text)
|
|
124
|
+
emit_inline(text)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def handle_BOLD(nodes)
|
|
128
|
+
emit_inline('<strong>')
|
|
129
|
+
super
|
|
130
|
+
emit_inline('</strong>')
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def handle_EM(nodes)
|
|
134
|
+
emit_inline('<em>')
|
|
135
|
+
super
|
|
136
|
+
emit_inline('</em>')
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def handle_BOLD_WORD(word)
|
|
140
|
+
emit_inline('<strong>')
|
|
141
|
+
super
|
|
142
|
+
emit_inline('</strong>')
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def handle_EM_WORD(word)
|
|
146
|
+
emit_inline('<em>')
|
|
147
|
+
super
|
|
148
|
+
emit_inline('</em>')
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def handle_TT(code)
|
|
152
|
+
emit_inline('<code>')
|
|
153
|
+
super
|
|
154
|
+
emit_inline('</code>')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def handle_STRIKE(nodes)
|
|
158
|
+
emit_inline('<del>')
|
|
159
|
+
super
|
|
160
|
+
emit_inline('</del>')
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def handle_HARD_BREAK
|
|
164
|
+
emit_inline('<br>')
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def emit_inline(text)
|
|
168
|
+
@inline_output << text
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Returns true if we are processing inside a tidy link label.
|
|
172
|
+
|
|
173
|
+
def in_tidylink_label?
|
|
174
|
+
@in_tidylink_label
|
|
175
|
+
end
|
|
118
176
|
|
|
119
|
-
|
|
120
|
-
|
|
177
|
+
# Special handling for tidy link labels.
|
|
178
|
+
# When a tidy link is <tt>{rdoc-image:path/to/image.jpg:alt text}[http://example.com]</tt>,
|
|
179
|
+
# label part is normally considered RDOCLINK <tt>rdoc-image:path/to/image.jpg:alt</tt> and a text <tt>" text"</tt>
|
|
180
|
+
# but RDoc's test code expects the whole label part to be treated as RDOCLINK only in tidy link label.
|
|
181
|
+
# When a tidy link is <tt>{^1}[url]</tt> or <tt>{*1}[url]</tt>, the label part needs to drop leading * or ^.
|
|
182
|
+
# TODO: reconsider this workaround.
|
|
183
|
+
|
|
184
|
+
def apply_tidylink_label_special_handling(label, url)
|
|
185
|
+
# ^1 *1 will be converted to just 1 in tidy link label.
|
|
186
|
+
return label[1..] if label.match?(/\A[*^]\d+\z/)
|
|
187
|
+
|
|
188
|
+
# rdoc-image in label specially allows spaces in alt text.
|
|
189
|
+
return handle_RDOCLINK(label) if label.start_with?('rdoc-image:')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def handle_TIDYLINK(label_part, url)
|
|
193
|
+
# When url is an image, ignore label part (maybe bug?) and just generate img tag.
|
|
194
|
+
if url.match?(/\Ahttps?:\/\/.+\.(png|gif|jpg|jpeg|bmp)\z/)
|
|
195
|
+
emit_inline("<img src=\"#{CGI.escapeHTML(url)}\" />")
|
|
196
|
+
return
|
|
197
|
+
elsif url.match?(/\Ardoc-image:/)
|
|
198
|
+
emit_inline(handle_RDOCLINK(url))
|
|
199
|
+
return
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
if label_part.size == 1 && String === label_part[0]
|
|
203
|
+
raw_label = label_part[0]
|
|
204
|
+
|
|
205
|
+
@in_tidylink_label = true
|
|
206
|
+
special = apply_tidylink_label_special_handling(raw_label, url)
|
|
207
|
+
@in_tidylink_label = false
|
|
208
|
+
|
|
209
|
+
if special
|
|
210
|
+
tag = gen_url(CGI.escapeHTML(url), special)
|
|
211
|
+
unless tag.empty?
|
|
212
|
+
emit_inline(tag)
|
|
213
|
+
return
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
tag = gen_url(CGI.escapeHTML(url), '')
|
|
219
|
+
open_tag, close_tag = tag.split(/(?=<\/a>)/, 2)
|
|
220
|
+
valid_tag = open_tag && close_tag
|
|
221
|
+
emit_inline(open_tag) if valid_tag
|
|
222
|
+
@in_tidylink_label = true
|
|
223
|
+
traverse_inline_nodes(label_part)
|
|
224
|
+
@in_tidylink_label = false
|
|
225
|
+
emit_inline(close_tag) if valid_tag
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def handle_inline(text) # :nodoc:
|
|
229
|
+
@inline_output = +''
|
|
230
|
+
super
|
|
231
|
+
out = @inline_output
|
|
232
|
+
@inline_output = nil
|
|
233
|
+
out
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Converts suppressed cross-reference +text+ to HTML by removing the leading backslash.
|
|
237
|
+
|
|
238
|
+
def handle_regexp_SUPPRESSED_CROSSREF(text)
|
|
239
|
+
convert_string(text.delete_prefix('\\'))
|
|
121
240
|
end
|
|
122
241
|
|
|
123
242
|
##
|
|
@@ -132,9 +251,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
132
251
|
# <tt>link:</tt>::
|
|
133
252
|
# Reference to a local file relative to the output directory.
|
|
134
253
|
|
|
135
|
-
def handle_regexp_HYPERLINK(
|
|
136
|
-
|
|
254
|
+
def handle_regexp_HYPERLINK(text)
|
|
255
|
+
return convert_string(text) if in_tidylink_label?
|
|
137
256
|
|
|
257
|
+
url = CGI.escapeHTML(text)
|
|
138
258
|
gen_url url, url
|
|
139
259
|
end
|
|
140
260
|
|
|
@@ -147,27 +267,8 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
147
267
|
# For the +rdoc-label+ scheme the footnote and label prefixes are stripped
|
|
148
268
|
# when creating a link. All other contents will be linked verbatim.
|
|
149
269
|
|
|
150
|
-
def handle_regexp_RDOCLINK(
|
|
151
|
-
handle_RDOCLINK
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
##
|
|
155
|
-
# This +target+ is a link where the label is different from the URL
|
|
156
|
-
# <tt>label[url]</tt> or <tt>{long label}[url]</tt>
|
|
157
|
-
|
|
158
|
-
def handle_regexp_TIDYLINK(target)
|
|
159
|
-
text = target.text
|
|
160
|
-
|
|
161
|
-
if tidy_link_capturing?
|
|
162
|
-
return finish_tidy_link(text)
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
if text.start_with?('{') && !text.include?('}')
|
|
166
|
-
start_tidy_link text
|
|
167
|
-
return ''
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
convert_complete_tidy_link(text)
|
|
270
|
+
def handle_regexp_RDOCLINK(text)
|
|
271
|
+
handle_RDOCLINK text
|
|
171
272
|
end
|
|
172
273
|
|
|
173
274
|
# :section: Visitor
|
|
@@ -181,6 +282,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
181
282
|
@res = []
|
|
182
283
|
@in_list_entry = []
|
|
183
284
|
@list = []
|
|
285
|
+
@heading_ids = {}
|
|
184
286
|
end
|
|
185
287
|
|
|
186
288
|
##
|
|
@@ -221,10 +323,15 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
221
323
|
|
|
222
324
|
def accept_verbatim(verbatim)
|
|
223
325
|
text = verbatim.text.rstrip
|
|
326
|
+
format = verbatim.format
|
|
224
327
|
|
|
225
328
|
klass = nil
|
|
226
329
|
|
|
227
|
-
|
|
330
|
+
# Apply Ruby syntax highlighting if
|
|
331
|
+
# - explicitly marked as Ruby (via ruby? which accepts :ruby or :rb)
|
|
332
|
+
# - no format specified but the text is parseable as Ruby
|
|
333
|
+
# Otherwise, add language class when applicable and skip Ruby highlighting
|
|
334
|
+
content = if verbatim.ruby? || (format.nil? && parseable?(text))
|
|
228
335
|
begin
|
|
229
336
|
tokens = RDoc::Parser::RipperStateLex.parse text
|
|
230
337
|
klass = ' class="ruby"'
|
|
@@ -236,6 +343,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
236
343
|
CGI.escapeHTML text
|
|
237
344
|
end
|
|
238
345
|
else
|
|
346
|
+
klass = " class=\"#{format}\"" if format
|
|
239
347
|
CGI.escapeHTML text
|
|
240
348
|
end
|
|
241
349
|
|
|
@@ -305,7 +413,14 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
305
413
|
def accept_heading(heading)
|
|
306
414
|
level = [6, heading.level].min
|
|
307
415
|
|
|
308
|
-
label = heading.label
|
|
416
|
+
label = deduplicate_heading_id(heading.label(@code_object))
|
|
417
|
+
legacy_label = deduplicate_heading_id(heading.legacy_label(@code_object))
|
|
418
|
+
|
|
419
|
+
# Add legacy anchor before the heading for backward compatibility.
|
|
420
|
+
# This allows old links with label- prefix to still work.
|
|
421
|
+
if @options.output_decoration && !@options.pipe
|
|
422
|
+
@res << "\n<span id=\"#{legacy_label}\" class=\"legacy-anchor\"></span>"
|
|
423
|
+
end
|
|
309
424
|
|
|
310
425
|
@res << if @options.output_decoration
|
|
311
426
|
"\n<h#{level} id=\"#{label}\">"
|
|
@@ -354,6 +469,20 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
354
469
|
|
|
355
470
|
# :section: Utilities
|
|
356
471
|
|
|
472
|
+
##
|
|
473
|
+
# Returns a unique heading ID, appending -1, -2, etc. for duplicates.
|
|
474
|
+
# Matches GitHub's behavior for duplicate heading anchors.
|
|
475
|
+
|
|
476
|
+
def deduplicate_heading_id(id)
|
|
477
|
+
if @heading_ids.key?(id)
|
|
478
|
+
@heading_ids[id] += 1
|
|
479
|
+
"#{id}-#{@heading_ids[id]}"
|
|
480
|
+
else
|
|
481
|
+
@heading_ids[id] = 0
|
|
482
|
+
id
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
357
486
|
##
|
|
358
487
|
# CGI-escapes +text+
|
|
359
488
|
|
|
@@ -362,14 +491,18 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
362
491
|
end
|
|
363
492
|
|
|
364
493
|
##
|
|
365
|
-
#
|
|
366
|
-
#
|
|
494
|
+
# Generates an HTML link or image tag for the given +url+ and +text+.
|
|
495
|
+
#
|
|
496
|
+
# - Image URLs (http/https/link ending in .gif, .png, .jpg, .jpeg, .bmp)
|
|
497
|
+
# become <img> tags
|
|
498
|
+
# - File references (.rb, .rdoc, .md) are converted to .html paths
|
|
499
|
+
# - Anchor URLs (#foo) pass through unchanged for GitHub-style header linking
|
|
500
|
+
# - Footnote links get wrapped in <sup> tags
|
|
367
501
|
|
|
368
502
|
def gen_url(url, text)
|
|
369
503
|
scheme, url, id = parse_url url
|
|
370
504
|
|
|
371
|
-
if %w[http https link].include?(scheme)
|
|
372
|
-
url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
|
|
505
|
+
if %w[http https link].include?(scheme) && url =~ /\.(gif|png|jpg|jpeg|bmp)\z/
|
|
373
506
|
"<img src=\"#{url}\" />"
|
|
374
507
|
else
|
|
375
508
|
if scheme != 'link' and %r%\A((?!https?:)(?:[^/#]*/)*+)([^/#]+)\.(rb|rdoc|md)(?=\z|#)%i =~ url
|
|
@@ -381,9 +514,11 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
381
514
|
|
|
382
515
|
link = "<a#{id} href=\"#{url}\">#{text}</a>"
|
|
383
516
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
517
|
+
if /"foot/.match?(id)
|
|
518
|
+
"<sup>#{link}</sup>"
|
|
519
|
+
else
|
|
520
|
+
link
|
|
521
|
+
end
|
|
387
522
|
end
|
|
388
523
|
end
|
|
389
524
|
|
|
@@ -396,15 +531,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
396
531
|
tags[open_tag ? 0 : 1]
|
|
397
532
|
end
|
|
398
533
|
|
|
399
|
-
##
|
|
400
|
-
# Maps attributes to HTML tags
|
|
401
|
-
|
|
402
|
-
def init_tags
|
|
403
|
-
add_tag :BOLD, "<strong>", "</strong>"
|
|
404
|
-
add_tag :TT, "<code>", "</code>"
|
|
405
|
-
add_tag :EM, "<em>", "</em>"
|
|
406
|
-
end
|
|
407
|
-
|
|
408
534
|
##
|
|
409
535
|
# Returns the HTML tag for +list_type+, possible using a label from
|
|
410
536
|
# +list_item+
|
|
@@ -454,141 +580,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|
|
454
580
|
# Converts +item+ to HTML using RDoc::Text#to_html
|
|
455
581
|
|
|
456
582
|
def to_html(item)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
def convert_flow(flow_items)
|
|
463
|
-
res = []
|
|
464
|
-
|
|
465
|
-
flow_items.each do |item|
|
|
466
|
-
case item
|
|
467
|
-
when String
|
|
468
|
-
append_flow_fragment res, convert_string(item)
|
|
469
|
-
when RDoc::Markup::AttrChanger
|
|
470
|
-
off_tags res, item
|
|
471
|
-
on_tags res, item
|
|
472
|
-
when RDoc::Markup::RegexpHandling
|
|
473
|
-
append_flow_fragment res, convert_regexp_handling(item)
|
|
474
|
-
else
|
|
475
|
-
raise "Unknown flow element: #{item.inspect}"
|
|
476
|
-
end
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
res.join
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
def append_flow_fragment(res, fragment)
|
|
483
|
-
return if fragment.nil? || fragment.empty?
|
|
484
|
-
|
|
485
|
-
emit_tidy_link_fragment(res, fragment)
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
def append_to_tidy_label(fragment)
|
|
489
|
-
@tidy_link_buffer << fragment
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
##
|
|
493
|
-
# Matches an entire tidy link with a braced label "{label}[url]".
|
|
494
|
-
#
|
|
495
|
-
# Capture 1: label contents.
|
|
496
|
-
# Capture 2: URL text.
|
|
497
|
-
# Capture 3: trailing content.
|
|
498
|
-
TIDY_LINK_WITH_BRACES = /\A\{(.*?)\}\[(.*?)\](.*)\z/
|
|
499
|
-
|
|
500
|
-
##
|
|
501
|
-
# Matches the tail of a braced tidy link when the opening brace was
|
|
502
|
-
# consumed earlier while accumulating the label text.
|
|
503
|
-
#
|
|
504
|
-
# Capture 1: remaining label content.
|
|
505
|
-
# Capture 2: URL text.
|
|
506
|
-
# Capture 3: trailing content.
|
|
507
|
-
TIDY_LINK_WITH_BRACES_TAIL = /\A(.*?)\}\[(.*?)\](.*)\z/
|
|
508
|
-
|
|
509
|
-
##
|
|
510
|
-
# Matches a tidy link with a single-word label "label[url]".
|
|
511
|
-
#
|
|
512
|
-
# Capture 1: the single-word label (no whitespace).
|
|
513
|
-
# Capture 2: URL text between the brackets.
|
|
514
|
-
TIDY_LINK_SINGLE_WORD = /\A(\S+)\[(.*?)\](.*)\z/
|
|
515
|
-
|
|
516
|
-
def convert_complete_tidy_link(text)
|
|
517
|
-
return text unless
|
|
518
|
-
text =~ TIDY_LINK_WITH_BRACES or text =~ TIDY_LINK_SINGLE_WORD
|
|
519
|
-
|
|
520
|
-
label = $1
|
|
521
|
-
url = CGI.escapeHTML($2)
|
|
522
|
-
|
|
523
|
-
label_html = if /^rdoc-image:/ =~ label
|
|
524
|
-
handle_RDOCLINK(label)
|
|
525
|
-
else
|
|
526
|
-
render_tidy_link_label(label)
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
gen_url url, label_html
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
def emit_tidy_link_fragment(res, fragment)
|
|
533
|
-
if tidy_link_capturing?
|
|
534
|
-
append_to_tidy_label fragment
|
|
535
|
-
else
|
|
536
|
-
res << fragment
|
|
537
|
-
end
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
def finish_tidy_link(text)
|
|
541
|
-
label_tail, url, trailing = extract_tidy_link_parts(text)
|
|
542
|
-
append_to_tidy_label CGI.escapeHTML(label_tail) unless label_tail.empty?
|
|
543
|
-
|
|
544
|
-
return '' unless url
|
|
545
|
-
|
|
546
|
-
label_html = @tidy_link_buffer
|
|
547
|
-
@tidy_link_buffer = nil
|
|
548
|
-
link = gen_url(url, label_html)
|
|
549
|
-
|
|
550
|
-
return link if trailing.empty?
|
|
551
|
-
|
|
552
|
-
link + CGI.escapeHTML(trailing)
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def extract_tidy_link_parts(text)
|
|
556
|
-
if text =~ TIDY_LINK_WITH_BRACES
|
|
557
|
-
[$1, CGI.escapeHTML($2), $3]
|
|
558
|
-
elsif text =~ TIDY_LINK_WITH_BRACES_TAIL
|
|
559
|
-
[$1, CGI.escapeHTML($2), $3]
|
|
560
|
-
elsif text =~ TIDY_LINK_SINGLE_WORD
|
|
561
|
-
[$1, CGI.escapeHTML($2), $3]
|
|
562
|
-
else
|
|
563
|
-
[text, nil, '']
|
|
564
|
-
end
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
def on_tags(res, item)
|
|
568
|
-
each_attr_tag(item.turn_on) do |tag|
|
|
569
|
-
emit_tidy_link_fragment(res, annotate(tag.on))
|
|
570
|
-
@in_tt += 1 if tt? tag
|
|
571
|
-
end
|
|
572
|
-
end
|
|
573
|
-
|
|
574
|
-
def off_tags(res, item)
|
|
575
|
-
each_attr_tag(item.turn_off, true) do |tag|
|
|
576
|
-
emit_tidy_link_fragment(res, annotate(tag.off))
|
|
577
|
-
@in_tt -= 1 if tt? tag
|
|
578
|
-
end
|
|
579
|
-
end
|
|
580
|
-
|
|
581
|
-
def start_tidy_link(text)
|
|
582
|
-
@tidy_link_buffer = String.new
|
|
583
|
-
append_to_tidy_label CGI.escapeHTML(text.delete_prefix('{'))
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
def tidy_link_capturing?
|
|
587
|
-
!!@tidy_link_buffer
|
|
588
|
-
end
|
|
589
|
-
|
|
590
|
-
def render_tidy_link_label(label)
|
|
591
|
-
RDoc::Markup::LinkLabelToHtml.render(label, @options, @from_path)
|
|
583
|
+
# Ideally, we should convert html characters at handle_PLAIN_TEXT or somewhere else,
|
|
584
|
+
# but we need to convert it here for now because to_html_characters converts pair of backticks to ’‘ and pair of double backticks to ”“.
|
|
585
|
+
# Known bugs: `...` in `<code>def f(...); end</code>` and `(c) in `<a href="(c)">` will be wrongly converted.
|
|
586
|
+
to_html_characters(handle_inline(item))
|
|
592
587
|
end
|
|
593
588
|
end
|
|
594
589
|
|
|
@@ -50,8 +50,6 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
50
50
|
# will be processed as a tidylink first and will be broken.
|
|
51
51
|
crossref_re = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
|
|
52
52
|
@markup.add_regexp_handling crossref_re, :CROSSREF
|
|
53
|
-
|
|
54
|
-
add_regexp_handling_TIDYLINK
|
|
55
53
|
end
|
|
56
54
|
|
|
57
55
|
##
|
|
@@ -63,8 +61,11 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
63
61
|
|
|
64
62
|
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
|
|
65
63
|
|
|
66
|
-
if !
|
|
67
|
-
|
|
64
|
+
if !name.end_with?('+@', '-@') && match = name.match(/(.*[^#:])?@(.*)/)
|
|
65
|
+
context_name = match[1]
|
|
66
|
+
label = RDoc::Text.decode_legacy_label(match[2])
|
|
67
|
+
text ||= "#{label} at <code>#{context_name}</code>" if context_name
|
|
68
|
+
text ||= label
|
|
68
69
|
code = false
|
|
69
70
|
else
|
|
70
71
|
text ||= name
|
|
@@ -80,9 +81,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
80
81
|
# example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix,
|
|
81
82
|
# because we look for it in module Markup first.
|
|
82
83
|
|
|
83
|
-
def handle_regexp_CROSSREF(
|
|
84
|
-
name
|
|
85
|
-
|
|
84
|
+
def handle_regexp_CROSSREF(name)
|
|
85
|
+
return convert_string(name) if in_tidylink_label?
|
|
86
86
|
return name if @options.autolink_excluded_words&.include?(name)
|
|
87
87
|
|
|
88
88
|
return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
|
|
@@ -101,8 +101,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
101
101
|
# Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to
|
|
102
102
|
# handle other schemes.
|
|
103
103
|
|
|
104
|
-
def handle_regexp_HYPERLINK(
|
|
105
|
-
url
|
|
104
|
+
def handle_regexp_HYPERLINK(url)
|
|
105
|
+
return convert_string(url) if in_tidylink_label?
|
|
106
106
|
|
|
107
107
|
case url
|
|
108
108
|
when /\Ardoc-ref:/
|
|
@@ -120,12 +120,14 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
120
120
|
# All other contents are handled by
|
|
121
121
|
# {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK]
|
|
122
122
|
|
|
123
|
-
def handle_regexp_RDOCLINK(
|
|
124
|
-
url = target.text
|
|
125
|
-
|
|
123
|
+
def handle_regexp_RDOCLINK(url)
|
|
126
124
|
case url
|
|
127
125
|
when /\Ardoc-ref:/
|
|
128
|
-
|
|
126
|
+
if in_tidylink_label?
|
|
127
|
+
convert_string(url)
|
|
128
|
+
else
|
|
129
|
+
cross_reference $', rdoc_ref: true
|
|
130
|
+
end
|
|
129
131
|
else
|
|
130
132
|
super
|
|
131
133
|
end
|
|
@@ -169,14 +171,34 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
169
171
|
end
|
|
170
172
|
|
|
171
173
|
if label
|
|
174
|
+
# Decode legacy labels (e.g., "What-27s+Here" -> "What's Here")
|
|
175
|
+
# then convert to GitHub-style anchor format
|
|
176
|
+
decoded_label = RDoc::Text.decode_legacy_label(label)
|
|
177
|
+
formatted_label = RDoc::Text.to_anchor(decoded_label)
|
|
178
|
+
|
|
179
|
+
# Case 1: Path already has an anchor (e.g., method link)
|
|
180
|
+
# Input: C1#method@label -> path="C1.html#method-i-m"
|
|
181
|
+
# Output: C1.html#method-i-m-label
|
|
172
182
|
if path =~ /#/
|
|
173
|
-
path << "
|
|
174
|
-
|
|
175
|
-
|
|
183
|
+
path << "-#{formatted_label}"
|
|
184
|
+
|
|
185
|
+
# Case 2: Label matches a section title
|
|
186
|
+
# Input: C1@Section -> path="C1.html", section "Section" exists
|
|
187
|
+
# Output: C1.html#section (uses section.aref for GitHub-style)
|
|
188
|
+
elsif (section = ref&.sections&.find { |s| decoded_label == s.title })
|
|
189
|
+
path << "##{section.aref}"
|
|
190
|
+
|
|
191
|
+
# Case 3: Ref has an aref (class/module context)
|
|
192
|
+
# Input: C1@heading -> path="C1.html", ref=C1 class
|
|
193
|
+
# Output: C1.html#class-c1-heading
|
|
176
194
|
elsif ref.respond_to?(:aref)
|
|
177
|
-
path << "##{ref.aref}
|
|
195
|
+
path << "##{ref.aref}-#{formatted_label}"
|
|
196
|
+
|
|
197
|
+
# Case 4: No context, just the label (e.g., TopLevel/file)
|
|
198
|
+
# Input: README@section -> path="README_md.html"
|
|
199
|
+
# Output: README_md.html#section
|
|
178
200
|
else
|
|
179
|
-
path << "
|
|
201
|
+
path << "##{formatted_label}"
|
|
180
202
|
end
|
|
181
203
|
end
|
|
182
204
|
|
|
@@ -184,73 +206,30 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|
|
184
206
|
end
|
|
185
207
|
end
|
|
186
208
|
|
|
187
|
-
def
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
i = 0
|
|
191
|
-
while i < flow_items.size
|
|
192
|
-
item = flow_items[i]
|
|
193
|
-
|
|
194
|
-
case item
|
|
195
|
-
when RDoc::Markup::AttrChanger
|
|
196
|
-
if !tidy_link_capturing? && (text = convert_tt_crossref(flow_items, i))
|
|
197
|
-
text = block.call(text, res) if block
|
|
198
|
-
append_flow_fragment res, text
|
|
199
|
-
i += 3
|
|
200
|
-
next
|
|
201
|
-
end
|
|
209
|
+
def handle_TT(code)
|
|
210
|
+
emit_inline(tt_cross_reference(code) || "<code>#{CGI.escapeHTML code}</code>")
|
|
211
|
+
end
|
|
202
212
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
when RDoc::Markup::RegexpHandling
|
|
212
|
-
text = convert_regexp_handling(item)
|
|
213
|
-
text = block.call(text, res) if block
|
|
214
|
-
append_flow_fragment res, text
|
|
215
|
-
i += 1
|
|
216
|
-
else
|
|
217
|
-
raise "Unknown flow element: #{item.inspect}"
|
|
218
|
-
end
|
|
213
|
+
# Applies additional special handling on top of the one defined in ToHtml.
|
|
214
|
+
# When a tidy link is <tt>{Foo}[rdoc-ref:Foo]</tt>, the label part is surrounded by <tt><code></code></tt>.
|
|
215
|
+
# TODO: reconsider this workaround.
|
|
216
|
+
def apply_tidylink_label_special_handling(label, url)
|
|
217
|
+
if url == "rdoc-ref:#{label}" && cross_reference(label).include?('<code>')
|
|
218
|
+
"<code>#{convert_string(label)}</code>"
|
|
219
|
+
else
|
|
220
|
+
super
|
|
219
221
|
end
|
|
220
|
-
|
|
221
|
-
res.join('')
|
|
222
222
|
end
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
##
|
|
227
|
-
# Detects <tt>...</tt> spans that contain a single cross-reference candidate.
|
|
228
|
-
# When the candidate occupies the whole span (aside from trailing
|
|
229
|
-
# punctuation), the tt markup is replaced by the resolved cross-reference.
|
|
230
|
-
|
|
231
|
-
def convert_tt_crossref(flow_items, index)
|
|
232
|
-
opener = flow_items[index]
|
|
233
|
-
return unless tt_tag?(opener.turn_on)
|
|
234
|
-
|
|
235
|
-
string = flow_items[index + 1]
|
|
236
|
-
closer = flow_items[index + 2]
|
|
237
|
-
|
|
238
|
-
return unless String === string
|
|
239
|
-
return unless RDoc::Markup::AttrChanger === closer
|
|
240
|
-
return unless tt_tag?(closer.turn_off, true)
|
|
224
|
+
def tt_cross_reference(code)
|
|
225
|
+
return if in_tidylink_label?
|
|
241
226
|
|
|
242
227
|
crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
|
|
243
|
-
match = crossref_regexp.match(
|
|
244
|
-
return unless match
|
|
245
|
-
return unless match.
|
|
246
|
-
|
|
247
|
-
trailing = match.post_match
|
|
248
|
-
# Only convert when the remainder is punctuation/whitespace so other tt text stays literal.
|
|
249
|
-
return unless trailing.match?(/\A[[:punct:]\s]*\z/)
|
|
250
|
-
|
|
251
|
-
text = cross_reference(string)
|
|
252
|
-
return if text == string
|
|
228
|
+
match = crossref_regexp.match(code)
|
|
229
|
+
return unless match && match.begin(1).zero?
|
|
230
|
+
return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
|
|
253
231
|
|
|
254
|
-
|
|
232
|
+
ref = cross_reference(code)
|
|
233
|
+
ref if ref != code
|
|
255
234
|
end
|
|
256
235
|
end
|