rdoc 7.0.3 → 7.1.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.
@@ -188,10 +188,26 @@ class RDoc::ClassModule < RDoc::Context
188
188
  end
189
189
 
190
190
  ##
191
- # HTML fragment reference for this module or class. See
192
- # RDoc::NormalClass#aref and RDoc::NormalModule#aref
191
+ # HTML fragment reference for this module or class using GitHub-style
192
+ # anchor format (lowercase, :: replaced with -).
193
+ #
194
+ # Examples:
195
+ # Foo -> class-foo
196
+ # Foo::Bar -> class-foo-bar
193
197
 
194
198
  def aref
199
+ "#{aref_prefix}-#{full_name.downcase.gsub('::', '-')}"
200
+ end
201
+
202
+ ##
203
+ # Legacy HTML fragment reference for backward compatibility.
204
+ # Returns the old RDoc-style anchor format.
205
+ #
206
+ # Examples:
207
+ # Foo -> class-Foo
208
+ # Foo::Bar -> class-Foo::Bar
209
+
210
+ def legacy_aref
195
211
  "#{aref_prefix}-#{full_name}"
196
212
  end
197
213
 
@@ -477,7 +493,12 @@ class RDoc::ClassModule < RDoc::Context
477
493
  document = document.merge other_document
478
494
 
479
495
  @comment = RDoc::Comment.from_document(document)
480
- @comment_location = document
496
+
497
+ @comment_location = if document.parts.first.is_a?(RDoc::Markup::Document)
498
+ document.parts.map { |doc| [doc, doc.file] }
499
+ else
500
+ [[document, document.file]]
501
+ end
481
502
  end
482
503
 
483
504
  cm = class_module
@@ -70,11 +70,30 @@ class RDoc::Context::Section
70
70
  end
71
71
 
72
72
  ##
73
- # Anchor reference for linking to this section
73
+ # Anchor reference for linking to this section using GitHub-style format.
74
+ #
75
+ # Examples:
76
+ # "Section" -> "section"
77
+ # "One Two" -> "one-two"
78
+ # "[untitled]" -> "untitled"
74
79
 
75
80
  def aref
76
81
  title = @title || '[untitled]'
77
82
 
83
+ RDoc::Text.to_anchor(title)
84
+ end
85
+
86
+ ##
87
+ # Legacy anchor reference for backward compatibility.
88
+ #
89
+ # Examples:
90
+ # "Section" -> "section"
91
+ # "One Two" -> "one+two"
92
+ # "[untitled]" -> "5Buntitled-5D"
93
+
94
+ def legacy_aref
95
+ title = @title || '[untitled]'
96
+
78
97
  CGI.escape(title).gsub('%', '-').sub(/^-/, '')
79
98
  end
80
99
 
@@ -132,47 +132,56 @@ class RDoc::CrossReference
132
132
  end
133
133
 
134
134
  ##
135
- # Returns a method reference to +name+.
135
+ # Returns a method, attribute or constant reference to +name+
136
+ # if it exists in the containing context object. It returns
137
+ # nil otherwise.
138
+ #
139
+ # For example, this method would decompose name = 'A::CONSTANT' into a
140
+ # container object A and a symbol 'CONSTANT', and it would try to find
141
+ # 'CONSTANT' in A.
136
142
 
137
- def resolve_method(name)
143
+ def resolve_local_symbol(name)
138
144
  ref = nil
145
+ type = nil
146
+ container = nil
139
147
 
140
- if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
148
+ case name
149
+ when /#{CLASS_REGEXP_STR}::([A-Z]\w*)\z/o then
150
+ symbol = $2
151
+ container = @context.find_symbol_module($1)
152
+ when /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o then
141
153
  type = $2
142
154
  if '.' == type # will find either #method or ::method
143
- method = $3
155
+ symbol = $3
144
156
  else
145
- method = "#{type}#{$3}"
157
+ symbol = "#{type}#{$3}"
146
158
  end
147
159
  container = @context.find_symbol_module($1)
