asciidoctor 1.5.8 → 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/.yardopts +11 -0
- data/CHANGELOG.adoc +628 -45
- data/LICENSE +2 -1
- data/README-de.adoc +28 -38
- data/README-fr.adoc +30 -43
- data/README-jp.adoc +255 -201
- data/README-zh_CN.adoc +40 -44
- data/README.adoc +170 -143
- data/asciidoctor.gemspec +22 -34
- data/bin/asciidoctor +5 -4
- 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 +6 -5
- 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 +296 -0
- data/data/stylesheets/asciidoctor-default.css +120 -114
- data/data/stylesheets/coderay-asciidoctor.css +15 -17
- data/lib/asciidoctor/abstract_block.rb +146 -140
- data/lib/asciidoctor/abstract_node.rb +152 -170
- data/lib/asciidoctor/attribute_list.rb +77 -89
- data/lib/asciidoctor/block.rb +29 -28
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli/invoker.rb +20 -24
- data/lib/asciidoctor/cli/options.rb +107 -96
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/convert.rb +199 -0
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +627 -644
- data/lib/asciidoctor/converter/html5.rb +1053 -951
- data/lib/asciidoctor/converter/manpage.rb +581 -532
- data/lib/asciidoctor/converter/template.rb +232 -271
- data/lib/asciidoctor/converter.rb +370 -185
- data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
- data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
- data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
- data/lib/asciidoctor/core_ext.rb +8 -17
- data/lib/asciidoctor/document.rb +503 -461
- data/lib/asciidoctor/extensions.rb +127 -174
- data/lib/asciidoctor/helpers.rb +184 -107
- data/lib/asciidoctor/inline.rb +9 -12
- data/lib/asciidoctor/list.rb +11 -29
- data/lib/asciidoctor/load.rb +119 -0
- data/lib/asciidoctor/logging.rb +22 -17
- data/lib/asciidoctor/parser.rb +673 -719
- data/lib/asciidoctor/path_resolver.rb +48 -33
- data/lib/asciidoctor/reader.rb +383 -338
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/rx.rb +723 -0
- data/lib/asciidoctor/section.rb +17 -16
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +926 -1022
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
- data/lib/asciidoctor/syntax_highlighter.rb +253 -0
- data/lib/asciidoctor/table.rb +152 -114
- data/lib/asciidoctor/timings.rb +7 -5
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/lib/asciidoctor.rb +266 -1340
- data/man/asciidoctor.1 +49 -47
- data/man/asciidoctor.adoc +54 -45
- metadata +50 -245
- data/CONTRIBUTING.adoc +0 -185
- data/Gemfile +0 -60
- data/Rakefile +0 -129
- data/bin/asciidoctor-safe +0 -15
- data/features/open_block.feature +0 -92
- data/features/pass_block.feature +0 -66
- data/features/step_definitions.rb +0 -49
- data/features/text_formatting.feature +0 -57
- data/features/xref.feature +0 -1039
- data/lib/asciidoctor/converter/base.rb +0 -59
- data/lib/asciidoctor/converter/docbook45.rb +0 -93
- data/lib/asciidoctor/converter/factory.rb +0 -226
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
- data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
- data/test/api_test.rb +0 -1240
- data/test/attribute_list_test.rb +0 -242
- data/test/attributes_test.rb +0 -1623
- data/test/blocks_test.rb +0 -3870
- data/test/converter_test.rb +0 -470
- data/test/document_test.rb +0 -1853
- data/test/extensions_test.rb +0 -1560
- data/test/fixtures/asciidoc_index.txt +0 -521
- data/test/fixtures/basic-docinfo-footer.html +0 -6
- data/test/fixtures/basic-docinfo-footer.xml +0 -8
- data/test/fixtures/basic-docinfo.html +0 -1
- data/test/fixtures/basic-docinfo.xml +0 -4
- data/test/fixtures/basic.asciidoc +0 -5
- data/test/fixtures/chapter-a.adoc +0 -3
- data/test/fixtures/child-include.adoc +0 -5
- data/test/fixtures/circle.svg +0 -9
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
- data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
- data/test/fixtures/docinfo-footer.html +0 -1
- data/test/fixtures/docinfo-footer.xml +0 -9
- data/test/fixtures/docinfo.html +0 -1
- data/test/fixtures/docinfo.xml +0 -3
- data/test/fixtures/doctime-localtime.adoc +0 -2
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +0 -13
- data/test/fixtures/file-with-missing-include.adoc +0 -1
- data/test/fixtures/grandchild-include.adoc +0 -3
- data/test/fixtures/hello-asciidoctor.pdf +0 -69
- data/test/fixtures/include-file.asciidoc +0 -24
- data/test/fixtures/include-file.jsx +0 -8
- data/test/fixtures/include-file.ml +0 -3
- data/test/fixtures/include-file.xml +0 -5
- data/test/fixtures/lists.adoc +0 -96
- data/test/fixtures/master.adoc +0 -5
- data/test/fixtures/mismatched-end-tag.adoc +0 -7
- data/test/fixtures/other-chapters.adoc +0 -11
- data/test/fixtures/outer-include.adoc +0 -5
- data/test/fixtures/parent-include-restricted.adoc +0 -5
- data/test/fixtures/parent-include.adoc +0 -5
- data/test/fixtures/sample.asciidoc +0 -30
- data/test/fixtures/section-a.adoc +0 -4
- data/test/fixtures/stylesheets/custom.css +0 -3
- data/test/fixtures/subdir/index.adoc +0 -3
- data/test/fixtures/subdir/inner-include.adoc +0 -3
- data/test/fixtures/subdir/middle-include.adoc +0 -5
- data/test/fixtures/subs-docinfo.html +0 -2
- data/test/fixtures/subs.adoc +0 -6
- data/test/fixtures/tagged-class-enclosed.rb +0 -25
- data/test/fixtures/tagged-class.rb +0 -23
- data/test/fixtures/tip.gif +0 -0
- data/test/fixtures/unclosed-tag.adoc +0 -3
- data/test/fixtures/unexpected-end-tag.adoc +0 -4
- data/test/invoker_test.rb +0 -745
- data/test/links_test.rb +0 -855
- data/test/lists_test.rb +0 -5151
- data/test/logger_test.rb +0 -211
- data/test/manpage_test.rb +0 -660
- data/test/options_test.rb +0 -262
- data/test/paragraphs_test.rb +0 -562
- data/test/parser_test.rb +0 -742
- data/test/paths_test.rb +0 -395
- data/test/preamble_test.rb +0 -173
- data/test/reader_test.rb +0 -2161
- data/test/sections_test.rb +0 -3575
- data/test/substitutions_test.rb +0 -2066
- data/test/tables_test.rb +0 -2036
- data/test/test_helper.rb +0 -447
- data/test/text_test.rb +0 -309
@@ -1,33 +1,30 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
module Cli
|
4
|
-
FS =
|
5
|
-
RS =
|
4
|
+
FS = ?/
|
5
|
+
RS = ?\\
|
6
6
|
|
7
7
|
# Public: List of options that can be specified on the command line
|
8
8
|
class Options < ::Hash
|
9
9
|
|
10
10
|
def initialize(options = {})
|
11
11
|
self[:attributes] = options[:attributes] || {}
|
12
|
-
self[:input_files] = options[:input_files]
|
13
|
-
self[:output_file] = options[:output_file]
|
12
|
+
self[:input_files] = options[:input_files]
|
13
|
+
self[:output_file] = options[:output_file]
|
14
14
|
self[:safe] = options[:safe] || SafeMode::UNSAFE
|
15
|
-
self[:
|
16
|
-
self[:template_dirs] = options[:template_dirs]
|
17
|
-
self[:template_engine] = options[:template_engine]
|
18
|
-
if options[:doctype]
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
self[:
|
25
|
-
self[:verbose] = options[:verbose] || 1
|
26
|
-
self[:load_paths] = options[:load_paths] || nil
|
27
|
-
self[:requires] = options[:requires] || nil
|
15
|
+
self[:standalone] = options.fetch :standalone, true
|
16
|
+
self[:template_dirs] = options[:template_dirs]
|
17
|
+
self[:template_engine] = options[:template_engine]
|
18
|
+
self[:attributes]['doctype'] = options[:doctype] if options[:doctype]
|
19
|
+
self[:attributes]['backend'] = options[:backend] if options[:backend]
|
20
|
+
self[:eruby] = options[:eruby]
|
21
|
+
self[:verbose] = options.fetch :verbose, 1
|
22
|
+
self[:warnings] = options.fetch :warnings, false
|
23
|
+
self[:load_paths] = options[:load_paths]
|
24
|
+
self[:requires] = options[:requires]
|
28
25
|
self[:base_dir] = options[:base_dir]
|
29
|
-
self[:source_dir] = options[:source_dir]
|
30
|
-
self[:destination_dir] = options[:destination_dir]
|
26
|
+
self[:source_dir] = options[:source_dir]
|
27
|
+
self[:destination_dir] = options[:destination_dir]
|
31
28
|
self[:failure_level] = ::Logger::Severity::FATAL
|
32
29
|
self[:trace] = false
|
33
30
|
self[:timings] = false
|
@@ -39,55 +36,61 @@ module Asciidoctor
|
|
39
36
|
|
40
37
|
def parse!(args)
|
41
38
|
opts_parser = ::OptionParser.new do |opts|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
# NOTE don't use squiggly heredoc to maintain compatibility with Ruby < 2.3
|
40
|
+
opts.banner = <<-'EOS'.gsub ' ', ''
|
41
|
+
Usage: asciidoctor [OPTION]... FILE...
|
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
|
47
46
|
|
48
47
|
EOS
|
49
48
|
|
50
|
-
opts.on('-b', '--backend BACKEND', 'set output format
|
51
|
-
|
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|
|
52
51
|
self[:attributes]['backend'] = backend
|
53
52
|
end
|
54
53
|
opts.on('-d', '--doctype DOCTYPE', ['article', 'book', 'manpage', 'inline'],
|
55
|
-
|
56
|
-
self[:attributes]['doctype'] =
|
54
|
+
'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doctype|
|
55
|
+
self[:attributes]['doctype'] = doctype
|
56
|
+
end
|
57
|
+
opts.on('-e', '--embedded', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
58
|
+
self[:standalone] = false
|
57
59
|
end
|
58
60
|
opts.on('-o', '--out-file FILE', 'output file (default: based on path of input file); use - to output to STDOUT') do |output_file|
|
59
61
|
self[:output_file] = output_file
|
60
62
|
end
|
61
63
|
opts.on('--safe',
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
65
67
|
self[:safe] = SafeMode::SAFE
|
66
68
|
end
|
67
69
|
opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
|
68
|
-
|
69
|
-
|
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|
|
70
72
|
self[:safe] = SafeMode.value_for_name name
|
71
73
|
end
|
72
|
-
opts.on('-s', '--no-header-footer', 'suppress
|
73
|
-
self[:
|
74
|
+
opts.on('-s', '--no-header-footer', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
75
|
+
self[:standalone] = false
|
74
76
|
end
|
75
77
|
opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
|
76
78
|
self[:attributes]['sectnums'] = ''
|
77
79
|
end
|
78
|
-
opts.on('
|
79
|
-
|
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|
|
80
82
|
self[:eruby] = eruby
|
81
83
|
end
|
82
|
-
opts.on('-a', '--attribute
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
|
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|
|
87
|
+
next if (attr = attr.rstrip).empty? || attr == '='
|
88
|
+
attr = attr.encode UTF_8 unless attr.encoding == UTF_8
|
89
|
+
name, _, val = attr.partition '='
|
90
|
+
self[:attributes][name] = val
|
88
91
|
end
|
89
92
|
opts.on('-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)',
|
90
|
-
|
93
|
+
'may be specified multiple times') do |template_dir|
|
91
94
|
if self[:template_dirs].nil?
|
92
95
|
self[:template_dirs] = [template_dir]
|
93
96
|
elsif ::Array === self[:template_dirs]
|
@@ -116,44 +119,49 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
116
119
|
'may be specified more than once') do |path|
|
117
120
|
(self[:requires] ||= []).concat(path.split ',')
|
118
121
|
end
|
119
|
-
opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR), 'set minimum
|
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|
|
120
123
|
level = 'WARN' if (level = level.upcase) == 'WARNING'
|
121
124
|
self[:failure_level] = ::Logger::Severity.const_get level
|
122
125
|
end
|
123
|
-
opts.on('-q', '--quiet', '
|
126
|
+
opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
|
124
127
|
self[:verbose] = 0
|
125
128
|
end
|
126
|
-
opts.on('--trace', 'include backtrace information
|
129
|
+
opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
|
127
130
|
self[:trace] = true
|
128
131
|
end
|
129
|
-
opts.on('-v', '--verbose', '
|
132
|
+
opts.on('-v', '--verbose', 'directs application messages logged at DEBUG or INFO level to STDERR (default: false)') do
|
130
133
|
self[:verbose] = 2
|
131
134
|
end
|
132
|
-
opts.on('-
|
135
|
+
opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
|
136
|
+
self[:warnings] = true
|
137
|
+
end
|
138
|
+
opts.on('-t', '--timings', 'print timings report (default: false)') do
|
133
139
|
self[:timings] = true
|
134
140
|
end
|
135
|
-
|
136
|
-
|
137
|
-
'show the
|
141
|
+
opts.on_tail('-h', '--help [TOPIC]', 'print a help message',
|
142
|
+
'show this usage if TOPIC is not specified or recognized',
|
143
|
+
'show an overview of the AsciiDoc syntax if TOPIC is syntax',
|
138
144
|
'dump the Asciidoctor man page (in troff/groff format) if TOPIC is manpage') do |topic|
|
139
|
-
|
140
|
-
|
145
|
+
case topic
|
146
|
+
# use `asciidoctor -h manpage | man -l -` to view with man pager
|
147
|
+
when 'manpage'
|
148
|
+
if (manpage_path = ::ENV['ASCIIDOCTOR_MANPAGE_PATH'])
|
141
149
|
if ::File.exist? manpage_path
|
142
150
|
if manpage_path.end_with? '.gz'
|
143
151
|
require 'zlib' unless defined? ::Zlib::GzipReader
|
144
152
|
$stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
|
145
153
|
else
|
146
|
-
$stdout.puts ::
|
154
|
+
$stdout.puts ::File.read manpage_path
|
147
155
|
end
|
148
156
|
else
|
149
157
|
$stderr.puts %(asciidoctor: FAILED: manual page not found: #{manpage_path})
|
150
158
|
return 1
|
151
159
|
end
|
152
|
-
|
153
|
-
|
160
|
+
# Ruby 2.3 requires the extra brackets around the ::File.join method call
|
161
|
+
elsif ::File.exist? (manpage_path = (::File.join ROOT_DIR, 'man', 'asciidoctor.1'))
|
162
|
+
$stdout.puts ::File.read manpage_path
|
154
163
|
else
|
155
|
-
|
156
|
-
manpage_path = ::Open3.popen3('man -w asciidoctor') {|_, out| out.read }.chop rescue ''
|
164
|
+
manpage_path = %x(man -w asciidoctor).chop rescue ''
|
157
165
|
if manpage_path.empty?
|
158
166
|
$stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
|
159
167
|
return 1
|
@@ -161,26 +169,32 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
161
169
|
require 'zlib' unless defined? ::Zlib::GzipReader
|
162
170
|
$stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
|
163
171
|
else
|
164
|
-
$stdout.puts ::
|
172
|
+
$stdout.puts ::File.read manpage_path
|
165
173
|
end
|
166
174
|
end
|
175
|
+
when 'syntax'
|
176
|
+
# Ruby 2.3 requires the extra brackets around the ::File.join method call
|
177
|
+
if ::File.exist? (syntax_path = (::File.join ROOT_DIR, 'data', 'reference', 'syntax.adoc'))
|
178
|
+
$stdout.puts ::File.read syntax_path
|
179
|
+
else
|
180
|
+
$stderr.puts 'asciidoctor: FAILED: syntax page not found; visit https://asciidoctor.org/docs'
|
181
|
+
return 1
|
182
|
+
end
|
167
183
|
else
|
168
184
|
$stdout.puts opts
|
169
185
|
end
|
170
186
|
return 0
|
171
187
|
end
|
172
|
-
|
173
188
|
opts.on_tail('-V', '--version', 'display the version and runtime environment (or -v if no other flags or arguments)') do
|
174
189
|
return print_version $stdout
|
175
190
|
end
|
176
|
-
|
177
191
|
end
|
178
192
|
|
179
|
-
|
193
|
+
old_verbose, $VERBOSE = $VERBOSE, (args.include? '-w')
|
180
194
|
opts_parser.parse! args
|
181
195
|
|
182
196
|
if args.empty?
|
183
|
-
if self[:verbose] == 2
|
197
|
+
if self[:verbose] == 2 # -v flag was specified
|
184
198
|
return print_version $stdout
|
185
199
|
else
|
186
200
|
$stderr.puts opts_parser
|
@@ -188,29 +202,28 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
188
202
|
end
|
189
203
|
end
|
190
204
|
|
205
|
+
infiles = []
|
191
206
|
# shave off the file to process so that options errors appear correctly
|
192
207
|
if args.size == 1 && args[0] == '-'
|
193
208
|
infiles << args.pop
|
194
|
-
|
209
|
+
else
|
195
210
|
args.each do |file|
|
196
|
-
if file
|
211
|
+
if file.start_with? '-'
|
197
212
|
# warn, but don't panic; we may have enough to proceed, so we won't force a failure
|
198
213
|
$stderr.puts %(asciidoctor: WARNING: extra arguments detected (unparsed arguments: '#{args.join "', '"}') or incorrect usage of stdin)
|
214
|
+
elsif ::File.file? file
|
215
|
+
infiles << file
|
216
|
+
# NOTE only attempt to glob if file is not found
|
199
217
|
else
|
200
|
-
|
218
|
+
# Tilt backslashes in Windows paths the Ruby-friendly way
|
219
|
+
if ::File::ALT_SEPARATOR == RS && (file.include? RS)
|
220
|
+
file = file.tr RS, FS
|
221
|
+
end
|
222
|
+
if (matches = ::Dir.glob file).empty?
|
223
|
+
# NOTE if no matches, assume it's just a missing file and proceed
|
201
224
|
infiles << file
|
202
|
-
# NOTE only attempt to glob if file is not found
|
203
225
|
else
|
204
|
-
|
205
|
-
if ::File::ALT_SEPARATOR == RS && (file.include? RS)
|
206
|
-
file = file.tr RS, FS
|
207
|
-
end
|
208
|
-
if (matches = ::Dir.glob file).empty?
|
209
|
-
# NOTE if no matches, assume it's just a missing file and proceed
|
210
|
-
infiles << file
|
211
|
-
else
|
212
|
-
infiles.concat matches
|
213
|
-
end
|
226
|
+
infiles.concat matches
|
214
227
|
end
|
215
228
|
end
|
216
229
|
end
|
@@ -236,16 +249,16 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
236
249
|
|
237
250
|
self[:input_files] = infiles
|
238
251
|
|
239
|
-
|
252
|
+
delete :attributes if self[:attributes].empty?
|
240
253
|
|
241
254
|
if self[:template_dirs]
|
242
255
|
begin
|
243
|
-
require 'tilt' unless defined? ::Tilt
|
256
|
+
require 'tilt' unless defined? ::Tilt.new
|
244
257
|
rescue ::LoadError
|
245
258
|
raise $! if self[:trace]
|
246
259
|
$stderr.puts 'asciidoctor: FAILED: \'tilt\' could not be loaded'
|
247
260
|
$stderr.puts ' You must have the tilt gem installed (gem install tilt) to use custom backend templates'
|
248
|
-
$stderr.puts ' Use --trace
|
261
|
+
$stderr.puts ' Use --trace to show backtrace'
|
249
262
|
return 1
|
250
263
|
rescue ::SystemExit
|
251
264
|
# not permitted here
|
@@ -253,19 +266,19 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
253
266
|
end
|
254
267
|
|
255
268
|
if (load_paths = self[:load_paths])
|
256
|
-
|
257
|
-
|
258
|
-
end
|
269
|
+
load_paths.uniq!
|
270
|
+
load_paths.reverse_each {|path| $:.unshift ::File.expand_path path }
|
259
271
|
end
|
260
272
|
|
261
273
|
if (requires = self[:requires])
|
262
|
-
|
274
|
+
requires.uniq!
|
275
|
+
requires.each do |path|
|
263
276
|
begin
|
264
277
|
require path
|
265
278
|
rescue ::LoadError
|
266
279
|
raise $! if self[:trace]
|
267
280
|
$stderr.puts %(asciidoctor: FAILED: '#{path}' could not be loaded)
|
268
|
-
$stderr.puts ' Use --trace
|
281
|
+
$stderr.puts ' Use --trace to show backtrace'
|
269
282
|
return 1
|
270
283
|
rescue ::SystemExit
|
271
284
|
# not permitted here
|
@@ -277,23 +290,21 @@ Example: asciidoctor -b html5 source.asciidoc
|
|
277
290
|
rescue ::OptionParser::MissingArgument
|
278
291
|
$stderr.puts %(asciidoctor: option #{$!.message})
|
279
292
|
$stdout.puts opts_parser
|
280
|
-
|
293
|
+
1
|
281
294
|
rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument
|
282
295
|
$stderr.puts %(asciidoctor: #{$!.message})
|
283
296
|
$stdout.puts opts_parser
|
284
|
-
|
297
|
+
1
|
298
|
+
ensure
|
299
|
+
$VERBOSE = old_verbose
|
285
300
|
end
|
286
301
|
|
287
302
|
def print_version os = $stdout
|
288
303
|
os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [https://asciidoctor.org])
|
289
|
-
|
290
|
-
|
291
|
-
%(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc }).encoding : (::Encoding.find v)})
|
292
|
-
end
|
293
|
-
os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}) (#{encoding_info.join ' '}))
|
294
|
-
else
|
295
|
-
os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}))
|
304
|
+
encoding_info = { 'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external' }.map do |k, v|
|
305
|
+
%(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc.encoding }) : (::Encoding.find v)})
|
296
306
|
end
|
307
|
+
os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}) (#{encoding_info.join ' '}))
|
297
308
|
0
|
298
309
|
end
|
299
310
|
end
|
data/lib/asciidoctor/cli.rb
CHANGED
@@ -0,0 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Asciidoctor
|
3
|
+
class << self
|
4
|
+
# Public: Parse the AsciiDoc source input into an Asciidoctor::Document and
|
5
|
+
# convert it to the specified backend format.
|
6
|
+
#
|
7
|
+
# Accepts input as an IO (or StringIO), String or String Array object. If the
|
8
|
+
# input is a File, the object is expected to be opened for reading and is not
|
9
|
+
# closed afterwards by this method. Information about the file (filename,
|
10
|
+
# directory name, etc) gets assigned to attributes on the Document object.
|
11
|
+
#
|
12
|
+
# If the :to_file option is true, and the input is a File, the output is
|
13
|
+
# written to a file adjacent to the input file, having an extension that
|
14
|
+
# corresponds to the backend format. Otherwise, if the :to_file option is
|
15
|
+
# specified, the file is written to that file. If :to_file is not an absolute
|
16
|
+
# path, it is resolved relative to :to_dir, if given, otherwise the
|
17
|
+
# Document#base_dir. If the target directory does not exist, it will not be
|
18
|
+
# created unless the :mkdirs option is set to true. If the file cannot be
|
19
|
+
# written because the target directory does not exist, or because it falls
|
20
|
+
# outside of the Document#base_dir in safe mode, an IOError is raised.
|
21
|
+
#
|
22
|
+
# If the output is going to be written to a file, the header and footer are
|
23
|
+
# included unless specified otherwise (writing to a file implies creating a
|
24
|
+
# standalone document). Otherwise, the header and footer are not included by
|
25
|
+
# default and the converted result is returned.
|
26
|
+
#
|
27
|
+
# input - the String AsciiDoc source filename
|
28
|
+
# options - a String, Array or Hash of options to control processing (default: {})
|
29
|
+
# String and Array values are converted into a Hash.
|
30
|
+
# See Asciidoctor::Document#initialize for details about options.
|
31
|
+
#
|
32
|
+
# Returns the Document object if the converted String is written to a
|
33
|
+
# file, otherwise the converted String
|
34
|
+
def convert input, options = {}
|
35
|
+
(options = options.merge).delete :parse
|
36
|
+
to_dir = options.delete :to_dir
|
37
|
+
mkdirs = options.delete :mkdirs
|
38
|
+
|
39
|
+
case (to_file = options.delete :to_file)
|
40
|
+
when true, nil
|
41
|
+
unless (write_to_target = to_dir)
|
42
|
+
sibling_path = ::File.absolute_path input.path if ::File === input
|
43
|
+
end
|
44
|
+
to_file = nil
|
45
|
+
when false
|
46
|
+
to_file = nil
|
47
|
+
when '/dev/null'
|
48
|
+
return load input, options
|
49
|
+
else
|
50
|
+
options[:to_file] = write_to_target = to_file unless (stream_output = to_file.respond_to? :write)
|
51
|
+
end
|
52
|
+
|
53
|
+
unless options.key? :standalone
|
54
|
+
if sibling_path || write_to_target
|
55
|
+
options[:standalone] = options.fetch :header_footer, true
|
56
|
+
elsif options.key? :header_footer
|
57
|
+
options[:standalone] = options[:header_footer]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# NOTE outfile may be controlled by document attributes, so resolve outfile after loading
|
62
|
+
if sibling_path
|
63
|
+
options[:to_dir] = outdir = ::File.dirname sibling_path
|
64
|
+
elsif write_to_target
|
65
|
+
if to_dir
|
66
|
+
if to_file
|
67
|
+
options[:to_dir] = ::File.dirname ::File.expand_path to_file, to_dir
|
68
|
+
else
|
69
|
+
options[:to_dir] = ::File.expand_path to_dir
|
70
|
+
end
|
71
|
+
elsif to_file
|
72
|
+
options[:to_dir] = ::File.dirname ::File.expand_path to_file
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# NOTE :to_dir is always set when outputting to a file
|
77
|
+
# NOTE :to_file option only passed if assigned an explicit path
|
78
|
+
doc = load input, options
|
79
|
+
|
80
|
+
if sibling_path # write to file in same directory
|
81
|
+
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
82
|
+
raise ::IOError, %(input file and output file cannot be the same: #{outfile}) if outfile == sibling_path
|
83
|
+
elsif write_to_target # write to explicit file or directory
|
84
|
+
working_dir = (options.key? :base_dir) ? (::File.expand_path options[:base_dir]) : ::Dir.pwd
|
85
|
+
# QUESTION should the jail be the working_dir or doc.base_dir???
|
86
|
+
jail = doc.safe >= SafeMode::SAFE ? working_dir : nil
|
87
|
+
if to_dir
|
88
|
+
outdir = doc.normalize_system_path(to_dir, working_dir, jail, target_name: 'to_dir', recover: false)
|
89
|
+
if to_file
|
90
|
+
outfile = doc.normalize_system_path(to_file, outdir, nil, target_name: 'to_dir', recover: false)
|
91
|
+
# reestablish outdir as the final target directory (in the case to_file had directory segments)
|
92
|
+
outdir = ::File.dirname outfile
|
93
|
+
else
|
94
|
+
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
95
|
+
end
|
96
|
+
elsif to_file
|
97
|
+
outfile = doc.normalize_system_path(to_file, working_dir, jail, target_name: 'to_dir', recover: false)
|
98
|
+
# establish outdir as the final target directory (in the case to_file had directory segments)
|
99
|
+
outdir = ::File.dirname outfile
|
100
|
+
end
|
101
|
+
|
102
|
+
if ::File === input && outfile == (::File.absolute_path input.path)
|
103
|
+
raise ::IOError, %(input file and output file cannot be the same: #{outfile})
|
104
|
+
end
|
105
|
+
|
106
|
+
if mkdirs
|
107
|
+
Helpers.mkdir_p outdir
|
108
|
+
else
|
109
|
+
# NOTE we intentionally refer to the directory as it was passed to the API
|
110
|
+
raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set :mkdirs option)) unless ::File.directory? outdir
|
111
|
+
end
|
112
|
+
else # write to stream
|
113
|
+
outfile = to_file
|
114
|
+
outdir = nil
|
115
|
+
end
|
116
|
+
|
117
|
+
if outfile && !stream_output
|
118
|
+
output = doc.convert 'outfile' => outfile, 'outdir' => outdir
|
119
|
+
else
|
120
|
+
output = doc.convert
|
121
|
+
end
|
122
|
+
|
123
|
+
if outfile
|
124
|
+
doc.write output, outfile
|
125
|
+
|
126
|
+
# NOTE document cannot control this behavior if safe >= SafeMode::SERVER
|
127
|
+
# NOTE skip if stylesdir is a URI
|
128
|
+
if !stream_output && doc.safe < SafeMode::SECURE && (doc.attr? 'linkcss') && (doc.attr? 'copycss') &&
|
129
|
+
(doc.basebackend? 'html') && !((stylesdir = (doc.attr 'stylesdir')) && (Helpers.uriish? stylesdir))
|
130
|
+
if (stylesheet = doc.attr 'stylesheet')
|
131
|
+
if DEFAULT_STYLESHEET_KEYS.include? stylesheet
|
132
|
+
copy_asciidoctor_stylesheet = true
|
133
|
+
elsif !(Helpers.uriish? stylesheet)
|
134
|
+
copy_user_stylesheet = true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
copy_syntax_hl_stylesheet = (syntax_hl = doc.syntax_highlighter) && (syntax_hl.write_stylesheet? doc)
|
138
|
+
if copy_asciidoctor_stylesheet || copy_user_stylesheet || copy_syntax_hl_stylesheet
|
139
|
+
stylesoutdir = doc.normalize_system_path(stylesdir, outdir, doc.safe >= SafeMode::SAFE ? outdir : nil)
|
140
|
+
if mkdirs
|
141
|
+
Helpers.mkdir_p stylesoutdir
|
142
|
+
else
|
143
|
+
raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set :mkdirs option)) unless ::File.directory? stylesoutdir
|
144
|
+
end
|
145
|
+
|
146
|
+
if copy_asciidoctor_stylesheet
|
147
|
+
Stylesheets.instance.write_primary_stylesheet stylesoutdir
|
148
|
+
# FIXME should Stylesheets also handle the user stylesheet?
|
149
|
+
elsif copy_user_stylesheet
|
150
|
+
if (stylesheet_src = doc.attr 'copycss') == '' || stylesheet_src == true
|
151
|
+
stylesheet_src = doc.normalize_system_path stylesheet
|
152
|
+
else
|
153
|
+
# NOTE in this case, copycss is a source location (but cannot be a URI)
|
154
|
+
stylesheet_src = doc.normalize_system_path stylesheet_src.to_s
|
155
|
+
end
|
156
|
+
stylesheet_dest = doc.normalize_system_path stylesheet, stylesoutdir, (doc.safe >= SafeMode::SAFE ? outdir : nil)
|
157
|
+
# NOTE don't warn if src can't be read and dest already exists (see #2323)
|
158
|
+
if stylesheet_src != stylesheet_dest && (stylesheet_data = doc.read_asset stylesheet_src,
|
159
|
+
warn_on_failure: !(::File.file? stylesheet_dest), label: 'stylesheet')
|
160
|
+
if (stylesheet_outdir = ::File.dirname stylesheet_dest) != stylesoutdir && !(::File.directory? stylesheet_outdir)
|
161
|
+
if mkdirs
|
162
|
+
Helpers.mkdir_p stylesheet_outdir
|
163
|
+
else
|
164
|
+
raise ::IOError, %(target stylesheet directory does not exist: #{stylesheet_outdir} (hint: set :mkdirs option))
|
165
|
+
end
|
166
|
+
end
|
167
|
+
::File.write stylesheet_dest, stylesheet_data, mode: FILE_WRITE_MODE
|
168
|
+
end
|
169
|
+
end
|
170
|
+
syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
|
171
|
+
end
|
172
|
+
end
|
173
|
+
doc
|
174
|
+
else
|
175
|
+
output
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Public: Parse the contents of the AsciiDoc source file into an
|
180
|
+
# Asciidoctor::Document and convert it to the specified backend format.
|
181
|
+
#
|
182
|
+
# input - the String AsciiDoc source filename
|
183
|
+
# options - a String, Array or Hash of options to control processing (default: {})
|
184
|
+
# String and Array values are converted into a Hash.
|
185
|
+
# See Asciidoctor::Document#initialize for details about options.
|
186
|
+
#
|
187
|
+
# Returns the Document object if the converted String is written to a
|
188
|
+
# file, otherwise the converted String
|
189
|
+
def convert_file filename, options = {}
|
190
|
+
::File.open(filename, FILE_READ_MODE) {|file| convert file, options }
|
191
|
+
end
|
192
|
+
|
193
|
+
# Deprecated: Use {Asciidoctor.convert} instead.
|
194
|
+
alias render convert
|
195
|
+
|
196
|
+
# Deprecated: Use {Asciidoctor.convert_file} instead.
|
197
|
+
alias render_file convert_file
|
198
|
+
end
|
199
|
+
end
|