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,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rouge' unless defined? Rouge.version
|
3
|
+
|
4
|
+
module Asciidoctor; module RougeExt; module Formatters
|
5
|
+
class HTMLTable < ::Rouge::Formatter
|
6
|
+
def initialize delegate, opts
|
7
|
+
@delegate = delegate
|
8
|
+
@start_line = opts[:start_line] || 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def stream tokens
|
12
|
+
formatted_code = @delegate.format tokens
|
13
|
+
formatted_code += LF unless formatted_code.end_with? LF, HangingEndSpanTagCs
|
14
|
+
last_lineno = (first_lineno = @start_line) + (formatted_code.count LF) - 1 # assume number of newlines is constant
|
15
|
+
lineno_format = %(%#{(::Math.log10 last_lineno).floor + 1}i)
|
16
|
+
formatted_linenos = ((first_lineno..last_lineno).map {|lineno| sprintf lineno_format, lineno } << '').join LF
|
17
|
+
yield %(<table class="linenotable"><tbody><tr><td class="linenos gl"><pre class="lineno">#{formatted_linenos}</pre></td><td class="code"><pre>#{formatted_code}</pre></td></tr></tbody></table>)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class HTMLLineHighlighter < ::Rouge::Formatter
|
22
|
+
def initialize delegate, opts
|
23
|
+
@delegate = delegate
|
24
|
+
@lines = opts[:lines] || []
|
25
|
+
end
|
26
|
+
|
27
|
+
def stream tokens
|
28
|
+
lineno = 0
|
29
|
+
token_lines tokens do |tokens_in_line|
|
30
|
+
yield (@lines.include? lineno += 1) ? %(<span class="hll">#{@delegate.format tokens_in_line}#{LF}</span>) : %(#{@delegate.format tokens_in_line}#{LF})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
LF = ?\n
|
36
|
+
HangingEndSpanTagCs = %(#{LF}</span>)
|
37
|
+
|
38
|
+
private_constant :HangingEndSpanTagCs, :LF
|
39
|
+
end; end; end
|
data/lib/asciidoctor/section.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# Public: Methods for managing sections of AsciiDoc content in a document.
|
4
4
|
# The section responds as an Array of content blocks by delegating
|
@@ -130,9 +130,9 @@ class Section < AbstractBlock
|
|
130
130
|
case xrefstyle
|
131
131
|
when 'full'
|
132
132
|
if (type = @sectname) == 'chapter' || type == 'appendix'
|
133
|
-
quoted_title =
|
133
|
+
quoted_title = sub_placeholder (sub_quotes '_%s_'), title
|
134
134
|
else
|
135
|
-
quoted_title =
|
135
|
+
quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title
|
136
136
|
end
|
137
137
|
if (signifier = @document.attributes[%(#{type}-refsig)])
|
138
138
|
%(#{signifier} #{sectnum '.', ','} #{quoted_title})
|
@@ -146,10 +146,10 @@ class Section < AbstractBlock
|
|
146
146
|
sectnum '.', ''
|
147
147
|
end
|
148
148
|
else # 'basic'
|
149
|
-
(type = @sectname) == 'chapter' || type == 'appendix' ? (
|
149
|
+
(type = @sectname) == 'chapter' || type == 'appendix' ? (sub_placeholder (sub_quotes '_%s_'), title) : title
|
150
150
|
end
|
151
151
|
else # apply basic styling
|
152
|
-
(type = @sectname) == 'chapter' || type == 'appendix' ? (
|
152
|
+
(type = @sectname) == 'chapter' || type == 'appendix' ? (sub_placeholder (sub_quotes '_%s_'), title) : title
|
153
153
|
end
|
154
154
|
else
|
155
155
|
title
|
@@ -215,9 +215,10 @@ class Section < AbstractBlock
|
|
215
215
|
# ensure id doesn't begin with idseparator if idprefix is empty (assuming idseparator is not empty)
|
216
216
|
gen_id = gen_id.slice 1, gen_id.length if pre.empty? && (gen_id.start_with? sep)
|
217
217
|
end
|
218
|
-
if document.catalog[:
|
219
|
-
ids
|
220
|
-
cnt
|
218
|
+
if document.catalog[:refs].key? gen_id
|
219
|
+
ids = document.catalog[:refs]
|
220
|
+
cnt = Compliance.unique_id_start_index
|
221
|
+
cnt += 1 while ids[candidate_id = %(#{gen_id}#{sep}#{cnt})]
|
221
222
|
candidate_id
|
222
223
|
else
|
223
224
|
gen_id
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# A utility class for working with the built-in stylesheets.
|
4
4
|
#--
|
@@ -6,9 +6,7 @@ module Asciidoctor
|
|
6
6
|
# QUESTION create method for user stylesheet?
|
7
7
|
class Stylesheets
|
8
8
|
DEFAULT_STYLESHEET_NAME = 'asciidoctor.css'
|
9
|
-
|
10
|
-
STYLESHEETS_DATA_PATH = ::File.join DATA_PATH, 'stylesheets'
|
11
|
-
PygmentsBgColorRx = /^\.pygments +\{ *background: *([^;]+);/
|
9
|
+
STYLESHEETS_DIR = ::File.join DATA_DIR, 'stylesheets'
|
12
10
|
|
13
11
|
@__instance__ = new
|
14
12
|
|
@@ -24,9 +22,12 @@ class Stylesheets
|
|
24
22
|
#
|
25
23
|
# returns the [String] Asciidoctor stylesheet data
|
26
24
|
def primary_stylesheet_data
|
27
|
-
@primary_stylesheet_data ||= ::
|
25
|
+
@primary_stylesheet_data ||= (::File.read (::File.join STYLESHEETS_DIR, 'asciidoctor-default.css'), mode: FILE_READ_MODE).rstrip
|
28
26
|
end
|
29
27
|
|
28
|
+
# Deprecated: Generate code to embed the primary stylesheet
|
29
|
+
#
|
30
|
+
# Returns the [String] primary stylesheet data wrapped in a <style> tag
|
30
31
|
def embed_primary_stylesheet
|
31
32
|
%(<style>
|
32
33
|
#{primary_stylesheet_data}
|
@@ -34,24 +35,23 @@ class Stylesheets
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def write_primary_stylesheet target_dir = '.'
|
37
|
-
::
|
38
|
+
::File.write (::File.join target_dir, primary_stylesheet_name), primary_stylesheet_data, mode: FILE_WRITE_MODE
|
38
39
|
end
|
39
40
|
|
40
41
|
def coderay_stylesheet_name
|
41
|
-
'coderay
|
42
|
+
(SyntaxHighlighter.for 'coderay').stylesheet_basename
|
42
43
|
end
|
43
44
|
|
44
45
|
# Public: Read the contents of the default CodeRay stylesheet
|
45
46
|
#
|
46
47
|
# returns the [String] CodeRay stylesheet data
|
47
48
|
def coderay_stylesheet_data
|
48
|
-
|
49
|
-
# unless load_coderay.nil?
|
50
|
-
# ::CodeRay::Encoders[:html]::CSS.new(:default).stylesheet
|
51
|
-
# end
|
52
|
-
@coderay_stylesheet_data ||= ::IO.read(::File.join(STYLESHEETS_DATA_PATH, 'coderay-asciidoctor.css')).rstrip
|
49
|
+
(SyntaxHighlighter.for 'coderay').read_stylesheet
|
53
50
|
end
|
54
51
|
|
52
|
+
# Deprecated: Generate code to embed the CodeRay stylesheet
|
53
|
+
#
|
54
|
+
# Returns the [String] CodeRay stylesheet data wrapped in a <style> tag
|
55
55
|
def embed_coderay_stylesheet
|
56
56
|
%(<style>
|
57
57
|
#{coderay_stylesheet_data}
|
@@ -59,33 +59,23 @@ class Stylesheets
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def write_coderay_stylesheet target_dir = '.'
|
62
|
-
::
|
62
|
+
::File.write (::File.join target_dir, coderay_stylesheet_name), coderay_stylesheet_data, mode: FILE_WRITE_MODE
|
63
63
|
end
|
64
64
|
|
65
65
|
def pygments_stylesheet_name style = nil
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def pygments_background style = nil
|
70
|
-
if load_pygments && PygmentsBgColorRx =~ (::Pygments.css '.pygments', :style => style || DEFAULT_PYGMENTS_STYLE)
|
71
|
-
$1
|
72
|
-
end
|
66
|
+
(SyntaxHighlighter.for 'pygments').stylesheet_basename style
|
73
67
|
end
|
74
68
|
|
75
69
|
# Public: Generate the Pygments stylesheet with the specified style.
|
76
70
|
#
|
77
71
|
# returns the [String] Pygments stylesheet data
|
78
72
|
def pygments_stylesheet_data style = nil
|
79
|
-
|
80
|
-
style ||= DEFAULT_PYGMENTS_STYLE
|
81
|
-
(@pygments_stylesheet_data ||= {})[style] ||=
|
82
|
-
((::Pygments.css '.listingblock .pygments', :classprefix => 'tok-', :style => style) || '/* Failed to load Pygments CSS. */').
|
83
|
-
sub('.listingblock .pygments {', '.listingblock .pygments, .listingblock .pygments code {')
|
84
|
-
else
|
85
|
-
'/* Pygments CSS disabled. Pygments is not available. */'
|
86
|
-
end
|
73
|
+
(SyntaxHighlighter.for 'pygments').read_stylesheet style
|
87
74
|
end
|
88
75
|
|
76
|
+
# Deprecated: Generate code to embed the Pygments stylesheet
|
77
|
+
#
|
78
|
+
# Returns the [String] Pygments stylesheet data for the specified style wrapped in a <style> tag
|
89
79
|
def embed_pygments_stylesheet style = nil
|
90
80
|
%(<style>
|
91
81
|
#{pygments_stylesheet_data style}
|
@@ -93,15 +83,7 @@ class Stylesheets
|
|
93
83
|
end
|
94
84
|
|
95
85
|
def write_pygments_stylesheet target_dir = '.', style = nil
|
96
|
-
::
|
97
|
-
end
|
98
|
-
|
99
|
-
#def load_coderay
|
100
|
-
# (defined? ::CodeRay) ? true : !(Helpers.require_library 'coderay', true, :ignore).nil?
|
101
|
-
#end
|
102
|
-
|
103
|
-
def load_pygments
|
104
|
-
(defined? ::Pygments) ? true : !(Helpers.require_library 'pygments', 'pygments.rb', :ignore).nil?
|
86
|
+
::File.write (::File.join target_dir, (pygments_stylesheet_name style)), (pygments_stylesheet_data style), mode: FILE_WRITE_MODE
|
105
87
|
end
|
106
88
|
end
|
107
89
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# Public: Methods to perform substitutions on lines of AsciiDoc text. This module
|
4
4
|
# is intented to be mixed-in to Section and Block to provide operations for performing
|
@@ -12,55 +12,45 @@ module Substitutors
|
|
12
12
|
|
13
13
|
(BASIC_SUBS = [:specialcharacters]).freeze
|
14
14
|
(HEADER_SUBS = [:specialcharacters, :attributes]).freeze
|
15
|
+
(NO_SUBS = []).freeze
|
15
16
|
(NORMAL_SUBS = [:specialcharacters, :quotes, :attributes, :replacements, :macros, :post_replacements]).freeze
|
16
|
-
(NONE_SUBS = []).freeze
|
17
|
-
(TITLE_SUBS = [:specialcharacters, :quotes, :replacements, :macros, :attributes, :post_replacements]).freeze
|
18
17
|
(REFTEXT_SUBS = [:specialcharacters, :quotes, :replacements]).freeze
|
19
18
|
(VERBATIM_SUBS = [:specialcharacters, :callouts]).freeze
|
20
19
|
|
21
20
|
SUB_GROUPS = {
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
21
|
+
none: NO_SUBS,
|
22
|
+
normal: NORMAL_SUBS,
|
23
|
+
verbatim: VERBATIM_SUBS,
|
24
|
+
specialchars: BASIC_SUBS,
|
26
25
|
}
|
27
26
|
|
28
27
|
SUB_HINTS = {
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
28
|
+
a: :attributes,
|
29
|
+
m: :macros,
|
30
|
+
n: :normal,
|
31
|
+
p: :post_replacements,
|
32
|
+
q: :quotes,
|
33
|
+
r: :replacements,
|
34
|
+
c: :specialcharacters,
|
35
|
+
v: :verbatim,
|
37
36
|
}
|
38
37
|
|
39
38
|
SUB_OPTIONS = {
|
40
|
-
:
|
41
|
-
:
|
39
|
+
block: SUB_GROUPS.keys + NORMAL_SUBS + [:callouts],
|
40
|
+
inline: SUB_GROUPS.keys + NORMAL_SUBS,
|
42
41
|
}
|
43
42
|
|
44
|
-
|
43
|
+
CAN = ?\u0018
|
44
|
+
DEL = ?\u007f
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
DEL = %(\u007f)
|
46
|
+
# Delimiters and matchers for the passthrough placeholder
|
47
|
+
# See http://www.aivosto.com/vbtips/control-characters.html#listabout for characters to use
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
# SPA, start of guarded protected area (\u0096)
|
50
|
+
PASS_START = ?\u0096
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
# EPA, end of guarded protected area (\u0097)
|
57
|
-
PASS_END = %(\u0097)
|
58
|
-
else
|
59
|
-
CAN = 24.chr
|
60
|
-
DEL = 127.chr
|
61
|
-
PASS_START = 150.chr
|
62
|
-
PASS_END = 151.chr
|
63
|
-
end
|
52
|
+
# EPA, end of guarded protected area (\u0097)
|
53
|
+
PASS_END = ?\u0097
|
64
54
|
|
65
55
|
# match passthrough slot
|
66
56
|
PassSlotRx = /#{PASS_START}(\d+)#{PASS_END}/
|
@@ -76,14 +66,6 @@ module Substitutors
|
|
76
66
|
|
77
67
|
PLUS = '+'
|
78
68
|
|
79
|
-
PygmentsWrapperDivRx = %r(<div class="pyhl">(.*)</div>)m
|
80
|
-
# NOTE handles all permutations of <pre> wrapper
|
81
|
-
# NOTE trailing whitespace appears when pygments-linenums-mode=table; <pre> has style attribute when pygments-css=inline
|
82
|
-
PygmentsWrapperPreRx = %r(<pre\b[^>]*?>(.*?)</pre>\s*)m
|
83
|
-
|
84
|
-
# Internal: A String Array of passthough (unprocessed) text captured from this block
|
85
|
-
attr_reader :passthroughs
|
86
|
-
|
87
69
|
# Public: Apply the specified substitutions to the text.
|
88
70
|
#
|
89
71
|
# text - The String or String Array of text to process; must not be nil.
|
@@ -93,14 +75,18 @@ module Substitutors
|
|
93
75
|
def apply_subs text, subs = NORMAL_SUBS
|
94
76
|
return text if text.empty? || !subs
|
95
77
|
|
96
|
-
if (
|
97
|
-
#text = text.size > 1 ? (text.join LF) : text[0]
|
78
|
+
if (is_multiline = ::Array === text)
|
98
79
|
text = text[1] ? (text.join LF) : text[0]
|
99
80
|
end
|
100
81
|
|
101
|
-
if
|
102
|
-
text = extract_passthroughs text
|
103
|
-
|
82
|
+
if subs.include? :macros
|
83
|
+
text, passthrus = extract_passthroughs text
|
84
|
+
if passthrus.empty?
|
85
|
+
passthrus = nil
|
86
|
+
else
|
87
|
+
# NOTE placeholders can move around, so we can only clear in the outermost substitution call
|
88
|
+
@passthroughs_locked ||= (reset_passthrus = true)
|
89
|
+
end
|
104
90
|
end
|
105
91
|
|
106
92
|
subs.each do |type|
|
@@ -125,9 +111,16 @@ module Substitutors
|
|
125
111
|
logger.warn %(unknown substitution type #{type})
|
126
112
|
end
|
127
113
|
end
|
128
|
-
text = restore_passthroughs text if has_passthroughs
|
129
114
|
|
130
|
-
|
115
|
+
if passthrus
|
116
|
+
text = restore_passthroughs text
|
117
|
+
if reset_passthrus
|
118
|
+
passthrus.clear
|
119
|
+
@passthroughs_locked = nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
is_multiline ? (text.split LF, -1) : text
|
131
124
|
end
|
132
125
|
|
133
126
|
# Public: Apply normal substitutions.
|
@@ -138,7 +131,7 @@ module Substitutors
|
|
138
131
|
#
|
139
132
|
# Returns the String with normal substitutions applied.
|
140
133
|
def apply_normal_subs text
|
141
|
-
apply_subs text
|
134
|
+
apply_subs text, NORMAL_SUBS
|
142
135
|
end
|
143
136
|
|
144
137
|
# Public: Apply substitutions for titles.
|
@@ -146,9 +139,7 @@ module Substitutors
|
|
146
139
|
# title - The String title to process
|
147
140
|
#
|
148
141
|
# returns - A String with title substitutions performed
|
149
|
-
|
150
|
-
apply_subs title, TITLE_SUBS
|
151
|
-
end
|
142
|
+
alias apply_title_subs apply_subs
|
152
143
|
|
153
144
|
# Public: Apply substitutions for reftext.
|
154
145
|
#
|
@@ -172,33 +163,30 @@ module Substitutors
|
|
172
163
|
#
|
173
164
|
# text - The String from which to extract passthrough fragements
|
174
165
|
#
|
175
|
-
# returns -
|
166
|
+
# returns - A tuple of the String text with passthrough regions substituted with placeholders and the passthroughs Hash
|
176
167
|
def extract_passthroughs(text)
|
177
168
|
compat_mode = @document.compat_mode
|
178
|
-
|
179
|
-
text = text.gsub
|
180
|
-
|
181
|
-
m = $~
|
182
|
-
preceding = nil
|
169
|
+
passthrus = @passthroughs
|
170
|
+
text = text.gsub InlinePassMacroRx do
|
171
|
+
preceding = ''
|
183
172
|
|
184
|
-
if (boundary =
|
173
|
+
if (boundary = $4) # $$, ++, or +++
|
185
174
|
# skip ++ in compat mode, handled as normal quoted text
|
186
175
|
if compat_mode && boundary == '++'
|
187
|
-
|
188
|
-
|
189
|
-
%(#{m[1]}#{m[3]}++#{extract_passthroughs m[5]}++)
|
176
|
+
content, _ = extract_passthroughs $5
|
177
|
+
next $2 ? %(#{$1}[#{$2}]#{$3}++#{content}++) : %(#{$1}#{$3}++#{content}++)
|
190
178
|
end
|
191
179
|
|
192
|
-
attributes =
|
193
|
-
escape_count =
|
194
|
-
content =
|
180
|
+
attributes = $2
|
181
|
+
escape_count = $3.length
|
182
|
+
content = $5
|
195
183
|
old_behavior = false
|
196
184
|
|
197
185
|
if attributes
|
198
186
|
if escape_count > 0
|
199
187
|
# NOTE we don't look for nested unconstrained pass macros
|
200
|
-
next %(#{
|
201
|
-
elsif
|
188
|
+
next %(#{$1}[#{attributes}]#{RS * (escape_count - 1)}#{boundary}#{$5}#{boundary})
|
189
|
+
elsif $1 == RS
|
202
190
|
preceding = %([#{attributes}])
|
203
191
|
attributes = nil
|
204
192
|
else
|
@@ -210,41 +198,36 @@ module Substitutors
|
|
210
198
|
end
|
211
199
|
elsif escape_count > 0
|
212
200
|
# NOTE we don't look for nested unconstrained pass macros
|
213
|
-
next %(#{RS * (escape_count - 1)}#{boundary}#{
|
201
|
+
next %(#{RS * (escape_count - 1)}#{boundary}#{$5}#{boundary})
|
214
202
|
end
|
215
203
|
subs = (boundary == '+++' ? [] : BASIC_SUBS)
|
216
204
|
|
217
|
-
pass_key = passes.size
|
218
205
|
if attributes
|
219
206
|
if old_behavior
|
220
|
-
|
207
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: NORMAL_SUBS, type: :monospaced, attributes: attributes }
|
221
208
|
else
|
222
|
-
|
209
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: subs, type: :unquoted, attributes: attributes }
|
223
210
|
end
|
224
211
|
else
|
225
|
-
|
212
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: subs }
|
226
213
|
end
|
227
214
|
else # pass:[]
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
passes[pass_key = passes.size] = {:text => (unescape_brackets m[8]), :subs => (m[7] ? (resolve_pass_subs m[7]) : nil)}
|
215
|
+
# NOTE we don't look for nested pass:[] macros
|
216
|
+
# honor the escape
|
217
|
+
next $&.slice 1, $&.length if $6 == RS
|
218
|
+
passthrus[passthru_key = passthrus.size] = { text: (unescape_brackets $8), subs: ($7 ? (resolve_pass_subs $7) : nil) }
|
234
219
|
end
|
235
220
|
|
236
|
-
%(#{preceding}#{PASS_START}#{
|
237
|
-
|
221
|
+
%(#{preceding}#{PASS_START}#{passthru_key}#{PASS_END})
|
222
|
+
end if (text.include? '++') || (text.include? '$$') || (text.include? 'ss:')
|
238
223
|
|
239
224
|
pass_inline_char1, pass_inline_char2, pass_inline_rx = InlinePassRx[compat_mode]
|
240
|
-
text = text.gsub
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
format_mark = m[4]
|
247
|
-
content = m[5]
|
225
|
+
text = text.gsub pass_inline_rx do
|
226
|
+
preceding = $1
|
227
|
+
attributes = $2
|
228
|
+
escape_mark = RS if (quoted_text = $3).start_with? RS
|
229
|
+
format_mark = $4
|
230
|
+
content = $5
|
248
231
|
|
249
232
|
if compat_mode
|
250
233
|
old_behavior = true
|
@@ -256,11 +239,8 @@ module Substitutors
|
|
256
239
|
|
257
240
|
if attributes
|
258
241
|
if format_mark == '`' && !old_behavior
|
259
|
-
|
260
|
-
|
261
|
-
end
|
262
|
-
|
263
|
-
if escape_mark
|
242
|
+
next extract_inner_passthrough content, %(#{preceding}[#{attributes}]#{escape_mark}), attributes
|
243
|
+
elsif escape_mark
|
264
244
|
# honor the escape of the formatting mark
|
265
245
|
next %(#{preceding}[#{attributes}]#{quoted_text.slice 1, quoted_text.length})
|
266
246
|
elsif preceding == RS
|
@@ -271,60 +251,55 @@ module Substitutors
|
|
271
251
|
attributes = parse_quoted_text_attributes attributes
|
272
252
|
end
|
273
253
|
elsif format_mark == '`' && !old_behavior
|
274
|
-
|
275
|
-
next (extract_inner_passthrough content, %(#{preceding}#{escape_mark}))
|
254
|
+
next extract_inner_passthrough content, %(#{preceding}#{escape_mark})
|
276
255
|
elsif escape_mark
|
277
256
|
# honor the escape of the formatting mark
|
278
257
|
next %(#{preceding}#{quoted_text.slice 1, quoted_text.length})
|
279
258
|
end
|
280
259
|
|
281
|
-
pass_key = passes.size
|
282
260
|
if compat_mode
|
283
|
-
|
261
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: BASIC_SUBS, attributes: attributes, type: :monospaced }
|
284
262
|
elsif attributes
|
285
263
|
if old_behavior
|
286
264
|
subs = (format_mark == '`' ? BASIC_SUBS : NORMAL_SUBS)
|
287
|
-
|
265
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: subs, attributes: attributes, type: :monospaced }
|
288
266
|
else
|
289
|
-
|
267
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: BASIC_SUBS, attributes: attributes, type: :unquoted }
|
290
268
|
end
|
291
269
|
else
|
292
|
-
|
270
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: BASIC_SUBS }
|
293
271
|
end
|
294
272
|
|
295
|
-
%(#{preceding}#{PASS_START}#{
|
296
|
-
|
273
|
+
%(#{preceding}#{PASS_START}#{passthru_key}#{PASS_END})
|
274
|
+
end if (text.include? pass_inline_char1) || (pass_inline_char2 && (text.include? pass_inline_char2))
|
297
275
|
|
298
276
|
# NOTE we need to do the stem in a subsequent step to allow it to be escaped by the former
|
299
|
-
text = text.gsub
|
300
|
-
# alias match for Ruby 1.8.7 compat
|
301
|
-
m = $~
|
277
|
+
text = text.gsub InlineStemMacroRx do
|
302
278
|
# honor the escape
|
303
|
-
if $&.start_with? RS
|
304
|
-
next m[0].slice 1, m[0].length
|
305
|
-
end
|
279
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
306
280
|
|
307
|
-
if (type =
|
281
|
+
if (type = $1.to_sym) == :stem
|
308
282
|
type = STEM_TYPE_ALIASES[@document.attributes['stem']].to_sym
|
309
283
|
end
|
310
|
-
content = unescape_brackets
|
311
|
-
subs =
|
312
|
-
|
313
|
-
%(#{PASS_START}#{
|
314
|
-
|
284
|
+
content = unescape_brackets $3
|
285
|
+
subs = $2 ? (resolve_pass_subs $2) : ((@document.basebackend? 'html') ? BASIC_SUBS : nil)
|
286
|
+
passthrus[passthru_key = passthrus.size] = { text: content, subs: subs, type: type }
|
287
|
+
%(#{PASS_START}#{passthru_key}#{PASS_END})
|
288
|
+
end if (text.include? ':') && ((text.include? 'stem:') || (text.include? 'math:'))
|
315
289
|
|
316
|
-
text
|
290
|
+
[text, passthrus]
|
317
291
|
end
|
318
292
|
|
293
|
+
# Internal: Extract nested single-plus passthrough; otherwise return unprocessed
|
319
294
|
def extract_inner_passthrough text, pre, attributes = nil
|
320
295
|
if (text.end_with? '+') && (text.start_with? '+', '\+') && SinglePlusInlinePassRx =~ text
|
321
296
|
if $1
|
322
297
|
%(#{pre}`+#{$2}+`)
|
323
298
|
else
|
324
|
-
@passthroughs[
|
325
|
-
{ :
|
326
|
-
{ :
|
327
|
-
%(#{pre}`#{PASS_START}#{
|
299
|
+
@passthroughs[passthru_key = @passthroughs.size] = attributes ?
|
300
|
+
{ text: $2, subs: BASIC_SUBS, attributes: attributes, type: :unquoted } :
|
301
|
+
{ text: $2, subs: BASIC_SUBS }
|
302
|
+
%(#{pre}`#{PASS_START}#{passthru_key}#{PASS_END}`)
|
328
303
|
end
|
329
304
|
else
|
330
305
|
%(#{pre}`#{text}`)
|
@@ -334,99 +309,71 @@ module Substitutors
|
|
334
309
|
# Internal: Restore the passthrough text by reinserting into the placeholder positions
|
335
310
|
#
|
336
311
|
# text - The String text into which to restore the passthrough text
|
337
|
-
# outer - A Boolean indicating whether we are in the outer call (default: true)
|
338
312
|
#
|
339
313
|
# returns The String text with the passthrough text restored
|
340
|
-
def restore_passthroughs text
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
text.gsub(PassSlotRx) {
|
348
|
-
# NOTE we can't remove entry from map because placeholder may have been duplicated by other substitutions
|
349
|
-
pass = passes[$1.to_i]
|
350
|
-
subbed_text = apply_subs(pass[:text], pass[:subs])
|
351
|
-
if (type = pass[:type])
|
352
|
-
subbed_text = Inline.new(self, :quoted, subbed_text, :type => type, :attributes => pass[:attributes]).convert
|
353
|
-
end
|
354
|
-
subbed_text.include?(PASS_START) ? restore_passthroughs(subbed_text, false) : subbed_text
|
355
|
-
}
|
356
|
-
ensure
|
357
|
-
# free memory if in outer call...we don't need these anymore
|
358
|
-
passes.clear if outer
|
359
|
-
end
|
360
|
-
|
361
|
-
if RUBY_ENGINE == 'opal'
|
362
|
-
def sub_quotes text
|
363
|
-
if QuotedTextSniffRx[compat = @document.compat_mode].match? text
|
364
|
-
QUOTE_SUBS[compat].each do |type, scope, pattern|
|
365
|
-
text = text.gsub(pattern) { convert_quoted_text $~, type, scope }
|
314
|
+
def restore_passthroughs text
|
315
|
+
passthrus = @passthroughs
|
316
|
+
text.gsub PassSlotRx do
|
317
|
+
if (pass = passthrus[$1.to_i])
|
318
|
+
subbed_text = apply_subs(pass[:text], pass[:subs])
|
319
|
+
if (type = pass[:type])
|
320
|
+
subbed_text = Inline.new(self, :quoted, subbed_text, type: type, attributes: pass[:attributes]).convert
|
366
321
|
end
|
322
|
+
subbed_text.include?(PASS_START) ? restore_passthroughs(subbed_text) : subbed_text
|
323
|
+
else
|
324
|
+
logger.error %(unresolved passthrough detected: #{text})
|
325
|
+
'??pass??'
|
367
326
|
end
|
368
|
-
text
|
369
327
|
end
|
328
|
+
end
|
370
329
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
# Public: Substitute quoted text (includes emphasis, strong, monospaced, etc)
|
381
|
-
#
|
382
|
-
# text - The String text to process
|
383
|
-
#
|
384
|
-
# returns The converted String text
|
385
|
-
def sub_quotes text
|
386
|
-
if QuotedTextSniffRx[compat = @document.compat_mode].match? text
|
387
|
-
# NOTE interpolation is faster than String#dup
|
388
|
-
text = %(#{text})
|
389
|
-
QUOTE_SUBS[compat].each do |type, scope, pattern|
|
390
|
-
# NOTE using gsub! here as an MRI Ruby optimization
|
391
|
-
text.gsub!(pattern) { convert_quoted_text $~, type, scope }
|
392
|
-
end
|
330
|
+
# Public: Substitute quoted text (includes emphasis, strong, monospaced, etc.)
|
331
|
+
#
|
332
|
+
# text - The String text to process
|
333
|
+
#
|
334
|
+
# returns The converted [String] text
|
335
|
+
def sub_quotes text
|
336
|
+
if QuotedTextSniffRx[compat = @document.compat_mode].match? text
|
337
|
+
QUOTE_SUBS[compat].each do |type, scope, pattern|
|
338
|
+
text = text.gsub(pattern) { convert_quoted_text $~, type, scope }
|
393
339
|
end
|
394
|
-
text
|
395
340
|
end
|
341
|
+
text
|
342
|
+
end
|
396
343
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
text =
|
406
|
-
REPLACEMENTS.each do |pattern, replacement, restore|
|
407
|
-
# NOTE Using gsub! as optimization
|
408
|
-
text.gsub!(pattern) { do_replacement $~, replacement, restore }
|
409
|
-
end
|
344
|
+
# Public: Substitute replacement characters (e.g., copyright, trademark, etc.)
|
345
|
+
#
|
346
|
+
# text - The String text to process
|
347
|
+
#
|
348
|
+
# returns The [String] text with the replacement characters substituted
|
349
|
+
def sub_replacements text
|
350
|
+
if ReplaceableTextRx.match? text
|
351
|
+
REPLACEMENTS.each do |pattern, replacement, restore|
|
352
|
+
text = text.gsub(pattern) { do_replacement $~, replacement, restore }
|
410
353
|
end
|
411
|
-
text
|
412
354
|
end
|
355
|
+
text
|
413
356
|
end
|
414
357
|
|
415
358
|
# Public: Substitute special characters (i.e., encode XML)
|
416
359
|
#
|
417
|
-
# The special characters <, &, and > get replaced with <,
|
418
|
-
# &, and >, respectively.
|
360
|
+
# The special characters <, &, and > get replaced with <, &, and >, respectively.
|
419
361
|
#
|
420
362
|
# text - The String text to process.
|
421
363
|
#
|
422
364
|
# returns The String text with special characters replaced.
|
423
|
-
if
|
365
|
+
if RUBY_ENGINE == 'opal'
|
424
366
|
def sub_specialchars text
|
425
|
-
(text.include?
|
367
|
+
(text.include? ?>) || (text.include? ?&) || (text.include? ?<) ? (text.gsub SpecialCharsRx, SpecialCharsTr) : text
|
426
368
|
end
|
427
369
|
else
|
370
|
+
CGI = ::CGI
|
428
371
|
def sub_specialchars text
|
429
|
-
(text.include?
|
372
|
+
if (text.include? ?>) || (text.include? ?&) || (text.include? ?<)
|
373
|
+
(text.include? ?') || (text.include? ?") ? (text.gsub SpecialCharsRx, SpecialCharsTr) : (CGI.escape_html text)
|
374
|
+
else
|
375
|
+
text
|
376
|
+
end
|
430
377
|
end
|
431
378
|
end
|
432
379
|
alias sub_specialcharacters sub_specialchars
|
@@ -535,7 +482,7 @@ module Substitutors
|
|
535
482
|
#return text if text.nil_or_empty?
|
536
483
|
# some look ahead assertions to cut unnecessary regex calls
|
537
484
|
found = {}
|
538
|
-
found_square_bracket = found[:square_bracket] =
|
485
|
+
found_square_bracket = found[:square_bracket] = text.include? '['
|
539
486
|
found_colon = text.include? ':'
|
540
487
|
found_macroish = found[:macroish] = found_square_bracket && found_colon
|
541
488
|
found_macroish_short = found_macroish && (text.include? ':[')
|
@@ -543,7 +490,7 @@ module Substitutors
|
|
543
490
|
|
544
491
|
if doc_attrs.key? 'experimental'
|
545
492
|
if found_macroish_short && ((text.include? 'kbd:') || (text.include? 'btn:'))
|
546
|
-
text = text.gsub
|
493
|
+
text = text.gsub InlineKbdBtnMacroRx do
|
547
494
|
# honor the escape
|
548
495
|
if $1
|
549
496
|
$&.slice 1, $&.length
|
@@ -564,25 +511,20 @@ module Substitutors
|
|
564
511
|
else
|
565
512
|
keys = [keys]
|
566
513
|
end
|
567
|
-
(Inline.new self, :kbd, nil, :
|
514
|
+
(Inline.new self, :kbd, nil, attributes: { 'keys' => keys }).convert
|
568
515
|
else # $2 == 'btn'
|
569
516
|
(Inline.new self, :button, (unescape_bracketed_text $3)).convert
|
570
517
|
end
|
571
|
-
|
518
|
+
end
|
572
519
|
end
|
573
520
|
|
574
521
|
if found_macroish && (text.include? 'menu:')
|
575
|
-
text = text.gsub
|
576
|
-
# alias match for Ruby 1.8.7 compat
|
577
|
-
m = $~
|
522
|
+
text = text.gsub InlineMenuMacroRx do
|
578
523
|
# honor the escape
|
579
|
-
if $&.start_with? RS
|
580
|
-
next m[0].slice 1, m[0].length
|
581
|
-
end
|
582
|
-
|
583
|
-
menu, items = m[1], m[2]
|
524
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
584
525
|
|
585
|
-
|
526
|
+
menu = $1
|
527
|
+
if (items = $2)
|
586
528
|
items = items.gsub ESC_R_SB, R_SB if items.include? R_SB
|
587
529
|
if (delim = items.include?('>') ? '>' : (items.include?(',') ? ',' : nil))
|
588
530
|
submenus = items.split(delim).map {|it| it.strip }
|
@@ -594,25 +536,19 @@ module Substitutors
|
|
594
536
|
submenus, menuitem = [], nil
|
595
537
|
end
|
596
538
|
|
597
|
-
Inline.new(self, :menu, nil, :
|
598
|
-
|
539
|
+
Inline.new(self, :menu, nil, attributes: { 'menu' => menu, 'submenus' => submenus, 'menuitem' => menuitem }).convert
|
540
|
+
end
|
599
541
|
end
|
600
542
|
|
601
543
|
if (text.include? '"') && (text.include? '>')
|
602
|
-
text = text.gsub
|
603
|
-
# alias match for Ruby 1.8.7 compat
|
604
|
-
m = $~
|
544
|
+
text = text.gsub InlineMenuRx do
|
605
545
|
# honor the escape
|
606
|
-
if $&.start_with? RS
|
607
|
-
next m[0].slice 1, m[0].length
|
608
|
-
end
|
609
|
-
|
610
|
-
input = m[1]
|
546
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
611
547
|
|
612
|
-
menu, *submenus =
|
548
|
+
menu, *submenus = $1.split('>').map {|it| it.strip }
|
613
549
|
menuitem = submenus.pop
|
614
|
-
Inline.new(self, :menu, nil, :
|
615
|
-
|
550
|
+
Inline.new(self, :menu, nil, attributes: { 'menu' => menu, 'submenus' => submenus, 'menuitem' => menuitem }).convert
|
551
|
+
end
|
616
552
|
end
|
617
553
|
end
|
618
554
|
|
@@ -620,61 +556,55 @@ module Substitutors
|
|
620
556
|
# TODO this handling needs some cleanup
|
621
557
|
if (extensions = doc.extensions) && extensions.inline_macros? # && found_macroish
|
622
558
|
extensions.inline_macros.each do |extension|
|
623
|
-
text = text.gsub
|
624
|
-
# alias match for Ruby 1.8.7 compat
|
625
|
-
m = $~
|
559
|
+
text = text.gsub extension.instance.regexp do
|
626
560
|
# honor the escape
|
627
|
-
if $&.start_with? RS
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
if (m.names rescue []).empty?
|
632
|
-
target, content, extconf = m[1], m[2], extension.config
|
561
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
562
|
+
extconf = extension.config
|
563
|
+
if $~.names.empty?
|
564
|
+
target, content = $1, $2
|
633
565
|
else
|
634
|
-
target, content
|
566
|
+
target, content = ($~[:target] rescue nil), ($~[:content] rescue nil)
|
635
567
|
end
|
636
568
|
attributes = (attributes = extconf[:default_attrs]) ? attributes.dup : {}
|
637
569
|
if content.nil_or_empty?
|
638
570
|
attributes['text'] = content if content && extconf[:content_model] != :attributes
|
639
571
|
else
|
640
572
|
content = unescape_bracketed_text content
|
573
|
+
# QUESTION should we store the unparsed attrlist in the attrlist key?
|
641
574
|
if extconf[:content_model] == :attributes
|
642
|
-
|
643
|
-
# NOTE bracked text has already been escaped
|
644
|
-
parse_attributes content, extconf[:pos_attrs] || [], :into => attributes
|
575
|
+
parse_attributes content, extconf[:pos_attrs] || [], into: attributes
|
645
576
|
else
|
646
577
|
attributes['text'] = content
|
647
578
|
end
|
648
579
|
end
|
649
|
-
# NOTE
|
650
|
-
|
580
|
+
# NOTE for convenience, map content (unparsed attrlist) to target when format is short
|
581
|
+
target ||= extconf[:format] == :short ? content : target
|
582
|
+
replacement = extension.process_method[self, target, attributes]
|
651
583
|
Inline === replacement ? replacement.convert : replacement
|
652
|
-
|
584
|
+
end
|
653
585
|
end
|
654
586
|
end
|
655
587
|
|
656
588
|
if found_macroish && ((text.include? 'image:') || (text.include? 'icon:'))
|
657
589
|
# image:filename.png[Alt Text]
|
658
|
-
text = text.gsub
|
659
|
-
# alias match for Ruby 1.8.7 compat
|
660
|
-
m = $~
|
590
|
+
text = text.gsub InlineImageMacroRx do
|
661
591
|
# honor the escape
|
662
|
-
if
|
663
|
-
next
|
664
|
-
elsif
|
592
|
+
if $&.start_with? RS
|
593
|
+
next $&.slice 1, $&.length
|
594
|
+
elsif $&.start_with? 'icon:'
|
665
595
|
type, posattrs = 'icon', ['size']
|
666
596
|
else
|
667
597
|
type, posattrs = 'image', ['alt', 'width', 'height']
|
668
598
|
end
|
669
|
-
if (target =
|
599
|
+
if (target = $1).include? ATTR_REF_HEAD
|
670
600
|
# TODO remove this special case once titles use normal substitution order
|
671
601
|
target = sub_attributes target
|
672
602
|
end
|
673
|
-
attrs = parse_attributes
|
603
|
+
attrs = parse_attributes $2, posattrs, unescape_input: true
|
674
604
|
doc.register :images, [target, (attrs['imagesdir'] = doc_attrs['imagesdir'])] unless type == 'icon'
|
675
605
|
attrs['alt'] ||= (attrs['default-alt'] = Helpers.basename(target, true).tr('_-', ' '))
|
676
|
-
Inline.new(self, :image, nil, :
|
677
|
-
|
606
|
+
Inline.new(self, :image, nil, type: type, target: target, attributes: attrs).convert
|
607
|
+
end
|
678
608
|
end
|
679
609
|
|
680
610
|
if ((text.include? '((') && (text.include? '))')) || (found_macroish_short && (text.include? 'dexterm'))
|
@@ -682,39 +612,34 @@ module Substitutors
|
|
682
612
|
# indexterm:[Tigers,Big cats]
|
683
613
|
# ((Tigers))
|
684
614
|
# indexterm2:[Tigers]
|
685
|
-
text = text.gsub
|
686
|
-
captured = $&
|
615
|
+
text = text.gsub InlineIndextermMacroRx do
|
687
616
|
case $1
|
688
617
|
when 'indexterm'
|
689
|
-
text = $2
|
690
618
|
# honor the escape
|
691
|
-
if
|
692
|
-
|
693
|
-
end
|
619
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
620
|
+
|
694
621
|
# indexterm:[Tigers,Big cats]
|
695
|
-
terms = split_simple_csv normalize_string
|
622
|
+
terms = split_simple_csv normalize_string $2, true
|
696
623
|
doc.register :indexterms, terms
|
697
|
-
(Inline.new self, :indexterm, nil, :
|
624
|
+
(Inline.new self, :indexterm, nil, attributes: { 'terms' => terms }).convert
|
698
625
|
when 'indexterm2'
|
699
|
-
text = $2
|
700
626
|
# honor the escape
|
701
|
-
if
|
702
|
-
|
703
|
-
end
|
627
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
628
|
+
|
704
629
|
# indexterm2:[Tigers]
|
705
|
-
term = normalize_string
|
630
|
+
term = normalize_string $2, true
|
706
631
|
doc.register :indexterms, [term]
|
707
|
-
(Inline.new self, :indexterm, term, :
|
632
|
+
(Inline.new self, :indexterm, term, type: :visible).convert
|
708
633
|
else
|
709
634
|
text = $3
|
710
635
|
# honor the escape
|
711
|
-
if
|
636
|
+
if $&.start_with? RS
|
712
637
|
# escape concealed index term, but process nested flow index term
|
713
638
|
if (text.start_with? '(') && (text.end_with? ')')
|
714
639
|
text = text.slice 1, text.length - 2
|
715
640
|
visible, before, after = true, '(', ')'
|
716
641
|
else
|
717
|
-
next
|
642
|
+
next $&.slice 1, $&.length
|
718
643
|
end
|
719
644
|
else
|
720
645
|
visible = true
|
@@ -725,43 +650,41 @@ module Substitutors
|
|
725
650
|
text, before, after = (text.slice 1, text.length), '(', ''
|
726
651
|
end
|
727
652
|
elsif text.end_with? ')'
|
728
|
-
text, before, after =
|
653
|
+
text, before, after = text.chop, '', ')'
|
729
654
|
end
|
730
655
|
end
|
731
656
|
if visible
|
732
657
|
# ((Tigers))
|
733
658
|
term = normalize_string text
|
734
659
|
doc.register :indexterms, [term]
|
735
|
-
subbed_term = (Inline.new self, :indexterm, term, :
|
660
|
+
subbed_term = (Inline.new self, :indexterm, term, type: :visible).convert
|
736
661
|
else
|
737
662
|
# (((Tigers,Big cats)))
|
738
663
|
terms = split_simple_csv(normalize_string text)
|
739
664
|
doc.register :indexterms, terms
|
740
|
-
subbed_term = (Inline.new self, :indexterm, nil, :
|
665
|
+
subbed_term = (Inline.new self, :indexterm, nil, attributes: { 'terms' => terms }).convert
|
741
666
|
end
|
742
667
|
before ? %(#{before}#{subbed_term}#{after}) : subbed_term
|
743
668
|
end
|
744
|
-
|
669
|
+
end
|
745
670
|
end
|
746
671
|
|
747
672
|
if found_colon && (text.include? '://')
|
748
673
|
# inline urls, target[text] (optionally prefixed with link: and optionally surrounded by <>)
|
749
|
-
text = text.gsub
|
750
|
-
|
751
|
-
m = $~
|
674
|
+
text = text.gsub InlineLinkRx do
|
675
|
+
target = $2
|
752
676
|
# honor the escape
|
753
|
-
|
754
|
-
|
755
|
-
end
|
677
|
+
next %(#{$1}#{target.slice 1, target.length}#{$3}) if target.start_with? RS
|
678
|
+
|
756
679
|
# NOTE if text is non-nil, then we've matched a formal macro (i.e., trailing square brackets)
|
757
|
-
prefix, text, suffix =
|
680
|
+
captured, prefix, text, suffix = $&, $1, (macro = $3) || '', ''
|
758
681
|
if prefix == 'link:'
|
759
682
|
if macro
|
760
683
|
prefix = ''
|
761
684
|
else
|
762
685
|
# invalid macro syntax (link: prefix w/o trailing square brackets)
|
763
686
|
# we probably shouldn't even get here...our regex is doing too much
|
764
|
-
next
|
687
|
+
next captured
|
765
688
|
end
|
766
689
|
end
|
767
690
|
unless macro || UriTerminatorRx !~ target
|
@@ -794,10 +717,10 @@ module Substitutors
|
|
794
717
|
end
|
795
718
|
end
|
796
719
|
# NOTE handle case when remaining target is a URI scheme (e.g., http://)
|
797
|
-
return
|
720
|
+
return captured if target.end_with? '://'
|
798
721
|
end
|
799
722
|
|
800
|
-
attrs, link_opts = nil, { :
|
723
|
+
attrs, link_opts = nil, { type: :link }
|
801
724
|
unless text.empty?
|
802
725
|
text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
|
803
726
|
if !doc.compat_mode && (text.include? '=')
|
@@ -810,7 +733,7 @@ module Substitutors
|
|
810
733
|
#unless attrs && (attrs.key? 'title')
|
811
734
|
# if text.include? '|'
|
812
735
|
# attrs ||= {}
|
813
|
-
# text, attrs['title'] = text.
|
736
|
+
# text, _, attrs['title'] = text.partition '|'
|
814
737
|
# end
|
815
738
|
#end
|
816
739
|
|
@@ -837,21 +760,23 @@ module Substitutors
|
|
837
760
|
doc.register :links, (link_opts[:target] = target)
|
838
761
|
link_opts[:attributes] = attrs if attrs
|
839
762
|
%(#{prefix}#{Inline.new(self, :anchor, text, link_opts).convert}#{suffix})
|
840
|
-
|
763
|
+
end
|
841
764
|
end
|
842
765
|
|
843
766
|
if found_macroish && ((text.include? 'link:') || (text.include? 'mailto:'))
|
844
767
|
# inline link macros, link:target[text]
|
845
|
-
text = text.gsub
|
846
|
-
# alias match for Ruby 1.8.7 compat
|
847
|
-
m = $~
|
768
|
+
text = text.gsub InlineLinkMacroRx do
|
848
769
|
# honor the escape
|
849
770
|
if $&.start_with? RS
|
850
|
-
next
|
771
|
+
next $&.slice 1, $&.length
|
772
|
+
elsif (mailto = $1)
|
773
|
+
target = %(mailto:#{$2})
|
774
|
+
mailto_text = $2
|
775
|
+
else
|
776
|
+
target = $2
|
851
777
|
end
|
852
|
-
|
853
|
-
|
854
|
-
unless (text = m[3]).empty?
|
778
|
+
attrs, link_opts = nil, { type: :link }
|
779
|
+
unless (text = $3).empty?
|
855
780
|
text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
|
856
781
|
if mailto
|
857
782
|
if !doc.compat_mode && (text.include? ',')
|
@@ -859,9 +784,9 @@ module Substitutors
|
|
859
784
|
link_opts[:id] = attrs.delete 'id' if attrs.key? 'id'
|
860
785
|
if attrs.key? 2
|
861
786
|
if attrs.key? 3
|
862
|
-
target = %(#{target}?subject=#{Helpers.
|
787
|
+
target = %(#{target}?subject=#{Helpers.encode_uri_component attrs[2]}&body=#{Helpers.encode_uri_component attrs[3]})
|
863
788
|
else
|
864
|
-
target = %(#{target}?subject=#{Helpers.
|
789
|
+
target = %(#{target}?subject=#{Helpers.encode_uri_component attrs[2]})
|
865
790
|
end
|
866
791
|
end
|
867
792
|
end
|
@@ -875,7 +800,7 @@ module Substitutors
|
|
875
800
|
#unless attrs && (attrs.key? 'title')
|
876
801
|
# if text.include? '|'
|
877
802
|
# attrs ||= {}
|
878
|
-
# text, attrs['title'] = text.
|
803
|
+
# text, _, attrs['title'] = text.partition '|'
|
879
804
|
# end
|
880
805
|
#end
|
881
806
|
|
@@ -892,7 +817,7 @@ module Substitutors
|
|
892
817
|
if text.empty?
|
893
818
|
# mailto is a special case, already processed
|
894
819
|
if mailto
|
895
|
-
text =
|
820
|
+
text = mailto_text
|
896
821
|
else
|
897
822
|
if doc_attrs.key? 'hide-uri-scheme'
|
898
823
|
if (text = target.sub UriSniffRx, '').empty?
|
@@ -913,41 +838,45 @@ module Substitutors
|
|
913
838
|
doc.register :links, (link_opts[:target] = target)
|
914
839
|
link_opts[:attributes] = attrs if attrs
|
915
840
|
Inline.new(self, :anchor, text, link_opts).convert
|
916
|
-
|
841
|
+
end
|
917
842
|
end
|
918
843
|
|
919
844
|
if text.include? '@'
|
920
|
-
text = text.gsub
|
921
|
-
|
922
|
-
if
|
923
|
-
next (tip == RS ? (address.slice 1, address.length) : address)
|
924
|
-
end
|
845
|
+
text = text.gsub InlineEmailRx do
|
846
|
+
# honor the escape
|
847
|
+
next $1 == RS ? ($&.slice 1, $&.length) : $& if $1
|
925
848
|
|
926
|
-
target = %(mailto:#{
|
849
|
+
target = %(mailto:#{$&})
|
927
850
|
# QUESTION should this be registered as an e-mail address?
|
928
851
|
doc.register(:links, target)
|
929
852
|
|
930
|
-
Inline.new(self, :anchor,
|
931
|
-
|
853
|
+
Inline.new(self, :anchor, $&, type: :link, target: target).convert
|
854
|
+
end
|
932
855
|
end
|
933
856
|
|
934
857
|
if found_macroish && (text.include? 'tnote')
|
935
|
-
text = text.gsub
|
936
|
-
# alias match for Ruby 1.8.7 compat
|
937
|
-
m = $~
|
858
|
+
text = text.gsub InlineFootnoteMacroRx do
|
938
859
|
# honor the escape
|
939
|
-
if $&.start_with? RS
|
940
|
-
|
941
|
-
|
942
|
-
if
|
943
|
-
|
860
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
861
|
+
|
862
|
+
# footnoteref
|
863
|
+
if $1
|
864
|
+
if $3
|
865
|
+
id, text = $3.split ',', 2
|
866
|
+
logger.warn %(found deprecated footnoteref macro: #{$&}; use footnote macro with target instead) unless doc.compat_mode
|
867
|
+
else
|
868
|
+
next $&
|
869
|
+
end
|
870
|
+
# footnote
|
944
871
|
else
|
945
|
-
id
|
872
|
+
id = $2
|
873
|
+
text = $3
|
946
874
|
end
|
875
|
+
|
947
876
|
if id
|
948
877
|
if text
|
949
878
|
# REVIEW it's a dirty job, but somebody's gotta do it
|
950
|
-
text = restore_passthroughs(sub_inline_xrefs(sub_inline_anchors(normalize_string text, true))
|
879
|
+
text = restore_passthroughs(sub_inline_xrefs(sub_inline_anchors(normalize_string text, true)))
|
951
880
|
index = doc.counter('footnote-number')
|
952
881
|
doc.register(:footnotes, Document::Footnote.new(index, id, text))
|
953
882
|
type, target = :ref, nil
|
@@ -962,15 +891,15 @@ module Substitutors
|
|
962
891
|
end
|
963
892
|
elsif text
|
964
893
|
# REVIEW it's a dirty job, but somebody's gotta do it
|
965
|
-
text = restore_passthroughs(sub_inline_xrefs(sub_inline_anchors(normalize_string text, true))
|
894
|
+
text = restore_passthroughs(sub_inline_xrefs(sub_inline_anchors(normalize_string text, true)))
|
966
895
|
index = doc.counter('footnote-number')
|
967
896
|
doc.register(:footnotes, Document::Footnote.new(index, id, text))
|
968
897
|
type = target = nil
|
969
898
|
else
|
970
|
-
next
|
899
|
+
next $&
|
971
900
|
end
|
972
|
-
Inline.new(self, :footnote, text, :
|
973
|
-
|
901
|
+
Inline.new(self, :footnote, text, attributes: { 'index' => index }, id: id, target: target, type: type).convert
|
902
|
+
end
|
974
903
|
end
|
975
904
|
|
976
905
|
sub_inline_xrefs(sub_inline_anchors(text, found), found)
|
@@ -979,17 +908,15 @@ module Substitutors
|
|
979
908
|
# Internal: Substitute normal and bibliographic anchors
|
980
909
|
def sub_inline_anchors(text, found = nil)
|
981
910
|
if @context == :list_item && @parent.style == 'bibliography'
|
982
|
-
text = text.sub(InlineBiblioAnchorRx) {
|
983
|
-
# NOTE target property on :bibref is deprecated
|
984
|
-
Inline.new(self, :anchor, %([#{$2 || $1}]), :type => :bibref, :id => $1, :target => $1).convert
|
985
|
-
}
|
911
|
+
text = text.sub(InlineBiblioAnchorRx) { (Inline.new self, :anchor, $2, type: :bibref, id: $1).convert }
|
986
912
|
end
|
987
913
|
|
988
914
|
if ((!found || found[:square_bracket]) && text.include?('[[')) ||
|
989
915
|
((!found || found[:macroish]) && text.include?('or:'))
|
990
|
-
text = text.gsub
|
916
|
+
text = text.gsub InlineAnchorRx do
|
991
917
|
# honor the escape
|
992
918
|
next $&.slice 1, $&.length if $1
|
919
|
+
|
993
920
|
# NOTE reftext is only relevant for DocBook output; used as value of xreflabel attribute
|
994
921
|
if (id = $2)
|
995
922
|
reftext = $3
|
@@ -999,9 +926,8 @@ module Substitutors
|
|
999
926
|
reftext = reftext.gsub ESC_R_SB, R_SB
|
1000
927
|
end
|
1001
928
|
end
|
1002
|
-
|
1003
|
-
|
1004
|
-
}
|
929
|
+
Inline.new(self, :anchor, reftext, type: :ref, id: id).convert
|
930
|
+
end
|
1005
931
|
end
|
1006
932
|
|
1007
933
|
text
|
@@ -1010,21 +936,18 @@ module Substitutors
|
|
1010
936
|
# Internal: Substitute cross reference links
|
1011
937
|
def sub_inline_xrefs(content, found = nil)
|
1012
938
|
if ((found ? found[:macroish] : (content.include? '[')) && (content.include? 'xref:')) || ((content.include? '&') && (content.include? 'lt;&'))
|
1013
|
-
content = content.gsub
|
1014
|
-
# alias match for Ruby 1.8.7 compat
|
1015
|
-
m = $~
|
939
|
+
content = content.gsub InlineXrefMacroRx do
|
1016
940
|
# honor the escape
|
1017
|
-
if $&.start_with? RS
|
1018
|
-
|
1019
|
-
end
|
941
|
+
next $&.slice 1, $&.length if $&.start_with? RS
|
942
|
+
|
1020
943
|
attrs, doc = {}, @document
|
1021
|
-
if (refid =
|
944
|
+
if (refid = $1)
|
1022
945
|
refid, text = refid.split ',', 2
|
1023
946
|
text = text.lstrip if text
|
1024
947
|
else
|
1025
948
|
macro = true
|
1026
|
-
refid =
|
1027
|
-
if (text =
|
949
|
+
refid = $2
|
950
|
+
if (text = $3)
|
1028
951
|
text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
|
1029
952
|
# NOTE if an equal sign (=) is present, parse text as attributes
|
1030
953
|
text = ((AttributeList.new text, self).parse_into attrs)[1] if !doc.compat_mode && (text.include? '=')
|
@@ -1035,21 +958,27 @@ module Substitutors
|
|
1035
958
|
fragment = refid
|
1036
959
|
elsif (hash_idx = refid.index '#')
|
1037
960
|
if hash_idx > 0
|
1038
|
-
if (fragment_len = refid.length -
|
961
|
+
if (fragment_len = refid.length - 1 - hash_idx) > 0
|
1039
962
|
path, fragment = (refid.slice 0, hash_idx), (refid.slice hash_idx + 1, fragment_len)
|
1040
963
|
else
|
1041
|
-
path = refid.
|
964
|
+
path = refid.chop
|
1042
965
|
end
|
1043
|
-
if
|
966
|
+
if macro
|
967
|
+
src2src = (path = path.slice 0, path.length - 5) if path.end_with? '.adoc'
|
968
|
+
elsif (last_dot_idx = path.rindex '.') && ASCIIDOC_EXTENSIONS[path.slice last_dot_idx, path.length]
|
969
|
+
src2src = (path = path.slice 0, last_dot_idx)
|
970
|
+
else
|
1044
971
|
src2src = path
|
1045
|
-
elsif ASCIIDOC_EXTENSIONS[ext]
|
1046
|
-
src2src = (path = path.slice 0, path.length - ext.length)
|
1047
972
|
end
|
1048
973
|
else
|
1049
974
|
target, fragment = refid, (refid.slice 1, refid.length)
|
1050
975
|
end
|
1051
|
-
elsif macro && (refid.
|
1052
|
-
|
976
|
+
elsif macro && (refid.include? '.')
|
977
|
+
if refid.end_with? '.adoc'
|
978
|
+
src2src = (path = refid.slice 0, refid.length - 5)
|
979
|
+
else
|
980
|
+
path = refid
|
981
|
+
end
|
1053
982
|
else
|
1054
983
|
fragment = refid
|
1055
984
|
end
|
@@ -1057,14 +986,14 @@ module Substitutors
|
|
1057
986
|
# handles: #id
|
1058
987
|
if target
|
1059
988
|
refid = fragment
|
1060
|
-
logger.
|
989
|
+
logger.debug %(possible invalid reference: #{refid}) if logger.debug? && !doc.catalog[:refs][refid]
|
1061
990
|
elsif path
|
1062
991
|
# handles: path#, path#id, path.adoc#, path.adoc#id, or path.adoc (xref macro only)
|
1063
992
|
# the referenced path is the current document, or its contents have been included in the current document
|
1064
993
|
if src2src && (doc.attributes['docname'] == path || doc.catalog[:includes][path])
|
1065
994
|
if fragment
|
1066
995
|
refid, path, target = fragment, nil, %(##{fragment})
|
1067
|
-
logger.
|
996
|
+
logger.debug %(possible invalid reference: #{refid}) if logger.debug? && !doc.catalog[:refs][refid]
|
1068
997
|
else
|
1069
998
|
refid, path, target = nil, nil, '#'
|
1070
999
|
end
|
@@ -1079,21 +1008,21 @@ module Substitutors
|
|
1079
1008
|
# handles: id (in compat mode or when natural xrefs are disabled)
|
1080
1009
|
elsif doc.compat_mode || !Compliance.natural_xrefs
|
1081
1010
|
refid, target = fragment, %(##{fragment})
|
1082
|
-
logger.
|
1011
|
+
logger.debug %(possible invalid reference: #{refid}) if logger.debug? && doc.catalog[:refs][refid]
|
1083
1012
|
# handles: id
|
1084
|
-
elsif doc.catalog[:
|
1013
|
+
elsif doc.catalog[:refs][fragment]
|
1085
1014
|
refid, target = fragment, %(##{fragment})
|
1086
1015
|
# handles: Node Title or Reference Text
|
1087
1016
|
# do reverse lookup on fragment if not a known ID and resembles reftext (contains a space or uppercase char)
|
1088
|
-
elsif (refid = doc.
|
1017
|
+
elsif (refid = doc.resolve_id fragment) && ((fragment.include? ' ') || fragment.downcase != fragment)
|
1089
1018
|
fragment, target = refid, %(##{refid})
|
1090
1019
|
else
|
1091
1020
|
refid, target = fragment, %(##{fragment})
|
1092
|
-
logger.
|
1021
|
+
logger.debug %(possible invalid reference: #{refid}) if logger.debug?
|
1093
1022
|
end
|
1094
1023
|
attrs['path'], attrs['fragment'], attrs['refid'] = path, fragment, refid
|
1095
|
-
Inline.new(self, :anchor, text, :
|
1096
|
-
|
1024
|
+
Inline.new(self, :anchor, text, type: :xref, target: target, attributes: attrs).convert
|
1025
|
+
end
|
1097
1026
|
end
|
1098
1027
|
|
1099
1028
|
content
|
@@ -1107,15 +1036,15 @@ module Substitutors
|
|
1107
1036
|
def sub_callouts(text)
|
1108
1037
|
callout_rx = (attr? 'line-comment') ? CalloutSourceRxMap[attr 'line-comment'] : CalloutSourceRx
|
1109
1038
|
autonum = 0
|
1110
|
-
text.gsub
|
1039
|
+
text.gsub callout_rx do
|
1111
1040
|
# honor the escape
|
1112
1041
|
if $2
|
1113
1042
|
# use sub since it might be behind a line comment
|
1114
1043
|
$&.sub(RS, '')
|
1115
1044
|
else
|
1116
|
-
Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, :
|
1045
|
+
Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, id: @document.callouts.read_next_id, attributes: { 'guard' => $1 }).convert
|
1117
1046
|
end
|
1118
|
-
|
1047
|
+
end
|
1119
1048
|
end
|
1120
1049
|
|
1121
1050
|
# Public: Substitute post replacements
|
@@ -1124,15 +1053,16 @@ module Substitutors
|
|
1124
1053
|
#
|
1125
1054
|
# Returns the converted String text
|
1126
1055
|
def sub_post_replacements(text)
|
1127
|
-
if
|
1056
|
+
#if attr? 'hardbreaks-option', nil, true
|
1057
|
+
if @attributes['hardbreaks-option'] || @document.attributes['hardbreaks-option']
|
1128
1058
|
lines = text.split LF, -1
|
1129
1059
|
return text if lines.size < 2
|
1130
1060
|
last = lines.pop
|
1131
|
-
(lines.map
|
1132
|
-
Inline.new(self, :break, (line.end_with? HARD_LINE_BREAK) ? (line.slice 0, line.length - 2) : line, :
|
1133
|
-
|
1061
|
+
(lines.map do |line|
|
1062
|
+
Inline.new(self, :break, (line.end_with? HARD_LINE_BREAK) ? (line.slice 0, line.length - 2) : line, type: :line).convert
|
1063
|
+
end << last).join LF
|
1134
1064
|
elsif (text.include? PLUS) && (text.include? HARD_LINE_BREAK)
|
1135
|
-
text.gsub(HardLineBreakRx) { Inline.new(self, :break, $1, :
|
1065
|
+
text.gsub(HardLineBreakRx) { Inline.new(self, :break, $1, type: :line).convert }
|
1136
1066
|
else
|
1137
1067
|
text
|
1138
1068
|
end
|
@@ -1156,20 +1086,20 @@ module Substitutors
|
|
1156
1086
|
|
1157
1087
|
if scope == :constrained
|
1158
1088
|
if unescaped_attrs
|
1159
|
-
%(#{unescaped_attrs}#{Inline.new(self, :quoted, match[3], :
|
1089
|
+
%(#{unescaped_attrs}#{Inline.new(self, :quoted, match[3], type: type).convert})
|
1160
1090
|
else
|
1161
1091
|
if (attrlist = match[2])
|
1162
1092
|
id = (attributes = parse_quoted_text_attributes attrlist).delete 'id'
|
1163
1093
|
type = :unquoted if type == :mark
|
1164
1094
|
end
|
1165
|
-
%(#{match[1]}#{Inline.new(self, :quoted, match[3], :
|
1095
|
+
%(#{match[1]}#{Inline.new(self, :quoted, match[3], type: type, id: id, attributes: attributes).convert})
|
1166
1096
|
end
|
1167
1097
|
else
|
1168
1098
|
if (attrlist = match[1])
|
1169
1099
|
id = (attributes = parse_quoted_text_attributes attrlist).delete 'id'
|
1170
1100
|
type = :unquoted if type == :mark
|
1171
1101
|
end
|
1172
|
-
Inline.new(self, :quoted, match[2], :
|
1102
|
+
Inline.new(self, :quoted, match[2], type: type, id: id, attributes: attributes).convert
|
1173
1103
|
end
|
1174
1104
|
end
|
1175
1105
|
|
@@ -1180,20 +1110,18 @@ module Substitutors
|
|
1180
1110
|
#
|
1181
1111
|
# Returns a Hash of attributes (role and id only)
|
1182
1112
|
def parse_quoted_text_attributes str
|
1113
|
+
return {} if (str = str.rstrip).empty?
|
1183
1114
|
# NOTE attributes are typically resolved after quoted text, so substitute eagerly
|
1184
1115
|
str = sub_attributes str if str.include? ATTR_REF_HEAD
|
1185
|
-
# for compliance, only consider first positional attribute
|
1116
|
+
# for compliance, only consider first positional attribute (very unlikely)
|
1186
1117
|
str = str.slice 0, (str.index ',') if str.include? ','
|
1187
1118
|
|
1188
|
-
if (str
|
1189
|
-
|
1190
|
-
elsif (str.start_with? '.', '#') && Compliance.shorthand_property_syntax
|
1191
|
-
segments = str.split('#', 2)
|
1119
|
+
if (str.start_with? '.', '#') && Compliance.shorthand_property_syntax
|
1120
|
+
segments = str.split '#', 2
|
1192
1121
|
|
1193
1122
|
if segments.size > 1
|
1194
1123
|
id, *more_roles = segments[1].split('.')
|
1195
1124
|
else
|
1196
|
-
id = nil
|
1197
1125
|
more_roles = []
|
1198
1126
|
end
|
1199
1127
|
|
@@ -1211,7 +1139,7 @@ module Substitutors
|
|
1211
1139
|
attrs['role'] = roles.join ' ' unless roles.empty?
|
1212
1140
|
attrs
|
1213
1141
|
else
|
1214
|
-
{'role' => str}
|
1142
|
+
{ 'role' => str }
|
1215
1143
|
end
|
1216
1144
|
end
|
1217
1145
|
|
@@ -1231,8 +1159,8 @@ module Substitutors
|
|
1231
1159
|
# Returns an empty Hash if attrlist is nil or empty, otherwise a Hash of parsed attributes.
|
1232
1160
|
def parse_attributes attrlist, posattrs = [], opts = {}
|
1233
1161
|
return {} unless attrlist && !attrlist.empty?
|
1234
|
-
attrlist = @document.sub_attributes attrlist if opts[:sub_input] && (attrlist.include? ATTR_REF_HEAD)
|
1235
1162
|
attrlist = unescape_bracketed_text attrlist if opts[:unescape_input]
|
1163
|
+
attrlist = @document.sub_attributes attrlist if opts[:sub_input] && (attrlist.include? ATTR_REF_HEAD)
|
1236
1164
|
# substitutions are only performed on attribute values if block is not nil
|
1237
1165
|
block = self if opts[:sub_result]
|
1238
1166
|
if (into = opts[:into])
|
@@ -1268,7 +1196,7 @@ module Substitutors
|
|
1268
1196
|
end
|
1269
1197
|
end
|
1270
1198
|
|
1271
|
-
# Internal: Strip bounding whitespace, fold
|
1199
|
+
# Internal: Strip bounding whitespace, fold newlines and unescape closing
|
1272
1200
|
# square brackets from text extracted from brackets
|
1273
1201
|
def unescape_bracketed_text text
|
1274
1202
|
if (text = text.strip.tr LF, ' ').include? R_SB
|
@@ -1277,7 +1205,7 @@ module Substitutors
|
|
1277
1205
|
text
|
1278
1206
|
end
|
1279
1207
|
|
1280
|
-
# Internal: Strip bounding whitespace and fold
|
1208
|
+
# Internal: Strip bounding whitespace and fold newlines
|
1281
1209
|
def normalize_string str, unescape_brackets = false
|
1282
1210
|
unless str.empty?
|
1283
1211
|
str = str.strip.tr LF, ' '
|
@@ -1299,33 +1227,30 @@ module Substitutors
|
|
1299
1227
|
# for double-quoted values (in which commas are ignored)
|
1300
1228
|
def split_simple_csv str
|
1301
1229
|
if str.empty?
|
1302
|
-
|
1230
|
+
[]
|
1303
1231
|
elsif str.include? '"'
|
1304
1232
|
values = []
|
1305
|
-
|
1233
|
+
accum = ''
|
1306
1234
|
quote_open = false
|
1307
1235
|
str.each_char do |c|
|
1308
1236
|
case c
|
1309
1237
|
when ','
|
1310
1238
|
if quote_open
|
1311
|
-
|
1239
|
+
accum = accum + c
|
1312
1240
|
else
|
1313
|
-
values <<
|
1314
|
-
|
1241
|
+
values << accum.strip
|
1242
|
+
accum = ''
|
1315
1243
|
end
|
1316
1244
|
when '"'
|
1317
1245
|
quote_open = !quote_open
|
1318
1246
|
else
|
1319
|
-
|
1247
|
+
accum = accum + c
|
1320
1248
|
end
|
1321
1249
|
end
|
1322
|
-
|
1323
|
-
values << current.join.strip
|
1250
|
+
values << accum.strip
|
1324
1251
|
else
|
1325
|
-
|
1252
|
+
str.split(',').map {|it| it.strip }
|
1326
1253
|
end
|
1327
|
-
|
1328
|
-
values
|
1329
1254
|
end
|
1330
1255
|
|
1331
1256
|
# Internal: Resolve the list of comma-delimited subs against the possible options.
|
@@ -1403,160 +1328,92 @@ module Substitutors
|
|
1403
1328
|
resolve_subs subs, :inline, nil, 'passthrough macro'
|
1404
1329
|
end
|
1405
1330
|
|
1406
|
-
# Public: Highlight the source code
|
1407
|
-
#
|
1331
|
+
# Public: Highlight (i.e., colorize) the source code during conversion using a syntax highlighter, if activated by the
|
1332
|
+
# source-highlighter document attribute. Otherwise return the text with verbatim substitutions applied.
|
1408
1333
|
#
|
1409
|
-
#
|
1410
|
-
# highlighter, then
|
1411
|
-
#
|
1334
|
+
# If the process_callouts argument is true, this method will extract the callout marks from the source before passing
|
1335
|
+
# it to the syntax highlighter, then subsequently restore those callout marks to the highlighted source so the callout
|
1336
|
+
# marks don't confuse the syntax highlighter.
|
1412
1337
|
#
|
1413
|
-
# source - the source code String to highlight
|
1414
|
-
# process_callouts - a Boolean flag indicating whether callout marks should be substituted
|
1338
|
+
# source - the source code String to syntax highlight
|
1339
|
+
# process_callouts - a Boolean flag indicating whether callout marks should be located and substituted
|
1415
1340
|
#
|
1416
|
-
#
|
1417
|
-
#
|
1418
|
-
def highlight_source source, process_callouts
|
1419
|
-
|
1420
|
-
|
1421
|
-
unless (highlighter_loaded = defined? ::CodeRay) ||
|
1422
|
-
(defined? @@coderay_unavailable) || @document.attributes['coderay-unavailable']
|
1423
|
-
if (Helpers.require_library 'coderay', true, :warn).nil?
|
1424
|
-
# prevent further attempts to load CodeRay in this process
|
1425
|
-
@@coderay_unavailable = true
|
1426
|
-
else
|
1427
|
-
highlighter_loaded = true
|
1428
|
-
end
|
1429
|
-
end
|
1430
|
-
when 'pygments'
|
1431
|
-
unless (highlighter_loaded = defined? ::Pygments) ||
|
1432
|
-
(defined? @@pygments_unavailable) || @document.attributes['pygments-unavailable']
|
1433
|
-
if (Helpers.require_library 'pygments', 'pygments.rb', :warn).nil?
|
1434
|
-
# prevent further attempts to load Pygments in this process
|
1435
|
-
@@pygments_unavailable = true
|
1436
|
-
else
|
1437
|
-
highlighter_loaded = true
|
1438
|
-
end
|
1439
|
-
end
|
1440
|
-
else
|
1441
|
-
# unknown highlighting library (something is misconfigured if we arrive here)
|
1442
|
-
highlighter_loaded = false
|
1443
|
-
end
|
1444
|
-
|
1445
|
-
return sub_source source, process_callouts unless highlighter_loaded
|
1341
|
+
# Returns the highlighted source code, if a syntax highlighter is defined on the document, otherwise the source with
|
1342
|
+
# verbatim substituions applied
|
1343
|
+
def highlight_source source, process_callouts
|
1344
|
+
# NOTE the call to highlight? is a defensive check since, normally, we wouldn't arrive here unless it returns true
|
1345
|
+
return sub_source source, process_callouts unless (syntax_hl = @document.syntax_highlighter) && syntax_hl.highlight?
|
1446
1346
|
|
1447
|
-
lineno = 0
|
1448
|
-
callout_on_last = false
|
1449
1347
|
if process_callouts
|
1450
1348
|
callout_marks = {}
|
1451
|
-
|
1349
|
+
lineno = 0
|
1350
|
+
last_lineno = nil
|
1452
1351
|
callout_rx = (attr? 'line-comment') ? CalloutExtractRxMap[attr 'line-comment'] : CalloutExtractRx
|
1453
1352
|
# extract callout marks, indexed by line number
|
1454
|
-
source = source.split
|
1455
|
-
lineno
|
1456
|
-
line.gsub
|
1353
|
+
source = (source.split LF, -1).map do |line|
|
1354
|
+
lineno += 1
|
1355
|
+
line.gsub callout_rx do
|
1457
1356
|
# honor the escape
|
1458
1357
|
if $2
|
1459
1358
|
# use sub since it might be behind a line comment
|
1460
|
-
$&.sub
|
1359
|
+
$&.sub RS, ''
|
1461
1360
|
else
|
1462
1361
|
(callout_marks[lineno] ||= []) << [$1, $4]
|
1463
|
-
|
1362
|
+
last_lineno = lineno
|
1464
1363
|
nil
|
1465
1364
|
end
|
1466
|
-
}
|
1467
|
-
}.join LF
|
1468
|
-
callout_on_last = (last == lineno)
|
1469
|
-
callout_marks = nil if callout_marks.empty?
|
1470
|
-
else
|
1471
|
-
callout_marks = nil
|
1472
|
-
end
|
1473
|
-
|
1474
|
-
linenums_mode = nil
|
1475
|
-
highlight_lines = nil
|
1476
|
-
|
1477
|
-
case highlighter
|
1478
|
-
when 'coderay'
|
1479
|
-
if (linenums_mode = (attr? 'linenums', nil, false) ? (@document.attributes['coderay-linenums-mode'] || :table).to_sym : nil)
|
1480
|
-
start = 1 if (start = (attr 'start', nil, 1).to_i) < 1
|
1481
|
-
if attr? 'highlight', nil, false
|
1482
|
-
highlight_lines = resolve_lines_to_highlight source, (attr 'highlight', nil, false)
|
1483
|
-
end
|
1484
|
-
end
|
1485
|
-
result = ::CodeRay::Duo[attr('language', :text, false).to_sym, :html, {
|
1486
|
-
:css => (@document.attributes['coderay-css'] || :class).to_sym,
|
1487
|
-
:line_numbers => linenums_mode,
|
1488
|
-
:line_number_start => start,
|
1489
|
-
:line_number_anchors => false,
|
1490
|
-
:highlight_lines => highlight_lines,
|
1491
|
-
:bold_every => false
|
1492
|
-
}].highlight source
|
1493
|
-
when 'pygments'
|
1494
|
-
lexer = ::Pygments::Lexer.find_by_alias(attr 'language', 'text', false) || ::Pygments::Lexer.find_by_mimetype('text/plain')
|
1495
|
-
opts = { :cssclass => 'pyhl', :classprefix => 'tok-', :nobackground => true, :stripnl => false }
|
1496
|
-
opts[:startinline] = !(option? 'mixed') if lexer.name == 'PHP'
|
1497
|
-
unless (@document.attributes['pygments-css'] || 'class') == 'class'
|
1498
|
-
opts[:noclasses] = true
|
1499
|
-
opts[:style] = (@document.attributes['pygments-style'] || Stylesheets::DEFAULT_PYGMENTS_STYLE)
|
1500
|
-
end
|
1501
|
-
if attr? 'highlight', nil, false
|
1502
|
-
unless (highlight_lines = resolve_lines_to_highlight source, (attr 'highlight', nil, false)).empty?
|
1503
|
-
opts[:hl_lines] = highlight_lines.join ' '
|
1504
|
-
end
|
1505
|
-
end
|
1506
|
-
# NOTE highlight can return nil if something goes wrong; fallback to source if this happens
|
1507
|
-
# TODO we could add the line numbers in ourselves instead of having to strip out the junk
|
1508
|
-
if (attr? 'linenums', nil, false) && (opts[:linenostart] = (start = attr 'start', 1, false).to_i < 1 ? 1 : start) &&
|
1509
|
-
(opts[:linenos] = @document.attributes['pygments-linenums-mode'] || 'table') == 'table'
|
1510
|
-
linenums_mode = :table
|
1511
|
-
if (result = lexer.highlight source, :options => opts)
|
1512
|
-
result = (result.sub PygmentsWrapperDivRx, '\1').gsub PygmentsWrapperPreRx, '\1'
|
1513
|
-
else
|
1514
|
-
result = sub_specialchars source
|
1515
|
-
end
|
1516
|
-
elsif (result = lexer.highlight source, :options => opts)
|
1517
|
-
if PygmentsWrapperPreRx =~ result
|
1518
|
-
result = $1
|
1519
1365
|
end
|
1366
|
+
end.join LF
|
1367
|
+
if last_lineno
|
1368
|
+
source = %(#{source}#{LF}) if last_lineno == lineno
|
1520
1369
|
else
|
1521
|
-
|
1370
|
+
callout_marks = nil
|
1522
1371
|
end
|
1523
1372
|
end
|
1524
1373
|
|
1374
|
+
doc_attrs = @document.attributes
|
1375
|
+
syntax_hl_name = syntax_hl.name
|
1376
|
+
if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil)
|
1377
|
+
start_line_number = 1 if (start_line_number = (attr 'start', 1).to_i) < 1
|
1378
|
+
end
|
1379
|
+
highlight_lines = resolve_lines_to_highlight source, (attr 'highlight') if attr? 'highlight'
|
1380
|
+
|
1381
|
+
highlighted, source_offset = syntax_hl.highlight self, source, (attr 'language'),
|
1382
|
+
callouts: callout_marks,
|
1383
|
+
css_mode: (doc_attrs[%(#{syntax_hl_name}-css)] || :class).to_sym,
|
1384
|
+
highlight_lines: highlight_lines,
|
1385
|
+
number_lines: linenums_mode,
|
1386
|
+
start_line_number: start_line_number,
|
1387
|
+
style: doc_attrs[%(#{syntax_hl_name}-style)]
|
1388
|
+
|
1525
1389
|
# fix passthrough placeholders that got caught up in syntax highlighting
|
1526
|
-
|
1390
|
+
highlighted = highlighted.gsub HighlightedPassSlotRx, %(#{PASS_START}\\1#{PASS_END}) unless @passthroughs.empty?
|
1527
1391
|
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
if highlighter == 'coderay' && (pos = line.index '</pre>')
|
1542
|
-
line, tail = (line.slice 0, pos), (line.slice pos, line.length)
|
1543
|
-
elsif highlighter == 'pygments' && (pos = line.start_with? '</td>')
|
1544
|
-
line, tail = '', line
|
1545
|
-
end
|
1546
|
-
end
|
1392
|
+
# NOTE highlight method may have depleted callouts
|
1393
|
+
if callout_marks.nil_or_empty?
|
1394
|
+
highlighted
|
1395
|
+
else
|
1396
|
+
if source_offset
|
1397
|
+
preamble = highlighted.slice 0, source_offset
|
1398
|
+
highlighted = highlighted.slice source_offset, highlighted.length
|
1399
|
+
else
|
1400
|
+
preamble = ''
|
1401
|
+
end
|
1402
|
+
autonum = lineno = 0
|
1403
|
+
preamble + ((highlighted.split LF, -1).map do |line|
|
1404
|
+
if (conums = callout_marks.delete lineno += 1)
|
1547
1405
|
if conums.size == 1
|
1548
1406
|
guard, conum = conums[0]
|
1549
|
-
%(#{line}#{Inline.new(self, :callout, conum == '.' ? (autonum += 1).to_s : conum, :
|
1407
|
+
%(#{line}#{Inline.new(self, :callout, conum == '.' ? (autonum += 1).to_s : conum, id: @document.callouts.read_next_id, attributes: { 'guard' => guard }).convert})
|
1550
1408
|
else
|
1551
|
-
|
1552
|
-
|
1409
|
+
%(#{line}#{conums.map do |guard_it, conum_it|
|
1410
|
+
Inline.new(self, :callout, conum_it == '.' ? (autonum += 1).to_s : conum_it, id: @document.callouts.read_next_id, attributes: { 'guard' => guard_it }).convert
|
1411
|
+
end.join ' '})
|
1553
1412
|
end
|
1554
1413
|
else
|
1555
1414
|
line
|
1556
1415
|
end
|
1557
|
-
|
1558
|
-
else
|
1559
|
-
result
|
1416
|
+
end.join LF)
|
1560
1417
|
end
|
1561
1418
|
end
|
1562
1419
|
|
@@ -1571,9 +1428,9 @@ module Substitutors
|
|
1571
1428
|
negate = true
|
1572
1429
|
end
|
1573
1430
|
if (delim = (entry.include? '..') ? '..' : ((entry.include? '-') ? '-' : nil))
|
1574
|
-
from, to = entry.
|
1431
|
+
from, delim, to = entry.partition delim
|
1575
1432
|
to = (source.count LF) + 1 if to.empty? || (to = to.to_i) < 0
|
1576
|
-
line_nums = (
|
1433
|
+
line_nums = (from.to_i..to).to_a
|
1577
1434
|
if negate
|
1578
1435
|
lines -= line_nums
|
1579
1436
|
else
|
@@ -1600,6 +1457,9 @@ module Substitutors
|
|
1600
1457
|
process_callouts ? sub_callouts(sub_specialchars source) : (sub_specialchars source)
|
1601
1458
|
end
|
1602
1459
|
|
1460
|
+
# Internal: Inserts text into a formatted text enclosure; used by xreftext
|
1461
|
+
alias sub_placeholder sprintf unless RUBY_ENGINE == 'opal'
|
1462
|
+
|
1603
1463
|
# Internal: Lock-in the substitutions for this block
|
1604
1464
|
#
|
1605
1465
|
# Looks for an attribute named "subs". If present, resolves substitutions
|
@@ -1615,16 +1475,11 @@ module Substitutors
|
|
1615
1475
|
when :simple
|
1616
1476
|
default_subs = NORMAL_SUBS
|
1617
1477
|
when :verbatim
|
1618
|
-
|
1619
|
-
|
1620
|
-
elsif @context == :verse
|
1621
|
-
default_subs = NORMAL_SUBS
|
1622
|
-
else
|
1623
|
-
default_subs = BASIC_SUBS
|
1624
|
-
end
|
1478
|
+
# NOTE :literal with listparagraph-option gets folded into text of list item later
|
1479
|
+
default_subs = @context == :verse ? NORMAL_SUBS : VERBATIM_SUBS
|
1625
1480
|
when :raw
|
1626
1481
|
# TODO make pass subs a compliance setting; AsciiDoc Python performs :attributes and :macros on a pass block
|
1627
|
-
default_subs = @context == :stem ? BASIC_SUBS :
|
1482
|
+
default_subs = @context == :stem ? BASIC_SUBS : NO_SUBS
|
1628
1483
|
else
|
1629
1484
|
return @subs
|
1630
1485
|
end
|
@@ -1637,8 +1492,8 @@ module Substitutors
|
|
1637
1492
|
end
|
1638
1493
|
|
1639
1494
|
# QUESION delegate this logic to a method?
|
1640
|
-
if @context == :listing && @style == 'source' && (
|
1641
|
-
|
1495
|
+
if @context == :listing && @style == 'source' && (syntax_hl = @document.syntax_highlighter) &&
|
1496
|
+
syntax_hl.highlight? && (idx = @subs.index :specialcharacters)
|
1642
1497
|
@subs[idx] = :highlight
|
1643
1498
|
end
|
1644
1499
|
|