rdoc 6.17.0 → 8.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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +193 -0
  3. data/LEGAL.rdoc +6 -0
  4. data/LICENSE.rdoc +4 -0
  5. data/README.md +132 -8
  6. data/RI.md +75 -75
  7. data/doc/markup_reference/markdown.md +659 -0
  8. data/doc/markup_reference/rdoc.rdoc +1169 -0
  9. data/exe/rdoc +2 -2
  10. data/lib/rdoc/code_object/alias.rb +70 -74
  11. data/lib/rdoc/code_object/any_method.rb +308 -293
  12. data/lib/rdoc/code_object/attr.rb +150 -142
  13. data/lib/rdoc/code_object/class_module.rb +802 -715
  14. data/lib/rdoc/code_object/constant.rb +181 -144
  15. data/lib/rdoc/code_object/context/section.rb +140 -130
  16. data/lib/rdoc/code_object/context.rb +925 -941
  17. data/lib/rdoc/code_object/extend.rb +7 -5
  18. data/lib/rdoc/code_object/include.rb +7 -5
  19. data/lib/rdoc/code_object/method_attr.rb +328 -315
  20. data/lib/rdoc/code_object/mixin.rb +97 -92
  21. data/lib/rdoc/code_object/normal_class.rb +77 -78
  22. data/lib/rdoc/code_object/normal_module.rb +61 -59
  23. data/lib/rdoc/code_object/require.rb +23 -39
  24. data/lib/rdoc/code_object/single_class.rb +21 -19
  25. data/lib/rdoc/code_object/top_level.rb +215 -202
  26. data/lib/rdoc/code_object.rb +305 -305
  27. data/lib/rdoc/comment.rb +274 -337
  28. data/lib/rdoc/cross_reference.rb +195 -206
  29. data/lib/rdoc/encoding.rb +105 -103
  30. data/lib/rdoc/erb_partial.rb +13 -11
  31. data/lib/rdoc/erbio.rb +29 -27
  32. data/lib/rdoc/generator/aliki.rb +196 -30
  33. data/lib/rdoc/generator/darkfish.rb +647 -629
  34. data/lib/rdoc/generator/json_index.rb +233 -229
  35. data/lib/rdoc/generator/markup.rb +165 -122
  36. data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
  37. data/lib/rdoc/generator/pot/po.rb +52 -51
  38. data/lib/rdoc/generator/pot/po_entry.rb +138 -132
  39. data/lib/rdoc/generator/pot.rb +85 -81
  40. data/lib/rdoc/generator/ri.rb +23 -19
  41. data/lib/rdoc/generator/template/aliki/DESIGN.md +538 -0
  42. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  43. data/lib/rdoc/generator/template/aliki/_footer.rhtml +2 -2
  44. data/lib/rdoc/generator/template/aliki/_head.rhtml +15 -10
  45. data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
  46. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  47. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  48. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  49. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +3 -3
  50. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +3 -3
  51. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  52. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  53. data/lib/rdoc/generator/template/aliki/class.rhtml +71 -61
  54. data/lib/rdoc/generator/template/aliki/css/rdoc.css +796 -323
  55. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  56. data/lib/rdoc/generator/template/aliki/js/aliki.js +119 -113
  57. data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
  58. data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +1 -1
  59. data/lib/rdoc/generator/template/aliki/js/{search.js → search_controller.js} +16 -7
  60. data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
  61. data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
  62. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  63. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  64. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  65. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
  66. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  67. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  68. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  69. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +2 -2
  70. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  71. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  72. data/lib/rdoc/generator/template/darkfish/class.rhtml +29 -32
  73. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -1
  74. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  75. data/lib/rdoc/generator.rb +48 -46
  76. data/lib/rdoc/i18n/locale.rb +99 -95
  77. data/lib/rdoc/i18n/text.rb +109 -105
  78. data/lib/rdoc/i18n.rb +7 -5
  79. data/lib/rdoc/markdown/byte_runtime.rb +80 -0
  80. data/lib/rdoc/markdown.kpeg +52 -33
  81. data/lib/rdoc/markdown.rb +365 -177
  82. data/lib/rdoc/markup/blank_line.rb +25 -23
  83. data/lib/rdoc/markup/block_quote.rb +12 -8
  84. data/lib/rdoc/markup/document.rb +127 -123
  85. data/lib/rdoc/markup/element.rb +21 -0
  86. data/lib/rdoc/markup/formatter.rb +220 -203
  87. data/lib/rdoc/markup/hard_break.rb +30 -27
  88. data/lib/rdoc/markup/heading.rb +163 -77
  89. data/lib/rdoc/markup/include.rb +33 -29
  90. data/lib/rdoc/markup/indented_paragraph.rb +37 -33
  91. data/lib/rdoc/markup/inline_parser.rb +316 -0
  92. data/lib/rdoc/markup/list.rb +80 -88
  93. data/lib/rdoc/markup/list_item.rb +73 -85
  94. data/lib/rdoc/markup/paragraph.rb +23 -19
  95. data/lib/rdoc/markup/parser.rb +501 -497
  96. data/lib/rdoc/markup/pre_process.rb +284 -305
  97. data/lib/rdoc/markup/raw.rb +52 -55
  98. data/lib/rdoc/markup/rule.rb +16 -12
  99. data/lib/rdoc/markup/table.rb +48 -40
  100. data/lib/rdoc/markup/to_ansi.rb +143 -92
  101. data/lib/rdoc/markup/to_bs.rb +86 -102
  102. data/lib/rdoc/markup/to_html.rb +608 -506
  103. data/lib/rdoc/markup/to_html_crossref.rb +219 -210
  104. data/lib/rdoc/markup/to_html_snippet.rb +210 -205
  105. data/lib/rdoc/markup/to_joined_paragraph.rb +40 -41
  106. data/lib/rdoc/markup/to_label.rb +64 -51
  107. data/lib/rdoc/markup/to_markdown.rb +212 -184
  108. data/lib/rdoc/markup/to_rdoc.rb +341 -277
  109. data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
  110. data/lib/rdoc/markup/to_test.rb +62 -50
  111. data/lib/rdoc/markup/to_tt_only.rb +83 -92
  112. data/lib/rdoc/markup/verbatim.rb +62 -58
  113. data/lib/rdoc/markup.rb +196 -215
  114. data/lib/rdoc/options.rb +1063 -1076
  115. data/lib/rdoc/parser/c.rb +1039 -1036
  116. data/lib/rdoc/parser/changelog.rb +320 -287
  117. data/lib/rdoc/parser/markdown.rb +17 -13
  118. data/lib/rdoc/parser/rbs.rb +279 -0
  119. data/lib/rdoc/parser/rd.rb +17 -13
  120. data/lib/rdoc/parser/ruby.rb +1231 -2222
  121. data/lib/rdoc/parser/ruby_colorizer.rb +303 -0
  122. data/lib/rdoc/parser/simple.rb +31 -27
  123. data/lib/rdoc/parser/text.rb +12 -8
  124. data/lib/rdoc/parser.rb +230 -221
  125. data/lib/rdoc/rbs_helper.rb +186 -0
  126. data/lib/rdoc/rd/inline.rb +57 -53
  127. data/lib/rdoc/rd.rb +90 -88
  128. data/lib/rdoc/rdoc.rb +547 -366
  129. data/lib/rdoc/ri/driver.rb +1141 -1130
  130. data/lib/rdoc/ri/formatter.rb +7 -3
  131. data/lib/rdoc/ri/paths.rb +140 -136
  132. data/lib/rdoc/ri/servlet.rb +456 -0
  133. data/lib/rdoc/ri/store.rb +4 -2
  134. data/lib/rdoc/ri/task.rb +55 -51
  135. data/lib/rdoc/ri.rb +14 -11
  136. data/lib/rdoc/rubygems_hook.rb +194 -192
  137. data/lib/rdoc/server.rb +462 -0
  138. data/lib/rdoc/stats/normal.rb +46 -42
  139. data/lib/rdoc/stats/quiet.rb +39 -35
  140. data/lib/rdoc/stats/verbose.rb +35 -31
  141. data/lib/rdoc/stats.rb +363 -338
  142. data/lib/rdoc/store.rb +919 -725
  143. data/lib/rdoc/task.rb +260 -255
  144. data/lib/rdoc/text.rb +164 -240
  145. data/lib/rdoc/token_stream.rb +88 -106
  146. data/lib/rdoc/tom_doc.rb +203 -201
  147. data/lib/rdoc/version.rb +1 -1
  148. data/lib/rdoc.rb +35 -7
  149. data/lib/rubygems_plugin.rb +2 -11
  150. data/rdoc-logo.svg +43 -0
  151. data/rdoc.gemspec +9 -7
  152. metadata +46 -32
  153. data/CONTRIBUTING.rdoc +0 -219
  154. data/ExampleMarkdown.md +0 -39
  155. data/ExampleRDoc.rdoc +0 -210
  156. data/lib/rdoc/code_object/anon_class.rb +0 -10
  157. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  158. data/lib/rdoc/code_object/meta_method.rb +0 -6
  159. data/lib/rdoc/markdown/literals.kpeg +0 -21
  160. data/lib/rdoc/markdown/literals.rb +0 -454
  161. data/lib/rdoc/markup/attr_changer.rb +0 -22
  162. data/lib/rdoc/markup/attr_span.rb +0 -35
  163. data/lib/rdoc/markup/attribute_manager.rb +0 -405
  164. data/lib/rdoc/markup/attributes.rb +0 -70
  165. data/lib/rdoc/markup/regexp_handling.rb +0 -40
  166. data/lib/rdoc/parser/prism_ruby.rb +0 -1100
  167. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  168. data/lib/rdoc/parser/ruby_tools.rb +0 -163
  169. data/lib/rdoc/servlet.rb +0 -452
