rdoc 7.0.3 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -4
- data/doc/markup_reference/markdown.md +558 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/lib/rdoc/code_object/attr.rb +2 -1
- data/lib/rdoc/code_object/class_module.rb +24 -3
- data/lib/rdoc/code_object/context/section.rb +46 -9
- data/lib/rdoc/code_object/context.rb +15 -4
- data/lib/rdoc/code_object/mixin.rb +3 -0
- data/lib/rdoc/code_object/top_level.rb +2 -0
- data/lib/rdoc/comment.rb +1 -1
- data/lib/rdoc/cross_reference.rb +31 -24
- data/lib/rdoc/generator/template/aliki/_head.rhtml +5 -0
- data/lib/rdoc/generator/template/aliki/class.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +48 -36
- data/lib/rdoc/generator/template/aliki/js/aliki.js +8 -2
- data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
- data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +1 -1
- data/lib/rdoc/generator/template/aliki/js/search_controller.js +1 -1
- data/lib/rdoc/generator/template/darkfish/class.rhtml +2 -0
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -0
- data/lib/rdoc/markdown.kpeg +22 -12
- data/lib/rdoc/markdown.rb +36 -26
- data/lib/rdoc/markup/formatter.rb +129 -106
- data/lib/rdoc/markup/heading.rb +101 -29
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/parser.rb +1 -1
- data/lib/rdoc/markup/to_ansi.rb +51 -4
- data/lib/rdoc/markup/to_bs.rb +22 -42
- data/lib/rdoc/markup/to_html.rb +178 -183
- data/lib/rdoc/markup/to_html_crossref.rb +58 -79
- data/lib/rdoc/markup/to_html_snippet.rb +62 -62
- data/lib/rdoc/markup/to_label.rb +29 -20
- data/lib/rdoc/markup/to_markdown.rb +61 -37
- data/lib/rdoc/markup/to_rdoc.rb +86 -26
- data/lib/rdoc/markup/to_test.rb +9 -1
- data/lib/rdoc/markup/to_tt_only.rb +10 -16
- data/lib/rdoc/markup/verbatim.rb +1 -1
- data/lib/rdoc/markup.rb +10 -32
- data/lib/rdoc/parser/changelog.rb +29 -0
- data/lib/rdoc/parser/prism_ruby.rb +44 -32
- data/lib/rdoc/parser/ruby.rb +1 -1
- data/lib/rdoc/text.rb +44 -5
- data/lib/rdoc/token_stream.rb +4 -8
- data/lib/rdoc/version.rb +1 -1
- data/rdoc.gemspec +2 -2
- metadata +7 -12
- data/ExampleMarkdown.md +0 -39
- data/ExampleRDoc.rdoc +0 -210
- data/lib/rdoc/markup/attr_changer.rb +0 -22
- data/lib/rdoc/markup/attr_span.rb +0 -35
- data/lib/rdoc/markup/attribute_manager.rb +0 -405
- data/lib/rdoc/markup/attributes.rb +0 -70
- data/lib/rdoc/markup/regexp_handling.rb +0 -40
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
require 'strscan'
|
|
5
|
+
|
|
6
|
+
# Parses inline markup in RDoc text.
|
|
7
|
+
# This parser handles em, bold, strike, tt, hard break, and tidylink.
|
|
8
|
+
# Block-level constructs are handled in RDoc::Markup::Parser.
|
|
9
|
+
|
|
10
|
+
class RDoc::Markup::InlineParser
|
|
11
|
+
|
|
12
|
+
# TT, BOLD_WORD, EM_WORD: regexp-handling(example: crossref) is disabled
|
|
13
|
+
WORD_PAIRS = {
|
|
14
|
+
'*' => :BOLD_WORD,
|
|
15
|
+
'**' => :BOLD_WORD,
|
|
16
|
+
'_' => :EM_WORD,
|
|
17
|
+
'__' => :EM_WORD,
|
|
18
|
+
'+' => :TT,
|
|
19
|
+
'++' => :TT,
|
|
20
|
+
'`' => :TT,
|
|
21
|
+
'``' => :TT
|
|
22
|
+
} # :nodoc:
|
|
23
|
+
|
|
24
|
+
# Other types: regexp-handling(example: crossref) is enabled
|
|
25
|
+
TAGS = {
|
|
26
|
+
'em' => :EM,
|
|
27
|
+
'i' => :EM,
|
|
28
|
+
'b' => :BOLD,
|
|
29
|
+
's' => :STRIKE,
|
|
30
|
+
'del' => :STRIKE,
|
|
31
|
+
} # :nodoc:
|
|
32
|
+
|
|
33
|
+
STANDALONE_TAGS = { 'br' => :HARD_BREAK } # :nodoc:
|
|
34
|
+
|
|
35
|
+
CODEBLOCK_TAGS = %w[tt code] # :nodoc:
|
|
36
|
+
|
|
37
|
+
TOKENS = {
|
|
38
|
+
**WORD_PAIRS.transform_values { [:word_pair, nil] },
|
|
39
|
+
**TAGS.keys.to_h {|tag| ["<#{tag}>", [:open_tag, tag]] },
|
|
40
|
+
**TAGS.keys.to_h {|tag| ["</#{tag}>", [:close_tag, tag]] },
|
|
41
|
+
**CODEBLOCK_TAGS.to_h {|tag| ["<#{tag}>", [:code_start, tag]] },
|
|
42
|
+
**STANDALONE_TAGS.keys.to_h {|tag| ["<#{tag}>", [:standalone_tag, tag]] },
|
|
43
|
+
'{' => [:tidylink_start, nil],
|
|
44
|
+
'}' => [:tidylink_mid, nil],
|
|
45
|
+
'\\' => [:escape, nil],
|
|
46
|
+
'[' => nil # To make `label[url]` scan as separate tokens
|
|
47
|
+
} # :nodoc:
|
|
48
|
+
|
|
49
|
+
multi_char_tokens_regexp = Regexp.union(TOKENS.keys.select {|s| s.size > 1 }).source
|
|
50
|
+
token_starts_regexp = TOKENS.keys.map {|s| s[0] }.uniq.map {|s| Regexp.escape(s) }.join
|
|
51
|
+
|
|
52
|
+
SCANNER_REGEXP =
|
|
53
|
+
/(?:
|
|
54
|
+
#{multi_char_tokens_regexp}
|
|
55
|
+
|[^#{token_starts_regexp}\sa-zA-Z0-9\.]+ # chunk of normal text
|
|
56
|
+
|\s+|[a-zA-Z0-9\.]+|.
|
|
57
|
+
)/x # :nodoc:
|
|
58
|
+
|
|
59
|
+
# Characters that can be escaped with backslash.
|
|
60
|
+
ESCAPING_CHARS = '\\*_+`{}[]<>' # :nodoc:
|
|
61
|
+
|
|
62
|
+
# Pattern to match code block content until <code></tt></code> or <tt></code></tt>.
|
|
63
|
+
CODEBLOCK_REGEXPS = CODEBLOCK_TAGS.to_h {|name| [name, /((?:\\.|[^\\])*?)<\/#{name}>/] } # :nodoc:
|
|
64
|
+
|
|
65
|
+
# Word contains alphanumeric and <tt>_./:[]-</tt> characters.
|
|
66
|
+
# Word may start with <tt>#</tt> and may end with any non-space character. (e.g. <tt>#eql?</tt>).
|
|
67
|
+
# Underscore delimiter have special rules.
|
|
68
|
+
WORD_REGEXPS = {
|
|
69
|
+
# Words including _, longest match.
|
|
70
|
+
# Example: `_::A_` `_-42_` `_A::B::C.foo_bar[baz]_` `_kwarg:_`
|
|
71
|
+
# Content must not include _ followed by non-alphanumeric character
|
|
72
|
+
# Example: `_host_:_port_` will be `_host_` + `:` + `_port_`
|
|
73
|
+
'_' => /#?([a-zA-Z0-9.\/:\[\]-]|_+[a-zA-Z0-9])+[^\s]?_(?=[^a-zA-Z0-9_]|\z)/,
|
|
74
|
+
# Words allowing _ but not allowing __
|
|
75
|
+
'__' => /#?[a-zA-Z0-9.\/:\[\]-]*(_[a-zA-Z0-9.\/:\[\]-]+)*[^\s]?__(?=[^a-zA-Z0-9]|\z)/,
|
|
76
|
+
**%w[* ** + ++ ` ``].to_h do |s|
|
|
77
|
+
# normal words that can be used within +word+ or *word*
|
|
78
|
+
[s, /#?[a-zA-Z0-9_.\/:\[\]-]+[^\s]?#{Regexp.escape(s)}(?=[^a-zA-Z0-9]|\z)/]
|
|
79
|
+
end
|
|
80
|
+
} # :nodoc:
|
|
81
|
+
|
|
82
|
+
def initialize(string)
|
|
83
|
+
@scanner = StringScanner.new(string)
|
|
84
|
+
@last_match = nil
|
|
85
|
+
@scanner_negative_cache = Set.new
|
|
86
|
+
@stack = []
|
|
87
|
+
@delimiters = {}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Return the current parsing node on <tt>@stack</tt>.
|
|
91
|
+
|
|
92
|
+
def current
|
|
93
|
+
@stack.last
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Parse and return an array of nodes.
|
|
97
|
+
# Node format:
|
|
98
|
+
# {
|
|
99
|
+
# type: :EM | :BOLD | :BOLD_WORD | :EM_WORD | :TT | :STRIKE | :HARD_BREAK | :TIDYLINK,
|
|
100
|
+
# url: string # only for :TIDYLINK
|
|
101
|
+
# children: [string_or_node, ...]
|
|
102
|
+
# }
|
|
103
|
+
|
|
104
|
+
def parse
|
|
105
|
+
stack_push(:root, nil)
|
|
106
|
+
while true
|
|
107
|
+
type, token, value = scan_token
|
|
108
|
+
close = nil
|
|
109
|
+
tidylink_url = nil
|
|
110
|
+
case type
|
|
111
|
+
when :node
|
|
112
|
+
current[:children] << value
|
|
113
|
+
invalidate_open_tidylinks if value[:type] == :TIDYLINK
|
|
114
|
+
when :eof
|
|
115
|
+
close = :root
|
|
116
|
+
when :tidylink_open
|
|
117
|
+
stack_push(:tidylink, token)
|
|
118
|
+
when :tidylink_close
|
|
119
|
+
close = :tidylink
|
|
120
|
+
if value
|
|
121
|
+
tidylink_url = value
|
|
122
|
+
else
|
|
123
|
+
# Tidylink closing brace without URL part. Treat opening and closing braces as normal text
|
|
124
|
+
# `{labelnodes}...` case.
|
|
125
|
+
current[:children] << token
|
|
126
|
+
end
|
|
127
|
+
when :invalidated_tidylink_close
|
|
128
|
+
# `{...{label}[url]...}` case. Nested tidylink invalidates outer one. The last `}` closes the invalidated tidylink.
|
|
129
|
+
current[:children] << token
|
|
130
|
+
close = :invalidated_tidylink
|
|
131
|
+
when :text
|
|
132
|
+
current[:children] << token
|
|
133
|
+
when :open
|
|
134
|
+
stack_push(value, token)
|
|
135
|
+
when :close
|
|
136
|
+
if @delimiters[value]
|
|
137
|
+
close = value
|
|
138
|
+
else
|
|
139
|
+
# closing tag without matching opening tag. Treat as normal text.
|
|
140
|
+
current[:children] << token
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
next unless close
|
|
145
|
+
|
|
146
|
+
while current[:delimiter] != close
|
|
147
|
+
children = current[:children]
|
|
148
|
+
open_token = current[:token]
|
|
149
|
+
stack_pop
|
|
150
|
+
current[:children] << open_token if open_token
|
|
151
|
+
current[:children].concat(children)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
token = current[:token]
|
|
155
|
+
children = compact_string(current[:children])
|
|
156
|
+
stack_pop
|
|
157
|
+
|
|
158
|
+
return children if close == :root
|
|
159
|
+
|
|
160
|
+
if close == :tidylink || close == :invalidated_tidylink
|
|
161
|
+
if tidylink_url
|
|
162
|
+
current[:children] << { type: :TIDYLINK, children: children, url: tidylink_url }
|
|
163
|
+
invalidate_open_tidylinks
|
|
164
|
+
else
|
|
165
|
+
current[:children] << token
|
|
166
|
+
current[:children].concat(children)
|
|
167
|
+
end
|
|
168
|
+
else
|
|
169
|
+
current[:children] << { type: TAGS[close], children: children }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
# When a valid tidylink node is encountered, invalidate all nested tidylinks.
|
|
177
|
+
|
|
178
|
+
def invalidate_open_tidylinks
|
|
179
|
+
return unless @delimiters[:tidylink]
|
|
180
|
+
|
|
181
|
+
@delimiters[:invalidated_tidylink] ||= []
|
|
182
|
+
@delimiters[:tidylink].each do |idx|
|
|
183
|
+
@delimiters[:invalidated_tidylink] << idx
|
|
184
|
+
@stack[idx][:delimiter] = :invalidated_tidylink
|
|
185
|
+
end
|
|
186
|
+
@delimiters.delete(:tidylink)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Pop the top node off the stack when node is closed by a closing delimiter or an error.
|
|
190
|
+
|
|
191
|
+
def stack_pop
|
|
192
|
+
delimiter = current[:delimiter]
|
|
193
|
+
@delimiters[delimiter].pop
|
|
194
|
+
@delimiters.delete(delimiter) if @delimiters[delimiter].empty?
|
|
195
|
+
@stack.pop
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Push a new node onto the stack when encountering an opening delimiter.
|
|
199
|
+
|
|
200
|
+
def stack_push(delimiter, token)
|
|
201
|
+
node = { delimiter: delimiter, token: token, children: [] }
|
|
202
|
+
(@delimiters[delimiter] ||= []) << @stack.size
|
|
203
|
+
@stack << node
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Compacts adjacent strings in +nodes+ into a single string.
|
|
207
|
+
|
|
208
|
+
def compact_string(nodes)
|
|
209
|
+
nodes.chunk {|e| String === e }.flat_map do |is_str, elems|
|
|
210
|
+
is_str ? elems.join : elems
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Scan from StringScanner with +pattern+
|
|
215
|
+
# If +negative_cache+ is true, caches scan failure result. <tt>scan(pattern, negative_cache: true)</tt> return nil when it is called again after a failure.
|
|
216
|
+
# Be careful to use +negative_cache+ with a pattern and position that does not match after previous failure.
|
|
217
|
+
|
|
218
|
+
def strscan(pattern, negative_cache: false)
|
|
219
|
+
return if negative_cache && @scanner_negative_cache.include?(pattern)
|
|
220
|
+
|
|
221
|
+
string = @scanner.scan(pattern)
|
|
222
|
+
@last_match = string if string
|
|
223
|
+
@scanner_negative_cache << pattern if !string && negative_cache
|
|
224
|
+
string
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Scan and return the next token for parsing.
|
|
228
|
+
# Returns <tt>[token_type, token_string_or_nil, extra_info]</tt>
|
|
229
|
+
|
|
230
|
+
def scan_token
|
|
231
|
+
last_match = @last_match
|
|
232
|
+
token = strscan(SCANNER_REGEXP)
|
|
233
|
+
type, name = TOKENS[token]
|
|
234
|
+
|
|
235
|
+
case type
|
|
236
|
+
when :word_pair
|
|
237
|
+
# If the character before word pair delimiter is alphanumeric, do not treat as word pair.
|
|
238
|
+
word_pair = strscan(WORD_REGEXPS[token]) unless /[a-zA-Z0-9]\z/.match?(last_match)
|
|
239
|
+
|
|
240
|
+
if word_pair.nil?
|
|
241
|
+
[:text, token, nil]
|
|
242
|
+
elsif token == '__' && word_pair.match?(/\A[a-zA-Z]+__\z/)
|
|
243
|
+
# Special exception: __FILE__, __LINE__, __send__ should be treated as normal text.
|
|
244
|
+
[:text, "#{token}#{word_pair}", nil]
|
|
245
|
+
else
|
|
246
|
+
[:node, nil, { type: WORD_PAIRS[token], children: [word_pair.delete_suffix(token)] }]
|
|
247
|
+
end
|
|
248
|
+
when :open_tag
|
|
249
|
+
[:open, token, name]
|
|
250
|
+
when :close_tag
|
|
251
|
+
[:close, token, name]
|
|
252
|
+
when :code_start
|
|
253
|
+
if (codeblock = strscan(CODEBLOCK_REGEXPS[name], negative_cache: true))
|
|
254
|
+
# Need to unescape `\\` and `\<`.
|
|
255
|
+
# RDoc also unescapes backslash + word separators, but this is not really necessary.
|
|
256
|
+
content = codeblock.delete_suffix("</#{name}>").gsub(/\\(.)/) { '\\<*+_`'.include?($1) ? $1 : $& }
|
|
257
|
+
[:node, nil, { type: :TT, children: content.empty? ? [] : [content] }]
|
|
258
|
+
else
|
|
259
|
+
[:text, token, nil]
|
|
260
|
+
end
|
|
261
|
+
when :standalone_tag
|
|
262
|
+
[:node, nil, { type: STANDALONE_TAGS[name], children: [] }]
|
|
263
|
+
when :tidylink_start
|
|
264
|
+
[:tidylink_open, token, nil]
|
|
265
|
+
when :tidylink_mid
|
|
266
|
+
if @delimiters[:tidylink]
|
|
267
|
+
if (url = read_tidylink_url)
|
|
268
|
+
[:tidylink_close, nil, url]
|
|
269
|
+
else
|
|
270
|
+
[:tidylink_close, token, nil]
|
|
271
|
+
end
|
|
272
|
+
elsif @delimiters[:invalidated_tidylink]
|
|
273
|
+
[:invalidated_tidylink_close, token, nil]
|
|
274
|
+
else
|
|
275
|
+
[:text, token, nil]
|
|
276
|
+
end
|
|
277
|
+
when :escape
|
|
278
|
+
next_char = strscan(/./)
|
|
279
|
+
if next_char.nil?
|
|
280
|
+
# backslash at end of string
|
|
281
|
+
[:text, '\\', nil]
|
|
282
|
+
elsif next_char && ESCAPING_CHARS.include?(next_char)
|
|
283
|
+
# escaped character
|
|
284
|
+
[:text, next_char, nil]
|
|
285
|
+
else
|
|
286
|
+
# If next_char not an escaping character, it is treated as text token with backslash + next_char
|
|
287
|
+
# For example, backslash of `\Ruby` (suppressed crossref) remains.
|
|
288
|
+
[:text, "\\#{next_char}", nil]
|
|
289
|
+
end
|
|
290
|
+
else
|
|
291
|
+
if token.nil?
|
|
292
|
+
[:eof, nil, nil]
|
|
293
|
+
elsif token.match?(/\A[A-Za-z0-9]*\z/) && (url = read_tidylink_url)
|
|
294
|
+
# Simplified tidylink: label[url]
|
|
295
|
+
[:node, nil, { type: :TIDYLINK, children: [token], url: url }]
|
|
296
|
+
else
|
|
297
|
+
[:text, token, nil]
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Read the URL part of a tidylink from the current position.
|
|
303
|
+
# Returns nil if no valid URL part is found.
|
|
304
|
+
# URL part is enclosed in square brackets and may contain escaped brackets.
|
|
305
|
+
# Example: <tt>[http://example.com/?q=\[\]]</tt> represents <tt>http://example.com/?q=[]</tt>.
|
|
306
|
+
# If we're accepting rdoc-style links in markdown, url may include <tt>*+<_</tt> with backslash escape.
|
|
307
|
+
|
|
308
|
+
def read_tidylink_url
|
|
309
|
+
bracketed_url = strscan(/\[([^\s\[\]\\]|\\[\[\]\\*+<_])+\]/)
|
|
310
|
+
bracketed_url[1...-1].gsub(/\\(.)/, '\1') if bracketed_url
|
|
311
|
+
end
|
|
312
|
+
end
|
data/lib/rdoc/markup/parser.rb
CHANGED
|
@@ -11,7 +11,7 @@ require 'strscan'
|
|
|
11
11
|
# The parser only handles the block-level constructs Paragraph, List,
|
|
12
12
|
# ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote.
|
|
13
13
|
# Inline markup such as <tt>\+blah\+</tt> is handled separately by
|
|
14
|
-
# RDoc::Markup::
|
|
14
|
+
# RDoc::Markup::InlineParser.
|
|
15
15
|
#
|
|
16
16
|
# To see what markup the Parser implements read RDoc. To see how to use
|
|
17
17
|
# RDoc markup to format text in your program read RDoc::Markup.
|
data/lib/rdoc/markup/to_ansi.rb
CHANGED
|
@@ -19,10 +19,57 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
|
|
|
19
19
|
##
|
|
20
20
|
# Maps attributes to ANSI sequences
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
ANSI_STYLE_CODES_ON = {
|
|
23
|
+
BOLD: 1,
|
|
24
|
+
TT: 7,
|
|
25
|
+
EM: 4,
|
|
26
|
+
STRIKE: 9
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ANSI_STYLE_CODES_OFF = {
|
|
30
|
+
BOLD: 22,
|
|
31
|
+
TT: 27,
|
|
32
|
+
EM: 24,
|
|
33
|
+
STRIKE: 29
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Apply the given attributes by emitting ANSI sequences.
|
|
37
|
+
# Emitting attribute changes are deferred until new text is added and applied in batch.
|
|
38
|
+
# This method computes the necessary ANSI codes to transition from the
|
|
39
|
+
# current set of applied attributes to the new set of +attributes+.
|
|
40
|
+
|
|
41
|
+
def apply_attributes(attributes)
|
|
42
|
+
before = @applied_attributes
|
|
43
|
+
after = attributes.sort
|
|
44
|
+
return if before == after
|
|
45
|
+
|
|
46
|
+
if after.empty?
|
|
47
|
+
emit_inline("\e[m")
|
|
48
|
+
elsif !before.empty? && before.size > (before & after).size + 1
|
|
49
|
+
codes = after.map {|attr| ANSI_STYLE_CODES_ON[attr] }.compact
|
|
50
|
+
emit_inline("\e[#{[0, *codes].join(';')}m")
|
|
51
|
+
else
|
|
52
|
+
off_codes = (before - after).map {|attr| ANSI_STYLE_CODES_OFF[attr] }.compact
|
|
53
|
+
on_codes = (after - before).map {|attr| ANSI_STYLE_CODES_ON[attr] }.compact
|
|
54
|
+
emit_inline("\e[#{(off_codes + on_codes).join(';')}m")
|
|
55
|
+
end
|
|
56
|
+
@applied_attributes = attributes
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def add_text(text)
|
|
60
|
+
attrs = @attributes.keys
|
|
61
|
+
if @applied_attributes != attrs
|
|
62
|
+
apply_attributes(attrs)
|
|
63
|
+
end
|
|
64
|
+
emit_inline(text)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def handle_inline(text)
|
|
68
|
+
@applied_attributes = []
|
|
69
|
+
res = super
|
|
70
|
+
res << "\e[m" unless @applied_attributes.empty?
|
|
71
|
+
@applied_attributes = []
|
|
72
|
+
res
|
|
26
73
|
end
|
|
27
74
|
|
|
28
75
|
##
|
data/lib/rdoc/markup/to_bs.rb
CHANGED
|
@@ -17,14 +17,29 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
|
|
|
17
17
|
@in_em = false
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
def handle_inline(text)
|
|
21
|
+
initial_style = []
|
|
22
|
+
initial_style << :BOLD if @in_b
|
|
23
|
+
initial_style << :EM if @in_em
|
|
24
|
+
super(text, initial_style)
|
|
25
|
+
end
|
|
23
26
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
def add_text(text)
|
|
28
|
+
attrs = @attributes.keys
|
|
29
|
+
if attrs.include? :BOLD
|
|
30
|
+
styled = +''
|
|
31
|
+
text.chars.each do |c|
|
|
32
|
+
styled << "#{c}\b#{c}"
|
|
33
|
+
end
|
|
34
|
+
text = styled
|
|
35
|
+
elsif attrs.include? :EM
|
|
36
|
+
styled = +''
|
|
37
|
+
text.chars.each do |c|
|
|
38
|
+
styled << "_\b#{c}"
|
|
39
|
+
end
|
|
40
|
+
text = styled
|
|
41
|
+
end
|
|
42
|
+
emit_inline(text)
|
|
28
43
|
end
|
|
29
44
|
|
|
30
45
|
##
|
|
@@ -68,39 +83,4 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
|
|
|
68
83
|
def calculate_text_width(text)
|
|
69
84
|
text.gsub(/_\x08/, '').gsub(/\x08./, '').size
|
|
70
85
|
end
|
|
71
|
-
|
|
72
|
-
##
|
|
73
|
-
# Turns on or off regexp handling for +convert_string+
|
|
74
|
-
|
|
75
|
-
def annotate(tag)
|
|
76
|
-
case tag
|
|
77
|
-
when '+b' then @in_b = true
|
|
78
|
-
when '-b' then @in_b = false
|
|
79
|
-
when '+_' then @in_em = true
|
|
80
|
-
when '-_' then @in_em = false
|
|
81
|
-
end
|
|
82
|
-
''
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
##
|
|
86
|
-
# Calls convert_string on the result of convert_regexp_handling
|
|
87
|
-
|
|
88
|
-
def convert_regexp_handling(target)
|
|
89
|
-
convert_string super
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
##
|
|
93
|
-
# Adds bold or underline mixed with backspaces
|
|
94
|
-
|
|
95
|
-
def convert_string(string)
|
|
96
|
-
return string unless @in_b or @in_em
|
|
97
|
-
chars = if @in_b then
|
|
98
|
-
string.chars.map do |char| "#{char}\b#{char}" end
|
|
99
|
-
elsif @in_em then
|
|
100
|
-
string.chars.map do |char| "_\b#{char}" end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
chars.join
|
|
104
|
-
end
|
|
105
|
-
|
|
106
86
|
end
|