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
data/lib/asciidoctor/table.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# Public: Methods and constants for managing AsciiDoc table content in a document.
|
4
4
|
# It supports all three of AsciiDoc's table formats: psv, dsv and csv.
|
5
5
|
class Table < AbstractBlock
|
6
|
-
#
|
7
|
-
|
6
|
+
# precision of column widths
|
7
|
+
DEFAULT_PRECISION = 4
|
8
8
|
|
9
9
|
# Public: A data object that encapsulates the collection of rows (head, foot, body) for a table
|
10
10
|
class Rows
|
@@ -18,7 +18,7 @@ class Table < AbstractBlock
|
|
18
18
|
|
19
19
|
alias [] send
|
20
20
|
|
21
|
-
# Public:
|
21
|
+
# Public: Retrieve the rows grouped by section as a nested Array.
|
22
22
|
#
|
23
23
|
# Creates a 2-dimensional array of two element entries. The first element
|
24
24
|
# is the section name as a symbol. The second element is the Array of rows
|
@@ -28,6 +28,16 @@ class Table < AbstractBlock
|
|
28
28
|
def by_section
|
29
29
|
[[:head, @head], [:body, @body], [:foot, @foot]]
|
30
30
|
end
|
31
|
+
|
32
|
+
# Public: Retrieve the rows as a Hash.
|
33
|
+
#
|
34
|
+
# The keys are the names of the section groups and the values are the Array of rows in that section.
|
35
|
+
# The keys are in document order (head, foot, body).
|
36
|
+
#
|
37
|
+
# Returns a Hash of rows grouped by section.
|
38
|
+
def to_h
|
39
|
+
{ head: @head, body: @body, foot: @foot }
|
40
|
+
end
|
31
41
|
end
|
32
42
|
|
33
43
|
# Public: Get/Set the columns for this table
|
@@ -48,7 +58,7 @@ class Table < AbstractBlock
|
|
48
58
|
@rows = Rows.new
|
49
59
|
@columns = []
|
50
60
|
|
51
|
-
@has_header_option =
|
61
|
+
@has_header_option = false
|
52
62
|
|
53
63
|
# smells like we need a utility method here
|
54
64
|
# to resolve an integer width from potential bogus input
|
@@ -61,19 +71,17 @@ class Table < AbstractBlock
|
|
61
71
|
end
|
62
72
|
@attributes['tablepcwidth'] = pcwidth_intval
|
63
73
|
|
64
|
-
if @document.attributes
|
65
|
-
|
66
|
-
@attributes['tableabswidth'] ||=
|
67
|
-
((@attributes['tablepcwidth'].to_f / 100) * @document.attributes['pagewidth']).round
|
74
|
+
if @document.attributes['pagewidth']
|
75
|
+
@attributes['tableabswidth'] = (abswidth_val = (((pcwidth_intval / 100.0) * @document.attributes['pagewidth'].to_f).truncate DEFAULT_PRECISION)) == abswidth_val.to_i ? abswidth_val.to_i : abswidth_val
|
68
76
|
end
|
69
77
|
|
70
|
-
attributes['orientation'] = 'landscape' if attributes
|
78
|
+
@attributes['orientation'] = 'landscape' if attributes['rotate-option']
|
71
79
|
end
|
72
80
|
|
73
|
-
# Internal: Returns
|
74
|
-
# the header row
|
81
|
+
# Internal: Returns the current state of the header option (true or :implicit) if
|
82
|
+
# the row being processed is (or is assumed to be) the header row, otherwise nil
|
75
83
|
def header_row?
|
76
|
-
@has_header_option && @rows.body.empty?
|
84
|
+
(val = @has_header_option) && @rows.body.empty? ? val : nil
|
77
85
|
end
|
78
86
|
|
79
87
|
# Internal: Creates the Column objects from the column spec
|
@@ -111,7 +119,7 @@ class Table < AbstractBlock
|
|
111
119
|
#
|
112
120
|
# returns nothing
|
113
121
|
def assign_column_widths width_base = nil, autowidth_cols = nil
|
114
|
-
|
122
|
+
precision = DEFAULT_PRECISION
|
115
123
|
total_width = col_pcwidth = 0
|
116
124
|
|
117
125
|
if width_base
|
@@ -120,32 +128,22 @@ class Table < AbstractBlock
|
|
120
128
|
autowidth = 0
|
121
129
|
logger.warn %(total column width must not exceed 100% when using autowidth columns; got #{width_base}%)
|
122
130
|
else
|
123
|
-
autowidth = ((100.0 - width_base) / autowidth_cols.size
|
131
|
+
autowidth = ((100.0 - width_base) / autowidth_cols.size).truncate precision
|
124
132
|
autowidth = autowidth.to_i if autowidth.to_i == autowidth
|
125
133
|
width_base = 100
|
126
134
|
end
|
127
135
|
autowidth_attrs = { 'width' => autowidth, 'autowidth-option' => '' }
|
128
136
|
autowidth_cols.each {|col| col.update_attributes autowidth_attrs }
|
129
137
|
end
|
130
|
-
@columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base,
|
138
|
+
@columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, precision) }
|
131
139
|
else
|
132
|
-
col_pcwidth = (
|
133
|
-
# or...
|
134
|
-
#col_pcwidth = (100.0 / @columns.size).truncate 4
|
140
|
+
col_pcwidth = (100.0 / @columns.size).truncate precision
|
135
141
|
col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
|
136
|
-
@columns.each {|col| total_width += col.assign_width col_pcwidth }
|
142
|
+
@columns.each {|col| total_width += col.assign_width col_pcwidth, nil, precision }
|
137
143
|
end
|
138
144
|
|
139
145
|
# donate balance, if any, to final column (using half up rounding)
|
140
|
-
unless total_width == 100
|
141
|
-
@columns[-1].assign_width(((100 - total_width + col_pcwidth) * pf).round / pf)
|
142
|
-
# or (manual half up rounding)...
|
143
|
-
#numerator = (raw_numerator = (100 - total_width + col_pcwidth) * pf).to_i
|
144
|
-
#numerator += 1 if raw_numerator >= numerator + 0.5
|
145
|
-
#@columns[-1].assign_width numerator / pf
|
146
|
-
# or...
|
147
|
-
#@columns[-1].assign_width((100 - total_width + col_pcwidth).round 4)
|
148
|
-
end
|
146
|
+
@columns[-1].assign_width(((100 - total_width + col_pcwidth).round precision), nil, precision) unless total_width == 100
|
149
147
|
|
150
148
|
nil
|
151
149
|
end
|
@@ -156,22 +154,19 @@ class Table < AbstractBlock
|
|
156
154
|
# returns nothing
|
157
155
|
def partition_header_footer(attrs)
|
158
156
|
# set rowcount before splitting up body rows
|
159
|
-
@attributes['rowcount'] = @rows.body.size
|
160
|
-
|
161
|
-
num_body_rows
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
@rows.head = [head]
|
157
|
+
num_body_rows = @attributes['rowcount'] = (body = @rows.body).size
|
158
|
+
|
159
|
+
if num_body_rows > 0
|
160
|
+
if @has_header_option
|
161
|
+
@rows.head = [body.shift.map {|cell| cell.reinitialize true }]
|
162
|
+
num_body_rows -= 1
|
163
|
+
elsif @has_header_option.nil?
|
164
|
+
@has_header_option = false
|
165
|
+
body.unshift(body.shift.map {|cell| cell.reinitialize false })
|
166
|
+
end
|
170
167
|
end
|
171
168
|
|
172
|
-
if num_body_rows > 0 && attrs
|
173
|
-
@rows.foot = [@rows.body.pop]
|
174
|
-
end
|
169
|
+
@rows.foot = [body.pop] if num_body_rows > 0 && attrs['footer-option']
|
175
170
|
|
176
171
|
nil
|
177
172
|
end
|
@@ -180,11 +175,11 @@ end
|
|
180
175
|
# Public: Methods to manage the columns of an AsciiDoc table. In particular, it
|
181
176
|
# keeps track of the column specs
|
182
177
|
class Table::Column < AbstractNode
|
183
|
-
# Public: Get/Set the Symbol
|
178
|
+
# Public: Get/Set the style Symbol for this column.
|
184
179
|
attr_accessor :style
|
185
180
|
|
186
181
|
def initialize table, index, attributes = {}
|
187
|
-
super table, :
|
182
|
+
super table, :table_column
|
188
183
|
@style = attributes['style']
|
189
184
|
attributes['colnumber'] = index + 1
|
190
185
|
attributes['width'] ||= 1
|
@@ -201,32 +196,29 @@ class Table::Column < AbstractNode
|
|
201
196
|
# This method assigns the colpcwidth and colabswidth attributes.
|
202
197
|
#
|
203
198
|
# returns the resolved colpcwidth value
|
204
|
-
def assign_width col_pcwidth, width_base
|
199
|
+
def assign_width col_pcwidth, width_base, precision
|
205
200
|
if width_base
|
206
|
-
col_pcwidth = (
|
207
|
-
# or...
|
208
|
-
#col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate 4
|
201
|
+
col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate precision
|
209
202
|
col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
|
210
203
|
end
|
211
|
-
|
212
|
-
|
213
|
-
# FIXME calculate more accurately (only used in DocBook output)
|
214
|
-
@attributes['colabswidth'] = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).round
|
204
|
+
if parent.attributes['tableabswidth']
|
205
|
+
@attributes['colabswidth'] = (col_abswidth = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).truncate precision) == col_abswidth.to_i ? col_abswidth.to_i : col_abswidth
|
215
206
|
end
|
216
|
-
col_pcwidth
|
207
|
+
@attributes['colpcwidth'] = col_pcwidth
|
217
208
|
end
|
218
|
-
end
|
219
209
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
attr_reader :source_location
|
210
|
+
def block?
|
211
|
+
false
|
212
|
+
end
|
224
213
|
|
225
|
-
|
226
|
-
|
214
|
+
def inline?
|
215
|
+
false
|
216
|
+
end
|
217
|
+
end
|
227
218
|
|
228
|
-
|
229
|
-
|
219
|
+
# Public: Methods for managing the a cell in an AsciiDoc table.
|
220
|
+
class Table::Cell < AbstractBlock
|
221
|
+
DOUBLE_LF = LF * 2
|
230
222
|
|
231
223
|
# Public: An Integer of the number of columns this cell will span (default: nil)
|
232
224
|
attr_accessor :colspan
|
@@ -237,14 +229,23 @@ class Table::Cell < AbstractNode
|
|
237
229
|
# Public: An alias to the parent block (which is always a Column)
|
238
230
|
alias column parent
|
239
231
|
|
240
|
-
# Public:
|
232
|
+
# Public: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
|
241
233
|
attr_reader :inner_document
|
242
234
|
|
243
235
|
def initialize column, cell_text, attributes = {}, opts = {}
|
244
|
-
super column, :
|
236
|
+
super column, :table_cell
|
237
|
+
@cursor = @reinitialize_args = nil
|
245
238
|
@source_location = opts[:cursor].dup if @document.sourcemap
|
239
|
+
# NOTE: column is always set when parsing; may not be set when building table from the API
|
246
240
|
if column
|
247
|
-
|
241
|
+
if (in_header_row = column.table.header_row?)
|
242
|
+
if in_header_row == :implicit && (cell_style = column.style || (attributes && attributes['style']))
|
243
|
+
@reinitialize_args = [column, cell_text, attributes && attributes.merge, opts] if cell_style == :asciidoc || cell_style == :literal
|
244
|
+
cell_style = nil
|
245
|
+
end
|
246
|
+
else
|
247
|
+
cell_style = column.style
|
248
|
+
end
|
248
249
|
# REVIEW feels hacky to inherit all attributes from column
|
249
250
|
update_attributes column.attributes
|
250
251
|
end
|
@@ -258,7 +259,8 @@ class Table::Cell < AbstractNode
|
|
258
259
|
cell_style = attributes['style'] || cell_style unless in_header_row
|
259
260
|
update_attributes attributes
|
260
261
|
end
|
261
|
-
|
262
|
+
case cell_style
|
263
|
+
when :asciidoc
|
262
264
|
asciidoc = true
|
263
265
|
inner_document_cursor = opts[:cursor]
|
264
266
|
if (cell_text = cell_text.rstrip).start_with? LF
|
@@ -269,7 +271,8 @@ class Table::Cell < AbstractNode
|
|
269
271
|
else
|
270
272
|
cell_text = cell_text.lstrip
|
271
273
|
end
|
272
|
-
|
274
|
+
when :literal
|
275
|
+
literal = true
|
273
276
|
cell_text = cell_text.rstrip
|
274
277
|
# QUESTION should we use same logic as :asciidoc cell? strip leading space if text doesn't start with newline?
|
275
278
|
cell_text = cell_text.slice 1, cell_text.length while cell_text.start_with? LF
|
@@ -303,21 +306,46 @@ class Table::Cell < AbstractNode
|
|
303
306
|
inner_document_lines.unshift(*preprocessed_lines) unless preprocessed_lines.empty?
|
304
307
|
end
|
305
308
|
end unless inner_document_lines.empty?
|
306
|
-
@inner_document = Document.new
|
309
|
+
@inner_document = Document.new inner_document_lines, standalone: false, parent: @document, cursor: inner_document_cursor
|
307
310
|
@document.attributes['doctitle'] = parent_doctitle unless parent_doctitle.nil?
|
308
311
|
@subs = nil
|
309
312
|
elsif literal
|
313
|
+
@content_model = :verbatim
|
310
314
|
@subs = BASIC_SUBS
|
311
315
|
else
|
312
|
-
if normal_psv
|
313
|
-
|
316
|
+
if normal_psv
|
317
|
+
if in_header_row
|
318
|
+
@cursor = opts[:cursor] # used in deferred catalog_inline_anchor call
|
319
|
+
else
|
320
|
+
catalog_inline_anchor cell_text, opts[:cursor]
|
321
|
+
end
|
314
322
|
end
|
323
|
+
@content_model = :simple
|
315
324
|
@subs = NORMAL_SUBS
|
316
325
|
end
|
317
326
|
@text = cell_text
|
318
327
|
@style = cell_style
|
319
328
|
end
|
320
329
|
|
330
|
+
def reinitialize has_header
|
331
|
+
if has_header
|
332
|
+
@reinitialize_args = nil
|
333
|
+
elsif @reinitialize_args
|
334
|
+
return Table::Cell.new(*@reinitialize_args)
|
335
|
+
else
|
336
|
+
@style = @attributes['style']
|
337
|
+
end
|
338
|
+
catalog_inline_anchor if @cursor
|
339
|
+
self
|
340
|
+
end
|
341
|
+
|
342
|
+
def catalog_inline_anchor cell_text = @text, cursor = nil
|
343
|
+
cursor, @cursor = @cursor, nil unless cursor
|
344
|
+
if (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
|
345
|
+
Parser.catalog_inline_anchor $1, $2, self, cursor, @document
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
321
349
|
# Public: Get the String text of this cell with substitutions applied.
|
322
350
|
#
|
323
351
|
# Used for cells in the head row as well as text-only (non-AsciiDoc) cells in
|
@@ -330,30 +358,40 @@ class Table::Cell < AbstractNode
|
|
330
358
|
apply_subs @text, @subs
|
331
359
|
end
|
332
360
|
|
333
|
-
# Public: Set the String text.
|
361
|
+
# Public: Set the String text for this cell.
|
334
362
|
#
|
335
363
|
# This method shouldn't be used for cells that have the AsciiDoc style.
|
336
|
-
|
337
|
-
# Returns the new String text assigned to this Cell
|
338
|
-
def text= val
|
339
|
-
@text = val
|
340
|
-
end
|
364
|
+
attr_writer :text
|
341
365
|
|
342
366
|
# Public: Handles the body data (tbody, tfoot), applying styles and partitioning into paragraphs
|
343
367
|
#
|
344
|
-
# This method should not be used for cells in the head row or that have the literal
|
368
|
+
# This method should not be used for cells in the head row or that have the literal style.
|
345
369
|
#
|
346
370
|
# Returns the converted String for this Cell
|
347
371
|
def content
|
348
|
-
if @style == :asciidoc
|
372
|
+
if (cell_style = @style) == :asciidoc
|
349
373
|
@inner_document.convert
|
350
|
-
|
351
|
-
text.split
|
352
|
-
|
374
|
+
elsif @text.include? DOUBLE_LF
|
375
|
+
(text.split BlankLineRx).map do |para|
|
376
|
+
cell_style && cell_style != :header ? (Inline.new parent, :quoted, para, type: cell_style).convert : para
|
353
377
|
end
|
378
|
+
elsif (subbed_text = text).empty?
|
379
|
+
[]
|
380
|
+
elsif cell_style && cell_style != :header
|
381
|
+
[(Inline.new parent, :quoted, subbed_text, type: cell_style).convert]
|
382
|
+
else
|
383
|
+
[subbed_text]
|
354
384
|
end
|
355
385
|
end
|
356
386
|
|
387
|
+
def lines
|
388
|
+
@text.split LF
|
389
|
+
end
|
390
|
+
|
391
|
+
def source
|
392
|
+
@text
|
393
|
+
end
|
394
|
+
|
357
395
|
# Public: Get the source file where this block started
|
358
396
|
def file
|
359
397
|
@source_location && @source_location.file
|
@@ -365,7 +403,7 @@ class Table::Cell < AbstractNode
|
|
365
403
|
end
|
366
404
|
|
367
405
|
def to_s
|
368
|
-
|
406
|
+
%(#{super} - [text: #{@text}, colspan: #{@colspan || 1}, rowspan: #{@rowspan || 1}, attributes: #{@attributes}])
|
369
407
|
end
|
370
408
|
end
|
371
409
|
|
@@ -373,7 +411,7 @@ end
|
|
373
411
|
# class are primarily responsible for tracking the buffer of a cell as the parser
|
374
412
|
# moves through the lines of the table using tail recursion. When a cell boundary
|
375
413
|
# is located, the previous cell is closed, an instance of Table::Cell is
|
376
|
-
# instantiated, the row is closed if the cell
|
414
|
+
# instantiated, the row is closed if the cell satisfies the column count and,
|
377
415
|
# finally, a new buffer is allocated to track the next cell.
|
378
416
|
class Table::ParserContext
|
379
417
|
include Logging
|
@@ -388,8 +426,8 @@ class Table::ParserContext
|
|
388
426
|
'psv' => ['|', /\|/],
|
389
427
|
'csv' => [',', /,/],
|
390
428
|
'dsv' => [':', /:/],
|
391
|
-
'tsv' => [
|
392
|
-
'!sv' => ['!', /!/]
|
429
|
+
'tsv' => [?\t, /\t/],
|
430
|
+
'!sv' => ['!', /!/],
|
393
431
|
}
|
394
432
|
|
395
433
|
# Public: The Table currently being parsed
|
@@ -427,7 +465,7 @@ class Table::ParserContext
|
|
427
465
|
xsv = '!sv'
|
428
466
|
end
|
429
467
|
else
|
430
|
-
logger.error message_with_context %(illegal table format: #{xsv}), :
|
468
|
+
logger.error message_with_context %(illegal table format: #{xsv}), source_location: reader.cursor_at_prev_line
|
431
469
|
@format, xsv = 'psv', (table.document.nested? ? '!sv' : 'psv')
|
432
470
|
end
|
433
471
|
else
|
@@ -436,15 +474,15 @@ class Table::ParserContext
|
|
436
474
|
|
437
475
|
if attributes.key? 'separator'
|
438
476
|
if (sep = attributes['separator']).nil_or_empty?
|
439
|
-
@delimiter, @
|
477
|
+
@delimiter, @delimiter_rx = DELIMITERS[xsv]
|
440
478
|
# QUESTION should we support any other escape codes or multiple tabs?
|
441
479
|
elsif sep == '\t'
|
442
|
-
@delimiter, @
|
480
|
+
@delimiter, @delimiter_rx = DELIMITERS['tsv']
|
443
481
|
else
|
444
|
-
@delimiter, @
|
482
|
+
@delimiter, @delimiter_rx = sep, /#{::Regexp.escape sep}/
|
445
483
|
end
|
446
484
|
else
|
447
|
-
@delimiter, @
|
485
|
+
@delimiter, @delimiter_rx = DELIMITERS[xsv]
|
448
486
|
end
|
449
487
|
|
450
488
|
@colcount = table.columns.empty? ? -1 : table.columns.size
|
@@ -470,7 +508,7 @@ class Table::ParserContext
|
|
470
508
|
#
|
471
509
|
# returns Regexp MatchData if the line contains the delimiter, false otherwise
|
472
510
|
def match_delimiter(line)
|
473
|
-
@
|
511
|
+
@delimiter_rx.match(line)
|
474
512
|
end
|
475
513
|
|
476
514
|
# Public: Skip past the matched delimiter because it's inside quoted text.
|
@@ -493,12 +531,13 @@ class Table::ParserContext
|
|
493
531
|
#
|
494
532
|
# returns true if the buffer has unclosed quotes, false if it doesn't or it
|
495
533
|
# isn't quoted data
|
496
|
-
def buffer_has_unclosed_quotes? append = nil
|
497
|
-
if (record = append ? (@buffer + append).strip : @buffer.strip) ==
|
534
|
+
def buffer_has_unclosed_quotes? append = nil, q = '"'
|
535
|
+
if (record = append ? (@buffer + append).strip : @buffer.strip) == q
|
498
536
|
true
|
499
|
-
elsif record.start_with?
|
500
|
-
|
501
|
-
|
537
|
+
elsif record.start_with? q
|
538
|
+
qq = q + q
|
539
|
+
if ((trailing_quote = record.end_with? q) && (record.end_with? qq)) || (record.start_with? qq)
|
540
|
+
((record = record.gsub qq, '').start_with? q) && !(record.end_with? q)
|
502
541
|
else
|
503
542
|
!trailing_quote
|
504
543
|
end
|
@@ -582,7 +621,7 @@ class Table::ParserContext
|
|
582
621
|
if (cellspec = take_cellspec)
|
583
622
|
repeat = cellspec.delete('repeatcol') || 1
|
584
623
|
else
|
585
|
-
logger.error message_with_context 'table missing leading separator; recovering automatically', :
|
624
|
+
logger.error message_with_context 'table missing leading separator; recovering automatically', source_location: Reader::Cursor.new(*@start_cursor_data)
|
586
625
|
cellspec = {}
|
587
626
|
repeat = 1
|
588
627
|
end
|
@@ -591,20 +630,20 @@ class Table::ParserContext
|
|
591
630
|
@buffer = ''
|
592
631
|
cellspec = nil
|
593
632
|
repeat = 1
|
594
|
-
if @format == 'csv' && !cell_text.empty? && cell_text.include?('"')
|
633
|
+
if @format == 'csv' && !cell_text.empty? && (cell_text.include? (q = '"'))
|
595
634
|
# this may not be perfect logic, but it hits the 99%
|
596
|
-
if cell_text.start_with?
|
635
|
+
if (cell_text.start_with? q) && (cell_text.end_with? q)
|
597
636
|
# unquote
|
598
637
|
if (cell_text = cell_text.slice(1, cell_text.length - 2))
|
599
638
|
# trim whitespace and collapse escaped quotes
|
600
|
-
cell_text = cell_text.strip.squeeze
|
639
|
+
cell_text = cell_text.strip.squeeze q
|
601
640
|
else
|
602
|
-
logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', :
|
641
|
+
logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', source_location: @reader.cursor_at_prev_line
|
603
642
|
cell_text = ''
|
604
643
|
end
|
605
644
|
else
|
606
645
|
# collapse escaped quotes
|
607
|
-
cell_text = cell_text.squeeze
|
646
|
+
cell_text = cell_text.squeeze q
|
608
647
|
end
|
609
648
|
end
|
610
649
|
end
|
@@ -622,12 +661,12 @@ class Table::ParserContext
|
|
622
661
|
else
|
623
662
|
# QUESTION is this right for cells that span columns?
|
624
663
|
unless (column = @table.columns[@current_row.size])
|
625
|
-
logger.error message_with_context 'dropping cell because it exceeds specified number of columns', :
|
626
|
-
return
|
664
|
+
logger.error message_with_context 'dropping cell because it exceeds specified number of columns', source_location: @reader.cursor_before_mark
|
665
|
+
return nil
|
627
666
|
end
|
628
667
|
end
|
629
668
|
|
630
|
-
cell = Table::Cell.new(column, cell_text, cellspec, :
|
669
|
+
cell = Table::Cell.new(column, cell_text, cellspec, cursor: @reader.cursor_before_mark)
|
631
670
|
@reader.mark
|
632
671
|
unless !cell.rowspan || cell.rowspan == 1
|
633
672
|
activate_rowspan(cell.rowspan, (cell.colspan || 1))
|
@@ -642,7 +681,9 @@ class Table::ParserContext
|
|
642
681
|
nil
|
643
682
|
end
|
644
683
|
|
645
|
-
|
684
|
+
private
|
685
|
+
|
686
|
+
# Internal: Close the row by adding it to the Table and resetting the row
|
646
687
|
# Array and counter variables.
|
647
688
|
#
|
648
689
|
# returns nothing
|
@@ -658,24 +699,21 @@ class Table::ParserContext
|
|
658
699
|
nil
|
659
700
|
end
|
660
701
|
|
661
|
-
#
|
702
|
+
# Internal: Activate a rowspan. The rowspan Array is consulted when
|
662
703
|
# determining the effective number of cells in the current row.
|
663
704
|
#
|
664
705
|
# returns nothing
|
665
706
|
def activate_rowspan(rowspan, colspan)
|
666
|
-
1.upto(rowspan - 1)
|
667
|
-
# longhand assignment used for Opal compatibility
|
668
|
-
@active_rowspans[i] = (@active_rowspans[i] || 0) + colspan
|
669
|
-
}
|
707
|
+
1.upto(rowspan - 1) {|i| @active_rowspans[i] = (@active_rowspans[i] || 0) + colspan }
|
670
708
|
nil
|
671
709
|
end
|
672
710
|
|
673
|
-
#
|
711
|
+
# Internal: Check whether we've met the number of effective columns for the current row.
|
674
712
|
def end_of_row?
|
675
713
|
@colcount == -1 || effective_column_visits == @colcount
|
676
714
|
end
|
677
715
|
|
678
|
-
#
|
716
|
+
# Internal: Calculate the effective column visits, which consists of the number of
|
679
717
|
# cells plus any active rowspans.
|
680
718
|
def effective_column_visits
|
681
719
|
@column_visits + @active_rowspans[0]
|
data/lib/asciidoctor/timings.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
class Timings
|
4
4
|
def initialize
|
@@ -49,12 +49,14 @@ module Asciidoctor
|
|
49
49
|
|
50
50
|
def print_report to = $stdout, subject = nil
|
51
51
|
to.puts %(Input file: #{subject}) if subject
|
52
|
-
to.puts %( Time to read and parse source: #{'%05.5f'
|
53
|
-
to.puts %( Time to convert document: #{'%05.5f'
|
54
|
-
to.puts %( Total time (read, parse and convert): #{'%05.5f'
|
52
|
+
to.puts %( Time to read and parse source: #{sprintf '%05.5f', read_parse.to_f})
|
53
|
+
to.puts %( Time to convert document: #{sprintf '%05.5f', convert.to_f})
|
54
|
+
to.puts %( Total time (read, parse and convert): #{sprintf '%05.5f', read_parse_convert.to_f})
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
private
|
58
|
+
|
59
|
+
if (::Process.const_defined? :CLOCK_MONOTONIC, false) && (defined? ::Process.clock_gettime) == 'method'
|
58
60
|
CLOCK_ID = ::Process::CLOCK_MONOTONIC
|
59
61
|
def now
|
60
62
|
::Process.clock_gettime CLOCK_ID
|
data/lib/asciidoctor/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Asciidoctor
|
3
|
+
# A module that can be used to mix the {#write} method into a {Converter} implementation to allow the converter to
|
4
|
+
# control how the output is written to disk.
|
5
|
+
module Writer
|
6
|
+
# Public: Writes the output to the specified target file name or stream.
|
7
|
+
#
|
8
|
+
# output - The output String to write
|
9
|
+
# target - The String file name or stream object to which the output should be written.
|
10
|
+
#
|
11
|
+
# Returns nothing
|
12
|
+
def write output, target
|
13
|
+
if target.respond_to? :write
|
14
|
+
# ensure there's a trailing newline to be nice to terminals
|
15
|
+
target.write output.chomp + LF
|
16
|
+
else
|
17
|
+
# QUESTION shouldn't we ensure a trailing newline here too?
|
18
|
+
::File.write target, output, mode: FILE_WRITE_MODE
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module VoidWriter
|
25
|
+
include Writer
|
26
|
+
|
27
|
+
# Public: Does not write output
|
28
|
+
def write output, target; end
|
29
|
+
end
|
30
|
+
end
|