asciidoctor 2.0.10 → 2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +294 -30
- data/LICENSE +1 -1
- data/README-de.adoc +16 -20
- data/README-fr.adoc +15 -22
- data/README-jp.adoc +15 -26
- data/README-zh_CN.adoc +21 -25
- data/README.adoc +161 -138
- data/asciidoctor.gemspec +6 -13
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +4 -4
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +8 -7
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +6 -5
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +6 -5
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +76 -76
- data/data/stylesheets/coderay-asciidoctor.css +9 -9
- data/lib/asciidoctor/abstract_block.rb +20 -13
- data/lib/asciidoctor/abstract_node.rb +23 -12
- data/lib/asciidoctor/attribute_list.rb +64 -72
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +3 -2
- data/lib/asciidoctor/cli/options.rb +32 -31
- data/lib/asciidoctor/convert.rb +168 -162
- data/lib/asciidoctor/converter/docbook5.rb +49 -34
- data/lib/asciidoctor/converter/html5.rb +180 -139
- data/lib/asciidoctor/converter/manpage.rb +118 -90
- data/lib/asciidoctor/converter/template.rb +15 -13
- data/lib/asciidoctor/converter.rb +19 -16
- data/lib/asciidoctor/core_ext/hash/merge.rb +1 -1
- data/lib/asciidoctor/document.rb +77 -86
- data/lib/asciidoctor/extensions.rb +22 -16
- data/lib/asciidoctor/helpers.rb +20 -15
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +103 -101
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +211 -220
- data/lib/asciidoctor/path_resolver.rb +17 -15
- data/lib/asciidoctor/reader.rb +87 -79
- data/lib/asciidoctor/rx.rb +9 -7
- data/lib/asciidoctor/section.rb +7 -0
- data/lib/asciidoctor/substitutors.rb +167 -148
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +3 -2
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +13 -5
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +19 -11
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +35 -20
- data/lib/asciidoctor/syntax_highlighter.rb +16 -16
- data/lib/asciidoctor/table.rb +70 -43
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/lib/asciidoctor.rb +45 -19
- data/man/asciidoctor.1 +29 -31
- data/man/asciidoctor.adoc +35 -29
- metadata +17 -70
@@ -11,7 +11,7 @@ class AbstractBlock < AbstractNode
|
|
11
11
|
# * :compound - this block contains other blocks
|
12
12
|
# * :simple - this block holds a paragraph of prose that receives normal substitutions
|
13
13
|
# * :verbatim - this block holds verbatim text (displayed "as is") that receives verbatim substitutions
|
14
|
-
# * :raw - this block holds unprocessed content passed directly to the output with no
|
14
|
+
# * :raw - this block holds unprocessed content passed directly to the output with no substitutions applied
|
15
15
|
# * :empty - this block has no content
|
16
16
|
attr_accessor :content_model
|
17
17
|
|
@@ -90,7 +90,7 @@ class AbstractBlock < AbstractNode
|
|
90
90
|
#
|
91
91
|
# context - the context Symbol context to assign to this block
|
92
92
|
#
|
93
|
-
# Returns the
|
93
|
+
# Returns the specified Symbol context
|
94
94
|
def context= context
|
95
95
|
@node_name = (@context = context).to_s
|
96
96
|
end
|
@@ -129,11 +129,13 @@ class AbstractBlock < AbstractNode
|
|
129
129
|
|
130
130
|
# Public: Check whether this block has any child Section objects.
|
131
131
|
#
|
132
|
-
#
|
132
|
+
# Acts an an abstract method that always returns false unless this block is an
|
133
|
+
# instance of Document or Section.
|
134
|
+
# Both Document and Section provide overrides for this method.
|
133
135
|
#
|
134
|
-
# Returns
|
136
|
+
# Returns false
|
135
137
|
def sections?
|
136
|
-
|
138
|
+
false
|
137
139
|
end
|
138
140
|
|
139
141
|
# Deprecated: Legacy property to get the String or Integer numeral of this section.
|
@@ -141,6 +143,11 @@ class AbstractBlock < AbstractNode
|
|
141
143
|
(Integer @numeral) rescue @numeral
|
142
144
|
end
|
143
145
|
|
146
|
+
# Deprecated: Legacy property to set the numeral of this section by coercing the value to a String.
|
147
|
+
def number= val
|
148
|
+
@numeral = val.to_s
|
149
|
+
end
|
150
|
+
|
144
151
|
# Public: Walk the document tree and find all block-level nodes that match the specified selector (context, style, id,
|
145
152
|
# role, and/or custom filter).
|
146
153
|
#
|
@@ -264,7 +271,7 @@ class AbstractBlock < AbstractNode
|
|
264
271
|
ORDERED_LIST_KEYWORDS[list_type || @style]
|
265
272
|
end
|
266
273
|
|
267
|
-
# Public: Get the String title of this Block with title
|
274
|
+
# Public: Get the String title of this Block with title substitutions applied
|
268
275
|
#
|
269
276
|
# The following substitutions are applied to block and section titles:
|
270
277
|
#
|
@@ -291,7 +298,7 @@ class AbstractBlock < AbstractNode
|
|
291
298
|
|
292
299
|
# Public: Set the String block title.
|
293
300
|
#
|
294
|
-
# Returns the
|
301
|
+
# Returns the specified String title
|
295
302
|
def title= val
|
296
303
|
@converted_title = nil
|
297
304
|
@title = val
|
@@ -338,17 +345,17 @@ class AbstractBlock < AbstractNode
|
|
338
345
|
if (val = reftext) && !val.empty?
|
339
346
|
val
|
340
347
|
# NOTE xrefstyle only applies to blocks with a title and a caption or number
|
341
|
-
elsif xrefstyle && @title &&
|
348
|
+
elsif xrefstyle && @title && !@caption.nil_or_empty?
|
342
349
|
case xrefstyle
|
343
350
|
when 'full'
|
344
351
|
quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title
|
345
|
-
if @numeral && (caption_attr_name =
|
352
|
+
if @numeral && (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[@context]) && (prefix = @document.attributes[caption_attr_name])
|
346
353
|
%(#{prefix} #{@numeral}, #{quoted_title})
|
347
354
|
else
|
348
355
|
%(#{@caption.chomp '. '}, #{quoted_title})
|
349
356
|
end
|
350
357
|
when 'short'
|
351
|
-
if @numeral && (caption_attr_name =
|
358
|
+
if @numeral && (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[@context]) && (prefix = @document.attributes[caption_attr_name])
|
352
359
|
%(#{prefix} #{@numeral})
|
353
360
|
else
|
354
361
|
@caption.chomp '. '
|
@@ -380,7 +387,7 @@ class AbstractBlock < AbstractNode
|
|
380
387
|
# Returns nothing.
|
381
388
|
def assign_caption value, caption_context = @context
|
382
389
|
unless @caption || !@title || (@caption = value || @document.attributes['caption'])
|
383
|
-
if (attr_name =
|
390
|
+
if (attr_name = CAPTION_ATTRIBUTE_NAMES[caption_context]) && (prefix = @document.attributes[attr_name])
|
384
391
|
@caption = %(#{prefix} #{@numeral = @document.increment_and_store_counter %(#{caption_context}-number), self}. )
|
385
392
|
nil
|
386
393
|
end
|
@@ -475,7 +482,7 @@ class AbstractBlock < AbstractNode
|
|
475
482
|
@header.find_by_internal selector, result, &block
|
476
483
|
end
|
477
484
|
@blocks.each do |b|
|
478
|
-
next if
|
485
|
+
next if context_selector == :section && b.context != :section # optimization
|
479
486
|
b.find_by_internal selector, result, &block
|
480
487
|
end
|
481
488
|
end
|
@@ -500,7 +507,7 @@ class AbstractBlock < AbstractNode
|
|
500
507
|
end
|
501
508
|
else
|
502
509
|
@blocks.each do |b|
|
503
|
-
next if
|
510
|
+
next if context_selector == :section && b.context != :section # optimization
|
504
511
|
b.find_by_internal selector, result, &block
|
505
512
|
end
|
506
513
|
end
|
@@ -4,7 +4,8 @@ module Asciidoctor
|
|
4
4
|
# node of AsciiDoc content. The state and methods on this class are common to
|
5
5
|
# all content segments in an AsciiDoc document.
|
6
6
|
class AbstractNode
|
7
|
-
include
|
7
|
+
include Logging
|
8
|
+
include Substitutors
|
8
9
|
|
9
10
|
# Public: Get the Hash of attributes for this node
|
10
11
|
attr_reader :attributes
|
@@ -65,7 +66,7 @@ class AbstractNode
|
|
65
66
|
#
|
66
67
|
# parent - The Block to set as the parent of this Block
|
67
68
|
#
|
68
|
-
# Returns the
|
69
|
+
# Returns the the specified Block parent
|
69
70
|
def parent= parent
|
70
71
|
@parent, @document = parent, parent.document
|
71
72
|
end
|
@@ -155,7 +156,7 @@ class AbstractNode
|
|
155
156
|
#
|
156
157
|
# name - the String name of the option
|
157
158
|
#
|
158
|
-
# Returns
|
159
|
+
# Returns nothing
|
159
160
|
def set_option name
|
160
161
|
@attributes[%(#{name}-option)] = ''
|
161
162
|
nil
|
@@ -216,6 +217,15 @@ class AbstractNode
|
|
216
217
|
(val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
|
217
218
|
end
|
218
219
|
|
220
|
+
# Public: Sets the value of the role attribute on this node.
|
221
|
+
#
|
222
|
+
# names - A single role name, a space-separated String of role names, or an Array of role names
|
223
|
+
#
|
224
|
+
# Returns the specified String role name or Array of role names
|
225
|
+
def role= names
|
226
|
+
@attributes['role'] = (::Array === names) ? (names.join ' ') : names
|
227
|
+
end
|
228
|
+
|
219
229
|
# Public: Adds the given role directly to this node.
|
220
230
|
#
|
221
231
|
# Returns a [Boolean] indicating whether the role was added.
|
@@ -453,8 +463,8 @@ class AbstractNode
|
|
453
463
|
start = doc.base_dir
|
454
464
|
end
|
455
465
|
else
|
456
|
-
start
|
457
|
-
jail
|
466
|
+
start ||= doc.base_dir
|
467
|
+
jail ||= doc.base_dir
|
458
468
|
end
|
459
469
|
doc.path_resolver.system_path target, start, jail, opts
|
460
470
|
end
|
@@ -514,6 +524,7 @@ class AbstractNode
|
|
514
524
|
# * :normalize a Boolean that indicates whether the data should be normalized (default: false)
|
515
525
|
# * :start the String relative base path to use when resolving the target (default: nil)
|
516
526
|
# * :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true)
|
527
|
+
# * :warn_if_empty a Boolean that indicates whether a warning is issued if contents of target is empty (default: false)
|
517
528
|
# Returns the contents of the resolved target or nil if the resolved target cannot be read
|
518
529
|
# --
|
519
530
|
# TODO refactor other methods in this class to use this method were possible (repurposing if necessary)
|
@@ -525,22 +536,22 @@ class AbstractNode
|
|
525
536
|
Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri'
|
526
537
|
begin
|
527
538
|
if opts[:normalize]
|
528
|
-
(Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
|
539
|
+
contents = (Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
|
529
540
|
else
|
530
|
-
::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
|
541
|
+
contents = ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
|
531
542
|
end
|
532
543
|
rescue
|
533
544
|
logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
|
534
|
-
return
|
535
545
|
end
|
536
|
-
|
537
|
-
logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled))
|
538
|
-
return
|
546
|
+
elsif opts.fetch :warn_on_failure, true
|
547
|
+
logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled))
|
539
548
|
end
|
540
549
|
else
|
541
550
|
target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
|
542
|
-
read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
|
551
|
+
contents = read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
|
543
552
|
end
|
553
|
+
logger.warn %(contents of #{opts[:label] || 'asset'} is empty: #{target}) if contents && opts[:warn_if_empty] && contents.empty?
|
554
|
+
contents
|
544
555
|
end
|
545
556
|
|
546
557
|
# Deprecated: Check whether the specified String is a URI by
|
@@ -22,19 +22,20 @@ module Asciidoctor
|
|
22
22
|
# => { 'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)' }
|
23
23
|
#
|
24
24
|
class AttributeList
|
25
|
-
BACKSLASH = '\\'
|
26
25
|
APOS = '\''
|
26
|
+
BACKSLASH = '\\'
|
27
|
+
QUOT = '"'
|
27
28
|
|
28
29
|
# Public: Regular expressions for detecting the boundary of a value
|
29
|
-
|
30
|
-
|
30
|
+
BoundaryRx = {
|
31
|
+
QUOT => /.*?[^\\](?=")/,
|
31
32
|
APOS => /.*?[^\\](?=')/,
|
32
33
|
',' => /.*?(?=[ \t]*(,|$))/
|
33
34
|
}
|
34
35
|
|
35
36
|
# Public: Regular expressions for unescaping quoted characters
|
36
37
|
EscapedQuotes = {
|
37
|
-
|
38
|
+
QUOT => '\\"',
|
38
39
|
APOS => '\\\''
|
39
40
|
}
|
40
41
|
|
@@ -45,14 +46,16 @@ class AttributeList
|
|
45
46
|
BlankRx = /[ \t]+/
|
46
47
|
|
47
48
|
# Public: Regular expressions for skipping delimiters
|
48
|
-
|
49
|
+
SkipRx = {
|
50
|
+
',' => /[ \t]*(,|$)/
|
51
|
+
}
|
49
52
|
|
50
53
|
def initialize source, block = nil, delimiter = ','
|
51
54
|
@scanner = ::StringScanner.new source
|
52
55
|
@block = block
|
53
56
|
@delimiter = delimiter
|
54
|
-
@delimiter_skip_pattern =
|
55
|
-
@delimiter_boundary_pattern =
|
57
|
+
@delimiter_skip_pattern = SkipRx[delimiter]
|
58
|
+
@delimiter_boundary_pattern = BoundaryRx[delimiter]
|
56
59
|
@attributes = nil
|
57
60
|
end
|
58
61
|
|
@@ -65,8 +68,6 @@ class AttributeList
|
|
65
68
|
return @attributes if @attributes
|
66
69
|
|
67
70
|
@attributes = {}
|
68
|
-
# QUESTION do we want to store the attribute list as the zero-index attribute?
|
69
|
-
#attributes[0] = @scanner.string
|
70
71
|
index = 0
|
71
72
|
|
72
73
|
while parse_attribute index, positional_attrs
|
@@ -83,75 +84,73 @@ class AttributeList
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def self.rekey attributes, positional_attrs
|
86
|
-
|
87
|
-
|
88
|
-
index += 1
|
89
|
-
if (val = attributes[index])
|
87
|
+
positional_attrs.each_with_index do |key, index|
|
88
|
+
if key && (val = attributes[index + 1])
|
90
89
|
# QUESTION should we delete the positional key?
|
91
90
|
attributes[key] = val
|
92
|
-
end
|
91
|
+
end
|
93
92
|
end
|
94
93
|
attributes
|
95
94
|
end
|
96
95
|
|
97
96
|
private
|
98
97
|
|
99
|
-
def parse_attribute index
|
100
|
-
|
98
|
+
def parse_attribute index, positional_attrs
|
99
|
+
continue = true
|
101
100
|
skip_blank
|
102
|
-
|
103
|
-
|
101
|
+
case @scanner.peek 1
|
102
|
+
# example: "quote" || "foo
|
103
|
+
when QUOT
|
104
104
|
name = parse_attribute_value @scanner.get_byte
|
105
|
-
|
106
|
-
|
107
|
-
elsif first == APOS
|
105
|
+
# example: 'quote' || 'foo
|
106
|
+
when APOS
|
108
107
|
name = parse_attribute_value @scanner.get_byte
|
109
|
-
|
110
|
-
single_quoted_value = true unless name.start_with? APOS
|
108
|
+
single_quoted = true unless name.start_with? APOS
|
111
109
|
else
|
112
|
-
name = scan_name
|
113
|
-
|
114
|
-
skipped = 0
|
115
|
-
c = nil
|
110
|
+
skipped = ((name = scan_name) && skip_blank) || 0
|
116
111
|
if @scanner.eos?
|
117
|
-
return
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
skip_blank
|
132
|
-
if @scanner.peek(1)
|
133
|
-
# example: foo="bar" || foo="ba\"zaar"
|
134
|
-
if (c = @scanner.get_byte) == '"'
|
112
|
+
return unless name || (@scanner.string.rstrip.end_with? @delimiter)
|
113
|
+
# example: quote (at eos)
|
114
|
+
continue = nil
|
115
|
+
# example: quote,
|
116
|
+
elsif (c = @scanner.get_byte) == @delimiter
|
117
|
+
@scanner.unscan
|
118
|
+
elsif name
|
119
|
+
# example: foo=...
|
120
|
+
if c == '='
|
121
|
+
skip_blank
|
122
|
+
case (c = @scanner.get_byte)
|
123
|
+
# example: foo="bar" || foo="ba\"zaar" || foo="bar
|
124
|
+
when QUOT
|
135
125
|
value = parse_attribute_value c
|
136
|
-
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar'
|
137
|
-
|
126
|
+
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar' || foo='bar
|
127
|
+
when APOS
|
138
128
|
value = parse_attribute_value c
|
139
|
-
|
129
|
+
single_quoted = true unless value.start_with? APOS
|
140
130
|
# example: foo=,
|
141
|
-
|
131
|
+
when @delimiter
|
132
|
+
value = ''
|
133
|
+
@scanner.unscan
|
134
|
+
# example: foo= (at eos)
|
135
|
+
when nil
|
142
136
|
value = ''
|
143
|
-
# example: foo=bar
|
137
|
+
# example: foo=bar || foo=None
|
144
138
|
else
|
145
139
|
value = %(#{c}#{scan_to_delimiter})
|
146
140
|
return true if value == 'None'
|
147
141
|
end
|
142
|
+
# example: foo bar
|
143
|
+
else
|
144
|
+
name = %(#{name}#{' ' * skipped}#{c}#{scan_to_delimiter})
|
148
145
|
end
|
146
|
+
# example: =foo= || !foo
|
147
|
+
else
|
148
|
+
name = %(#{c}#{scan_to_delimiter})
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
152
|
if value
|
153
|
-
# example: options="opt1,opt2,opt3"
|
154
|
-
# opts is an alias for options
|
153
|
+
# example: options="opt1,opt2,opt3" || opts="opts1,opt2,opt3"
|
155
154
|
case name
|
156
155
|
when 'options', 'opts'
|
157
156
|
if value.include? ','
|
@@ -161,7 +160,7 @@ class AttributeList
|
|
161
160
|
@attributes[%(#{value}-option)] = '' unless value.empty?
|
162
161
|
end
|
163
162
|
else
|
164
|
-
if
|
163
|
+
if single_quoted && @block
|
165
164
|
case name
|
166
165
|
when 'title', 'reftext'
|
167
166
|
@attributes[name] = value
|
@@ -173,33 +172,26 @@ class AttributeList
|
|
173
172
|
end
|
174
173
|
end
|
175
174
|
else
|
176
|
-
|
177
|
-
if (positional_attr_name = positional_attrs[index])
|
178
|
-
@attributes[positional_attr_name] =
|
175
|
+
name = @block.apply_subs name if single_quoted && @block
|
176
|
+
if (positional_attr_name = positional_attrs[index]) && name
|
177
|
+
@attributes[positional_attr_name] = name
|
179
178
|
end
|
180
|
-
# QUESTION should we
|
181
|
-
@attributes[index + 1] =
|
182
|
-
# QUESTION should we assign the resolved name as an attribute?
|
183
|
-
#@attributes[resolved_name] = nil
|
179
|
+
# QUESTION should we assign the positional key even when it's claimed by a positional attribute?
|
180
|
+
@attributes[index + 1] = name
|
184
181
|
end
|
185
182
|
|
186
|
-
|
183
|
+
continue
|
187
184
|
end
|
188
185
|
|
189
186
|
def parse_attribute_value quote
|
190
187
|
# empty quoted value
|
191
|
-
if @scanner.peek
|
188
|
+
if (@scanner.peek 1) == quote
|
192
189
|
@scanner.get_byte
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
if (value = scan_to_quote quote)
|
190
|
+
''
|
191
|
+
elsif (value = scan_to_quote quote)
|
197
192
|
@scanner.get_byte
|
198
|
-
|
199
|
-
|
200
|
-
else
|
201
|
-
value
|
202
|
-
end
|
193
|
+
(value.include? BACKSLASH) ? (value.gsub EscapedQuotes[quote], quote) : value
|
194
|
+
# leading quote only
|
203
195
|
else
|
204
196
|
%(#{quote}#{scan_to_delimiter})
|
205
197
|
end
|
@@ -222,7 +214,7 @@ class AttributeList
|
|
222
214
|
end
|
223
215
|
|
224
216
|
def scan_to_quote quote
|
225
|
-
@scanner.scan
|
217
|
+
@scanner.scan BoundaryRx[quote]
|
226
218
|
end
|
227
219
|
end
|
228
220
|
end
|
data/lib/asciidoctor/block.rb
CHANGED
@@ -54,21 +54,21 @@ class Block < AbstractBlock
|
|
54
54
|
# FIXME feels funky; we have to be defensive to get commit_subs to honor override
|
55
55
|
# FIXME does not resolve substitution groups inside Array (e.g., [:normal])
|
56
56
|
if (subs = opts[:subs])
|
57
|
-
|
57
|
+
case subs
|
58
|
+
# e.g., subs: :default
|
58
59
|
# subs attribute is honored; falls back to opts[:default_subs], then built-in defaults based on context
|
59
|
-
|
60
|
+
when :default
|
60
61
|
@default_subs = opts[:default_subs]
|
61
62
|
# e.g., subs: [:quotes]
|
62
63
|
# subs attribute is not honored
|
63
|
-
|
64
|
+
when ::Array
|
64
65
|
@default_subs = subs.drop 0
|
65
66
|
@attributes.delete 'subs'
|
66
67
|
# e.g., subs: :normal or subs: 'normal'
|
67
68
|
# subs attribute is not honored
|
68
69
|
else
|
69
70
|
@default_subs = nil
|
70
|
-
|
71
|
-
@attributes['subs'] = %(#{subs})
|
71
|
+
@attributes['subs'] = subs.to_s
|
72
72
|
end
|
73
73
|
# resolve the subs eagerly only if subs option is specified
|
74
74
|
# QUESTION should we skip subsequent calls to commit_subs?
|
@@ -123,7 +123,7 @@ class Block < AbstractBlock
|
|
123
123
|
result.join LF
|
124
124
|
end
|
125
125
|
else
|
126
|
-
logger.warn %(Unknown content model '#{@content_model}' for block: #{
|
126
|
+
logger.warn %(Unknown content model '#{@content_model}' for block: #{self}) unless @content_model == :empty
|
127
127
|
nil
|
128
128
|
end
|
129
129
|
end
|
@@ -42,6 +42,8 @@ module Asciidoctor
|
|
42
42
|
non_posix_env = ::File::ALT_SEPARATOR == RS
|
43
43
|
err = @err || $stderr
|
44
44
|
show_timings = false
|
45
|
+
# NOTE in Ruby 2.7, RubyGems sets SOURCE_DATE_EPOCH if it's not set
|
46
|
+
::ENV.delete 'SOURCE_DATE_EPOCH' if (::ENV.key? 'IGNORE_SOURCE_DATE_EPOCH') && (::Gem.respond_to? :source_date_epoch)
|
45
47
|
|
46
48
|
@options.map do |key, val|
|
47
49
|
case key
|
@@ -86,7 +88,6 @@ module Asciidoctor
|
|
86
88
|
end
|
87
89
|
|
88
90
|
if outfile == '-'
|
89
|
-
# NOTE set_encoding returns nil on JRuby 9.1
|
90
91
|
(tofile = @out) || ((tofile = $stdout).set_encoding UTF_8)
|
91
92
|
elsif outfile
|
92
93
|
opts[:mkdirs] = true
|
@@ -141,7 +142,7 @@ module Asciidoctor
|
|
141
142
|
raise e
|
142
143
|
else
|
143
144
|
err.puts ::RuntimeError === e ? %(#{e.message} (#{e.class})) : e.message
|
144
|
-
err.puts ' Use --trace
|
145
|
+
err.puts ' Use --trace to show backtrace'
|
145
146
|
end
|
146
147
|
end
|
147
148
|
nil
|
@@ -39,19 +39,20 @@ module Asciidoctor
|
|
39
39
|
# NOTE don't use squiggly heredoc to maintain compatibility with Ruby < 2.3
|
40
40
|
opts.banner = <<-'EOS'.gsub ' ', ''
|
41
41
|
Usage: asciidoctor [OPTION]... FILE...
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
Convert the AsciiDoc input FILE(s) to the backend output format (e.g., HTML 5, DocBook 5, etc.)
|
43
|
+
Unless specified otherwise, the output is written to a file whose name is derived from the input file.
|
44
|
+
Application log messages are printed to STDERR.
|
45
|
+
Example: asciidoctor input.adoc
|
45
46
|
|
46
47
|
EOS
|
47
48
|
|
48
|
-
opts.on('-b', '--backend BACKEND', 'set output format
|
49
|
-
|
49
|
+
opts.on('-b', '--backend BACKEND', 'set backend output format: [html5, xhtml5, docbook5, manpage] (default: html5)',
|
50
|
+
'additional backends are supported via extended converters (e.g., pdf, epub3)') do |backend|
|
50
51
|
self[:attributes]['backend'] = backend
|
51
52
|
end
|
52
53
|
opts.on('-d', '--doctype DOCTYPE', ['article', 'book', 'manpage', 'inline'],
|
53
|
-
|
54
|
-
self[:attributes]['doctype'] =
|
54
|
+
'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doctype|
|
55
|
+
self[:attributes]['doctype'] = doctype
|
55
56
|
end
|
56
57
|
opts.on('-e', '--embedded', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
57
58
|
self[:standalone] = false
|
@@ -60,14 +61,14 @@ module Asciidoctor
|
|
60
61
|
self[:output_file] = output_file
|
61
62
|
end
|
62
63
|
opts.on('--safe',
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
'set safe mode level to safe (default: unsafe)',
|
65
|
+
'enables include directives, but prevents access to ancestor paths of source file',
|
66
|
+
'provided for compatibility with the asciidoc command') do
|
66
67
|
self[:safe] = SafeMode::SAFE
|
67
68
|
end
|
68
69
|
opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
|
69
|
-
|
70
|
-
|
70
|
+
%(set safe mode level explicitly: [#{safe_mode_names.join ', '}] (default: unsafe)),
|
71
|
+
'disables potentially dangerous macros in source files, such as include::[]') do |name|
|
71
72
|
self[:safe] = SafeMode.value_for_name name
|
72
73
|
end
|
73
74
|
opts.on('-s', '--no-header-footer', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
@@ -76,20 +77,20 @@ module Asciidoctor
|
|
76
77
|
opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
|
77
78
|
self[:attributes]['sectnums'] = ''
|
78
79
|
end
|
79
|
-
opts.on('--eruby ERUBY', ['erb', 'erubis'],
|
80
|
-
|
80
|
+
opts.on('--eruby ERUBY', ['erb', 'erubi', 'erubis'],
|
81
|
+
'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubi, erubis] (default: erb)') do |eruby|
|
81
82
|
self[:eruby] = eruby
|
82
83
|
end
|
83
84
|
opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
|
84
|
-
|
85
|
-
|
85
|
+
'this attribute takes precedence over the same attribute defined in the source document',
|
86
|
+
'unless either the name or value ends in @ (i.e., name@=value or name=value@)') do |attr|
|
86
87
|
next if (attr = attr.rstrip).empty? || attr == '='
|
87
88
|
attr = attr.encode UTF_8 unless attr.encoding == UTF_8
|
88
89
|
name, _, val = attr.partition '='
|
89
90
|
self[:attributes][name] = val
|
90
91
|
end
|
91
92
|
opts.on('-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)',
|
92
|
-
|
93
|
+
'may be specified multiple times') do |template_dir|
|
93
94
|
if self[:template_dirs].nil?
|
94
95
|
self[:template_dirs] = [template_dir]
|
95
96
|
elsif ::Array === self[:template_dirs]
|
@@ -118,23 +119,23 @@ module Asciidoctor
|
|
118
119
|
'may be specified more than once') do |path|
|
119
120
|
(self[:requires] ||= []).concat(path.split ',')
|
120
121
|
end
|
121
|
-
opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR
|
122
|
+
opts.on('--failure-level LEVEL', %w(info INFO warning WARNING error ERROR fatal FATAL), 'set minimum log level that yields a non-zero exit code: [INFO, WARN, ERROR, FATAL] (default: FATAL)') do |level|
|
122
123
|
level = 'WARN' if (level = level.upcase) == 'WARNING'
|
123
|
-
self[:failure_level] = ::Logger::Severity.const_get level
|
124
|
+
self[:failure_level] = ::Logger::Severity.const_get level
|
124
125
|
end
|
125
|
-
opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
|
126
|
+
opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
|
126
127
|
self[:verbose] = 0
|
127
128
|
end
|
128
|
-
opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
|
129
|
+
opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
|
129
130
|
self[:trace] = true
|
130
131
|
end
|
131
|
-
opts.on('-v', '--verbose', '
|
132
|
+
opts.on('-v', '--verbose', 'directs application messages logged at DEBUG or INFO level to STDERR (default: false)') do
|
132
133
|
self[:verbose] = 2
|
133
134
|
end
|
134
|
-
opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
|
135
|
+
opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
|
135
136
|
self[:warnings] = true
|
136
137
|
end
|
137
|
-
opts.on('-t', '--timings', 'print timings report (default: false)') do
|
138
|
+
opts.on('-t', '--timings', 'print timings report (default: false)') do
|
138
139
|
self[:timings] = true
|
139
140
|
end
|
140
141
|
opts.on_tail('-h', '--help [TOPIC]', 'print a help message',
|
@@ -160,7 +161,7 @@ module Asciidoctor
|
|
160
161
|
elsif ::File.exist? (manpage_path = (::File.join ROOT_DIR, 'man', 'asciidoctor.1'))
|
161
162
|
$stdout.puts ::File.read manpage_path
|
162
163
|
else
|
163
|
-
manpage_path =
|
164
|
+
manpage_path = %x(man -w asciidoctor).chop rescue ''
|
164
165
|
if manpage_path.empty?
|
165
166
|
$stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
|
166
167
|
return 1
|
@@ -205,7 +206,7 @@ module Asciidoctor
|
|
205
206
|
# shave off the file to process so that options errors appear correctly
|
206
207
|
if args.size == 1 && args[0] == '-'
|
207
208
|
infiles << args.pop
|
208
|
-
|
209
|
+
else
|
209
210
|
args.each do |file|
|
210
211
|
if file.start_with? '-'
|
211
212
|
# warn, but don't panic; we may have enough to proceed, so we won't force a failure
|
@@ -248,7 +249,7 @@ module Asciidoctor
|
|
248
249
|
|
249
250
|
self[:input_files] = infiles
|
250
251
|
|
251
|
-
|
252
|
+
delete :attributes if self[:attributes].empty?
|
252
253
|
|
253
254
|
if self[:template_dirs]
|
254
255
|
begin
|
@@ -257,7 +258,7 @@ module Asciidoctor
|
|
257
258
|
raise $! if self[:trace]
|
258
259
|
$stderr.puts 'asciidoctor: FAILED: \'tilt\' could not be loaded'
|
259
260
|
$stderr.puts ' You must have the tilt gem installed (gem install tilt) to use custom backend templates'
|
260
|
-
$stderr.puts ' Use --trace
|
261
|
+
$stderr.puts ' Use --trace to show backtrace'
|
261
262
|
return 1
|
262
263
|
rescue ::SystemExit
|
263
264
|
# not permitted here
|
@@ -277,7 +278,7 @@ module Asciidoctor
|
|
277
278
|
rescue ::LoadError
|
278
279
|
raise $! if self[:trace]
|
279
280
|
$stderr.puts %(asciidoctor: FAILED: '#{path}' could not be loaded)
|
280
|
-
$stderr.puts ' Use --trace
|
281
|
+
$stderr.puts ' Use --trace to show backtrace'
|
281
282
|
return 1
|
282
283
|
rescue ::SystemExit
|
283
284
|
# not permitted here
|
@@ -289,11 +290,11 @@ module Asciidoctor
|
|
289
290
|
rescue ::OptionParser::MissingArgument
|
290
291
|
$stderr.puts %(asciidoctor: option #{$!.message})
|
291
292
|
$stdout.puts opts_parser
|
292
|
-
|
293
|
+
1
|
293
294
|
rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument
|
294
295
|
$stderr.puts %(asciidoctor: #{$!.message})
|
295
296
|
$stdout.puts opts_parser
|
296
|
-
|
297
|
+
1
|
297
298
|
ensure
|
298
299
|
$VERBOSE = old_verbose
|
299
300
|
end
|