rdoc 6.3.4.1 → 8.0.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/CONTRIBUTING.md +195 -0
- data/History.rdoc +65 -63
- data/LEGAL.rdoc +7 -1
- data/LICENSE.rdoc +6 -0
- data/README.md +236 -0
- data/RI.md +842 -0
- data/TODO.rdoc +8 -7
- data/doc/markup_reference/markdown.md +659 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/exe/rdoc +0 -1
- data/lib/rdoc/{alias.rb → code_object/alias.rb} +4 -18
- data/lib/rdoc/{any_method.rb → code_object/any_method.rb} +50 -24
- data/lib/rdoc/{attr.rb → code_object/attr.rb} +16 -14
- data/lib/rdoc/{class_module.rb → code_object/class_module.rb} +225 -58
- data/lib/rdoc/{constant.rb → code_object/constant.rb} +44 -10
- data/lib/rdoc/code_object/context/section.rb +182 -0
- data/lib/rdoc/{context.rb → code_object/context.rb} +78 -106
- data/lib/rdoc/{extend.rb → code_object/extend.rb} +0 -1
- data/lib/rdoc/{include.rb → code_object/include.rb} +0 -1
- data/lib/rdoc/{method_attr.rb → code_object/method_attr.rb} +46 -48
- data/lib/rdoc/{mixin.rb → code_object/mixin.rb} +6 -4
- data/lib/rdoc/{normal_class.rb → code_object/normal_class.rb} +2 -3
- data/lib/rdoc/{normal_module.rb → code_object/normal_module.rb} +2 -3
- data/lib/rdoc/{require.rb → code_object/require.rb} +1 -2
- data/lib/rdoc/{single_class.rb → code_object/single_class.rb} +5 -1
- data/lib/rdoc/{top_level.rb → code_object/top_level.rb} +60 -63
- data/lib/rdoc/code_object.rb +11 -39
- data/lib/rdoc/code_objects.rb +1 -2
- data/lib/rdoc/comment.rb +202 -99
- data/lib/rdoc/cross_reference.rb +75 -62
- data/lib/rdoc/encoding.rb +8 -24
- data/lib/rdoc/erb_partial.rb +1 -2
- data/lib/rdoc/erbio.rb +3 -8
- data/lib/rdoc/generator/aliki.rb +200 -0
- data/lib/rdoc/generator/darkfish.rb +156 -122
- data/lib/rdoc/generator/json_index.rb +8 -24
- data/lib/rdoc/generator/markup.rb +70 -34
- data/lib/rdoc/generator/pot/message_extractor.rb +7 -7
- data/lib/rdoc/generator/pot/po.rb +1 -1
- data/lib/rdoc/generator/pot/po_entry.rb +8 -8
- data/lib/rdoc/generator/pot.rb +1 -5
- data/lib/rdoc/generator/ri.rb +1 -2
- data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
- data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +8 -0
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +23 -0
- data/lib/rdoc/generator/template/aliki/_head.rhtml +163 -0
- data/lib/rdoc/generator/template/aliki/_header.rhtml +56 -0
- data/lib/rdoc/generator/template/aliki/_icons.rhtml +208 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml +16 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml +15 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +27 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +27 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +16 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml +41 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +67 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +15 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +21 -0
- data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +3 -0
- data/lib/rdoc/generator/template/aliki/class.rhtml +230 -0
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +2181 -0
- data/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
- data/lib/rdoc/generator/template/aliki/js/aliki.js +513 -0
- data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
- data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +299 -0
- data/lib/rdoc/generator/template/aliki/js/search_controller.js +129 -0
- data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
- data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
- data/lib/rdoc/generator/template/aliki/js/theme-toggle.js +112 -0
- data/lib/rdoc/generator/template/aliki/page.rhtml +18 -0
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +14 -0
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +65 -0
- data/lib/rdoc/generator/template/darkfish/_footer.rhtml +3 -3
- data/lib/rdoc/generator/template/darkfish/_head.rhtml +35 -14
- data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +1 -5
- data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +11 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +11 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +7 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +20 -11
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +25 -5
- data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +4 -9
- data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +2 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +4 -4
- data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +28 -7
- data/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml +3 -0
- data/lib/rdoc/generator/template/darkfish/class.rhtml +138 -90
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +420 -358
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/index.rhtml +14 -12
- data/lib/rdoc/generator/template/darkfish/js/darkfish.js +59 -3
- data/lib/rdoc/generator/template/darkfish/js/search.js +15 -5
- data/lib/rdoc/generator/template/darkfish/page.rhtml +7 -6
- data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +12 -9
- data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +24 -21
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +35 -21
- data/lib/rdoc/generator/template/json_index/js/navigation.js +8 -8
- data/lib/rdoc/generator/template/json_index/js/searcher.js +48 -6
- data/lib/rdoc/generator.rb +6 -5
- data/lib/rdoc/i18n/text.rb +3 -3
- data/lib/rdoc/i18n.rb +1 -1
- data/lib/rdoc/known_classes.rb +5 -4
- data/lib/rdoc/markdown/entities.rb +0 -1
- data/lib/rdoc/markdown/literals.kpeg +0 -2
- data/lib/rdoc/markdown/literals.rb +0 -1
- data/lib/rdoc/markdown.kpeg +140 -62
- data/lib/rdoc/markdown.rb +1015 -873
- data/lib/rdoc/markup/blank_line.rb +25 -24
- data/lib/rdoc/markup/block_quote.rb +1 -2
- data/lib/rdoc/markup/document.rb +10 -11
- data/lib/rdoc/markup/element.rb +21 -0
- data/lib/rdoc/markup/formatter.rb +134 -115
- data/lib/rdoc/markup/hard_break.rb +30 -28
- data/lib/rdoc/markup/heading.rb +163 -72
- data/lib/rdoc/markup/include.rb +3 -4
- data/lib/rdoc/markup/indented_paragraph.rb +4 -5
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/list.rb +6 -7
- data/lib/rdoc/markup/list_item.rb +6 -7
- data/lib/rdoc/markup/paragraph.rb +2 -3
- data/lib/rdoc/markup/parser.rb +29 -19
- data/lib/rdoc/markup/pre_process.rb +39 -18
- data/lib/rdoc/markup/raw.rb +52 -56
- data/lib/rdoc/markup/rule.rb +2 -3
- data/lib/rdoc/markup/table.rb +49 -32
- data/lib/rdoc/markup/to_ansi.rb +58 -8
- data/lib/rdoc/markup/to_bs.rb +47 -38
- data/lib/rdoc/markup/to_html.rb +343 -105
- data/lib/rdoc/markup/to_html_crossref.rb +143 -58
- data/lib/rdoc/markup/to_html_snippet.rb +78 -76
- data/lib/rdoc/markup/to_joined_paragraph.rb +3 -9
- data/lib/rdoc/markup/to_label.rb +34 -25
- data/lib/rdoc/markup/to_markdown.rb +74 -51
- data/lib/rdoc/markup/to_rdoc.rb +141 -82
- data/lib/rdoc/markup/to_table_of_contents.rb +4 -5
- data/lib/rdoc/markup/to_test.rb +10 -3
- data/lib/rdoc/markup/to_tt_only.rb +17 -31
- data/lib/rdoc/markup/verbatim.rb +5 -6
- data/lib/rdoc/markup.rb +59 -707
- data/lib/rdoc/options.rb +228 -101
- data/lib/rdoc/parser/c.rb +186 -184
- data/lib/rdoc/parser/changelog.rb +57 -13
- data/lib/rdoc/parser/markdown.rb +0 -2
- data/lib/rdoc/parser/rbs.rb +275 -0
- data/lib/rdoc/parser/rd.rb +0 -1
- data/lib/rdoc/parser/ruby.rb +963 -2024
- data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
- data/lib/rdoc/parser/simple.rb +6 -23
- data/lib/rdoc/parser/text.rb +0 -1
- data/lib/rdoc/parser.rb +35 -14
- data/lib/rdoc/rbs_helper.rb +186 -0
- data/lib/rdoc/rd/block_parser.rb +659 -11
- data/lib/rdoc/rd/block_parser.ry +13 -9
- data/lib/rdoc/rd/inline.rb +4 -5
- data/lib/rdoc/rd/inline_parser.rb +646 -2
- data/lib/rdoc/rd.rb +4 -5
- data/lib/rdoc/rdoc.rb +234 -90
- data/lib/rdoc/ri/driver.rb +172 -172
- data/lib/rdoc/ri/paths.rb +3 -3
- data/lib/rdoc/{servlet.rb → ri/servlet.rb} +28 -27
- data/lib/rdoc/ri/store.rb +0 -1
- data/lib/rdoc/ri/task.rb +3 -3
- data/lib/rdoc/ri.rb +5 -5
- data/lib/rdoc/rubygems_hook.rb +106 -25
- data/lib/rdoc/server.rb +460 -0
- data/lib/rdoc/stats/normal.rb +1 -1
- data/lib/rdoc/stats/quiet.rb +1 -2
- data/lib/rdoc/stats/verbose.rb +3 -5
- data/lib/rdoc/stats.rb +158 -136
- data/lib/rdoc/store.rb +267 -48
- data/lib/rdoc/task.rb +54 -28
- data/lib/rdoc/text.rb +60 -120
- data/lib/rdoc/token_stream.rb +30 -45
- data/lib/rdoc/tom_doc.rb +9 -15
- data/lib/rdoc/version.rb +3 -1
- data/lib/rdoc.rb +90 -52
- data/lib/rubygems_plugin.rb +14 -0
- data/man/ri.1 +2 -0
- data/rdoc-logo.svg +43 -0
- data/rdoc.gemspec +25 -200
- metadata +120 -53
- data/CONTRIBUTING.rdoc +0 -220
- data/ExampleMarkdown.md +0 -37
- data/ExampleRDoc.rdoc +0 -208
- data/Gemfile +0 -12
- data/README.rdoc +0 -129
- data/RI.rdoc +0 -57
- data/Rakefile +0 -101
- data/bin/console +0 -7
- data/bin/setup +0 -6
- data/lib/rdoc/anon_class.rb +0 -11
- data/lib/rdoc/context/section.rb +0 -232
- data/lib/rdoc/generator/template/darkfish/.document +0 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +0 -19
- data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +0 -9
- data/lib/rdoc/generator/template/json_index/.document +0 -1
- data/lib/rdoc/ghost_method.rb +0 -7
- data/lib/rdoc/markup/attr_changer.rb +0 -23
- data/lib/rdoc/markup/attr_span.rb +0 -36
- data/lib/rdoc/markup/attribute_manager.rb +0 -409
- data/lib/rdoc/markup/attributes.rb +0 -71
- data/lib/rdoc/markup/regexp_handling.rb +0 -41
- data/lib/rdoc/meta_method.rb +0 -7
- data/lib/rdoc/parser/ripper_state_lex.rb +0 -590
- data/lib/rdoc/parser/ruby_tools.rb +0 -167
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'prism'
|
|
4
|
+
require 'set'
|
|
5
|
+
|
|
6
|
+
# Ruby code syntax highlighter.
|
|
7
|
+
# Colorize result is an array of +RDoc::Parser::RubyColorizer::ColoredToken+
|
|
8
|
+
# Actual color for each token kind is determined elsewhere (e.g., HTML generator)
|
|
9
|
+
module RDoc::Parser::RubyColorizer
|
|
10
|
+
|
|
11
|
+
ColoredToken = Struct.new(:kind, :text)
|
|
12
|
+
|
|
13
|
+
# Prism operator token types except assignment '='
|
|
14
|
+
OP_TOKENS = %i[
|
|
15
|
+
AMPERSAND AMPERSAND_AMPERSAND
|
|
16
|
+
BANG BANG_EQUAL BANG_TILDE CARET COLON COLON_COLON
|
|
17
|
+
EQUAL_EQUAL EQUAL_GREATER EQUAL_TILDE
|
|
18
|
+
GREATER GREATER_GREATER
|
|
19
|
+
LESS LESS_EQUAL LESS_EQUAL_GREATER LESS_LESS
|
|
20
|
+
MINUS MINUS_GREATER PERCENT PIPE PIPE_PIPE PLUS
|
|
21
|
+
QUESTION_MARK SLASH STAR STAR_STAR TILDE
|
|
22
|
+
UAMPERSAND UMINUS UPLUS USTAR USTAR_STAR
|
|
23
|
+
].to_set
|
|
24
|
+
|
|
25
|
+
# Prism token type to ColoredToken kind map
|
|
26
|
+
TOKEN_TYPE_MAP = {
|
|
27
|
+
IDENTIFIER: :identifier,
|
|
28
|
+
METHOD_NAME: :identifier,
|
|
29
|
+
INSTANCE_VARIABLE: :ivar,
|
|
30
|
+
CLASS_VARIABLE: :identifier,
|
|
31
|
+
GLOBAL_VARIABLE: :identifier,
|
|
32
|
+
BACK_REFERENCE: :identifier,
|
|
33
|
+
NUMBERED_REFERENCE: :identifier,
|
|
34
|
+
CONSTANT: :constant,
|
|
35
|
+
LABEL: :value,
|
|
36
|
+
INTEGER: :value,
|
|
37
|
+
INTEGER_IMAGINARY: :value,
|
|
38
|
+
INTEGER_RATIONAL: :value,
|
|
39
|
+
INTEGER_RATIONAL_IMAGINARY: :value,
|
|
40
|
+
FLOAT: :value,
|
|
41
|
+
FLOAT_IMAGINARY: :value,
|
|
42
|
+
FLOAT_RATIONAL: :value,
|
|
43
|
+
FLOAT_RATIONAL_IMAGINARY: :value,
|
|
44
|
+
COMMENT: :comment,
|
|
45
|
+
EMBDOC_BEGIN: :comment,
|
|
46
|
+
EMBDOC_LINE: :comment,
|
|
47
|
+
EMBDOC_END: :comment
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
|
|
52
|
+
# Colorize the entire +code+ and returns colored token stream.
|
|
53
|
+
def colorize(code)
|
|
54
|
+
result = Prism.parse_lex(code)
|
|
55
|
+
program_node, unordered_tokens = result.value
|
|
56
|
+
prism_tokens = unordered_tokens.map(&:first).sort_by! { |token| token.location.start_offset }
|
|
57
|
+
partial_colorize(code, program_node, prism_tokens, 0, code.bytesize)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Colorize partial +node+ in +whole_code+ and returns colored token stream.
|
|
61
|
+
def partial_colorize(whole_code, node, prism_tokens, start_offset = nil, end_offset = nil)
|
|
62
|
+
start_offset ||= node.location.start_offset
|
|
63
|
+
end_offset ||= node.location.end_offset
|
|
64
|
+
visitor = NodeColorizeVisitor.new
|
|
65
|
+
node.accept(visitor)
|
|
66
|
+
prior_tokens = visitor.tokens.sort_by {|_, start_offset, _| start_offset }
|
|
67
|
+
normal_tokens = normal_tokens(slice_by_location(prism_tokens, start_offset, end_offset))
|
|
68
|
+
colored_tokens = unify_tokens(whole_code, prior_tokens, normal_tokens, start_offset, end_offset)
|
|
69
|
+
colored_tokens.unshift(ColoredToken.new(:plain, ' ' * node.location.start_column)) if node.location.start_column > 0
|
|
70
|
+
colored_tokens
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def slice_by_location(items, start_offset, end_offset)
|
|
76
|
+
start_index = items.bsearch_index { |item| item.location.end_offset > start_offset } || items.size
|
|
77
|
+
end_index = items.bsearch_index { |item| item.location.start_offset >= end_offset } || items.size
|
|
78
|
+
items[start_index...end_index]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Unify prior tokens and normal tokens into a single token stream.
|
|
82
|
+
# Prior tokens have higher priority than normal tokens.
|
|
83
|
+
# Also adds missing text (spaces, newlines, etc.) as :plain tokens
|
|
84
|
+
# so that the entire range is covered.
|
|
85
|
+
def unify_tokens(whole_code, prior_tokens, normal_tokens, start_offset, end_offset)
|
|
86
|
+
tokens = []
|
|
87
|
+
offset = start_offset
|
|
88
|
+
|
|
89
|
+
# Add missing text such as spaces and newlines as a separate :plain token
|
|
90
|
+
flush = -> next_offset {
|
|
91
|
+
return if offset == next_offset
|
|
92
|
+
|
|
93
|
+
whole_code.byteslice(offset...next_offset).scan(/\n|\s+|[^\s]+/) do |text|
|
|
94
|
+
tokens << ColoredToken.new(:plain, text)
|
|
95
|
+
end
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
until prior_tokens.empty? && normal_tokens.empty?
|
|
99
|
+
ptok = prior_tokens.first
|
|
100
|
+
ntok = normal_tokens.first
|
|
101
|
+
if ntok && (!ptok || ntok[2] <= ptok[1])
|
|
102
|
+
token = normal_tokens.shift
|
|
103
|
+
else
|
|
104
|
+
token = prior_tokens.shift
|
|
105
|
+
end
|
|
106
|
+
kind, start_pos, end_pos = token
|
|
107
|
+
next if start_pos < offset
|
|
108
|
+
|
|
109
|
+
flush.call(start_pos)
|
|
110
|
+
tokens << ColoredToken.new(kind, whole_code.byteslice(start_pos...end_pos))
|
|
111
|
+
offset = end_pos
|
|
112
|
+
end
|
|
113
|
+
flush.call(end_offset)
|
|
114
|
+
tokens
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Convert normal Prism tokens to [kind, start_offset, end_offset]
|
|
118
|
+
def normal_tokens(tokens)
|
|
119
|
+
tokens.map do |token,|
|
|
120
|
+
kind =
|
|
121
|
+
if token.type.start_with?('KEYWORD_')
|
|
122
|
+
:keyword
|
|
123
|
+
elsif OP_TOKENS.include?(token.type.to_sym)
|
|
124
|
+
:operator
|
|
125
|
+
else
|
|
126
|
+
TOKEN_TYPE_MAP[token.type] || :plain
|
|
127
|
+
end
|
|
128
|
+
[kind, token.location.start_offset, token.location.end_offset]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Visitor to determine node colorizing which can't be determined by tokens.
|
|
134
|
+
# STRING_CONTENT/EMBEXPR_BEGIN/EMBEXPR_END in string/regexp/symbol have different colorizing
|
|
135
|
+
class NodeColorizeVisitor < Prism::Visitor # :nodoc:
|
|
136
|
+
attr_reader :tokens
|
|
137
|
+
|
|
138
|
+
def initialize
|
|
139
|
+
@tokens = []
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def visit_symbol_node(node)
|
|
143
|
+
# SymbolNode#location may contain heredoc content and closing
|
|
144
|
+
# e.g., `<<A; :\\\nA\nsymbol`
|
|
145
|
+
# So we need to colorize opening, content and closing separately.
|
|
146
|
+
push_location(:symbol, node.opening_loc)
|
|
147
|
+
push_location(:symbol, node.value_loc)
|
|
148
|
+
push_location(:symbol, node.closing_loc)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def visit_interpolated_symbol_node(node)
|
|
152
|
+
push_location(:symbol, node.opening_loc)
|
|
153
|
+
handle_interpolated_parts(:symbol, node.parts)
|
|
154
|
+
push_location(:symbol, node.closing_loc)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def visit_regular_expression_node(node)
|
|
158
|
+
push_location(:regexp, node.location)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def visit_interpolated_regular_expression_node(node)
|
|
162
|
+
push_location(:regexp, node.opening_loc)
|
|
163
|
+
handle_interpolated_parts(:regexp, node.parts)
|
|
164
|
+
push_location(:regexp, node.closing_loc)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
alias visit_match_last_line_node visit_regular_expression_node
|
|
168
|
+
alias visit_interpolated_match_last_line_node visit_interpolated_regular_expression_node
|
|
169
|
+
|
|
170
|
+
def visit_string_node(node)
|
|
171
|
+
# Node's location may not cover the entire string literal.
|
|
172
|
+
# For example, in a heredoc string, the node's location covers only the heredoc opening.
|
|
173
|
+
# We need to colorize opening, content and closing separately.
|
|
174
|
+
push_location(:string, node.opening_loc)
|
|
175
|
+
push_location(:string, node.content_loc)
|
|
176
|
+
push_location(:string, node.closing_loc)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def visit_interpolated_string_node(node)
|
|
180
|
+
push_location(:string, node.opening_loc)
|
|
181
|
+
handle_interpolated_parts(:string, node.parts)
|
|
182
|
+
push_location(:string, node.closing_loc)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def visit_x_string_node(node)
|
|
186
|
+
# Same as visit_string_node, node.location of <<`X` only covers opening,
|
|
187
|
+
# so we need to colorize opening, content and closing separately.
|
|
188
|
+
push_location(:x_string, node.opening_loc)
|
|
189
|
+
push_location(:x_string, node.content_loc)
|
|
190
|
+
push_location(:x_string, node.closing_loc)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def visit_interpolated_x_string_node(node)
|
|
194
|
+
push_location(:x_string, node.opening_loc)
|
|
195
|
+
handle_interpolated_parts(:x_string, node.parts)
|
|
196
|
+
push_location(:x_string, node.closing_loc)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def visit_array_node(node)
|
|
200
|
+
super
|
|
201
|
+
# Colorize %w[...] array literal like string literals, and %i[...] like symbol literals
|
|
202
|
+
case node.opening
|
|
203
|
+
when /\A%[wW].\z/
|
|
204
|
+
push_location(:string, node.opening_loc)
|
|
205
|
+
push_location(:string, node.closing_loc)
|
|
206
|
+
when /\A%[iI].\z/
|
|
207
|
+
push_location(:symbol, node.opening_loc)
|
|
208
|
+
push_location(:symbol, node.closing_loc)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def visit_def_node(node)
|
|
213
|
+
# For special colorizing of method name in def node
|
|
214
|
+
# e.g., `def <=>; end`
|
|
215
|
+
push_location(:identifier, node.name_loc)
|
|
216
|
+
super
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
def push_location(kind, location)
|
|
222
|
+
# Only push tokens that have a non-zero length
|
|
223
|
+
if location && location.start_offset < location.end_offset
|
|
224
|
+
@tokens << [kind, location.start_offset, location.end_offset]
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def handle_interpolated_parts(kind, parts)
|
|
229
|
+
# StringNode, EmbeddedStatementsNode brackets, and EmbeddedVariableNode hash in
|
|
230
|
+
# interpolated regexp/symbol/string parts should be colored as regexp/symbol/string respectively.
|
|
231
|
+
parts.each do |part|
|
|
232
|
+
case part
|
|
233
|
+
when Prism::StringNode
|
|
234
|
+
# InterpolatedStringNode#parts may have its own opening/closing. e.g., `'a' "b"`
|
|
235
|
+
push_location(kind, part.opening_loc)
|
|
236
|
+
push_location(kind, part.content_loc)
|
|
237
|
+
push_location(kind, part.closing_loc)
|
|
238
|
+
when Prism::InterpolatedStringNode
|
|
239
|
+
# InterpolatedStringNode#parts may contain InterpolatedStringNode. e.g., `'a' "#{}"`
|
|
240
|
+
part.accept(self)
|
|
241
|
+
when Prism::EmbeddedStatementsNode
|
|
242
|
+
push_location(kind, part.opening_loc)
|
|
243
|
+
push_location(kind, part.closing_loc)
|
|
244
|
+
part.accept(self)
|
|
245
|
+
when Prism::EmbeddedVariableNode
|
|
246
|
+
push_location(kind, part.operator_loc)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private_constant :NodeColorizeVisitor
|
|
253
|
+
end
|
data/lib/rdoc/parser/simple.rb
CHANGED
|
@@ -14,22 +14,22 @@ class RDoc::Parser::Simple < RDoc::Parser
|
|
|
14
14
|
##
|
|
15
15
|
# Prepare to parse a plain file
|
|
16
16
|
|
|
17
|
-
def initialize(top_level,
|
|
17
|
+
def initialize(top_level, content, options, stats)
|
|
18
18
|
super
|
|
19
19
|
|
|
20
20
|
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
content = RDoc::Text.expand_tabs(@content)
|
|
23
|
+
@content, = preprocess.run_pre_processes(content, @top_level, 1, :simple)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
##
|
|
26
27
|
# Extract the file contents and attach them to the TopLevel as a comment
|
|
27
28
|
|
|
28
29
|
def scan
|
|
29
|
-
|
|
30
|
-
comment = remove_private_comment comment
|
|
30
|
+
content = remove_coding_comment @content
|
|
31
31
|
|
|
32
|
-
comment = RDoc::Comment.new
|
|
32
|
+
comment = RDoc::Comment.new content, @top_level
|
|
33
33
|
|
|
34
34
|
@top_level.comment = comment
|
|
35
35
|
@top_level
|
|
@@ -38,24 +38,7 @@ class RDoc::Parser::Simple < RDoc::Parser
|
|
|
38
38
|
##
|
|
39
39
|
# Removes the encoding magic comment from +text+
|
|
40
40
|
|
|
41
|
-
def remove_coding_comment
|
|
41
|
+
def remove_coding_comment(text)
|
|
42
42
|
text.sub(/\A# .*coding[=:].*$/, '')
|
|
43
43
|
end
|
|
44
|
-
|
|
45
|
-
##
|
|
46
|
-
# Removes private comments.
|
|
47
|
-
#
|
|
48
|
-
# Unlike RDoc::Comment#remove_private this implementation only looks for two
|
|
49
|
-
# dashes at the beginning of the line. Three or more dashes are considered
|
|
50
|
-
# to be a rule and ignored.
|
|
51
|
-
|
|
52
|
-
def remove_private_comment comment
|
|
53
|
-
# Workaround for gsub encoding for Ruby 1.9.2 and earlier
|
|
54
|
-
empty = ''
|
|
55
|
-
empty = RDoc::Encoding.change_encoding empty, comment.encoding
|
|
56
|
-
|
|
57
|
-
comment = comment.gsub(%r%^--\n.*?^\+\+\n?%m, empty)
|
|
58
|
-
comment.sub(%r%^--\n.*%m, empty)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
44
|
end
|
data/lib/rdoc/parser/text.rb
CHANGED
data/lib/rdoc/parser.rb
CHANGED
|
@@ -91,7 +91,7 @@ class RDoc::Parser
|
|
|
91
91
|
# Checks if +file+ is a zip file in disguise. Signatures from
|
|
92
92
|
# http://www.garykessler.net/library/file_sigs.html
|
|
93
93
|
|
|
94
|
-
def self.zip?
|
|
94
|
+
def self.zip?(file)
|
|
95
95
|
zip_signature = File.read file, 4
|
|
96
96
|
|
|
97
97
|
zip_signature == "PK\x03\x04" or
|
|
@@ -104,7 +104,7 @@ class RDoc::Parser
|
|
|
104
104
|
##
|
|
105
105
|
# Return a parser that can handle a particular extension
|
|
106
106
|
|
|
107
|
-
def self.can_parse
|
|
107
|
+
def self.can_parse(file_name)
|
|
108
108
|
parser = can_parse_by_name file_name
|
|
109
109
|
|
|
110
110
|
# HACK Selenium hides a jar file using a .txt extension
|
|
@@ -117,7 +117,7 @@ class RDoc::Parser
|
|
|
117
117
|
# Returns a parser that can handle the extension for +file_name+. This does
|
|
118
118
|
# not depend upon the file being readable.
|
|
119
119
|
|
|
120
|
-
def self.can_parse_by_name
|
|
120
|
+
def self.can_parse_by_name(file_name)
|
|
121
121
|
_, parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }
|
|
122
122
|
|
|
123
123
|
# The default parser must not parse binary files
|
|
@@ -125,9 +125,11 @@ class RDoc::Parser
|
|
|
125
125
|
return parser if ext_name.empty?
|
|
126
126
|
|
|
127
127
|
if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then
|
|
128
|
-
case check_modeline
|
|
128
|
+
case mode = check_modeline(file_name)
|
|
129
129
|
when nil, 'rdoc' then # continue
|
|
130
|
-
else
|
|
130
|
+
else
|
|
131
|
+
RDoc::Parser.parsers.find { |_, p| return p if mode.casecmp?(p.name[/\w+\z/]) }
|
|
132
|
+
return nil
|
|
131
133
|
end
|
|
132
134
|
end
|
|
133
135
|
|
|
@@ -138,7 +140,7 @@ class RDoc::Parser
|
|
|
138
140
|
##
|
|
139
141
|
# Returns the file type from the modeline in +file_name+
|
|
140
142
|
|
|
141
|
-
def self.check_modeline
|
|
143
|
+
def self.check_modeline(file_name)
|
|
142
144
|
line = File.open file_name do |io|
|
|
143
145
|
io.gets
|
|
144
146
|
end
|
|
@@ -164,7 +166,8 @@ class RDoc::Parser
|
|
|
164
166
|
# Finds and instantiates the correct parser for the given +file_name+ and
|
|
165
167
|
# +content+.
|
|
166
168
|
|
|
167
|
-
def self.for
|
|
169
|
+
def self.for(top_level, content, options, stats)
|
|
170
|
+
file_name = top_level.absolute_name
|
|
168
171
|
return if binary? file_name
|
|
169
172
|
|
|
170
173
|
parser = use_markup content
|
|
@@ -188,7 +191,7 @@ class RDoc::Parser
|
|
|
188
191
|
|
|
189
192
|
content = remove_modeline content
|
|
190
193
|
|
|
191
|
-
parser.new top_level,
|
|
194
|
+
parser.new top_level, content, options, stats
|
|
192
195
|
rescue SystemCallError
|
|
193
196
|
nil
|
|
194
197
|
end
|
|
@@ -205,7 +208,7 @@ class RDoc::Parser
|
|
|
205
208
|
##
|
|
206
209
|
# Removes an emacs-style modeline from the first line of the document
|
|
207
210
|
|
|
208
|
-
def self.remove_modeline
|
|
211
|
+
def self.remove_modeline(content)
|
|
209
212
|
content.sub(/\A.*-\*-\s*(.*?\S)\s*-\*-.*\r?\n/, '')
|
|
210
213
|
end
|
|
211
214
|
|
|
@@ -226,7 +229,7 @@ class RDoc::Parser
|
|
|
226
229
|
#
|
|
227
230
|
# Any comment style may be used to hide the markup comment.
|
|
228
231
|
|
|
229
|
-
def self.use_markup
|
|
232
|
+
def self.use_markup(content)
|
|
230
233
|
markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first
|
|
231
234
|
|
|
232
235
|
return unless markup
|
|
@@ -249,12 +252,12 @@ class RDoc::Parser
|
|
|
249
252
|
# RDoc::Markup::PreProcess object is created which allows processing of
|
|
250
253
|
# directives.
|
|
251
254
|
|
|
252
|
-
def initialize
|
|
255
|
+
def initialize(top_level, content, options, stats)
|
|
253
256
|
@top_level = top_level
|
|
254
257
|
@top_level.parser = self.class
|
|
255
258
|
@store = @top_level.store
|
|
256
259
|
|
|
257
|
-
@file_name =
|
|
260
|
+
@file_name = top_level.absolute_name
|
|
258
261
|
@content = content
|
|
259
262
|
@options = options
|
|
260
263
|
@stats = stats
|
|
@@ -263,9 +266,25 @@ class RDoc::Parser
|
|
|
263
266
|
@preprocess.options = @options
|
|
264
267
|
end
|
|
265
268
|
|
|
266
|
-
autoload :
|
|
267
|
-
autoload :Text, 'rdoc/parser/text'
|
|
269
|
+
autoload :Text, "#{__dir__}/parser/text"
|
|
268
270
|
|
|
271
|
+
##
|
|
272
|
+
# Normalizes tabs in +body+
|
|
273
|
+
|
|
274
|
+
def handle_tab_width(body)
|
|
275
|
+
if /\t/ =~ body
|
|
276
|
+
tab_width = @options.tab_width
|
|
277
|
+
body.split(/\n/).map do |line|
|
|
278
|
+
1 while line.gsub!(/\t+/) do
|
|
279
|
+
b, e = $~.offset(0)
|
|
280
|
+
' ' * (tab_width * (e-b) - b % tab_width)
|
|
281
|
+
end
|
|
282
|
+
line
|
|
283
|
+
end.join "\n"
|
|
284
|
+
else
|
|
285
|
+
body
|
|
286
|
+
end
|
|
287
|
+
end
|
|
269
288
|
end
|
|
270
289
|
|
|
271
290
|
# simple must come first in order to show up last in the parsers list
|
|
@@ -274,4 +293,6 @@ require_relative 'parser/c'
|
|
|
274
293
|
require_relative 'parser/changelog'
|
|
275
294
|
require_relative 'parser/markdown'
|
|
276
295
|
require_relative 'parser/rd'
|
|
296
|
+
require_relative 'parser/rbs'
|
|
277
297
|
require_relative 'parser/ruby'
|
|
298
|
+
require_relative 'parser/ruby_colorizer'
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'rbs'
|
|
6
|
+
require 'rdoc/markup/formatter'
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# RBS type signature support.
|
|
10
|
+
# Loads type information from .rbs files, validates inline annotations,
|
|
11
|
+
# and converts type signatures to HTML with linked type names.
|
|
12
|
+
|
|
13
|
+
module RDoc
|
|
14
|
+
module RbsHelper
|
|
15
|
+
class << self
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Returns true if +sig+ is a valid RBS method type signature.
|
|
19
|
+
|
|
20
|
+
def valid_method_type?(sig)
|
|
21
|
+
RBS::Parser.parse_method_type(sig, require_eof: true)
|
|
22
|
+
true
|
|
23
|
+
rescue RBS::ParsingError
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Returns true if +sig+ is a valid RBS type signature.
|
|
29
|
+
|
|
30
|
+
def valid_type?(sig)
|
|
31
|
+
RBS::Parser.parse_type(sig, require_eof: true)
|
|
32
|
+
true
|
|
33
|
+
rescue RBS::ParsingError
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Loads RBS signatures from the given directories.
|
|
39
|
+
# Returns a Hash mapping "ClassName#method_name" => ["type sig string", ...].
|
|
40
|
+
|
|
41
|
+
def load_signatures(*dirs)
|
|
42
|
+
loader = RBS::EnvironmentLoader.new
|
|
43
|
+
dirs.each { |dir| loader.add(path: Pathname(dir)) }
|
|
44
|
+
|
|
45
|
+
env = RBS::Environment.new
|
|
46
|
+
loader.load(env: env)
|
|
47
|
+
|
|
48
|
+
signatures = {}
|
|
49
|
+
|
|
50
|
+
env.class_decls.each do |type_name, entry|
|
|
51
|
+
class_name = type_name.to_s.delete_prefix('::')
|
|
52
|
+
|
|
53
|
+
entry.each_decl do |decl|
|
|
54
|
+
decl.members.each do |member|
|
|
55
|
+
case member
|
|
56
|
+
when RBS::AST::Members::MethodDefinition
|
|
57
|
+
sigs = member.overloads.map { |o| o.method_type.to_s }
|
|
58
|
+
method_keys_for(class_name, member).each do |key|
|
|
59
|
+
signatures[key] ||= sigs
|
|
60
|
+
end
|
|
61
|
+
when RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter, RBS::AST::Members::AttrAccessor
|
|
62
|
+
key = member.kind == :singleton ? "#{class_name}.#{member.name}" : "#{class_name}##{member.name}"
|
|
63
|
+
signatures[key] ||= [member.type.to_s]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
signatures
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Converts type signature lines to HTML with type names linked to
|
|
74
|
+
# their documentation pages. Uses the RBS parser to extract type
|
|
75
|
+
# name locations precisely.
|
|
76
|
+
#
|
|
77
|
+
# +lines+ is an Array of signature line strings.
|
|
78
|
+
# +lookup+ is a Hash mapping type names to their doc paths.
|
|
79
|
+
# +from_path+ is the current page path for generating relative URLs.
|
|
80
|
+
#
|
|
81
|
+
# Returns escaped HTML with +->+ replaced by +→+.
|
|
82
|
+
|
|
83
|
+
def signature_to_html(lines, lookup:, from_path:)
|
|
84
|
+
lines.map { |line|
|
|
85
|
+
link_type_names_in_line(line, lookup, from_path).gsub('->', '→')
|
|
86
|
+
}.join("\n")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# `def self?.foo: ...` produces a member whose kind is :singleton_instance —
|
|
92
|
+
# it defines both Class.foo (singleton) and a private Class#foo (instance),
|
|
93
|
+
# so we need to register the signature under both keys.
|
|
94
|
+
def method_keys_for(class_name, member)
|
|
95
|
+
case member.kind
|
|
96
|
+
when :singleton
|
|
97
|
+
["#{class_name}.#{member.name}"]
|
|
98
|
+
when :singleton_instance
|
|
99
|
+
["#{class_name}.#{member.name}", "#{class_name}##{member.name}"]
|
|
100
|
+
else
|
|
101
|
+
["#{class_name}##{member.name}"]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def link_type_names_in_line(line, lookup, from_path)
|
|
106
|
+
escaped = ERB::Util.html_escape(line)
|
|
107
|
+
|
|
108
|
+
locs = collect_type_name_locations(line)
|
|
109
|
+
return escaped if locs.empty?
|
|
110
|
+
|
|
111
|
+
result = escaped.dup
|
|
112
|
+
|
|
113
|
+
# Replace type names with links, working backwards to preserve positions.
|
|
114
|
+
# HTML escaping (e.g. -> becomes ->) shifts positions, so we
|
|
115
|
+
# re-escape the prefix to find the correct offset in the result.
|
|
116
|
+
locs.sort_by { |l| -l[:start] }.each do |loc|
|
|
117
|
+
name = loc[:name]
|
|
118
|
+
next unless (target_path = lookup[name])
|
|
119
|
+
|
|
120
|
+
prefix = ERB::Util.html_escape(line[0...loc[:start]])
|
|
121
|
+
escaped_name = ERB::Util.html_escape(name)
|
|
122
|
+
start_in_escaped = prefix.length
|
|
123
|
+
end_in_escaped = start_in_escaped + escaped_name.length
|
|
124
|
+
|
|
125
|
+
href = ERB::Util.html_escape(::RDoc::Markup::Formatter.gen_relative_url(from_path, target_path))
|
|
126
|
+
result[start_in_escaped...end_in_escaped] =
|
|
127
|
+
"<a href=\"#{href}\" class=\"rbs-type\">#{escaped_name}</a>"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
result
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Extracts type name locations from a signature line using the RBS parser.
|
|
135
|
+
|
|
136
|
+
def collect_type_name_locations(line)
|
|
137
|
+
locs = []
|
|
138
|
+
|
|
139
|
+
begin
|
|
140
|
+
mt = RBS::Parser.parse_method_type(line, require_eof: true)
|
|
141
|
+
rescue RBS::ParsingError
|
|
142
|
+
begin
|
|
143
|
+
type = RBS::Parser.parse_type(line, require_eof: true)
|
|
144
|
+
collect_from_type(type, locs)
|
|
145
|
+
return locs
|
|
146
|
+
rescue RBS::ParsingError
|
|
147
|
+
return locs
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
mt.type.each_param { |p| collect_from_type(p.type, locs) }
|
|
152
|
+
if mt.block
|
|
153
|
+
mt.block.type.each_param { |p| collect_from_type(p.type, locs) }
|
|
154
|
+
collect_from_type(mt.block.type.return_type, locs)
|
|
155
|
+
end
|
|
156
|
+
collect_from_type(mt.type.return_type, locs)
|
|
157
|
+
|
|
158
|
+
locs
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
##
|
|
162
|
+
# Recursively collects type name locations from an RBS type AST node.
|
|
163
|
+
|
|
164
|
+
def collect_from_type(type, locs)
|
|
165
|
+
case type
|
|
166
|
+
when RBS::Types::ClassInstance
|
|
167
|
+
name = type.name.to_s.delete_prefix('::')
|
|
168
|
+
if type.location
|
|
169
|
+
name_loc = type.location[:name] || type.location
|
|
170
|
+
locs << { name: name, start: name_loc.end_pos - name.length }
|
|
171
|
+
end
|
|
172
|
+
type.args.each { |a| collect_from_type(a, locs) }
|
|
173
|
+
when RBS::Types::Union, RBS::Types::Intersection, RBS::Types::Tuple
|
|
174
|
+
type.types.each { |t| collect_from_type(t, locs) }
|
|
175
|
+
when RBS::Types::Optional
|
|
176
|
+
collect_from_type(type.type, locs)
|
|
177
|
+
when RBS::Types::Record
|
|
178
|
+
type.all_fields.each_value { |t| collect_from_type(t, locs) }
|
|
179
|
+
when RBS::Types::Proc
|
|
180
|
+
type.type.each_param { |p| collect_from_type(p.type, locs) }
|
|
181
|
+
collect_from_type(type.type.return_type, locs)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|