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
data/lib/asciidoctor/convert.rb
CHANGED
@@ -1,193 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Asciidoctor
|
2
|
-
|
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
|
3
38
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
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)
|
43
51
|
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
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
58
59
|
end
|
59
|
-
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
70
73
|
end
|
71
|
-
elsif to_file
|
72
|
-
options[:to_dir] = ::File.dirname ::File.expand_path to_file
|
73
74
|
end
|
74
|
-
end
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
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
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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)
|
92
99
|
outdir = ::File.dirname outfile
|
93
|
-
else
|
94
|
-
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
95
100
|
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
101
|
|
102
|
-
|
103
|
-
|
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
|
104
115
|
end
|
105
116
|
|
106
|
-
if
|
107
|
-
|
117
|
+
if outfile && !stream_output
|
118
|
+
output = doc.convert 'outfile' => outfile, 'outdir' => outdir
|
108
119
|
else
|
109
|
-
|
110
|
-
raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set :mkdirs option)) unless ::File.directory? outdir
|
120
|
+
output = doc.convert
|
111
121
|
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
122
|
|
123
|
-
|
124
|
-
|
123
|
+
if outfile
|
124
|
+
doc.write output, outfile
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
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
|
144
136
|
end
|
145
|
-
|
146
|
-
if copy_asciidoctor_stylesheet
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
if (stylesheet_src = doc.attr 'copycss').empty?
|
151
|
-
stylesheet_src = doc.normalize_system_path stylesheet
|
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
|
152
142
|
else
|
153
|
-
|
154
|
-
stylesheet_src = doc.normalize_system_path stylesheet_src
|
143
|
+
raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set :mkdirs option)) unless ::File.directory? stylesoutdir
|
155
144
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
161
169
|
end
|
170
|
+
syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
|
162
171
|
end
|
163
|
-
syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
|
164
172
|
end
|
173
|
+
doc
|
174
|
+
else
|
175
|
+
output
|
165
176
|
end
|
166
|
-
doc
|
167
|
-
else
|
168
|
-
output
|
169
177
|
end
|
170
|
-
end
|
171
178
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
185
192
|
|
186
|
-
|
187
|
-
|
188
|
-
module_function :render
|
193
|
+
# Deprecated: Use {Asciidoctor.convert} instead.
|
194
|
+
alias render convert
|
189
195
|
|
190
|
-
|
191
|
-
|
192
|
-
|
196
|
+
# Deprecated: Use {Asciidoctor.convert_file} instead.
|
197
|
+
alias render_file convert_file
|
198
|
+
end
|
193
199
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# A built-in {Converter} implementation that generates DocBook 5 output. The output is inspired by the output produced
|
4
|
-
# by the docbook45 backend from AsciiDoc
|
4
|
+
# by the docbook45 backend from AsciiDoc.py, except it has been migrated to the DocBook 5 specification.
|
5
5
|
class Converter::DocBook5Converter < Converter::Base
|
6
6
|
register_for 'docbook5'
|
7
7
|
|
8
8
|
# default represents variablelist
|
9
9
|
(DLIST_TAGS = {
|
10
|
-
'qanda' => { list:
|
11
|
-
'glossary' => { list:
|
12
|
-
}).default = { list:
|
10
|
+
'qanda' => { list: 'qandaset', entry: 'qandaentry', label: 'question', term: 'simpara', item: 'answer' },
|
11
|
+
'glossary' => { list: nil, entry: 'glossentry', term: 'glossterm', item: 'glossdef' },
|
12
|
+
}).default = { list: 'variablelist', entry: 'varlistentry', term: 'term', item: 'listitem' }
|
13
13
|
|
14
14
|
(QUOTE_TAGS = {
|
15
15
|
monospaced: ['<literal>', '</literal>'],
|
@@ -25,7 +25,7 @@ class Converter::DocBook5Converter < Converter::Base
|
|
25
25
|
MANPAGE_SECTION_TAGS = { 'section' => 'refsection', 'synopsis' => 'refsynopsisdiv' }
|
26
26
|
TABLE_PI_NAMES = ['dbhtml', 'dbfo', 'dblatex']
|
27
27
|
|
28
|
-
CopyrightRx = /^(#{CC_ANY}+?)(?: ((?:\d{4}
|
28
|
+
CopyrightRx = /^(#{CC_ANY}+?)(?: ((?:\d{4}-)?\d{4}))?$/
|
29
29
|
ImageMacroRx = /^image::?(\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
|
30
30
|
|
31
31
|
def initialize backend, opts = {}
|
@@ -41,7 +41,8 @@ class Converter::DocBook5Converter < Converter::Base
|
|
41
41
|
if (root_tag_name = node.doctype) == 'manpage'
|
42
42
|
root_tag_name = 'refentry'
|
43
43
|
end
|
44
|
-
|
44
|
+
root_tag_idx = result.size
|
45
|
+
id = node.id
|
45
46
|
result << (document_info_tag node) unless node.noheader
|
46
47
|
unless (docinfo_content = node.docinfo :header).empty?
|
47
48
|
result << docinfo_content
|
@@ -50,6 +51,9 @@ class Converter::DocBook5Converter < Converter::Base
|
|
50
51
|
unless (docinfo_content = node.docinfo :footer).empty?
|
51
52
|
result << docinfo_content
|
52
53
|
end
|
54
|
+
id, node.id = node.id, nil unless id
|
55
|
+
# defer adding root tag in case document ID is auto-generated on demand
|
56
|
+
result.insert root_tag_idx, %(<#{root_tag_name} xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"#{lang_attribute}#{common_attributes id}>)
|
53
57
|
result << %(</#{root_tag_name}>)
|
54
58
|
result.join LF
|
55
59
|
end
|
@@ -298,13 +302,13 @@ class Converter::DocBook5Converter < Converter::Base
|
|
298
302
|
</abstract>)
|
299
303
|
end
|
300
304
|
when 'partintro'
|
301
|
-
|
302
|
-
logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
|
303
|
-
''
|
304
|
-
else
|
305
|
+
if node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
|
305
306
|
%(<partintro#{common_attributes node.id, node.role, node.reftext}>
|
306
307
|
#{title_tag node}#{enclose_content node}
|
307
308
|
</partintro>)
|
309
|
+
else
|
310
|
+
logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
|
311
|
+
''
|
308
312
|
end
|
309
313
|
else
|
310
314
|
reftext = node.reftext if (id = node.id)
|
@@ -371,24 +375,22 @@ class Converter::DocBook5Converter < Converter::Base
|
|
371
375
|
has_body = false
|
372
376
|
result = []
|
373
377
|
pgwide_attribute = (node.option? 'pgwide') ? ' pgwide="1"' : ''
|
374
|
-
if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
|
375
|
-
frame = 'topbot'
|
376
|
-
end
|
378
|
+
frame = 'topbot' if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
|
377
379
|
grid = node.attr 'grid', nil, 'table-grid'
|
378
380
|
result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{frame}" rowsep="#{['none', 'cols'].include?(grid) ? 0 : 1}" colsep="#{['none', 'rows'].include?(grid) ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', 'table-orientation') ? ' orient="land"' : ''}>)
|
379
|
-
if
|
381
|
+
if node.option? 'unbreakable'
|
380
382
|
result << '<?dbfo keep-together="always"?>'
|
381
|
-
elsif
|
383
|
+
elsif node.option? 'breakable'
|
382
384
|
result << '<?dbfo keep-together="auto"?>'
|
383
385
|
end
|
384
386
|
result << %(<title>#{node.title}</title>) if tag_name == 'table'
|
385
|
-
|
387
|
+
if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
|
386
388
|
TABLE_PI_NAMES.each do |pi_name|
|
387
389
|
result << %(<?#{pi_name} table-width="#{width}"?>)
|
388
390
|
end
|
389
|
-
'colabswidth'
|
391
|
+
col_width_key = 'colabswidth'
|
390
392
|
else
|
391
|
-
'colpcwidth'
|
393
|
+
col_width_key = 'colpcwidth'
|
392
394
|
end
|
393
395
|
result << %(<tgroup cols="#{node.attr 'colcount'}">)
|
394
396
|
node.columns.each do |col|
|
@@ -401,12 +403,10 @@ class Converter::DocBook5Converter < Converter::Base
|
|
401
403
|
rows.each do |row|
|
402
404
|
result << '<row>'
|
403
405
|
row.each do |cell|
|
404
|
-
halign_attribute = (cell.attr? 'halign') ? %( align="#{cell.attr 'halign'}") : ''
|
405
|
-
valign_attribute = (cell.attr? 'valign') ? %( valign="#{cell.attr 'valign'}") : ''
|
406
406
|
colspan_attribute = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{colnum + cell.colspan - 1}") : ''
|
407
407
|
rowspan_attribute = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
|
408
408
|
# NOTE <entry> may not have whitespace (e.g., line breaks) as a direct descendant according to DocBook rules
|
409
|
-
entry_start = %(<entry#{
|
409
|
+
entry_start = %(<entry align="#{cell.attr 'halign'}" valign="#{cell.attr 'valign'}"#{colspan_attribute}#{rowspan_attribute}>)
|
410
410
|
if tsec == :head
|
411
411
|
cell_content = cell.text
|
412
412
|
else
|
@@ -478,16 +478,22 @@ class Converter::DocBook5Converter < Converter::Base
|
|
478
478
|
%(<anchor#{common_attributes((id = node.id), nil, node.reftext || %([#{id}]))}/>)
|
479
479
|
when :xref
|
480
480
|
if (path = node.attributes['path'])
|
481
|
-
# QUESTION should we use refid as fallback text instead? (like the html5 backend?)
|
482
481
|
%(<link xl:href="#{node.target}">#{node.text || path}</link>)
|
483
482
|
else
|
484
|
-
linkend = node.attributes['
|
483
|
+
if (linkend = node.attributes['refid']).nil_or_empty?
|
484
|
+
root_doc = get_root_document node
|
485
|
+
# Q: should we warn instead of generating a document ID on demand?
|
486
|
+
linkend = (root_doc.id ||= generate_document_id root_doc)
|
487
|
+
end
|
488
|
+
# NOTE the xref tag in DocBook does not support explicit link text, so the link tag must be used instead
|
489
|
+
# The section at http://www.sagehill.net/docbookxsl/CrossRefs.html#IdrefLinks gives an explanation for this choice
|
490
|
+
# "link - a cross reference where you supply the text of the reference as the content of the link element."
|
485
491
|
(text = node.text) ? %(<link linkend="#{linkend}">#{text}</link>) : %(<xref linkend="#{linkend}"/>)
|
486
492
|
end
|
487
493
|
when :link
|
488
494
|
%(<link xl:href="#{node.target}">#{node.text}</link>)
|
489
495
|
when :bibref
|
490
|
-
%(<anchor#{common_attributes node.id, nil, "[#{node.reftext || node.id}]"}/>#{text})
|
496
|
+
%(<anchor#{common_attributes node.id, nil, (text = "[#{node.reftext || node.id}]")}/>#{text})
|
491
497
|
else
|
492
498
|
logger.warn %(unknown anchor type: #{node.type.inspect})
|
493
499
|
nil
|
@@ -517,7 +523,7 @@ class Converter::DocBook5Converter < Converter::Base
|
|
517
523
|
def convert_inline_image node
|
518
524
|
width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
|
519
525
|
depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
|
520
|
-
%(<inlinemediaobject>
|
526
|
+
%(<inlinemediaobject#{common_attributes nil, node.role}>
|
521
527
|
<imageobject>
|
522
528
|
<imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{width_attribute}#{depth_attribute}/>
|
523
529
|
</imageobject>
|
@@ -537,9 +543,8 @@ class Converter::DocBook5Converter < Converter::Base
|
|
537
543
|
%(<indexterm>
|
538
544
|
<primary>#{node.text}</primary>#{rel}
|
539
545
|
</indexterm>#{node.text})
|
540
|
-
|
541
|
-
|
542
|
-
%(<indexterm>
|
546
|
+
elsif (numterms = (terms = node.attr 'terms').size) > 2
|
547
|
+
%(<indexterm>
|
543
548
|
<primary>#{terms[0]}</primary><secondary>#{terms[1]}</secondary><tertiary>#{terms[2]}</tertiary>#{rel}
|
544
549
|
</indexterm>#{(node.document.option? 'indexterm-promotion') ? %[
|
545
550
|
<indexterm>
|
@@ -548,18 +553,17 @@ class Converter::DocBook5Converter < Converter::Base
|
|
548
553
|
<indexterm>
|
549
554
|
<primary>#{terms[2]}</primary>
|
550
555
|
</indexterm>] : ''})
|
551
|
-
|
552
|
-
|
556
|
+
elsif numterms > 1
|
557
|
+
%(<indexterm>
|
553
558
|
<primary>#{terms[0]}</primary><secondary>#{terms[1]}</secondary>#{rel}
|
554
|
-
</indexterm>#{(node.document.option?
|
559
|
+
</indexterm>#{(node.document.option? 'indexterm-promotion') ? %[
|
555
560
|
<indexterm>
|
556
561
|
<primary>#{terms[1]}</primary>
|
557
562
|
</indexterm>] : ''})
|
558
|
-
|
559
|
-
|
563
|
+
else
|
564
|
+
%(<indexterm>
|
560
565
|
<primary>#{terms[0]}</primary>#{rel}
|
561
566
|
</indexterm>)
|
562
|
-
end
|
563
567
|
end
|
564
568
|
end
|
565
569
|
|
@@ -714,6 +718,17 @@ class Converter::DocBook5Converter < Converter::Base
|
|
714
718
|
result.join LF
|
715
719
|
end
|
716
720
|
|
721
|
+
def get_root_document node
|
722
|
+
while (node = node.document).nested?
|
723
|
+
node = node.parent_document
|
724
|
+
end
|
725
|
+
node
|
726
|
+
end
|
727
|
+
|
728
|
+
def generate_document_id doc
|
729
|
+
%(__#{doc.doctype}-root__)
|
730
|
+
end
|
731
|
+
|
717
732
|
# FIXME this should be handled through a template mechanism
|
718
733
|
def enclose_content node
|
719
734
|
node.content_model == :compound ? node.content : %(<simpara>#{node.content}</simpara>)
|