@@ -1,256 +1,265 @@
1
1
  # frozen_string_literal: true
2
- ##
3
- # Subclass of the RDoc::Markup::ToHtml class that supports looking up method
4
- # names, classes, etc to create links. RDoc::CrossReference is used to
5
- # generate those links based on the current context.
2
+ module RDoc
3
+ class Markup
4
+ ##
5
+ # Subclass of the RDoc::Markup::ToHtml class that supports looking up method
6
+ # names, classes, etc to create links. RDoc::CrossReference is used to
7
+ # generate those links based on the current context.
6
8
 
7
- class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
9
+ class ToHtmlCrossref < Markup::ToHtml
8
10
 
9
- # :stopdoc:
10
- ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP
11
- CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR
12
- CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP
13
- METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR
14
- # :startdoc:
11
+ # :stopdoc:
12
+ ALL_CROSSREF_REGEXP = CrossReference::ALL_CROSSREF_REGEXP
13
+ CROSSREF_REGEXP = CrossReference::CROSSREF_REGEXP
14
+ # :startdoc:
15
15
 
16
- ##
17
- # RDoc::CodeObject for generating references
16
+ ##
17
+ # RDoc::CodeObject for generating references
18
18
 
19
- attr_accessor :context
19
+ attr_accessor :context
20
20
 
