asciidoctor 2.0.10 → 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/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
@@ -32,7 +32,7 @@ class SyntaxHighlighter::CodeRayAdapter < SyntaxHighlighter::Base
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def docinfo? location
|
35
|
-
@requires_stylesheet && location == :
|
35
|
+
@requires_stylesheet && location == :head
|
36
36
|
end
|
37
37
|
|
38
38
|
def docinfo location, doc, opts
|
@@ -78,7 +78,8 @@ class SyntaxHighlighter::CodeRayAdapter < SyntaxHighlighter::Base
|
|
78
78
|
end
|
79
79
|
|
80
80
|
extend Styles # exports static methods
|
81
|
-
include
|
81
|
+
include Styles # adds methods to instance
|
82
|
+
include Loader # adds methods to instance
|
82
83
|
|
83
84
|
CodeCellStartTagCs = '<td class="code"><pre>'
|
84
85
|
|
@@ -9,18 +9,26 @@ class SyntaxHighlighter::HighlightJsAdapter < SyntaxHighlighter::Base
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def format node, lang, opts
|
12
|
-
super node, lang, (opts.merge transform: proc {|_, code| code['class'] = %(language-#{lang || 'none'} hljs) }
|
12
|
+
super node, lang, (opts.merge transform: proc {|_, code| code['class'] = %(language-#{lang || 'none'} hljs) })
|
13
13
|
end
|
14
14
|
|
15
15
|
def docinfo? location
|
16
|
-
|
16
|
+
true
|
17
17
|
end
|
18
18
|
|
19
19
|
def docinfo location, doc, opts
|
20
20
|
base_url = doc.attr 'highlightjsdir', %(#{opts[:cdn_base_url]}/highlight.js/#{HIGHLIGHT_JS_VERSION})
|
21
|
-
|
22
|
-
<
|
23
|
-
|
21
|
+
if location == :head
|
22
|
+
%(<link rel="stylesheet" href="#{base_url}/styles/#{doc.attr 'highlightjs-theme', 'github'}.min.css"#{opts[:self_closing_tag_slash]}>)
|
23
|
+
else # :footer
|
24
|
+
%(<script src="#{base_url}/highlight.min.js"></script>
|
25
|
+
#{(doc.attr? 'highlightjs-languages') ? ((doc.attr 'highlightjs-languages').split ',').map {|lang| %[<script src="#{base_url}/languages/#{lang.lstrip}.min.js"></script>\n] }.join : ''}<script>
|
26
|
+
if (!hljs.initHighlighting.called) {
|
27
|
+
hljs.initHighlighting.called = true
|
28
|
+
;[].slice.call(document.querySelectorAll('pre.highlight > code')).forEach(function (el) { hljs.highlightBlock(el) })
|
29
|
+
}
|
30
|
+
</script>)
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
@@ -14,14 +14,17 @@ class SyntaxHighlighter::PrettifyAdapter < SyntaxHighlighter::Base
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def docinfo? location
|
17
|
-
|
17
|
+
true
|
18
18
|
end
|
19
19
|
|
20
20
|
def docinfo location, doc, opts
|
21
21
|
base_url = doc.attr 'prettifydir', %(#{opts[:cdn_base_url]}/prettify/r298)
|
22
|
-
|
23
|
-
|
24
|
-
<
|
22
|
+
if location == :head
|
23
|
+
prettify_theme_url = ((prettify_theme = doc.attr 'prettify-theme', 'prettify').start_with? 'http://', 'https://') ? prettify_theme : %(#{base_url}/#{prettify_theme}.min.css)
|
24
|
+
%(<link rel="stylesheet" href="#{prettify_theme_url}"#{opts[:self_closing_tag_slash]}>)
|
25
|
+
else # :footer
|
26
|
+
%(<script src="#{base_url}/run_prettify.min.js"></script>)
|
27
|
+
end
|
25
28
|
end
|
26
29
|
end
|
27
30
|
end
|
@@ -5,8 +5,7 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
|
|
5
5
|
|
6
6
|
def initialize *args
|
7
7
|
super
|
8
|
-
@requires_stylesheet = nil
|
9
|
-
@style = nil
|
8
|
+
@requires_stylesheet = @style = nil
|
10
9
|
end
|
11
10
|
|
12
11
|
def highlight?
|
@@ -34,13 +33,19 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
|
|
34
33
|
highlighted = highlighted.sub WrapperTagRx, PreTagCs
|
35
34
|
opts[:callouts] ? [highlighted, (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil] : highlighted
|
36
35
|
else
|
37
|
-
node.
|
36
|
+
node.sub_source source, false # handles nil response from ::Pygments::Lexer#highlight
|
38
37
|
end
|
39
38
|
elsif (highlighted = lexer.highlight source, options: highlight_opts)
|
40
|
-
|
39
|
+
if linenos
|
40
|
+
if noclasses
|
41
|
+
highlighted = highlighted.gsub StyledLinenoSpanTagRx, LinenoSpanTagCs
|
42
|
+
elsif highlighted.include? LegacyLinenoSpanStartTagCs
|
43
|
+
highlighted = highlighted.gsub LegacyLinenoSpanTagRx, LinenoSpanTagCs
|
44
|
+
end
|
45
|
+
end
|
41
46
|
highlighted.sub WrapperTagRx, '\1'
|
42
47
|
else
|
43
|
-
node.
|
48
|
+
node.sub_source source, false # handles nil response from ::Pygments::Lexer#highlight
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
@@ -53,7 +58,7 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def docinfo? location
|
56
|
-
@requires_stylesheet && location == :
|
61
|
+
@requires_stylesheet && location == :head
|
57
62
|
end
|
58
63
|
|
59
64
|
def docinfo location, doc, opts
|
@@ -115,6 +120,7 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
|
|
115
120
|
end
|
116
121
|
@@stylesheet_cache = ::Hash.new do |cache, key|
|
117
122
|
if (stylesheet = ::Pygments.css BASE_SELECTOR, classprefix: TOKEN_CLASS_PREFIX, style: key)
|
123
|
+
stylesheet = stylesheet.slice (stylesheet.index BASE_SELECTOR), stylesheet.length unless stylesheet.start_with? BASE_SELECTOR
|
118
124
|
@@stylesheet_cache = cache.merge key => stylesheet
|
119
125
|
stylesheet
|
120
126
|
end
|
@@ -123,27 +129,29 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
|
|
123
129
|
DEFAULT_STYLE = 'default'
|
124
130
|
BASE_SELECTOR = 'pre.pygments'
|
125
131
|
TOKEN_CLASS_PREFIX = 'tok-'
|
126
|
-
|
127
132
|
BaseStyleRx = /^#{BASE_SELECTOR.gsub '.', '\\.'} +\{([^}]+?)\}/
|
128
133
|
|
129
134
|
private_constant :BASE_SELECTOR, :TOKEN_CLASS_PREFIX, :BaseStyleRx
|
130
135
|
end
|
131
136
|
|
132
137
|
extend Styles # exports static methods
|
133
|
-
include
|
138
|
+
include Styles # adds methods to instance
|
139
|
+
include Loader # adds methods to instance
|
134
140
|
|
135
141
|
CodeCellStartTagCs = '<td class="code">'
|
142
|
+
LegacyLinenoSpanStartTagCs = '<span class="lineno">'
|
143
|
+
LegacyLinenoSpanTagRx = %r(#{LegacyLinenoSpanStartTagCs}( *\d+) ?</span>)
|
136
144
|
LinenoColumnStartTagsCs = '<td class="linenos"><div class="linenodiv"><pre>'
|
137
|
-
LinenoSpanTagCs = '<span class="
|
145
|
+
LinenoSpanTagCs = '<span class="linenos">\1</span>'
|
138
146
|
PreTagCs = '<pre>\1</pre>'
|
139
147
|
StyledLinenoColumnStartTagsRx = /<td><div class="linenodiv" style="[^"]+?"><pre style="[^"]+?">/
|
140
|
-
StyledLinenoSpanTagRx = %r(<span style="
|
148
|
+
StyledLinenoSpanTagRx = %r((?<=^|<span></span>)<span style="[^"]+">( *\d+) ?</span>)
|
141
149
|
WRAPPER_CLASS = 'lineno' # doesn't appear in output; Pygments appends "table" to this value to make nested table class
|
142
150
|
# NOTE <pre> has style attribute when pygments-css=style
|
143
151
|
# NOTE <div> has trailing newline when pygments-linenums-mode=table
|
144
152
|
# NOTE initial <span></span> preserves leading blank lines
|
145
153
|
WrapperTagRx = %r(<div class="#{WRAPPER_CLASS}"><pre\b[^>]*?>(.*)</pre></div>\n*)m
|
146
154
|
|
147
|
-
private_constant :CodeCellStartTagCs, :LinenoColumnStartTagsCs, :LinenoSpanTagCs, :PreTagCs, :StyledLinenoColumnStartTagsRx, :StyledLinenoSpanTagRx, :WrapperTagRx, :WRAPPER_CLASS
|
155
|
+
private_constant :CodeCellStartTagCs, :LegacyLinenoSpanStartTagCs, :LegacyLinenoSpanTagRx, :LinenoColumnStartTagsCs, :LinenoSpanTagCs, :PreTagCs, :StyledLinenoColumnStartTagsRx, :StyledLinenoSpanTagRx, :WrapperTagRx, :WRAPPER_CLASS
|
148
156
|
end
|
149
157
|
end
|
@@ -13,40 +13,30 @@ class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def highlight node, source, lang, opts
|
16
|
-
lexer = (::Rouge::Lexer.find_fancy lang) || ::Rouge::Lexers::PlainText
|
17
|
-
lexer_opts = lexer.tag == 'php' && !(node.option? 'mixed') ? { start_inline: true } : {}
|
18
16
|
@style ||= (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE
|
19
|
-
if opts[:css_mode] == :class
|
20
|
-
|
21
|
-
|
17
|
+
@requires_stylesheet = true if opts[:css_mode] == :class
|
18
|
+
lexer = create_lexer node, source, lang, opts
|
19
|
+
formatter = create_formatter node, source, lang, opts
|
20
|
+
highlighted = formatter.format lexer.lex source
|
21
|
+
if opts[:number_lines] && opts[:callouts]
|
22
|
+
[highlighted, (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
|
22
23
|
else
|
23
|
-
|
24
|
+
highlighted
|
24
25
|
end
|
25
|
-
if (highlight_lines = opts[:highlight_lines])
|
26
|
-
formatter = RougeExt::Formatters::HTMLLineHighlighter.new formatter, lines: highlight_lines
|
27
|
-
end
|
28
|
-
if opts[:number_lines]
|
29
|
-
formatter = RougeExt::Formatters::HTMLTable.new formatter, start_line: opts[:start_line_number]
|
30
|
-
if opts[:callouts]
|
31
|
-
return [(highlighted = formatter.format lexer.lex source, lexer_opts), (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
formatter.format lexer.lex source, lexer_opts
|
35
26
|
end
|
36
27
|
|
37
28
|
def format node, lang, opts
|
38
29
|
if (query_idx = lang && (lang.index '?'))
|
39
30
|
lang = lang.slice 0, query_idx
|
40
31
|
end
|
41
|
-
if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) &&
|
42
|
-
(pre_style_attr_val = base_style @style)
|
32
|
+
if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) && (pre_style_attr_val = base_style @style)
|
43
33
|
opts[:transform] = proc {|pre| pre['style'] = pre_style_attr_val }
|
44
34
|
end
|
45
35
|
super
|
46
36
|
end
|
47
37
|
|
48
38
|
def docinfo? location
|
49
|
-
@requires_stylesheet && location == :
|
39
|
+
@requires_stylesheet && location == :head
|
50
40
|
end
|
51
41
|
|
52
42
|
def docinfo location, doc, opts
|
@@ -67,6 +57,30 @@ class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
|
|
67
57
|
::File.write (::File.join to_dir, (stylesheet_basename @style)), (read_stylesheet @style), mode: FILE_WRITE_MODE
|
68
58
|
end
|
69
59
|
|
60
|
+
def create_lexer node, source, lang, opts
|
61
|
+
if lang.include? '?'
|
62
|
+
# NOTE cgi-style options only properly supported in Rouge >= 2.1
|
63
|
+
if (lexer = ::Rouge::Lexer.find_fancy lang)
|
64
|
+
unless lexer.tag != 'php' || (node.option? 'mixed') || ((lexer_opts = lexer.options).key? 'start_inline')
|
65
|
+
lexer = lexer.class.new lexer_opts.merge 'start_inline' => true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
elsif (lexer = ::Rouge::Lexer.find lang)
|
69
|
+
lexer = lexer.tag == 'php' && !(node.option? 'mixed') ? (lexer.new start_inline: true) : lexer.new
|
70
|
+
end if lang
|
71
|
+
lexer || ::Rouge::Lexers::PlainText.new
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_formatter node, source, lang, opts
|
75
|
+
formatter = opts[:css_mode] == :class ?
|
76
|
+
(::Rouge::Formatters::HTML.new inline_theme: @style) :
|
77
|
+
(::Rouge::Formatters::HTMLInline.new (::Rouge::Theme.find @style).new)
|
78
|
+
if (highlight_lines = opts[:highlight_lines])
|
79
|
+
formatter = RougeExt::Formatters::HTMLLineHighlighter.new formatter, lines: highlight_lines
|
80
|
+
end
|
81
|
+
opts[:number_lines] ? (RougeExt::Formatters::HTMLTable.new formatter, start_line: opts[:start_line_number]) : formatter
|
82
|
+
end
|
83
|
+
|
70
84
|
module Loader
|
71
85
|
private
|
72
86
|
|
@@ -119,7 +133,8 @@ class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
|
|
119
133
|
end
|
120
134
|
|
121
135
|
extend Styles # exports static methods
|
122
|
-
include
|
136
|
+
include Styles # adds methods to instance
|
137
|
+
include Loader # adds methods to instance
|
123
138
|
|
124
139
|
CodeCellStartTagCs = '<td class="code">'
|
125
140
|
|
@@ -20,7 +20,7 @@ module SyntaxHighlighter
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# Public: Indicates whether this syntax highlighter has docinfo (i.e., markup) to insert into the output document at
|
23
|
-
# the specified location.
|
23
|
+
# the specified location. Should be called by converter after main content has been converted.
|
24
24
|
#
|
25
25
|
# location - The Symbol representing the location slot (:head or :footer).
|
26
26
|
#
|
@@ -28,6 +28,7 @@ module SyntaxHighlighter
|
|
28
28
|
def docinfo? location; end
|
29
29
|
|
30
30
|
# Public: Generates docinfo markup for this syntax highlighter to insert at the specified location in the output document.
|
31
|
+
# Should be called by converter after main content has been converted.
|
31
32
|
#
|
32
33
|
# location - The Symbol representing the location slot (:head or :footer).
|
33
34
|
# doc - The Document in which this syntax highlighter is being used.
|
@@ -98,9 +99,10 @@ module SyntaxHighlighter
|
|
98
99
|
raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #write_stylesheet? returns true)
|
99
100
|
end
|
100
101
|
|
101
|
-
|
102
|
+
def self.included into
|
102
103
|
into.extend Config
|
103
|
-
end
|
104
|
+
end
|
105
|
+
private_class_method :included # use separate declaration for Ruby 2.0.x
|
104
106
|
|
105
107
|
module Config
|
106
108
|
# Public: Statically register the current class in the registry for the specified names.
|
@@ -139,7 +141,7 @@ module SyntaxHighlighter
|
|
139
141
|
# name - The String name of the syntax highlighter to create.
|
140
142
|
# backend - The String name of the backend for which this syntax highlighter is being used (default: 'html5').
|
141
143
|
# opts - A Hash of options providing information about the context in which this syntax highlighter is used:
|
142
|
-
# :
|
144
|
+
# :document - The Document for which this syntax highlighter was created.
|
143
145
|
#
|
144
146
|
# Returns a [SyntaxHighlighter] instance for the specified name.
|
145
147
|
def create name, backend = 'html5', opts = {}
|
@@ -151,7 +153,7 @@ module SyntaxHighlighter
|
|
151
153
|
end
|
152
154
|
|
153
155
|
private
|
154
|
-
|
156
|
+
|
155
157
|
def registry
|
156
158
|
raise ::NotImplementedError, %(#{Factory} subclass #{self.class} must implement the ##{__method__} method)
|
157
159
|
end
|
@@ -165,19 +167,17 @@ module SyntaxHighlighter
|
|
165
167
|
end
|
166
168
|
|
167
169
|
private
|
168
|
-
|
169
|
-
|
170
|
-
@registry
|
171
|
-
end
|
170
|
+
|
171
|
+
attr_reader :registry
|
172
172
|
end
|
173
173
|
|
174
174
|
module DefaultFactory
|
175
175
|
include Factory
|
176
176
|
|
177
|
-
private
|
178
|
-
|
179
177
|
@@registry = {}
|
180
178
|
|
179
|
+
private
|
180
|
+
|
181
181
|
def registry
|
182
182
|
@@registry
|
183
183
|
end
|
@@ -215,8 +215,6 @@ module SyntaxHighlighter
|
|
215
215
|
'rouge' => %(#{__dir__}/syntax_highlighter/rouge),
|
216
216
|
}
|
217
217
|
|
218
|
-
private
|
219
|
-
|
220
218
|
@@mutex = ::Mutex.new
|
221
219
|
end
|
222
220
|
end
|
@@ -235,9 +233,11 @@ module SyntaxHighlighter
|
|
235
233
|
def format node, lang, opts
|
236
234
|
class_attr_val = opts[:nowrap] ? %(#{@pre_class} highlight nowrap) : %(#{@pre_class} highlight)
|
237
235
|
if (transform = opts[:transform])
|
238
|
-
pre = { 'class' => class_attr_val }
|
239
|
-
|
240
|
-
|
236
|
+
transform[(pre = { 'class' => class_attr_val }), (code = lang ? { 'data-lang' => lang } : {})]
|
237
|
+
# NOTE: make sure data-lang is the last attribute on the code tag to remain consistent with 1.5.x
|
238
|
+
if (lang = code.delete 'data-lang')
|
239
|
+
code['data-lang'] = lang
|
240
|
+
end
|
241
241
|
%(<pre#{pre.map {|k, v| %[ #{k}="#{v}"] }.join}><code#{code.map {|k, v| %[ #{k}="#{v}"] }.join}>#{node.content}</code></pre>)
|
242
242
|
else
|
243
243
|
%(<pre class="#{class_attr_val}"><code#{lang ? %[ data-lang="#{lang}"] : ''}>#{node.content}</code></pre>)
|
data/lib/asciidoctor/table.rb
CHANGED
@@ -58,7 +58,7 @@ class Table < AbstractBlock
|
|
58
58
|
@rows = Rows.new
|
59
59
|
@columns = []
|
60
60
|
|
61
|
-
@has_header_option =
|
61
|
+
@has_header_option = false
|
62
62
|
|
63
63
|
# smells like we need a utility method here
|
64
64
|
# to resolve an integer width from potential bogus input
|
@@ -78,10 +78,10 @@ class Table < AbstractBlock
|
|
78
78
|
@attributes['orientation'] = 'landscape' if attributes['rotate-option']
|
79
79
|
end
|
80
80
|
|
81
|
-
# Internal: Returns
|
82
|
-
# 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
|
83
83
|
def header_row?
|
84
|
-
@has_header_option && @rows.body.empty?
|
84
|
+
(val = @has_header_option) && @rows.body.empty? ? val : nil
|
85
85
|
end
|
86
86
|
|
87
87
|
# Internal: Creates the Column objects from the column spec
|
@@ -154,22 +154,19 @@ class Table < AbstractBlock
|
|
154
154
|
# returns nothing
|
155
155
|
def partition_header_footer(attrs)
|
156
156
|
# set rowcount before splitting up body rows
|
157
|
-
@attributes['rowcount'] = @rows.body.size
|
158
|
-
|
159
|
-
num_body_rows
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
@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
|
168
167
|
end
|
169
168
|
|
170
|
-
if num_body_rows > 0 && attrs['footer-option']
|
171
|
-
@rows.foot = [@rows.body.pop]
|
172
|
-
end
|
169
|
+
@rows.foot = [body.pop] if num_body_rows > 0 && attrs['footer-option']
|
173
170
|
|
174
171
|
nil
|
175
172
|
end
|
@@ -232,14 +229,23 @@ class Table::Cell < AbstractBlock
|
|
232
229
|
# Public: An alias to the parent block (which is always a Column)
|
233
230
|
alias column parent
|
234
231
|
|
235
|
-
#
|
232
|
+
# Public: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
|
236
233
|
attr_reader :inner_document
|
237
234
|
|
238
235
|
def initialize column, cell_text, attributes = {}, opts = {}
|
239
236
|
super column, :table_cell
|
237
|
+
@cursor = @reinitialize_args = nil
|
240
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
|
241
240
|
if column
|
242
|
-
|
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
|
243
249
|
# REVIEW feels hacky to inherit all attributes from column
|
244
250
|
update_attributes column.attributes
|
245
251
|
end
|
@@ -253,7 +259,8 @@ class Table::Cell < AbstractBlock
|
|
253
259
|
cell_style = attributes['style'] || cell_style unless in_header_row
|
254
260
|
update_attributes attributes
|
255
261
|
end
|
256
|
-
|
262
|
+
case cell_style
|
263
|
+
when :asciidoc
|
257
264
|
asciidoc = true
|
258
265
|
inner_document_cursor = opts[:cursor]
|
259
266
|
if (cell_text = cell_text.rstrip).start_with? LF
|
@@ -264,7 +271,7 @@ class Table::Cell < AbstractBlock
|
|
264
271
|
else
|
265
272
|
cell_text = cell_text.lstrip
|
266
273
|
end
|
267
|
-
|
274
|
+
when :literal
|
268
275
|
literal = true
|
269
276
|
cell_text = cell_text.rstrip
|
270
277
|
# QUESTION should we use same logic as :asciidoc cell? strip leading space if text doesn't start with newline?
|
@@ -306,8 +313,12 @@ class Table::Cell < AbstractBlock
|
|
306
313
|
@content_model = :verbatim
|
307
314
|
@subs = BASIC_SUBS
|
308
315
|
else
|
309
|
-
if normal_psv
|
310
|
-
|
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
|
311
322
|
end
|
312
323
|
@content_model = :simple
|
313
324
|
@subs = NORMAL_SUBS
|
@@ -316,6 +327,25 @@ class Table::Cell < AbstractBlock
|
|
316
327
|
@style = cell_style
|
317
328
|
end
|
318
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
|
+
|
319
349
|
# Public: Get the String text of this cell with substitutions applied.
|
320
350
|
#
|
321
351
|
# Used for cells in the head row as well as text-only (non-AsciiDoc) cells in
|
@@ -328,18 +358,14 @@ class Table::Cell < AbstractBlock
|
|
328
358
|
apply_subs @text, @subs
|
329
359
|
end
|
330
360
|
|
331
|
-
# Public: Set the String text.
|
361
|
+
# Public: Set the String text for this cell.
|
332
362
|
#
|
333
363
|
# This method shouldn't be used for cells that have the AsciiDoc style.
|
334
|
-
|
335
|
-
# Returns the new String text assigned to this Cell
|
336
|
-
def text= val
|
337
|
-
@text = val
|
338
|
-
end
|
364
|
+
attr_writer :text
|
339
365
|
|
340
366
|
# Public: Handles the body data (tbody, tfoot), applying styles and partitioning into paragraphs
|
341
367
|
#
|
342
|
-
# 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.
|
343
369
|
#
|
344
370
|
# Returns the converted String for this Cell
|
345
371
|
def content
|
@@ -377,7 +403,7 @@ class Table::Cell < AbstractBlock
|
|
377
403
|
end
|
378
404
|
|
379
405
|
def to_s
|
380
|
-
|
406
|
+
%(#{super} - [text: #{@text}, colspan: #{@colspan || 1}, rowspan: #{@rowspan || 1}, attributes: #{@attributes}])
|
381
407
|
end
|
382
408
|
end
|
383
409
|
|
@@ -385,7 +411,7 @@ end
|
|
385
411
|
# class are primarily responsible for tracking the buffer of a cell as the parser
|
386
412
|
# moves through the lines of the table using tail recursion. When a cell boundary
|
387
413
|
# is located, the previous cell is closed, an instance of Table::Cell is
|
388
|
-
# instantiated, the row is closed if the cell
|
414
|
+
# instantiated, the row is closed if the cell satisfies the column count and,
|
389
415
|
# finally, a new buffer is allocated to track the next cell.
|
390
416
|
class Table::ParserContext
|
391
417
|
include Logging
|
@@ -505,12 +531,13 @@ class Table::ParserContext
|
|
505
531
|
#
|
506
532
|
# returns true if the buffer has unclosed quotes, false if it doesn't or it
|
507
533
|
# isn't quoted data
|
508
|
-
def buffer_has_unclosed_quotes? append = nil
|
509
|
-
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
|
510
536
|
true
|
511
|
-
elsif record.start_with?
|
512
|
-
|
513
|
-
|
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)
|
514
541
|
else
|
515
542
|
!trailing_quote
|
516
543
|
end
|
@@ -603,20 +630,20 @@ class Table::ParserContext
|
|
603
630
|
@buffer = ''
|
604
631
|
cellspec = nil
|
605
632
|
repeat = 1
|
606
|
-
if @format == 'csv' && !cell_text.empty? && cell_text.include?('"')
|
633
|
+
if @format == 'csv' && !cell_text.empty? && (cell_text.include? (q = '"'))
|
607
634
|
# this may not be perfect logic, but it hits the 99%
|
608
|
-
if cell_text.start_with?
|
635
|
+
if (cell_text.start_with? q) && (cell_text.end_with? q)
|
609
636
|
# unquote
|
610
637
|
if (cell_text = cell_text.slice(1, cell_text.length - 2))
|
611
638
|
# trim whitespace and collapse escaped quotes
|
612
|
-
cell_text = cell_text.strip.squeeze
|
639
|
+
cell_text = cell_text.strip.squeeze q
|
613
640
|
else
|
614
641
|
logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', source_location: @reader.cursor_at_prev_line
|
615
642
|
cell_text = ''
|
616
643
|
end
|
617
644
|
else
|
618
645
|
# collapse escaped quotes
|
619
|
-
cell_text = cell_text.squeeze
|
646
|
+
cell_text = cell_text.squeeze q
|
620
647
|
end
|
621
648
|
end
|
622
649
|
end
|
@@ -635,7 +662,7 @@ class Table::ParserContext
|
|
635
662
|
# QUESTION is this right for cells that span columns?
|
636
663
|
unless (column = @table.columns[@current_row.size])
|
637
664
|
logger.error message_with_context 'dropping cell because it exceeds specified number of columns', source_location: @reader.cursor_before_mark
|
638
|
-
return
|
665
|
+
return nil
|
639
666
|
end
|
640
667
|
end
|
641
668
|
|
data/lib/asciidoctor/timings.rb
CHANGED
@@ -49,9 +49,9 @@ 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
|
data/lib/asciidoctor/version.rb
CHANGED