asciidoctor 1.5.8 → 2.0.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +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
|
|