21
- ##
22
- # Should we show '#' characters on method references?
21
+ ##
22
+ # Should we show '#' characters on method references?
23
23
 
24
- attr_accessor :show_hash
24
+ attr_accessor :show_hash
25
25
 
26
- ##
27
- # Creates a new crossref resolver that generates links relative to +context+
28
- # which lives at +from_path+ in the generated files. '#' characters on
29
- # references are removed unless +show_hash+ is true. Only method names
30
- # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
26
+ ##
27
+ # Creates a new crossref resolver that generates links relative to +context+
28
+ # which lives at +from_path+ in the generated files. '#' characters on
29
+ # references are removed unless +show_hash+ is true. Only method names
30
+ # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
31
31
 
32
- def initialize(options, from_path, context, markup = nil)
33
- raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
32
+ def initialize(from_path, context, pipe: false, output_decoration: true,
33
+ hyperlink_all: false, show_hash: false,
34
+ autolink_excluded_words: [], warn_missing_rdoc_ref: true)
35
+ raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
34
36
 
35
- super options, markup
37
+ super(pipe: pipe, output_decoration: output_decoration)
36
38
 
37
- @context = context
38
- @from_path = from_path
39
- @hyperlink_all = @options.hyperlink_all
40
- @show_hash = @options.show_hash
39
+ @context = context
40
+ @from_path = from_path
41
+ @hyperlink_all = hyperlink_all
42
+ @show_hash = show_hash
43
+ @autolink_excluded_words = autolink_excluded_words
44
+ @warn_missing_rdoc_ref = warn_missing_rdoc_ref
41
45
 
42
- @cross_reference = RDoc::CrossReference.new @context
43
- end
44
-
45
- # :nodoc:
46
- def init_link_notation_regexp_handlings
47
- add_regexp_handling_RDOCLINK
46
+ @cross_reference = CrossReference.new @context
47
+ end
48
48
 