148
- elsif /^([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
160
+ when /^([.#]|::)#{METHOD_REGEXP_STR}/o then
149
161
  type = $1
150
162
  if '.' == type
151
- method = $2
163
+ symbol = $2
152
164
  else
153
- method = "#{type}#{$2}"
165
+ symbol = "#{type}#{$2}"
154
166
  end
155
167
  container = @context
156
- else
157
- type = nil
158
- container = nil
159
168
  end
160
169
 
161
170
  if container then
162
171
  unless RDoc::TopLevel === container then
163
172
  if '.' == type then
164
- if 'new' == method then # AnyClassName.new will be class method
165
- ref = container.find_local_symbol method
166
- ref = container.find_ancestor_local_symbol method unless ref
173
+ if 'new' == symbol then # AnyClassName.new will be class method
174
+ ref = container.find_local_symbol symbol
175
+ ref = container.find_ancestor_local_symbol symbol unless ref
167
176
  else
168
- ref = container.find_local_symbol "::#{method}"
169
- ref = container.find_ancestor_local_symbol "::#{method}" unless ref
170
- ref = container.find_local_symbol "##{method}" unless ref
171
- ref = container.find_ancestor_local_symbol "##{method}" unless ref
177
+ ref = container.find_local_symbol "::#{symbol}"
178
+ ref = container.find_ancestor_local_symbol "::#{symbol}" unless ref
179
+ ref = container.find_local_symbol "##{symbol}" unless ref
180
+ ref = container.find_ancestor_local_symbol "##{symbol}" unless ref
172
181
  end
173
182
  else
174
- ref = container.find_local_symbol method
175
- ref = container.find_ancestor_local_symbol method unless ref
183
+ ref = container.find_local_symbol symbol
184
+ ref = container.find_ancestor_local_symbol symbol unless ref
176
185
  end
177
186
  end
178
187
  end
@@ -197,7 +206,7 @@ class RDoc::CrossReference
197
206
  @context.find_symbol name
198
207
  end
199
208
 
200
- ref = resolve_method name unless ref
209
+ ref = resolve_local_symbol name unless ref
201
210
 
202
211
  # Try a page name
203
212
  ref = @store.page name if not ref and name =~ /^[\w.\/]+$/
@@ -29,6 +29,7 @@
29
29
  </ol>
30
30
  <% end %>
31
31
 
32
+ <span id="<%= h klass.legacy_aref %>" class="legacy-anchor"></span>
32
33
  <h1 id="<%= h klass.aref %>" class="anchor-link <%= klass.type %>">
33
34
  <%= klass.type %> <%= klass.full_name %>
34
35
  </h1>
@@ -38,6 +39,7 @@
38
39
  </section>
39
40
 
40
41
  <%- klass.each_section do |section, constants, attributes| %>
42
+ <span id="<%= section.legacy_aref %>" class="legacy-anchor"></span>
41
43
  <section id="<%= section.aref %>" class="documentation-section anchor-link">
42
44
  <%- if section.title then %>
43
45
  <header class="documentation-section-title">
@@ -157,7 +159,7 @@
157
159
  </details>
158
160
  </div>
159
161
  <div class="method-source-code" id="<%= method.html_name %>-source">
160
- <pre class="<%= method.source_language %>" data-language="<%= method.source_language %>"><%= method.markup_code %></pre>
162
+ <pre class="<%= method.source_language %>"><%= method.markup_code %></pre>
161
163
  </div>
162
164
  <%- end %>
163
165
 
@@ -1190,6 +1190,26 @@ main .anchor-link:target {
1190
1190
  scroll-margin-top: calc(var(--layout-header-height) + 2rem);
1191
1191
  }
1192
1192
 
1193
+ /* Legacy anchor for backward compatibility with old label- prefix links */
1194
+ .legacy-anchor {
1195
+ display: block;
1196
+ position: relative;
1197
+ visibility: hidden;
1198
+ scroll-margin-top: calc(var(--layout-header-height) + 2rem);
1199
+ }
1200
+
1201
+ /* When a legacy anchor is targeted, highlight the next heading sibling */
1202
+ .legacy-anchor:target + h1,
1203
+ .legacy-anchor:target + h2,
1204
+ .legacy-anchor:target + h3,
1205
+ .legacy-anchor:target + h4,
1206
+ .legacy-anchor:target + h5,
1207
+ .legacy-anchor:target + h6 {
1208
+ margin-left: calc(-1 * var(--space-5));
1209
+ padding-left: calc(var(--space-5) / 2);
1210
+ border-left: calc(var(--space-5) / 2) solid var(--color-border-default);
1211
+ }
1212
+
1193
1213
 
1194
1214
  /* Utility Classes */
1195
1215
  .hide { display: none !important; }
@@ -276,7 +276,7 @@
276
276
  * Initialize C syntax highlighting on page load
277
277
  */
278
278
  function initHighlighting() {
279
- const codeBlocks = document.querySelectorAll('pre[data-language="c"]');
279
+ const codeBlocks = document.querySelectorAll('pre.c');
280
280
 
281
281
  codeBlocks.forEach(block => {
282
282
  if (block.getAttribute('data-highlighted') === 'true') {
@@ -33,6 +33,7 @@
33
33
  </ol>
34
34
  <% end %>
35
35
 
36
+ <span id="<%= h klass.legacy_aref %>" class="legacy-anchor"></span>
36
37
  <h1 id="<%= h klass.aref %>" class="anchor-link <%= klass.type %>">
37
38
  <%= klass.type %> <%= klass.full_name %>
38
39
  </h1>
@@ -42,6 +43,7 @@
42
43
  </section>
43
44
 
44
45
  <%- klass.each_section do |section, constants, attributes| %>
46
+ <span id="<%= section.legacy_aref %>" class="legacy-anchor"></span>
45
47
  <section id="<%= section.aref %>" class="documentation-section anchor-link">
46
48
  <%- if section.title then %>
47
49
  <header class="documentation-section-title">
@@ -92,6 +92,25 @@ main .anchor-link:target {
92
92
  scroll-margin-top: 1rem;
93
93
  }
94
94
 
95
+ /* Legacy anchor for backward compatibility with old label- prefix links */
96
+ .legacy-anchor {
97
+ display: block;
98
+ position: relative;
99
+ visibility: hidden;
100
+ scroll-margin-top: 1rem;
101
+ }
102
+
103
+ /* When a legacy anchor is targeted, highlight the next heading sibling */
104
+ .legacy-anchor:target + h1,
105
+ .legacy-anchor:target + h2,
106
+ .legacy-anchor:target + h3,
107
+ .legacy-anchor:target + h4,
108
+ .legacy-anchor:target + h5,
109
+ .legacy-anchor:target + h6 {
110
+ margin-left: -10px;
111
+ border-left: 10px solid var(--border-color);
112
+ }
113
+
95
114
  /* 4. Links */
96
115
  a {
97
116
  color: var(--link-color);
@@ -490,11 +490,7 @@
490
490
  # Wraps `text` in strike markup for rdoc inline formatting
491
491
 
492
492
  def strike text
493
- if text =~ /\A[a-z\d.\/-]+\z/i then
494
- "~#{text}~"
495
- else
496
- "<s>#{text}</s>"
497
- end
493
+ "<del>#{text}</del>"
498
494
  end
499
495
 
500
496
  ##
data/lib/rdoc/markdown.rb CHANGED
@@ -875,11 +875,7 @@ class RDoc::Markdown
875
875
  # Wraps `text` in strike markup for rdoc inline formatting
876
876
 
877
877
  def strike text
878
- if text =~ /\A[a-z\d.\/-]+\z/i then
879
- "~#{text}~"
880
- else
881
- "<s>#{text}</s>"
882
- end
878
+ "<del>#{text}</del>"
883
879
  end
884
880
 
885
881
  ##
@@ -89,12 +89,21 @@ class RDoc::Markup::AttributeManager
89
89
  add_word_pair "*", "*", :BOLD, true
90
90
  add_word_pair "_", "_", :EM, true
91
91
  add_word_pair "+", "+", :TT, true
92
+ add_word_pair "`", "`", :TT, true
92
93
 
93
94
  add_html "em", :EM, true
94
95
  add_html "i", :EM, true
95
96
  add_html "b", :BOLD, true
96
97
  add_html "tt", :TT, true
97
98
  add_html "code", :TT, true
99
+ add_html "s", :STRIKE, true
100
+ add_html "del", :STRIKE, true
101
+
102
+ @word_pair_chars = @matching_word_pairs.keys.join
103
+
104
+ # Matches a word pair delimiter (*, _, +, `) that is NOT already protected.
105
+ # Used by #protect_code_markup to escape delimiters inside <code>/<tt> tags.
106
+ @unprotected_word_pair_regexp = /([#{@word_pair_chars}])(?!#{PROTECT_ATTR})/
98
107
  end
99
108
 
100
109
  ##
@@ -164,7 +173,7 @@ class RDoc::Markup::AttributeManager
164
173
  }.keys
165
174
  return if tags.empty?
166
175
  tags = "[#{tags.join("")}](?!#{PROTECT_ATTR})"
167
- all_tags = "[#{@matching_word_pairs.keys.join("")}](?!#{PROTECT_ATTR})"
176
+ all_tags = "[#{@word_pair_chars}](?!#{PROTECT_ATTR})"
168
177
 
169
178
  re = /(?:^|\W|#{all_tags})\K(#{tags})(\1*[#\\]?[\w:#{PROTECT_ATTR}.\/\[\]-]+?\S?)\1(?!\1)(?=#{all_tags}|\W|$)/
170
179
 
@@ -245,6 +254,23 @@ class RDoc::Markup::AttributeManager
245
254
  @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1")
246
255
  end
247
256
 
257
+ ##
258
+ # Protects word pair delimiters (*, _, +) inside
259
+ # <code> and <tt> tags from being processed as inline formatting.
260
+ # For example, *bold* in +*bold*+ will NOT be rendered as bold.
261
+
262
+ def protect_code_markup
263
+ @str.gsub!(/<(code|tt)>(.*?)<\/\1>/im) do
264
+ tag = $1
265
+ content = $2
266
+ # Protect word pair delimiters (*, _, +) from being processed
267
+ escaped = content.gsub(@unprotected_word_pair_regexp, "\\1#{PROTECT_ATTR}")
268
+ # Protect HTML-like tags from being processed (e.g., <del> inside code)
269
+ escaped = escaped.gsub(/<(?!#{PROTECT_ATTR})/, "<#{PROTECT_ATTR}")
270
+ "<#{tag}>#{escaped}</#{tag}>"
271
+ end
272
+ end
273
+
248
274
  ##
249
275
  # Unescapes regexp handling sequences of text
250
276
 
@@ -308,6 +334,7 @@ class RDoc::Markup::AttributeManager
308
334
  @str = str.dup
309
335
 
310
336
  mask_protected_sequences
337
+ protect_code_markup
311
338
 
312
339
  @attrs = RDoc::Markup::AttrSpan.new @str.length, @exclusive_bitmap
313
340
 
@@ -2,6 +2,33 @@
2
2
 
3
3
  module RDoc
4
4
  class Markup
5
+ # IMPORTANT! This weird workaround is required to ensure that RDoc can correctly deserializing Marshal data from
6
+ # older rubies. Older rubies have `Heading` as a struct, so if we change it to a class, deserialization fails
7
+ if RUBY_VERSION.start_with?("4.")
8
+ class Heading < Element
9
+ #: String
10
+ attr_reader :text
11
+
12
+ #: Integer
13
+ attr_accessor :level
14
+
15
+ #: (Integer, String) -> void
16
+ def initialize(level, text)
17
+ super()
18
+
19
+ @level = level
20
+ @text = text
21
+ end
22
+
23
+ #: (Object) -> bool
24
+ def ==(other)
25
+ other.is_a?(Heading) && other.level == @level && other.text == @text
26
+ end
27
+ end
28
+ else
29
+ Heading = Struct.new(:level, :text)
30
+ end
31
+
5
32
  # A heading with a level (1-6) and text
6
33
  #
7
34
  # RDoc syntax:
@@ -13,13 +40,8 @@ module RDoc
13
40
  # # Heading 1
14
41
  # ## Heading 2
15
42
  # ### Heading 3
16
- class Heading < Element
17
- #: String
18
- attr_reader :text
19
-
20
- #: Integer
21
- attr_accessor :level
22
-
43
+ #
44
+ class Heading
23
45
  # A singleton RDoc::Markup::ToLabel formatter for headings.
24
46
  #: () -> RDoc::Markup::ToLabel
25
47
  def self.to_label
@@ -43,38 +65,88 @@ module RDoc
43
65
  end
44
66
  end
45
67
 
46
- #: (Integer, String) -> void
47
- def initialize(level, text)
48
- super()
49
-
50
- @level = level
51
- @text = text
52
- end
53
-
54
- #: (Object) -> bool
55
- def ==(other)
56
- other.is_a?(Heading) && other.level == @level && other.text == @text
57
- end
58
-
59
68
  # @override
60
69
  #: (untyped) -> void
61
70
  def accept(visitor)
62
71
  visitor.accept_heading(self)
63
72
  end
64
73
 
65
- # An HTML-safe anchor reference for this header.
74
+ # An HTML-safe anchor reference for this header using GitHub-style formatting:
75
+ # - Lowercase
76
+ # - Spaces converted to hyphens
77
+ # - Special characters removed (except hyphens)
78
+ #
79
+ # Examples:
80
+ # "Hello" -> "hello"
81
+ # "Hello World" -> "hello-world"
82
+ # "Foo Bar Baz" -> "foo-bar-baz"
83
+ #
66
84
  #: () -> String
67
85
  def aref
68
- "label-#{self.class.to_label.convert text.dup}"
86
+ self.class.to_label.convert text.dup
87
+ end
88
+
89
+ # An HTML-safe anchor reference using legacy RDoc formatting:
90
+ # - Prefixed with "label-"
91
+ # - Original case preserved
92
+ # - Spaces converted to + (URL encoding style)
93
+ # - Special characters percent-encoded
94
+ #
95
+ # Returns nil if it would be the same as the GitHub-style aref (no alias needed).
96
+ #
97
+ # Examples:
98
+ # "hello" -> "label-hello" (different due to label- prefix)
99
+ # "Hello" -> "label-Hello"
100
+ # "Hello World" -> "label-Hello+World"
101
+ # "Foo Bar Baz" -> "label-Foo+Bar+Baz"
102
+ #
103
+ #: () -> String?
104
+ def legacy_aref
105
+ "label-#{self.class.to_label.convert_legacy text.dup}"
69
106
  end
70
107
 
71
- # Creates a fully-qualified label which will include the label from +context+. This helps keep ids unique in HTML.
108
+ # Creates a fully-qualified label (GitHub-style) which includes the context's aref prefix.
109
+ # This helps keep IDs unique in HTML when headings appear within class/method documentation.
110
+ #
111
+ # Examples (without context):
112
+ # "Hello World" -> "hello-world"
113
+ #
114
+ # Examples (with context being class Foo):
115
+ # "Hello World" -> "class-foo-hello-world"
116
+ #
117
+ # Examples (with context being method #bar):
118
+ # "Hello World" -> "method-i-bar-hello-world"
119
+ #
72
120
  #: (RDoc::Context?) -> String
73
121
  def label(context = nil)
74
- label = +""
75
- label << "#{context.aref}-" if context&.respond_to?(:aref)
76
- label << aref
77
- label
122
+ result = +""
123
+ result << "#{context.aref}-" if context&.respond_to?(:aref)
124
+ result << aref
125
+ result
126
+ end
127
+
128
+ # Creates a fully-qualified legacy label for backward compatibility.
129
+ # This is used to generate a secondary ID attribute on the heading's inner anchor,
130
+ # allowing old-style links (e.g., #label-Hello+World) to continue working.
131
+ #
132
+ # Examples (without context):
133
+ # "hello" -> "label-hello"
134
+ # "Hello World" -> "label-Hello+World"
135
+ #
136
+ # Examples (with context being class Foo):
137
+ # "hello" -> "class-Foo-label-hello"
138
+ # "Hello World" -> "class-Foo-label-Hello+World"
139
+ #
140
+ #: (RDoc::Context?) -> String
141
+ def legacy_label(context = nil)
142
+ result = +""
143
+ if context&.respond_to?(:legacy_aref)
144
+ result << "#{context.legacy_aref}-"
145
+ elsif context&.respond_to?(:aref)
146
+ result << "#{context.aref}-"
147
+ end
148
+ result << legacy_aref
149
+ result
78
150
  end
79
151
 
80
152
  # HTML markup of the text of this label without the surrounding header element.
@@ -221,10 +221,15 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
221
221
 
222
222
  def accept_verbatim(verbatim)
223
223
  text = verbatim.text.rstrip
224
+ format = verbatim.format
224
225
 
225
226
  klass = nil
226
227
 
227
- content = if verbatim.ruby? or parseable? text then
228
+ # Apply Ruby syntax highlighting if
229
+ # - explicitly marked as Ruby (via ruby? which accepts :ruby or :rb)
230
+ # - no format specified but the text is parseable as Ruby
231
+ # Otherwise, add language class when applicable and skip Ruby highlighting
232
+ content = if verbatim.ruby? || (format.nil? && parseable?(text))
228
233
  begin
229
234
  tokens = RDoc::Parser::RipperStateLex.parse text
230
235
  klass = ' class="ruby"'
@@ -236,6 +241,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
236
241
  CGI.escapeHTML text
237
242
  end
238
243
  else
244
+ klass = " class=\"#{format}\"" if format
239
245
  CGI.escapeHTML text
240
246
  end
241
247
 
@@ -306,6 +312,13 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
306
312
  level = [6, heading.level].min
307
313
 
308
314
  label = heading.label @code_object
315
+ legacy_label = heading.legacy_label @code_object
316
+
317
+ # Add legacy anchor before the heading for backward compatibility.
318
+ # This allows old links with label- prefix to still work.
319
+ if @options.output_decoration && !@options.pipe
320
+ @res << "\n<span id=\"#{legacy_label}\" class=\"legacy-anchor\"></span>"
321
+ end
309
322
 
310
323
  @res << if @options.output_decoration
311
324
  "\n<h#{level} id=\"#{label}\">"
@@ -362,14 +375,18 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
362
375
  end
363
376
 
364
377
  ##
365
- # Generate a link to +url+ with content +text+. Handles the special cases
366
- # for img: and link: described under handle_regexp_HYPERLINK
378
+ # Generates an HTML link or image tag for the given +url+ and +text+.
379
+ #
380
+ # - Image URLs (http/https/link ending in .gif, .png, .jpg, .jpeg, .bmp)
381
+ # become <img> tags
382
+ # - File references (.rb, .rdoc, .md) are converted to .html paths
383
+ # - Anchor URLs (#foo) pass through unchanged for GitHub-style header linking
384
+ # - Footnote links get wrapped in <sup> tags
367
385
 
368
386
  def gen_url(url, text)
369
387
  scheme, url, id = parse_url url
370
388
 
371
- if %w[http https link].include?(scheme) and
372
- url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
389
+ if %w[http https link].include?(scheme) && url =~ /\.(gif|png|jpg|jpeg|bmp)\z/
373
390
  "<img src=\"#{url}\" />"
374
391
  else
375
392
  if scheme != 'link' and %r%\A((?!https?:)(?:[^/#]*/)*+)([^/#]+)\.(rb|rdoc|md)(?=\z|#)%i =~ url
@@ -381,9 +398,11 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
381
398
 
382
399
  link = "<a#{id} href=\"#{url}\">#{text}</a>"
383
400
 
384
- link = "<sup>#{link}</sup>" if /"foot/ =~ id
385
-
386
- link
401
+ if /"foot/.match?(id)
402
+ "<sup>#{link}</sup>"
403
+ else
404
+ link
405
+ end
387
406
  end
388
407
  end
389
408
 
@@ -400,9 +419,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
400
419
  # Maps attributes to HTML tags
401
420
 
402
421
  def init_tags
403
- add_tag :BOLD, "<strong>", "</strong>"
404
- add_tag :TT, "<code>", "</code>"
405
- add_tag :EM, "<em>", "</em>"
422
+ add_tag :BOLD, "<strong>", "</strong>"
423
+ add_tag :TT, "<code>", "</code>"
424
+ add_tag :EM, "<em>", "</em>"
425
+ add_tag :STRIKE, "<del>", "</del>"
406
426
  end
407
427
 
408
428
  ##
@@ -169,14 +169,33 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
169
169
  end
170
170
 
171
171
  if label
172
+ # Convert label to GitHub-style anchor format
173
+ # First convert + to space (URL encoding), then apply GitHub-style rules
174
+ formatted_label = RDoc::Text.to_anchor(label.tr('+', ' '))
175
+
176
+ # Case 1: Path already has an anchor (e.g., method link)
177
+ # Input: C1#method@label -> path="C1.html#method-i-m"
178
+ # Output: C1.html#method-i-m-label
172
179
  if path =~ /#/
173
- path << "-label-#{label}"
174
- elsif ref&.sections&.any? { |section| label == section.title }
175
- path << "##{label}"
180
+ path << "-#{formatted_label}"
181
+
182
+ # Case 2: Label matches a section title
183
+ # Input: C1@Section -> path="C1.html", section "Section" exists
184
+ # Output: C1.html#section (uses section.aref for GitHub-style)
185
+ elsif (section = ref&.sections&.find { |s| label.tr('+', ' ') == s.title })
186
+ path << "##{section.aref}"
187
+
188
+ # Case 3: Ref has an aref (class/module context)
189
+ # Input: C1@heading -> path="C1.html", ref=C1 class
190
+ # Output: C1.html#class-c1-heading
176
191
  elsif ref.respond_to?(:aref)
177
- path << "##{ref.aref}-label-#{label}"
192
+ path << "##{ref.aref}-#{formatted_label}"
193
+
194
+ # Case 4: No context, just the label (e.g., TopLevel/file)
195
+ # Input: README@section -> path="README_md.html"
196
+ # Output: README_md.html#section
178
197
  else
179
- path << "#label-#{label}"
198
+ path << "##{formatted_label}"
180
199
  end
181
200
  end
182
201
 
@@ -28,11 +28,21 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
28
28
  end
29
29
 
30
30
  ##
31
- # Converts +text+ to an HTML-safe label
31
+ # Converts +text+ to an HTML-safe label using GitHub-style anchor formatting.
32
32
 
33
33
  def convert(text)
34
34
  label = convert_flow @am.flow text
35
35
 
36
+ RDoc::Text.to_anchor(label)
37
+ end
38
+
39
+ ##
40
+ # Converts +text+ to an HTML-safe label using legacy RDoc formatting.
41
+ # Used for generating backward-compatible anchor aliases.
42
+
43
+ def convert_legacy(text)
44
+ label = convert_flow @am.flow text
45
+
36
46
  CGI.escape(label).gsub('%', '-').sub(/^-/, '')
37
47
  end
38
48
 
@@ -70,7 +70,7 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw
70
70
 
71
71
  def ruby?
72
72
  @format ||= nil # TODO for older ri data, switch the tree to marshal_dump
73
- @format == :ruby
73
+ @format == :ruby || @format == :rb
74
74
  end
75
75
 
76
76
  ##