rdoc 6.17.0 → 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/CONTRIBUTING.md +196 -0
- data/LEGAL.rdoc +6 -0
- data/README.md +90 -7
- data/doc/markup_reference/markdown.md +558 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/lib/rdoc/code_object/any_method.rb +15 -7
- data/lib/rdoc/code_object/attr.rb +2 -1
- data/lib/rdoc/code_object/class_module.rb +62 -11
- data/lib/rdoc/code_object/constant.rb +9 -0
- data/lib/rdoc/code_object/context/section.rb +46 -9
- data/lib/rdoc/code_object/context.rb +15 -4
- data/lib/rdoc/code_object/method_attr.rb +13 -1
- data/lib/rdoc/code_object/mixin.rb +3 -0
- data/lib/rdoc/code_object/top_level.rb +15 -1
- data/lib/rdoc/comment.rb +1 -1
- data/lib/rdoc/cross_reference.rb +31 -24
- data/lib/rdoc/generator/aliki.rb +141 -0
- data/lib/rdoc/generator/darkfish.rb +3 -1
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +9 -4
- data/lib/rdoc/generator/template/aliki/_header.rhtml +4 -4
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +3 -3
- data/lib/rdoc/generator/template/aliki/class.rhtml +17 -17
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +278 -60
- data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/js/aliki.js +51 -23
- 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.js → search_controller.js} +16 -7
- 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/page.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/class.rhtml +11 -11
- 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/blank_line.rb +25 -23
- data/lib/rdoc/markup/element.rb +21 -0
- data/lib/rdoc/markup/formatter.rb +129 -106
- data/lib/rdoc/markup/hard_break.rb +30 -27
- data/lib/rdoc/markup/heading.rb +166 -77
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/parser.rb +1 -1
- data/lib/rdoc/markup/raw.rb +52 -55
- data/lib/rdoc/markup/table.rb +48 -40
- 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 +11 -32
- data/lib/rdoc/options.rb +1 -1
- 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/rubygems_hook.rb +3 -3
- 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 +3 -3
- metadata +13 -15
- data/CONTRIBUTING.rdoc +0 -219
- 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
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aliki Search Implementation
|
|
3
|
+
*
|
|
4
|
+
* Search algorithm with the following priorities:
|
|
5
|
+
* 1. Exact full_name match always wins (for namespace/method queries)
|
|
6
|
+
* 2. Exact name match gets high priority
|
|
7
|
+
* 3. Match types:
|
|
8
|
+
* - Namespace queries (::) and method queries (# or .) match against full_name
|
|
9
|
+
* - Regular queries match against unqualified name
|
|
10
|
+
* - Prefix (10000) > substring (5000) > fuzzy (1000)
|
|
11
|
+
* 4. First character determines type priority:
|
|
12
|
+
* - Starts with lowercase: methods first
|
|
13
|
+
* - Starts with uppercase: classes/modules/constants first
|
|
14
|
+
* 5. Within same type priority:
|
|
15
|
+
* - Unqualified match > qualified match
|
|
16
|
+
* - Shorter name > longer name
|
|
17
|
+
* 6. Class methods > instance methods
|
|
18
|
+
* 7. Result limit: 30
|
|
19
|
+
* 8. Minimum query length: 1 character
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
var MAX_RESULTS = 30;
|
|
23
|
+
var MIN_QUERY_LENGTH = 1;
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* Scoring constants - organized in tiers where each tier dominates lower tiers.
|
|
27
|
+
* This ensures match type always beats type priority, etc.
|
|
28
|
+
*
|
|
29
|
+
* Tier 0: Exact matches (immediate return)
|
|
30
|
+
* Tier 1: Match type (prefix > substring > fuzzy)
|
|
31
|
+
* Tier 2: Exact name bonus
|
|
32
|
+
* Tier 3: Type priority (method vs class based on query case)
|
|
33
|
+
* Tier 4: Minor bonuses (top-level, class method, name length)
|
|
34
|
+
*/
|
|
35
|
+
var SCORE_EXACT_FULL_NAME = 1000000; // Tier 0: Query exactly matches full_name
|
|
36
|
+
var SCORE_MATCH_PREFIX = 10000; // Tier 1: Query is prefix of name
|
|
37
|
+
var SCORE_MATCH_SUBSTRING = 5000; // Tier 1: Query is substring of name
|
|
38
|
+
var SCORE_MATCH_FUZZY = 1000; // Tier 1: Query chars appear in order
|
|
39
|
+
var SCORE_EXACT_NAME = 500; // Tier 2: Name exactly equals query
|
|
40
|
+
var SCORE_TYPE_PRIORITY = 100; // Tier 3: Preferred type (method/class)
|
|
41
|
+
var SCORE_TOP_LEVEL = 50; // Tier 4: Top-level over namespaced
|
|
42
|
+
var SCORE_CLASS_METHOD = 10; // Tier 4: Class method over instance method
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if all characters in query appear in order in target
|
|
46
|
+
* e.g., "addalias" fuzzy matches "add_foo_alias"
|
|
47
|
+
*/
|
|
48
|
+
function fuzzyMatch(target, query) {
|
|
49
|
+
var ti = 0;
|
|
50
|
+
for (var qi = 0; qi < query.length; qi++) {
|
|
51
|
+
ti = target.indexOf(query[qi], ti);
|
|
52
|
+
if (ti === -1) return false;
|
|
53
|
+
ti++;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parse and normalize a search query
|
|
60
|
+
* @param {string} query - The raw search query
|
|
61
|
+
* @returns {Object} Parsed query with normalized form and flags
|
|
62
|
+
*/
|
|
63
|
+
function parseQuery(query) {
|
|
64
|
+
// Lowercase for case-insensitive matching (so "hash" finds both Hash class and #hash methods)
|
|
65
|
+
var normalized = query.toLowerCase();
|
|
66
|
+
var isNamespaceQuery = query.includes('::');
|
|
67
|
+
var isMethodQuery = query.includes('#') || query.includes('.');
|
|
68
|
+
|
|
69
|
+
// Normalize . to :: (RDoc uses :: for class methods in full_name)
|
|
70
|
+
if (query.includes('.')) {
|
|
71
|
+
normalized = normalized.replace(/\./g, '::');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
original: query,
|
|
76
|
+
normalized: normalized,
|
|
77
|
+
isNamespaceQuery: isNamespaceQuery,
|
|
78
|
+
isMethodQuery: isMethodQuery,
|
|
79
|
+
// Namespace and method queries match against full_name instead of name
|
|
80
|
+
matchesFullName: isNamespaceQuery || isMethodQuery,
|
|
81
|
+
// If query starts with lowercase, prioritize methods; otherwise prioritize classes/modules/constants
|
|
82
|
+
prioritizeMethod: !/^[A-Z]/.test(query)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Main search function
|
|
88
|
+
* @param {string} query - The search query
|
|
89
|
+
* @param {Array} index - The search index to search in
|
|
90
|
+
* @returns {Array} Array of matching entries, sorted by relevance
|
|
91
|
+
*/
|
|
92
|
+
function search(query, index) {
|
|
93
|
+
if (!query || query.length < MIN_QUERY_LENGTH) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
var q = parseQuery(query);
|
|
98
|
+
var results = [];
|
|
99
|
+
|
|
100
|
+
for (var i = 0; i < index.length; i++) {
|
|
101
|
+
var entry = index[i];
|
|
102
|
+
var score = computeScore(entry, q);
|
|
103
|
+
|
|
104
|
+
if (score !== null) {
|
|
105
|
+
results.push({ entry: entry, score: score });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
results.sort(function(a, b) {
|
|
110
|
+
return b.score - a.score;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return results.slice(0, MAX_RESULTS).map(function(r) {
|
|
114
|
+
return r.entry;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Compute the relevance score for an entry
|
|
120
|
+
* @param {Object} entry - The search index entry
|
|
121
|
+
* @param {Object} q - Parsed query from parseQuery()
|
|
122
|
+
* @returns {number|null} Score or null if no match
|
|
123
|
+
*/
|
|
124
|
+
function computeScore(entry, q) {
|
|
125
|
+
var name = entry.name;
|
|
126
|
+
var fullName = entry.full_name;
|
|
127
|
+
var type = entry.type;
|
|
128
|
+
|
|
129
|
+
var nameLower = name.toLowerCase();
|
|
130
|
+
var fullNameLower = fullName.toLowerCase();
|
|
131
|
+
|
|
132
|
+
// Exact full_name match (e.g., "Array#filter" matches Array#filter)
|
|
133
|
+
if (q.matchesFullName && fullNameLower === q.normalized) {
|
|
134
|
+
return SCORE_EXACT_FULL_NAME;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var matchScore = 0;
|
|
138
|
+
var target = q.matchesFullName ? fullNameLower : nameLower;
|
|
139
|
+
|
|
140
|
+
if (target.startsWith(q.normalized)) {
|
|
141
|
+
matchScore = SCORE_MATCH_PREFIX; // Prefix (e.g., "Arr" matches "Array")
|
|
142
|
+
} else if (target.includes(q.normalized)) {
|
|
143
|
+
matchScore = SCORE_MATCH_SUBSTRING; // Substring (e.g., "ray" matches "Array")
|
|
144
|
+
} else if (fuzzyMatch(target, q.normalized)) {
|
|
145
|
+
matchScore = SCORE_MATCH_FUZZY; // Fuzzy (e.g., "addalias" matches "add_foo_alias")
|
|
146
|
+
} else {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
var score = matchScore;
|
|
151
|
+
var isMethod = (type === 'instance_method' || type === 'class_method');
|
|
152
|
+
|
|
153
|
+
if (q.prioritizeMethod ? isMethod : !isMethod) {
|
|
154
|
+
score += SCORE_TYPE_PRIORITY;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (type === 'class_method') score += SCORE_CLASS_METHOD;
|
|
158
|
+
if (name === fullName) score += SCORE_TOP_LEVEL; // Top-level (Hash) > namespaced (Foo::Hash)
|
|
159
|
+
if (nameLower === q.normalized) score += SCORE_EXACT_NAME; // Exact name match
|
|
160
|
+
score -= name.length;
|
|
161
|
+
|
|
162
|
+
return score;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* SearchRanker class for compatibility with the Search UI
|
|
167
|
+
* Provides ready() and find() interface
|
|
168
|
+
*/
|
|
169
|
+
function SearchRanker(index) {
|
|
170
|
+
this.index = index;
|
|
171
|
+
this.handlers = [];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
SearchRanker.prototype.ready = function(fn) {
|
|
175
|
+
this.handlers.push(fn);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
SearchRanker.prototype.find = function(query) {
|
|
179
|
+
var q = parseQuery(query);
|
|
180
|
+
var rawResults = search(query, this.index);
|
|
181
|
+
var results = rawResults.map(function(entry) {
|
|
182
|
+
return formatResult(entry, q);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
var _this = this;
|
|
186
|
+
this.handlers.forEach(function(fn) {
|
|
187
|
+
fn.call(_this, results, true);
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Format a search result entry for display
|
|
193
|
+
*/
|
|
194
|
+
function formatResult(entry, q) {
|
|
195
|
+
var result = {
|
|
196
|
+
title: highlightMatch(entry.full_name, q),
|
|
197
|
+
path: entry.path,
|
|
198
|
+
type: entry.type
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
if (entry.snippet) {
|
|
202
|
+
result.snippet = entry.snippet;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Add highlight markers (\u0001 and \u0002) to matching portions of text
|
|
210
|
+
* @param {string} text - The text to highlight
|
|
211
|
+
* @param {Object} q - Parsed query from parseQuery()
|
|
212
|
+
*/
|
|
213
|
+
function highlightMatch(text, q) {
|
|
214
|
+
if (!text || !q) return text;
|
|
215
|
+
|
|
216
|
+
var textLower = text.toLowerCase();
|
|
217
|
+
var query = q.normalized;
|
|
218
|
+
|
|
219
|
+
// Try contiguous match first (prefix or substring)
|
|
220
|
+
var matchIndex = textLower.indexOf(query);
|
|
221
|
+
if (matchIndex !== -1) {
|
|
222
|
+
return text.substring(0, matchIndex) +
|
|
223
|
+
'\u0001' + text.substring(matchIndex, matchIndex + query.length) + '\u0002' +
|
|
224
|
+
text.substring(matchIndex + query.length);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Fall back to fuzzy highlight (highlight each matched character)
|
|
228
|
+
var result = '';
|
|
229
|
+
var ti = 0;
|
|
230
|
+
for (var qi = 0; qi < query.length; qi++) {
|
|
231
|
+
var charIndex = textLower.indexOf(query[qi], ti);
|
|
232
|
+
if (charIndex === -1) return text;
|
|
233
|
+
result += text.substring(ti, charIndex);
|
|
234
|
+
result += '\u0001' + text[charIndex] + '\u0002';
|
|
235
|
+
ti = charIndex + 1;
|
|
236
|
+
}
|
|
237
|
+
result += text.substring(ti);
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
@@ -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">
|
|
@@ -117,10 +119,10 @@
|
|
|
117
119
|
</section>
|
|
118
120
|
<%- end %>
|
|
119
121
|
|
|
120
|
-
<%- klass.methods_by_type(section).each do |type, visibilities|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
<%- klass.methods_by_type(section).each do |type, visibilities| %>
|
|
123
|
+
<%- next if visibilities.empty? %>
|
|
124
|
+
<%- visibilities.each do |visibility, methods| %>
|
|
125
|
+
<%- next if methods.empty? %>
|
|
124
126
|
<section id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details" class="method-section anchor-link">
|
|
125
127
|
<header>
|
|
126
128
|
<h3><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
|
|
@@ -163,15 +165,13 @@
|
|
|
163
165
|
<summary>Source</summary>
|
|
164
166
|
</details>
|
|
165
167
|
</div>
|
|
168
|
+
<div class="method-source-code" id="<%= method.html_name %>-source">
|
|
169
|
+
<pre><%= method.markup_code %></pre>
|
|
170
|
+
</div>
|
|
166
171
|
<%- end %>
|
|
167
172
|
|
|
168
173
|
<%- unless method.skip_description? then %>
|
|
169
174
|
<div class="method-description">
|
|
170
|
-
<%- if method.token_stream then %>
|
|
171
|
-
<div class="method-source-code" id="<%= method.html_name %>-source">
|
|
172
|
-
<pre><%= method.markup_code %></pre>
|
|
173
|
-
</div>
|
|
174
|
-
<%- end %>
|
|
175
175
|
<%- if method.mixin_from then %>
|
|
176
176
|
<div class="mixin-from">
|
|
177
177
|
<%= method.singleton ? "Extended" : "Included" %> from <a href="<%= klass.aref_to(method.mixin_from.path) %>"><%= method.mixin_from.full_name %></a>
|
|
@@ -215,8 +215,8 @@
|
|
|
215
215
|
|
|
216
216
|
<%- end %>
|
|
217
217
|
</section>
|
|
218
|
-
<%- end
|
|
219
|
-
|
|
218
|
+
<%- end %>
|
|
219
|
+
<%- end %>
|
|
220
220
|
</section>
|
|
221
221
|
<%- end %>
|
|
222
222
|
</main>
|
|
@@ -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);
|
data/lib/rdoc/markdown.kpeg
CHANGED
|
@@ -303,6 +303,20 @@
|
|
|
303
303
|
end
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
+
# Escape character that has special meaning in RDoc format.
|
|
307
|
+
# To allow rdoc-styled link used in markdown format for now, bracket and brace are not escaped.
|
|
308
|
+
|
|
309
|
+
def rdoc_escape(text)
|
|
310
|
+
text.gsub(/[*+<\\_]/) {|s| "\\#{s}" }
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Escape link url that contains brackets.
|
|
314
|
+
# Brackets needs escape because link url will be surrounded by `[]` in RDoc format.
|
|
315
|
+
|
|
316
|
+
def rdoc_link_url_escape(text)
|
|
317
|
+
text.gsub(/[\[\]\\]/) {|s| "\\#{s}" }
|
|
318
|
+
end
|
|
319
|
+
|
|
306
320
|
##
|
|
307
321
|
# :category: Extensions
|
|
308
322
|
#
|
|
@@ -490,11 +504,7 @@
|
|
|
490
504
|
# Wraps `text` in strike markup for rdoc inline formatting
|
|
491
505
|
|
|
492
506
|
def strike text
|
|
493
|
-
|
|
494
|
-
"~#{text}~"
|
|
495
|
-
else
|
|
496
|
-
"<s>#{text}</s>"
|
|
497
|
-
end
|
|
507
|
+
"<del>#{text}</del>"
|
|
498
508
|
end
|
|
499
509
|
|
|
500
510
|
##
|
|
@@ -973,11 +983,11 @@ Space = @Spacechar+ { " " }
|
|
|
973
983
|
|
|
974
984
|
Str = @StartList:a
|
|
975
985
|
< @NormalChar+ > { a = text }
|
|
976
|
-
( StrChunk:c { a << c } )* { a }
|
|
986
|
+
( StrChunk:c { a << c } )* { rdoc_escape(a) }
|
|
977
987
|
|
|
978
988
|
StrChunk = < (@NormalChar | /_+/ &Alphanumeric)+ > { text }
|
|
979
989
|
|
|
980
|
-
EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text }
|
|
990
|
+
EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { rdoc_escape(text) }
|
|
981
991
|
|
|
982
992
|
Entity = ( HexEntity | DecEntity | CharEntity ):a { a }
|
|
983
993
|
|
|
@@ -992,7 +1002,7 @@ TerminalEndline = @Sp @Newline @Eof
|
|
|
992
1002
|
LineBreak = " " @NormalEndline { RDoc::Markup::HardBreak.new }
|
|
993
1003
|
|
|
994
1004
|
Symbol = < @SpecialChar >
|
|
995
|
-
{ text }
|
|
1005
|
+
{ rdoc_escape(text) }
|
|
996
1006
|
|
|
997
1007
|
# This keeps the parser from getting bogged down on long strings of '*' or '_',
|
|
998
1008
|
# or strings of '*' or '_' with space on each side:
|
|
@@ -1057,7 +1067,7 @@ ReferenceLinkSingle = Label:content < (Spnl "[]")? >
|
|
|
1057
1067
|
{ link_to content, content, text }
|
|
1058
1068
|
|
|
1059
1069
|
ExplicitLink = ExplicitLinkWithLabel:a
|
|
1060
|
-
{ "{#{a[:label]}}[#{a[:link]}]" }
|
|
1070
|
+
{ "{#{a[:label]}}[#{rdoc_link_url_escape(a[:link])}]" }
|
|
1061
1071
|
|
|
1062
1072
|
ExplicitLinkWithLabel = Label:label "(" @Sp Source:link Spnl Title @Sp ")"
|
|
1063
1073
|
{ { label: label, link: link } }
|
|
@@ -1167,12 +1177,12 @@ Newline = %literals.Newline
|
|
|
1167
1177
|
Spacechar = %literals.Spacechar
|
|
1168
1178
|
|
|
1169
1179
|
HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";"
|
|
1170
|
-
{ [text.to_i(16)].pack
|
|
1180
|
+
{ rdoc_escape([text.to_i(16)].pack('U')) }
|
|
1171
1181
|
DecEntity = "&#" < /[0-9]+/ > ";"
|
|
1172
|
-
{ [text.to_i].pack
|
|
1182
|
+
{ rdoc_escape([text.to_i].pack('U')) }
|
|
1173
1183
|
CharEntity = "&" </[A-Za-z0-9]+/ > ";"
|
|
1174
1184
|
{ if entity = HTML_ENTITIES[text] then
|
|
1175
|
-
entity.pack
|
|
1185
|
+
rdoc_escape(entity.pack('U*'))
|
|
1176
1186
|
else
|
|
1177
1187
|
"&#{text};"
|
|
1178
1188
|
end
|
data/lib/rdoc/markdown.rb
CHANGED
|
@@ -688,6 +688,20 @@ class RDoc::Markdown
|
|
|
688
688
|
end
|
|
689
689
|
end
|
|
690
690
|
|
|
691
|
+
# Escape character that has special meaning in RDoc format.
|
|
692
|
+
# To allow rdoc-styled link used in markdown format for now, bracket and brace are not escaped.
|
|
693
|
+
|
|
694
|
+
def rdoc_escape(text)
|
|
695
|
+
text.gsub(/[*+<\\_]/) {|s| "\\#{s}" }
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
# Escape link url that contains brackets.
|
|
699
|
+
# Brackets needs escape because link url will be surrounded by `[]` in RDoc format.
|
|
700
|
+
|
|
701
|
+
def rdoc_link_url_escape(text)
|
|
702
|
+
text.gsub(/[\[\]\\]/) {|s| "\\#{s}" }
|
|
703
|
+
end
|
|
704
|
+
|
|
691
705
|
##
|
|
692
706
|
# :category: Extensions
|
|
693
707
|
#
|
|
@@ -875,11 +889,7 @@ class RDoc::Markdown
|
|
|
875
889
|
# Wraps `text` in strike markup for rdoc inline formatting
|
|
876
890
|
|
|
877
891
|
def strike text
|
|
878
|
-
|
|
879
|
-
"~#{text}~"
|
|
880
|
-
else
|
|
881
|
-
"<s>#{text}</s>"
|
|
882
|
-
end
|
|
892
|
+
"<del>#{text}</del>"
|
|
883
893
|
end
|
|
884
894
|
|
|
885
895
|
##
|
|
@@ -9735,7 +9745,7 @@ class RDoc::Markdown
|
|
|
9735
9745
|
return _tmp
|
|
9736
9746
|
end
|
|
9737
9747
|
|
|
9738
|
-
# Str = @StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }
|
|
9748
|
+
# Str = @StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { rdoc_escape(a) }
|
|
9739
9749
|
def _Str
|
|
9740
9750
|
|
|
9741
9751
|
_save = self.pos
|
|
@@ -9796,7 +9806,7 @@ class RDoc::Markdown
|
|
|
9796
9806
|
self.pos = _save
|
|
9797
9807
|
break
|
|
9798
9808
|
end
|
|
9799
|
-
@result = begin; a ; end
|
|
9809
|
+
@result = begin; rdoc_escape(a) ; end
|
|
9800
9810
|
_tmp = true
|
|
9801
9811
|
unless _tmp
|
|
9802
9812
|
self.pos = _save
|
|
@@ -9898,7 +9908,7 @@ class RDoc::Markdown
|
|
|
9898
9908
|
return _tmp
|
|
9899
9909
|
end
|
|
9900
9910
|
|
|
9901
|
-
# EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text }
|
|
9911
|
+
# EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { rdoc_escape(text) }
|
|
9902
9912
|
def _EscapedChar
|
|
9903
9913
|
|
|
9904
9914
|
_save = self.pos
|
|
@@ -9925,7 +9935,7 @@ class RDoc::Markdown
|
|
|
9925
9935
|
self.pos = _save
|
|
9926
9936
|
break
|
|
9927
9937
|
end
|
|
9928
|
-
@result = begin; text ; end
|
|
9938
|
+
@result = begin; rdoc_escape(text) ; end
|
|
9929
9939
|
_tmp = true
|
|
9930
9940
|
unless _tmp
|
|
9931
9941
|
self.pos = _save
|
|
@@ -10126,7 +10136,7 @@ class RDoc::Markdown
|
|
|
10126
10136
|
return _tmp
|
|
10127
10137
|
end
|
|
10128
10138
|
|
|
10129
|
-
# Symbol = < @SpecialChar > { text }
|
|
10139
|
+
# Symbol = < @SpecialChar > { rdoc_escape(text) }
|
|
10130
10140
|
def _Symbol
|
|
10131
10141
|
|
|
10132
10142
|
_save = self.pos
|
|
@@ -10140,7 +10150,7 @@ class RDoc::Markdown
|
|
|
10140
10150
|
self.pos = _save
|
|
10141
10151
|
break
|
|
10142
10152
|
end
|
|
10143
|
-
@result = begin; text ; end
|
|
10153
|
+
@result = begin; rdoc_escape(text) ; end
|
|
10144
10154
|
_tmp = true
|
|
10145
10155
|
unless _tmp
|
|
10146
10156
|
self.pos = _save
|
|
@@ -11193,7 +11203,7 @@ class RDoc::Markdown
|
|
|
11193
11203
|
return _tmp
|
|
11194
11204
|
end
|
|
11195
11205
|
|
|
11196
|
-
# ExplicitLink = ExplicitLinkWithLabel:a { "{#{a[:label]}}[#{a[:link]}]" }
|
|
11206
|
+
# ExplicitLink = ExplicitLinkWithLabel:a { "{#{a[:label]}}[#{rdoc_link_url_escape(a[:link])}]" }
|
|
11197
11207
|
def _ExplicitLink
|
|
11198
11208
|
|
|
11199
11209
|
_save = self.pos
|
|
@@ -11204,7 +11214,7 @@ class RDoc::Markdown
|
|
|
11204
11214
|
self.pos = _save
|
|
11205
11215
|
break
|
|
11206
11216
|
end
|
|
11207
|
-
@result = begin; "{#{a[:label]}}[#{a[:link]}]" ; end
|
|
11217
|
+
@result = begin; "{#{a[:label]}}[#{rdoc_link_url_escape(a[:link])}]" ; end
|
|
11208
11218
|
_tmp = true
|
|
11209
11219
|
unless _tmp
|
|
11210
11220
|
self.pos = _save
|
|
@@ -14619,7 +14629,7 @@ class RDoc::Markdown
|
|
|
14619
14629
|
return _tmp
|
|
14620
14630
|
end
|
|
14621
14631
|
|
|
14622
|
-
# HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";" { [text.to_i(16)].pack
|
|
14632
|
+
# HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";" { rdoc_escape([text.to_i(16)].pack('U')) }
|
|
14623
14633
|
def _HexEntity
|
|
14624
14634
|
|
|
14625
14635
|
_save = self.pos
|
|
@@ -14643,7 +14653,7 @@ class RDoc::Markdown
|
|
|
14643
14653
|
self.pos = _save
|
|
14644
14654
|
break
|
|
14645
14655
|
end
|
|
14646
|
-
@result = begin; [text.to_i(16)].pack
|
|
14656
|
+
@result = begin; rdoc_escape([text.to_i(16)].pack('U')) ; end
|
|
14647
14657
|
_tmp = true
|
|
14648
14658
|
unless _tmp
|
|
14649
14659
|
self.pos = _save
|
|
@@ -14655,7 +14665,7 @@ class RDoc::Markdown
|
|
|
14655
14665
|
return _tmp
|
|
14656
14666
|
end
|
|
14657
14667
|
|
|
14658
|
-
# DecEntity = "&#" < /[0-9]+/ > ";" { [text.to_i].pack
|
|
14668
|
+
# DecEntity = "&#" < /[0-9]+/ > ";" { rdoc_escape([text.to_i].pack('U')) }
|
|
14659
14669
|
def _DecEntity
|
|
14660
14670
|
|
|
14661
14671
|
_save = self.pos
|
|
@@ -14679,7 +14689,7 @@ class RDoc::Markdown
|
|
|
14679
14689
|
self.pos = _save
|
|
14680
14690
|
break
|
|
14681
14691
|
end
|
|
14682
|
-
@result = begin; [text.to_i].pack
|
|
14692
|
+
@result = begin; rdoc_escape([text.to_i].pack('U')) ; end
|
|
14683
14693
|
_tmp = true
|
|
14684
14694
|
unless _tmp
|
|
14685
14695
|
self.pos = _save
|
|
@@ -14691,7 +14701,7 @@ class RDoc::Markdown
|
|
|
14691
14701
|
return _tmp
|
|
14692
14702
|
end
|
|
14693
14703
|
|
|
14694
|
-
# CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then entity.pack
|
|
14704
|
+
# CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then rdoc_escape(entity.pack('U*')) else "&#{text};" end }
|
|
14695
14705
|
def _CharEntity
|
|
14696
14706
|
|
|
14697
14707
|
_save = self.pos
|
|
@@ -14716,7 +14726,7 @@ class RDoc::Markdown
|
|
|
14716
14726
|
break
|
|
14717
14727
|
end
|
|
14718
14728
|
@result = begin; if entity = HTML_ENTITIES[text] then
|
|
14719
|
-
entity.pack
|
|
14729
|
+
rdoc_escape(entity.pack('U*'))
|
|
14720
14730
|
else
|
|
14721
14731
|
"&#{text};"
|
|
14722
14732
|
end
|
|
@@ -16567,15 +16577,15 @@ class RDoc::Markdown
|
|
|
16567
16577
|
Rules[:_Inlines] = rule_info("Inlines", "(!@Endline Inline:i { i } | @Endline:c !(&{ github? } Ticks3 /[^`\\n]*$/) &Inline { c })+:chunks @Endline? { chunks }")
|
|
16568
16578
|
Rules[:_Inline] = rule_info("Inline", "(Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Strike | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)")
|
|
16569
16579
|
Rules[:_Space] = rule_info("Space", "@Spacechar+ { \" \" }")
|
|
16570
|
-
Rules[:_Str] = rule_info("Str", "@StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }")
|
|
16580
|
+
Rules[:_Str] = rule_info("Str", "@StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { rdoc_escape(a) }")
|
|
16571
16581
|
Rules[:_StrChunk] = rule_info("StrChunk", "< (@NormalChar | /_+/ &Alphanumeric)+ > { text }")
|
|
16572
|
-
Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !@Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { text }")
|
|
16582
|
+
Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !@Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { rdoc_escape(text) }")
|
|
16573
16583
|
Rules[:_Entity] = rule_info("Entity", "(HexEntity | DecEntity | CharEntity):a { a }")
|
|
16574
16584
|
Rules[:_Endline] = rule_info("Endline", "(@LineBreak | @TerminalEndline | @NormalEndline)")
|
|
16575
16585
|
Rules[:_NormalEndline] = rule_info("NormalEndline", "@Sp @Newline !@BlankLine !\">\" !AtxStart !(Line /={1,}|-{1,}/ @Newline) { \"\\n\" }")
|
|
16576
16586
|
Rules[:_TerminalEndline] = rule_info("TerminalEndline", "@Sp @Newline @Eof")
|
|
16577
16587
|
Rules[:_LineBreak] = rule_info("LineBreak", "\" \" @NormalEndline { RDoc::Markup::HardBreak.new }")
|
|
16578
|
-
Rules[:_Symbol] = rule_info("Symbol", "< @SpecialChar > { text }")
|
|
16588
|
+
Rules[:_Symbol] = rule_info("Symbol", "< @SpecialChar > { rdoc_escape(text) }")
|
|
16579
16589
|
Rules[:_UlOrStarLine] = rule_info("UlOrStarLine", "(UlLine | StarLine):a { a }")
|
|
16580
16590
|
Rules[:_StarLine] = rule_info("StarLine", "(< /\\*{4,}/ > { text } | < @Spacechar /\\*+/ &@Spacechar > { text })")
|
|
16581
16591
|
Rules[:_UlLine] = rule_info("UlLine", "(< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text })")
|
|
@@ -16592,7 +16602,7 @@ class RDoc::Markdown
|
|
|
16592
16602
|
Rules[:_ReferenceLink] = rule_info("ReferenceLink", "(ReferenceLinkDouble | ReferenceLinkSingle)")
|
|
16593
16603
|
Rules[:_ReferenceLinkDouble] = rule_info("ReferenceLinkDouble", "Label:content < Spnl > !\"[]\" Label:label { link_to content, label, text }")
|
|
16594
16604
|
Rules[:_ReferenceLinkSingle] = rule_info("ReferenceLinkSingle", "Label:content < (Spnl \"[]\")? > { link_to content, content, text }")
|
|
16595
|
-
Rules[:_ExplicitLink] = rule_info("ExplicitLink", "ExplicitLinkWithLabel:a { \"{\#{a[:label]}}[\#{a[:link]}]\" }")
|
|
16605
|
+
Rules[:_ExplicitLink] = rule_info("ExplicitLink", "ExplicitLinkWithLabel:a { \"{\#{a[:label]}}[\#{rdoc_link_url_escape(a[:link])}]\" }")
|
|
16596
16606
|
Rules[:_ExplicitLinkWithLabel] = rule_info("ExplicitLinkWithLabel", "Label:label \"(\" @Sp Source:link Spnl Title @Sp \")\" { { label: label, link: link } }")
|
|
16597
16607
|
Rules[:_Source] = rule_info("Source", "(\"<\" < SourceContents > \">\" | < SourceContents >) { text }")
|
|
16598
16608
|
Rules[:_SourceContents] = rule_info("SourceContents", "((!\"(\" !\")\" !\">\" Nonspacechar)+ | \"(\" SourceContents \")\")*")
|
|
@@ -16635,9 +16645,9 @@ class RDoc::Markdown
|
|
|
16635
16645
|
Rules[:_BOM] = rule_info("BOM", "%literals.BOM")
|
|
16636
16646
|
Rules[:_Newline] = rule_info("Newline", "%literals.Newline")
|
|
16637
16647
|
Rules[:_Spacechar] = rule_info("Spacechar", "%literals.Spacechar")
|
|
16638
|
-
Rules[:_HexEntity] = rule_info("HexEntity", "/&\#x/i < /[0-9a-fA-F]+/ > \";\" { [text.to_i(16)].pack
|
|
16639
|
-
Rules[:_DecEntity] = rule_info("DecEntity", "\"&\#\" < /[0-9]+/ > \";\" { [text.to_i].pack
|
|
16640
|
-
Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then entity.pack
|
|
16648
|
+
Rules[:_HexEntity] = rule_info("HexEntity", "/&\#x/i < /[0-9a-fA-F]+/ > \";\" { rdoc_escape([text.to_i(16)].pack('U')) }")
|
|
16649
|
+
Rules[:_DecEntity] = rule_info("DecEntity", "\"&\#\" < /[0-9]+/ > \";\" { rdoc_escape([text.to_i].pack('U')) }")
|
|
16650
|
+
Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then rdoc_escape(entity.pack('U*')) else \"&\#{text};\" end }")
|
|
16641
16651
|
Rules[:_NonindentSpace] = rule_info("NonindentSpace", "/ {0,3}/")
|
|
16642
16652
|
Rules[:_Indent] = rule_info("Indent", "/\\t| /")
|
|
16643
16653
|
Rules[:_IndentedLine] = rule_info("IndentedLine", "Indent Line")
|