49
- # The crossref must be linked before tidylink because Klass.method[:sym]
50
- # will be processed as a tidylink first and will be broken.
51
- crossref_re = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
52
- @markup.add_regexp_handling crossref_re, :CROSSREF
49
+ # :nodoc:
50
+ def init_link_notation_regexp_handlings
51
+ add_regexp_handling_RDOCLINK
53
52
 
54
- add_regexp_handling_TIDYLINK
55
- end
56
-
57
- ##
58
- # Creates a link to the reference +name+ if the name exists. If +text+ is
59
- # given it is used as the link text, otherwise +name+ is used.
53
+ # The crossref must be linked before tidylink because Klass.method[:sym]
54
+ # will be processed as a tidylink first and will be broken.
55
+ crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
56
+ @markup.add_regexp_handling crossref_re, :CROSSREF
57
+ end
60
58
 
61
- def cross_reference(name, text = nil, code = true, rdoc_ref: false)
62
- lookup = name
59
+ ##
60
+ # Creates a link to the reference +name+ if the name exists. If +text+ is
61
+ # given it is used as the link text, otherwise +name+ is used.
62
+ # Returns +nil+ if the link target could not be resolved.
63
+
64
+ def cross_reference(name, text = nil, code = true, rdoc_ref: false)
65
+ # Strip '#' for link display text (e.g. #method shows as "method" in links)
66
+ display = !@show_hash && name.start_with?('#') ? name[1..] : name
67
+
68
+ if !display.end_with?('+@', '-@') && match = display.match(/(.*[^#:])?@(.*)/)
69
+ context_name = match[1]
70
+ label = convert_string(Text.decode_legacy_label(match[2]))
71
+ text ||= "#{label} at <code>#{convert_string(context_name)}</code>" if context_name
72
+ text ||= label
73
+ code = false
74
+ else
75
+ text ||= convert_string(display)
76
+ end
63
77
 
64
- name = name[1..-1] unless @show_hash if name[0, 1] == '#'
78
+ link(name, text, code, rdoc_ref: rdoc_ref)
79
+ end
65
80
 
66
- if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
67
- text ||= [CGI.unescape($'), (" at <code>#{$1}</code>" if $~.begin(1))].join("")
68
- code = false
69
- else
70
- text ||= name
71
- end
81
+ ##
82
+ # We're invoked when any text matches the CROSSREF pattern. If we find the
83
+ # corresponding reference, generate a link. If the name we're looking for
84
+ # contains no punctuation, we look for it up the module/class chain. For
85
+ # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix,
86
+ # because we look for it in module Markup first.
72
87
 
73
- link lookup, text, code, rdoc_ref: rdoc_ref
74
- end
88
+ def handle_regexp_CROSSREF(name)
89
+ return convert_string(name) if in_tidylink_label?
90
+ return convert_string(name) if @autolink_excluded_words&.include?(name)
75
91
 
76
- ##
77
- # We're invoked when any text matches the CROSSREF pattern. If we find the
78
- # corresponding reference, generate a link. If the name we're looking for
79
- # contains no punctuation, we look for it up the module/class chain. For
80
- # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix,
81
- # because we look for it in module Markup first.
92
+ return convert_string(name) if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
82
93
 
83
- def handle_regexp_CROSSREF(target)
84
- name = target.text
94
+ unless @hyperlink_all
95
+ # This ensures that words entirely consisting of lowercase letters will
96
+ # not have cross-references generated (to suppress lots of erroneous
97
+ # cross-references to "new" in text, for instance)
98
+ return name if name =~ /\A[a-z]*\z/
99
+ end
100
+ cross_reference(name, rdoc_ref: false) || convert_string(name)
101
+ end
85
102
 
86
- return name if @options.autolink_excluded_words&.include?(name)
103
+ ##
104
+ # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to
105
+ # handle other schemes.
87
106
 
88
- return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
107
+ def handle_regexp_HYPERLINK(url)
108
+ return convert_string(url) if in_tidylink_label?
89
109
 
90
- unless @hyperlink_all then
91
- # This ensures that words entirely consisting of lowercase letters will
92
- # not have cross-references generated (to suppress lots of erroneous
93
- # cross-references to "new" in text, for instance)
94
- return name if name =~ /\A[a-z]*\z/
95
- end
110
+ case url
111
+ when /\Ardoc-ref:/
112
+ ref = $'
113
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
114
+ else
115
+ super
116
+ end
117
+ end
96
118
 
97
- cross_reference name, rdoc_ref: false
98
- end
119
+ ##
120
+ # +target+ is an rdoc-schemed link that will be converted into a hyperlink.
121
+ # For the rdoc-ref scheme the cross-reference will be looked up and the
122
+ # given name will be used.
123
+ #
124
+ # All other contents are handled by
125
+ # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK]
126
+
127
+ def handle_regexp_RDOCLINK(url)
128
+ case url
129
+ when /\Ardoc-ref:/
130
+ if in_tidylink_label?
131
+ convert_string(url)
132
+ else
133
+ ref = $'
134
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
135
+ end
136
+ else
137
+ super
138
+ end
139
+ end
99
140
 
100
- ##
101
- # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to
102
- # handle other schemes.
141
+ ##
142
+ # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows
143
+ # RDoc::Markup::ToHtml to handle other schemes.
103
144
 
104
- def handle_regexp_HYPERLINK(target)
105
- url = target.text
145
+ def gen_url(url, text)
146
+ if url =~ /\Ardoc-ref:/
147
+ name = $'
148
+ cross_reference(name, text, name == text, rdoc_ref: true) || text
149
+ else
150
+ super
151
+ end
152
+ end
106
153
 
107
- case url
108
- when /\Ardoc-ref:/
109
- cross_reference $', rdoc_ref: true
110
- else
111
- super
112
- end
113
- end
154
+ ##
155
+ # Creates an HTML link to +name+ with the given +html_string+.
156
+ # +html_string+ should be already escaped and may contain HTML tags.
157
+ # Returns the link HTML string, or +nil+ if the reference could not be resolved.
114
158
 
115
- ##
116
- # +target+ is an rdoc-schemed link that will be converted into a hyperlink.
117
- # For the rdoc-ref scheme the cross-reference will be looked up and the
118
- # given name will be used.
119
- #
120
- # All other contents are handled by
121
- # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK]
122
-
123
- def handle_regexp_RDOCLINK(target)
124
- url = target.text
125
-
126
- case url
127
- when /\Ardoc-ref:/
128
- cross_reference $', rdoc_ref: true
129
- else
130
- super
131
- end
132
- end
133
-
134
- ##
135
- # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows
136
- # RDoc::Markup::ToHtml to handle other schemes.
159
+ def link(name, html_string, code = true, rdoc_ref: false)
160
+ if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
161
+ name = $1
162
+ label = $'
163
+ end
137
164
 
138
- def gen_url(url, text)
139
- if url =~ /\Ardoc-ref:/
140
- name = $'
141
- cross_reference name, text, name == text, rdoc_ref: true
142
- else
143
- super
144
- end
145
- end
165
+ ref = @cross_reference.resolve name if name
146
166
 
147
- ##
148
- # Creates an HTML link to +name+ with the given +text+.
167
+ # Non-text source files (C, Ruby, etc.) don't get HTML pages generated,
168
+ # so don't auto-link to them. Explicit rdoc-ref: links are still allowed.
169
+ if !rdoc_ref && TopLevel === ref && !ref.text?
170
+ return
171
+ end
149
172
 
150
- def link(name, text, code = true, rdoc_ref: false)
151
- if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
152
- name = $1
153
- label = $'
154
- end
173
+ if ref
174
+ path = ref.as_href(@from_path)
175
+
176
+ if code and CodeObject === ref and !(TopLevel === ref)
177
+ html_string = "<code>#{html_string}</code>"
178
+ end
179
+ elsif name
180
+ if rdoc_ref && @warn_missing_rdoc_ref
181
+ puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{html_string}`"
182
+ end
183
+ return
184
+ else
185
+ # A bare label reference like @foo still produces a valid anchor link
186
+ return unless label
187
+ path = +""
188
+ end
155
189
 
156
- ref = @cross_reference.resolve name, text if name
190
+ if label
191
+ # Decode legacy labels (e.g., "What-27s+Here" -> "What's Here")
192
+ # then convert to GitHub-style anchor format
193
+ decoded_label = Text.decode_legacy_label(label)
194
+ formatted_label = Text.to_anchor(decoded_label)
195
+
196
+ # Case 1: Path already has an anchor (e.g., method link)
197
+ # Input: C1#method@label -> path="C1.html#method-i-m"
198
+ # Output: C1.html#method-i-m-label
199
+ if path =~ /#/
200
+ path << "-#{formatted_label}"
201
+
202
+ # Case 2: Label matches a section title
203
+ # Input: C1@Section -> path="C1.html", section "Section" exists
204
+ # Output: C1.html#section (uses section.aref for GitHub-style)
205
+ elsif (section = ref&.sections&.find { |s| decoded_label == s.title })
206
+ path << "##{section.aref}"
207
+
208
+ # Case 3: Ref has an aref (class/module context)
209
+ # Input: C1@heading -> path="C1.html", ref=C1 class
210
+ # Output: C1.html#class-c1-heading
211
+ elsif ref.respond_to?(:aref)
212
+ path << "##{ref.aref}-#{formatted_label}"
213
+
214
+ # Case 4: No context, just the label (e.g., TopLevel/file)
215
+ # Input: README@section -> path="README_md.html"
216
+ # Output: README_md.html#section
217
+ else
218
+ path << "##{formatted_label}"
219
+ end
220
+ end
157
221
 
158
- case ref
159
- when String then
160
- if rdoc_ref && @options.warn_missing_rdoc_ref
161
- puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{text}`"
222
+ "<a href=\"#{path}\">#{html_string}</a>"
162
223
  end
163
- ref
164
- else
165
- path = ref ? ref.as_href(@from_path) : +""
166
224
 
167
- if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
168
- text = "<code>#{CGI.escapeHTML text}</code>"
225
+ def handle_TT(code)
226
+ emit_inline(tt_cross_reference(code) || "<code>#{convert_string(code)}</code>")
169
227
  end
170
228
 
171
- if label
172
- if path =~ /#/
173
- path << "-label-#{label}"
174
- elsif ref&.sections&.any? { |section| label == section.title }
175
- path << "##{label}"
176
- elsif ref.respond_to?(:aref)
177
- path << "##{ref.aref}-label-#{label}"
229
+ # Applies additional special handling on top of the one defined in ToHtml.
230
+ # When a tidy link is <tt>{Foo}[rdoc-ref:Foo]</tt>, the label part is surrounded by <tt><code></code></tt>.
231
+ # TODO: reconsider this workaround.
232
+ def apply_tidylink_label_special_handling(label, url)
233
+ if url == "rdoc-ref:#{label}" && cross_reference(label)&.include?('<code>')
234
+ "<code>#{convert_string(label)}</code>"
178
235
  else
179
- path << "#label-#{label}"
236
+ super
180
237
  end
181
238
  end
182
239
 
183
- "<a href=\"#{path}\">#{text}</a>"
184
- end
185
- end
186
-
187
- def convert_flow(flow_items, &block)
188
- res = []
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
240
+ # Handles cross-reference and suppressed-crossref inside tt tag.
241
+ # Returns nil if code is not an existing cross-reference nor a suppressed-crossref.
242
+ def tt_cross_reference(code)
243
+ return if in_tidylink_label?
244
+
245
+ crossref_regexp = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
246
+ # REGEXP sometimes matches a string that starts with a backslash but is not a
247
+ # suppressed cross-reference (for example, `\+`), so the backslash-removed
248
+ # part needs to be checked against crossref_regexp.
249
+ match = crossref_regexp.match(code.delete_prefix('\\'))
250
+ return unless match && match.begin(1).zero?
251
+ return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
252
+
253
+ # cross_reference(file_page) may return a link without code tag.
254
+ # We need to check it because this method shouldn't return an html text without code tag.
255
+ if code.start_with?('\\')
256
+ # Remove leading backslash if crossref exists
257
+ "<code>#{convert_string(code[1..])}</code>" if cross_reference(code[1..])&.include?('<code>')
258
+ else
259
+ html = cross_reference(code)
260
+ html if html&.include?('<code>')
201
261
  end
202
-
203
- off_tags res, item
204
- on_tags res, item
205
- i += 1
206
- when String
207
- text = convert_string(item)
208
- text = block.call(text, res) if block
209
- append_flow_fragment res, text
210
- i += 1
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
262
  end
219
263
  end
220
-
221
- res.join('')
222
- end
223
-
224
- private
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)
241
-
242
- crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
243
- match = crossref_regexp.match(string)
244
- return unless match
245
- return unless match.begin(1).zero?
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
253
-
254
- text
255
264
  end
256
265
  end