asciidoctor 2.0.10 → 2.0.17
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/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
|