asciidoctor 1.5.8 → 2.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +162 -17
- data/LICENSE +1 -1
- data/README-de.adoc +12 -13
- data/README-fr.adoc +11 -12
- data/README-jp.adoc +11 -12
- data/README-zh_CN.adoc +12 -13
- data/README.adoc +6 -7
- data/asciidoctor.gemspec +19 -24
- data/bin/asciidoctor +5 -4
- data/data/reference/syntax.adoc +283 -0
- data/data/stylesheets/asciidoctor-default.css +56 -52
- data/data/stylesheets/coderay-asciidoctor.css +7 -9
- data/lib/asciidoctor.rb +171 -232
- data/lib/asciidoctor/abstract_block.rb +96 -105
- data/lib/asciidoctor/abstract_node.rb +118 -139
- data/lib/asciidoctor/attribute_list.rb +10 -14
- data/lib/asciidoctor/block.rb +20 -19
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/cli/invoker.rb +14 -21
- data/lib/asciidoctor/cli/options.rb +64 -54
- data/lib/asciidoctor/converter.rb +357 -185
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +604 -640
- data/lib/asciidoctor/converter/html5.rb +949 -963
- data/lib/asciidoctor/converter/manpage.rb +569 -548
- data/lib/asciidoctor/converter/template.rb +231 -272
- data/lib/asciidoctor/core_ext.rb +5 -18
- data/lib/asciidoctor/core_ext/float/truncate.rb +19 -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/document.rb +399 -377
- data/lib/asciidoctor/extensions.rb +72 -140
- data/lib/asciidoctor/helpers.rb +122 -83
- data/lib/asciidoctor/inline.rb +5 -1
- data/lib/asciidoctor/list.rb +13 -11
- data/lib/asciidoctor/logging.rb +17 -16
- data/lib/asciidoctor/parser.rb +390 -423
- data/lib/asciidoctor/path_resolver.rb +10 -5
- data/lib/asciidoctor/reader.rb +286 -263
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/section.rb +9 -8
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +364 -509
- data/lib/asciidoctor/syntax_highlighter.rb +238 -0
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
- data/lib/asciidoctor/table.rb +73 -66
- data/lib/asciidoctor/timings.rb +4 -2
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/man/asciidoctor.1 +19 -15
- data/man/asciidoctor.adoc +14 -12
- metadata +69 -216
- 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-tweaks/block_paragraph.html.haml +0 -1
- 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/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
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Asciidoctor
|
3
|
+
class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
|
4
|
+
register_for 'rouge'
|
5
|
+
|
6
|
+
def initialize *args
|
7
|
+
super
|
8
|
+
@requires_stylesheet = nil
|
9
|
+
@style = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def highlight?
|
13
|
+
library_available?
|
14
|
+
end
|
15
|
+
|
16
|
+
def highlight node, source, lang, opts
|
17
|
+
lexer = (::Rouge::Lexer.find_fancy lang) || ::Rouge::Lexers::PlainText
|
18
|
+
lexer_opts = lexer.tag == 'php' && !(node.option? 'mixed') ? { start_inline: true } : {}
|
19
|
+
@style ||= (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE
|
20
|
+
if opts[:css_mode] == :class
|
21
|
+
@requires_stylesheet = true
|
22
|
+
formatter = ::Rouge::Formatters::HTML.new @style
|
23
|
+
else
|
24
|
+
formatter = ::Rouge::Formatters::HTMLInline.new @style
|
25
|
+
end
|
26
|
+
if (highlight_lines = opts[:highlight_lines])
|
27
|
+
formatter = RougeExt::Formatters::HTMLLineHighlighter.new formatter, lines: highlight_lines
|
28
|
+
end
|
29
|
+
if opts[:number_lines]
|
30
|
+
formatter = RougeExt::Formatters::HTMLTable.new formatter, start_line: opts[:start_line_number]
|
31
|
+
if opts[:callouts]
|
32
|
+
return [(highlighted = formatter.format lexer.lex source, lexer_opts), (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
formatter.format lexer.lex source, lexer_opts
|
36
|
+
end
|
37
|
+
|
38
|
+
def format node, lang, opts
|
39
|
+
if (query_idx = lang.index '?')
|
40
|
+
lang = lang.slice 0, query_idx
|
41
|
+
end
|
42
|
+
if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) &&
|
43
|
+
(pre_style_attr_val = base_style @style)
|
44
|
+
opts[:transform] = proc {|pre| pre['style'] = pre_style_attr_val }
|
45
|
+
end
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def docinfo? location
|
50
|
+
@requires_stylesheet && location == :footer
|
51
|
+
end
|
52
|
+
|
53
|
+
def docinfo location, doc, opts
|
54
|
+
if opts[:linkcss]
|
55
|
+
%(<link rel="stylesheet" href="#{doc.normalize_web_path (stylesheet_basename @style), (doc.attr 'stylesdir', ''), false}"#{opts[:self_closing_tag_slash]}>)
|
56
|
+
else
|
57
|
+
%(<style>
|
58
|
+
#{read_stylesheet @style}
|
59
|
+
</style>)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def write_stylesheet? doc
|
64
|
+
@requires_stylesheet
|
65
|
+
end
|
66
|
+
|
67
|
+
def write_stylesheet doc, to_dir
|
68
|
+
::File.write (::File.join to_dir, (stylesheet_basename @style)), (read_stylesheet @style), mode: FILE_WRITE_MODE
|
69
|
+
end
|
70
|
+
|
71
|
+
module Loader
|
72
|
+
private
|
73
|
+
|
74
|
+
def library_available?
|
75
|
+
(@@library_status ||= load_library) == :loaded ? true : nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_library
|
79
|
+
(defined? RougeExt) ? :loaded : (Helpers.require_library %(#{::File.dirname __dir__}/rouge_ext), 'rouge', :warn).nil? ? :unavailable : :loaded
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module Styles
|
84
|
+
include Loader
|
85
|
+
|
86
|
+
def read_stylesheet style
|
87
|
+
library_available? ? @@stylesheet_cache[style || DEFAULT_STYLE] : '/* Rouge CSS disabled because Rouge is not available. */'
|
88
|
+
end
|
89
|
+
|
90
|
+
def stylesheet_basename style
|
91
|
+
%(rouge-#{style || DEFAULT_STYLE}.css)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def base_style style
|
97
|
+
library_available? ? @@base_style_cache[style || DEFAULT_STYLE] : nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def style_available? style
|
101
|
+
(::Rouge::Theme.find style) && style
|
102
|
+
end
|
103
|
+
|
104
|
+
@@base_style_cache = ::Hash.new do |cache, key|
|
105
|
+
base_style = (theme = ::Rouge::Theme.find key).base_style
|
106
|
+
(val = base_style[:fg]) && ((style ||= []) << %(color: #{theme.palette val}))
|
107
|
+
(val = base_style[:bg]) && ((style ||= []) << %(background-color: #{theme.palette val}))
|
108
|
+
@@base_style_cache = cache.merge key => (resolved_base_style = style && (style.join ';'))
|
109
|
+
resolved_base_style
|
110
|
+
end
|
111
|
+
@@stylesheet_cache = ::Hash.new do |cache, key|
|
112
|
+
@@stylesheet_cache = cache.merge key => (stylesheet = ((::Rouge::Theme.find key).render scope: BASE_SELECTOR))
|
113
|
+
stylesheet
|
114
|
+
end
|
115
|
+
|
116
|
+
DEFAULT_STYLE = 'github'
|
117
|
+
BASE_SELECTOR = 'pre.rouge'
|
118
|
+
|
119
|
+
private_constant :BASE_SELECTOR
|
120
|
+
end
|
121
|
+
|
122
|
+
extend Styles # exports static methods
|
123
|
+
include Loader, Styles # adds methods to instance
|
124
|
+
|
125
|
+
CodeCellStartTagCs = '<td class="code">'
|
126
|
+
|
127
|
+
private_constant :CodeCellStartTagCs
|
128
|
+
end
|
129
|
+
end
|
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 = attributes
|
61
|
+
@has_header_option = attributes['header-option'] ? true : false
|
52
62
|
|
53
63
|
# smells like we need a utility method here
|
54
64
|
# to resolve an integer width from potential bogus input
|
@@ -67,7 +77,7 @@ class Table < AbstractBlock
|
|
67
77
|
((@attributes['tablepcwidth'].to_f / 100) * @document.attributes['pagewidth']).round
|
68
78
|
end
|
69
79
|
|
70
|
-
attributes['orientation'] = 'landscape' if attributes
|
80
|
+
attributes['orientation'] = 'landscape' if attributes['rotate-option']
|
71
81
|
end
|
72
82
|
|
73
83
|
# Internal: Returns whether the current row being processed is
|
@@ -111,7 +121,7 @@ class Table < AbstractBlock
|
|
111
121
|
#
|
112
122
|
# returns nothing
|
113
123
|
def assign_column_widths width_base = nil, autowidth_cols = nil
|
114
|
-
|
124
|
+
precision = DEFAULT_PRECISION
|
115
125
|
total_width = col_pcwidth = 0
|
116
126
|
|
117
127
|
if width_base
|
@@ -120,32 +130,22 @@ class Table < AbstractBlock
|
|
120
130
|
autowidth = 0
|
121
131
|
logger.warn %(total column width must not exceed 100% when using autowidth columns; got #{width_base}%)
|
122
132
|
else
|
123
|
-
autowidth = ((100.0 - width_base) / autowidth_cols.size
|
133
|
+
autowidth = ((100.0 - width_base) / autowidth_cols.size).truncate precision
|
124
134
|
autowidth = autowidth.to_i if autowidth.to_i == autowidth
|
125
135
|
width_base = 100
|
126
136
|
end
|
127
137
|
autowidth_attrs = { 'width' => autowidth, 'autowidth-option' => '' }
|
128
138
|
autowidth_cols.each {|col| col.update_attributes autowidth_attrs }
|
129
139
|
end
|
130
|
-
@columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base,
|
140
|
+
@columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, precision) }
|
131
141
|
else
|
132
|
-
col_pcwidth = (
|
133
|
-
# or...
|
134
|
-
#col_pcwidth = (100.0 / @columns.size).truncate 4
|
142
|
+
col_pcwidth = (100.0 / @columns.size).truncate precision
|
135
143
|
col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
|
136
|
-
@columns.each {|col| total_width += col.assign_width col_pcwidth }
|
144
|
+
@columns.each {|col| total_width += col.assign_width col_pcwidth, nil, precision }
|
137
145
|
end
|
138
146
|
|
139
147
|
# 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
|
148
|
+
@columns[-1].assign_width(((100 - total_width + col_pcwidth).round precision), nil, precision) unless total_width == 100
|
149
149
|
|
150
150
|
nil
|
151
151
|
end
|
@@ -169,7 +169,7 @@ class Table < AbstractBlock
|
|
169
169
|
@rows.head = [head]
|
170
170
|
end
|
171
171
|
|
172
|
-
if num_body_rows > 0 && attrs
|
172
|
+
if num_body_rows > 0 && attrs['footer-option']
|
173
173
|
@rows.foot = [@rows.body.pop]
|
174
174
|
end
|
175
175
|
|
@@ -180,11 +180,11 @@ end
|
|
180
180
|
# Public: Methods to manage the columns of an AsciiDoc table. In particular, it
|
181
181
|
# keeps track of the column specs
|
182
182
|
class Table::Column < AbstractNode
|
183
|
-
# Public: Get/Set the Symbol
|
183
|
+
# Public: Get/Set the style Symbol for this column.
|
184
184
|
attr_accessor :style
|
185
185
|
|
186
186
|
def initialize table, index, attributes = {}
|
187
|
-
super table, :
|
187
|
+
super table, :table_column
|
188
188
|
@style = attributes['style']
|
189
189
|
attributes['colnumber'] = index + 1
|
190
190
|
attributes['width'] ||= 1
|
@@ -201,11 +201,9 @@ class Table::Column < AbstractNode
|
|
201
201
|
# This method assigns the colpcwidth and colabswidth attributes.
|
202
202
|
#
|
203
203
|
# returns the resolved colpcwidth value
|
204
|
-
def assign_width col_pcwidth, width_base
|
204
|
+
def assign_width col_pcwidth, width_base, precision
|
205
205
|
if width_base
|
206
|
-
col_pcwidth = (
|
207
|
-
# or...
|
208
|
-
#col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate 4
|
206
|
+
col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate precision
|
209
207
|
col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
|
210
208
|
end
|
211
209
|
@attributes['colpcwidth'] = col_pcwidth
|
@@ -215,18 +213,19 @@ class Table::Column < AbstractNode
|
|
215
213
|
end
|
216
214
|
col_pcwidth
|
217
215
|
end
|
218
|
-
end
|
219
216
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
attr_reader :source_location
|
217
|
+
def block?
|
218
|
+
false
|
219
|
+
end
|
224
220
|
|
225
|
-
|
226
|
-
|
221
|
+
def inline?
|
222
|
+
false
|
223
|
+
end
|
224
|
+
end
|
227
225
|
|
228
|
-
|
229
|
-
|
226
|
+
# Public: Methods for managing the a cell in an AsciiDoc table.
|
227
|
+
class Table::Cell < AbstractBlock
|
228
|
+
DOUBLE_LF = LF * 2
|
230
229
|
|
231
230
|
# Public: An Integer of the number of columns this cell will span (default: nil)
|
232
231
|
attr_accessor :colspan
|
@@ -237,11 +236,11 @@ class Table::Cell < AbstractNode
|
|
237
236
|
# Public: An alias to the parent block (which is always a Column)
|
238
237
|
alias column parent
|
239
238
|
|
240
|
-
#
|
239
|
+
# Internal: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
|
241
240
|
attr_reader :inner_document
|
242
241
|
|
243
242
|
def initialize column, cell_text, attributes = {}, opts = {}
|
244
|
-
super column, :
|
243
|
+
super column, :table_cell
|
245
244
|
@source_location = opts[:cursor].dup if @document.sourcemap
|
246
245
|
if column
|
247
246
|
cell_style = column.attributes['style'] unless (in_header_row = column.table.header_row?)
|
@@ -269,7 +268,8 @@ class Table::Cell < AbstractNode
|
|
269
268
|
else
|
270
269
|
cell_text = cell_text.lstrip
|
271
270
|
end
|
272
|
-
elsif
|
271
|
+
elsif cell_style == :literal
|
272
|
+
literal = true
|
273
273
|
cell_text = cell_text.rstrip
|
274
274
|
# QUESTION should we use same logic as :asciidoc cell? strip leading space if text doesn't start with newline?
|
275
275
|
cell_text = cell_text.slice 1, cell_text.length while cell_text.start_with? LF
|
@@ -303,15 +303,17 @@ class Table::Cell < AbstractNode
|
|
303
303
|
inner_document_lines.unshift(*preprocessed_lines) unless preprocessed_lines.empty?
|
304
304
|
end
|
305
305
|
end unless inner_document_lines.empty?
|
306
|
-
@inner_document = Document.new(inner_document_lines, :
|
306
|
+
@inner_document = Document.new(inner_document_lines, header_footer: false, parent: @document, cursor: inner_document_cursor)
|
307
307
|
@document.attributes['doctitle'] = parent_doctitle unless parent_doctitle.nil?
|
308
308
|
@subs = nil
|
309
309
|
elsif literal
|
310
|
+
@content_model = :verbatim
|
310
311
|
@subs = BASIC_SUBS
|
311
312
|
else
|
312
313
|
if normal_psv && (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
|
313
314
|
Parser.catalog_inline_anchor $1, $2, self, opts[:cursor], @document
|
314
315
|
end
|
316
|
+
@content_model = :simple
|
315
317
|
@subs = NORMAL_SUBS
|
316
318
|
end
|
317
319
|
@text = cell_text
|
@@ -345,12 +347,18 @@ class Table::Cell < AbstractNode
|
|
345
347
|
#
|
346
348
|
# Returns the converted String for this Cell
|
347
349
|
def content
|
348
|
-
if @style == :asciidoc
|
350
|
+
if (cell_style = @style) == :asciidoc
|
349
351
|
@inner_document.convert
|
350
|
-
|
351
|
-
text.split
|
352
|
-
|
352
|
+
elsif @text.include? DOUBLE_LF
|
353
|
+
(text.split BlankLineRx).map do |para|
|
354
|
+
cell_style && cell_style != :header ? (Inline.new parent, :quoted, para, type: cell_style).convert : para
|
353
355
|
end
|
356
|
+
elsif (subbed_text = text).empty?
|
357
|
+
[]
|
358
|
+
elsif cell_style && cell_style != :header
|
359
|
+
[(Inline.new parent, :quoted, subbed_text, type: cell_style).convert]
|
360
|
+
else
|
361
|
+
[subbed_text]
|
354
362
|
end
|
355
363
|
end
|
356
364
|
|
@@ -388,8 +396,8 @@ class Table::ParserContext
|
|
388
396
|
'psv' => ['|', /\|/],
|
389
397
|
'csv' => [',', /,/],
|
390
398
|
'dsv' => [':', /:/],
|
391
|
-
'tsv' => [
|
392
|
-
'!sv' => ['!', /!/]
|
399
|
+
'tsv' => [?\t, /\t/],
|
400
|
+
'!sv' => ['!', /!/],
|
393
401
|
}
|
394
402
|
|
395
403
|
# Public: The Table currently being parsed
|
@@ -427,7 +435,7 @@ class Table::ParserContext
|
|
427
435
|
xsv = '!sv'
|
428
436
|
end
|
429
437
|
else
|
430
|
-
logger.error message_with_context %(illegal table format: #{xsv}), :
|
438
|
+
logger.error message_with_context %(illegal table format: #{xsv}), source_location: reader.cursor_at_prev_line
|
431
439
|
@format, xsv = 'psv', (table.document.nested? ? '!sv' : 'psv')
|
432
440
|
end
|
433
441
|
else
|
@@ -436,15 +444,15 @@ class Table::ParserContext
|
|
436
444
|
|
437
445
|
if attributes.key? 'separator'
|
438
446
|
if (sep = attributes['separator']).nil_or_empty?
|
439
|
-
@delimiter, @
|
447
|
+
@delimiter, @delimiter_rx = DELIMITERS[xsv]
|
440
448
|
# QUESTION should we support any other escape codes or multiple tabs?
|
441
449
|
elsif sep == '\t'
|
442
|
-
@delimiter, @
|
450
|
+
@delimiter, @delimiter_rx = DELIMITERS['tsv']
|
443
451
|
else
|
444
|
-
@delimiter, @
|
452
|
+
@delimiter, @delimiter_rx = sep, /#{::Regexp.escape sep}/
|
445
453
|
end
|
446
454
|
else
|
447
|
-
@delimiter, @
|
455
|
+
@delimiter, @delimiter_rx = DELIMITERS[xsv]
|
448
456
|
end
|
449
457
|
|
450
458
|
@colcount = table.columns.empty? ? -1 : table.columns.size
|
@@ -470,7 +478,7 @@ class Table::ParserContext
|
|
470
478
|
#
|
471
479
|
# returns Regexp MatchData if the line contains the delimiter, false otherwise
|
472
480
|
def match_delimiter(line)
|
473
|
-
@
|
481
|
+
@delimiter_rx.match(line)
|
474
482
|
end
|
475
483
|
|
476
484
|
# Public: Skip past the matched delimiter because it's inside quoted text.
|
@@ -582,7 +590,7 @@ class Table::ParserContext
|
|
582
590
|
if (cellspec = take_cellspec)
|
583
591
|
repeat = cellspec.delete('repeatcol') || 1
|
584
592
|
else
|
585
|
-
logger.error message_with_context 'table missing leading separator; recovering automatically', :
|
593
|
+
logger.error message_with_context 'table missing leading separator; recovering automatically', source_location: Reader::Cursor.new(*@start_cursor_data)
|
586
594
|
cellspec = {}
|
587
595
|
repeat = 1
|
588
596
|
end
|
@@ -599,7 +607,7 @@ class Table::ParserContext
|
|
599
607
|
# trim whitespace and collapse escaped quotes
|
600
608
|
cell_text = cell_text.strip.squeeze('"')
|
601
609
|
else
|
602
|
-
logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', :
|
610
|
+
logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', source_location: @reader.cursor_at_prev_line
|
603
611
|
cell_text = ''
|
604
612
|
end
|
605
613
|
else
|
@@ -622,12 +630,12 @@ class Table::ParserContext
|
|
622
630
|
else
|
623
631
|
# QUESTION is this right for cells that span columns?
|
624
632
|
unless (column = @table.columns[@current_row.size])
|
625
|
-
logger.error message_with_context 'dropping cell because it exceeds specified number of columns', :
|
633
|
+
logger.error message_with_context 'dropping cell because it exceeds specified number of columns', source_location: @reader.cursor_before_mark
|
626
634
|
return
|
627
635
|
end
|
628
636
|
end
|
629
637
|
|
630
|
-
cell = Table::Cell.new(column, cell_text, cellspec, :
|
638
|
+
cell = Table::Cell.new(column, cell_text, cellspec, cursor: @reader.cursor_before_mark)
|
631
639
|
@reader.mark
|
632
640
|
unless !cell.rowspan || cell.rowspan == 1
|
633
641
|
activate_rowspan(cell.rowspan, (cell.colspan || 1))
|
@@ -642,7 +650,9 @@ class Table::ParserContext
|
|
642
650
|
nil
|
643
651
|
end
|
644
652
|
|
645
|
-
|
653
|
+
private
|
654
|
+
|
655
|
+
# Internal: Close the row by adding it to the Table and resetting the row
|
646
656
|
# Array and counter variables.
|
647
657
|
#
|
648
658
|
# returns nothing
|
@@ -658,24 +668,21 @@ class Table::ParserContext
|
|
658
668
|
nil
|
659
669
|
end
|
660
670
|
|
661
|
-
#
|
671
|
+
# Internal: Activate a rowspan. The rowspan Array is consulted when
|
662
672
|
# determining the effective number of cells in the current row.
|
663
673
|
#
|
664
674
|
# returns nothing
|
665
675
|
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
|
-
}
|
676
|
+
1.upto(rowspan - 1) {|i| @active_rowspans[i] = (@active_rowspans[i] || 0) + colspan }
|
670
677
|
nil
|
671
678
|
end
|
672
679
|
|
673
|
-
#
|
680
|
+
# Internal: Check whether we've met the number of effective columns for the current row.
|
674
681
|
def end_of_row?
|
675
682
|
@colcount == -1 || effective_column_visits == @colcount
|
676
683
|
end
|
677
684
|
|
678
|
-
#
|
685
|
+
# Internal: Calculate the effective column visits, which consists of the number of
|
679
686
|
# cells plus any active rowspans.
|
680
687
|
def effective_column_visits
|
681
688
|
@column_visits + @active_rowspans[0]
|