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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +162 -17
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +12 -13
  5. data/README-fr.adoc +11 -12
  6. data/README-jp.adoc +11 -12
  7. data/README-zh_CN.adoc +12 -13
  8. data/README.adoc +6 -7
  9. data/asciidoctor.gemspec +19 -24
  10. data/bin/asciidoctor +5 -4
  11. data/data/reference/syntax.adoc +283 -0
  12. data/data/stylesheets/asciidoctor-default.css +56 -52
  13. data/data/stylesheets/coderay-asciidoctor.css +7 -9
  14. data/lib/asciidoctor.rb +171 -232
  15. data/lib/asciidoctor/abstract_block.rb +96 -105
  16. data/lib/asciidoctor/abstract_node.rb +118 -139
  17. data/lib/asciidoctor/attribute_list.rb +10 -14
  18. data/lib/asciidoctor/block.rb +20 -19
  19. data/lib/asciidoctor/callouts.rb +4 -2
  20. data/lib/asciidoctor/cli.rb +3 -2
  21. data/lib/asciidoctor/cli/invoker.rb +14 -21
  22. data/lib/asciidoctor/cli/options.rb +64 -54
  23. data/lib/asciidoctor/converter.rb +357 -185
  24. data/lib/asciidoctor/converter/composite.rb +40 -48
  25. data/lib/asciidoctor/converter/docbook5.rb +604 -640
  26. data/lib/asciidoctor/converter/html5.rb +949 -963
  27. data/lib/asciidoctor/converter/manpage.rb +569 -548
  28. data/lib/asciidoctor/converter/template.rb +231 -272
  29. data/lib/asciidoctor/core_ext.rb +5 -18
  30. data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
  31. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  32. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  33. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  34. data/lib/asciidoctor/document.rb +399 -377
  35. data/lib/asciidoctor/extensions.rb +72 -140
  36. data/lib/asciidoctor/helpers.rb +122 -83
  37. data/lib/asciidoctor/inline.rb +5 -1
  38. data/lib/asciidoctor/list.rb +13 -11
  39. data/lib/asciidoctor/logging.rb +17 -16
  40. data/lib/asciidoctor/parser.rb +390 -423
  41. data/lib/asciidoctor/path_resolver.rb +10 -5
  42. data/lib/asciidoctor/reader.rb +286 -263
  43. data/lib/asciidoctor/rouge_ext.rb +39 -0
  44. data/lib/asciidoctor/section.rb +9 -8
  45. data/lib/asciidoctor/stylesheets.rb +19 -37
  46. data/lib/asciidoctor/substitutors.rb +364 -509
  47. data/lib/asciidoctor/syntax_highlighter.rb +238 -0
  48. data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
  49. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
  50. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  51. data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
  52. data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
  53. data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
  54. data/lib/asciidoctor/table.rb +73 -66
  55. data/lib/asciidoctor/timings.rb +4 -2
  56. data/lib/asciidoctor/version.rb +2 -1
  57. data/lib/asciidoctor/writer.rb +30 -0
  58. data/man/asciidoctor.1 +19 -15
  59. data/man/asciidoctor.adoc +14 -12
  60. metadata +69 -216
  61. data/CONTRIBUTING.adoc +0 -185
  62. data/Gemfile +0 -60
  63. data/Rakefile +0 -129
  64. data/bin/asciidoctor-safe +0 -15
  65. data/features/open_block.feature +0 -92
  66. data/features/pass_block.feature +0 -66
  67. data/features/step_definitions.rb +0 -49
  68. data/features/text_formatting.feature +0 -57
  69. data/features/xref.feature +0 -1039
  70. data/lib/asciidoctor/converter/base.rb +0 -59
  71. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  72. data/lib/asciidoctor/converter/factory.rb +0 -226
  73. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  74. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  75. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  76. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  77. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  78. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  79. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  80. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  81. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  82. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  83. data/test/api_test.rb +0 -1240
  84. data/test/attribute_list_test.rb +0 -242
  85. data/test/attributes_test.rb +0 -1623
  86. data/test/blocks_test.rb +0 -3870
  87. data/test/converter_test.rb +0 -470
  88. data/test/document_test.rb +0 -1853
  89. data/test/extensions_test.rb +0 -1560
  90. data/test/fixtures/asciidoc_index.txt +0 -521
  91. data/test/fixtures/basic-docinfo-footer.html +0 -6
  92. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  93. data/test/fixtures/basic-docinfo.html +0 -1
  94. data/test/fixtures/basic-docinfo.xml +0 -4
  95. data/test/fixtures/basic.asciidoc +0 -5
  96. data/test/fixtures/chapter-a.adoc +0 -3
  97. data/test/fixtures/child-include.adoc +0 -5
  98. data/test/fixtures/circle.svg +0 -9
  99. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  100. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  101. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  102. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  103. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  104. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  105. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  106. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  107. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  108. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  109. data/test/fixtures/docinfo-footer.html +0 -1
  110. data/test/fixtures/docinfo-footer.xml +0 -9
  111. data/test/fixtures/docinfo.html +0 -1
  112. data/test/fixtures/docinfo.xml +0 -3
  113. data/test/fixtures/doctime-localtime.adoc +0 -2
  114. data/test/fixtures/dot.gif +0 -0
  115. data/test/fixtures/encoding.asciidoc +0 -13
  116. data/test/fixtures/file-with-missing-include.adoc +0 -1
  117. data/test/fixtures/grandchild-include.adoc +0 -3
  118. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  119. data/test/fixtures/include-file.asciidoc +0 -24
  120. data/test/fixtures/include-file.jsx +0 -8
  121. data/test/fixtures/include-file.ml +0 -3
  122. data/test/fixtures/include-file.xml +0 -5
  123. data/test/fixtures/lists.adoc +0 -96
  124. data/test/fixtures/master.adoc +0 -5
  125. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  126. data/test/fixtures/other-chapters.adoc +0 -11
  127. data/test/fixtures/outer-include.adoc +0 -5
  128. data/test/fixtures/parent-include-restricted.adoc +0 -5
  129. data/test/fixtures/parent-include.adoc +0 -5
  130. data/test/fixtures/sample.asciidoc +0 -30
  131. data/test/fixtures/section-a.adoc +0 -4
  132. data/test/fixtures/stylesheets/custom.css +0 -3
  133. data/test/fixtures/subdir/index.adoc +0 -3
  134. data/test/fixtures/subdir/inner-include.adoc +0 -3
  135. data/test/fixtures/subdir/middle-include.adoc +0 -5
  136. data/test/fixtures/subs-docinfo.html +0 -2
  137. data/test/fixtures/subs.adoc +0 -6
  138. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  139. data/test/fixtures/tagged-class.rb +0 -23
  140. data/test/fixtures/tip.gif +0 -0
  141. data/test/fixtures/unclosed-tag.adoc +0 -3
  142. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  143. data/test/invoker_test.rb +0 -745
  144. data/test/links_test.rb +0 -855
  145. data/test/lists_test.rb +0 -5151
  146. data/test/logger_test.rb +0 -211
  147. data/test/manpage_test.rb +0 -660
  148. data/test/options_test.rb +0 -262
  149. data/test/paragraphs_test.rb +0 -562
  150. data/test/parser_test.rb +0 -742
  151. data/test/paths_test.rb +0 -395
  152. data/test/preamble_test.rb +0 -173
  153. data/test/reader_test.rb +0 -2161
  154. data/test/sections_test.rb +0 -3575
  155. data/test/substitutions_test.rb +0 -2066
  156. data/test/tables_test.rb +0 -2036
  157. data/test/test_helper.rb +0 -447
  158. data/test/text_test.rb +0 -309
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ # Public: A pluggable adapter for integrating a syntax (aka code) highlighter into AsciiDoc processing.
4
+ #
5
+ # There are two types of syntax highlighter adapters. The first performs syntax highlighting during the convert phase.
6
+ # This adapter type must define a highlight? method that returns true. The companion highlight method will then be
7
+ # called to handle the :specialcharacters substitution for source blocks. The second assumes syntax highlighting is
8
+ # performed on the client (e.g., when the HTML document is loaded). This adapter type must define a docinfo? method
9
+ # that returns true. The companion docinfo method will then be called to insert markup into the output document. The
10
+ # docinfo functionality is available to both adapter types.
11
+ #
12
+ # Asciidoctor provides several built-in adapters, including coderay, pygments, rouge, highlight.js, html-pipeline, and
13
+ # prettify. Additional adapters can be registered using SyntaxHighlighter.register or by supplying a custom factory.
14
+ module SyntaxHighlighter
15
+ # Public: Returns the String name of this syntax highlighter for referencing it in messages and option names.
16
+ attr_reader :name
17
+
18
+ def initialize name, backend = 'html5', opts = {}
19
+ @name = @pre_class = name
20
+ end
21
+
22
+ # Public: Indicates whether this syntax highlighter has docinfo (i.e., markup) to insert into the output document at
23
+ # the specified location.
24
+ #
25
+ # location - The Symbol representing the location slot (:head or :footer).
26
+ #
27
+ # Returns a [Boolean] indicating whether the docinfo method should be called for this location.
28
+ def docinfo? location; end
29
+
30
+ # Public: Generates docinfo markup to insert in the output document at the specified location.
31
+ #
32
+ # location - The Symbol representing the location slot (:head or :footer).
33
+ #
34
+ # Return the [String] markup to insert.
35
+ def docinfo location
36
+ raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #docinfo? returns true)
37
+ end
38
+
39
+ # Public: Indicates whether highlighting is handled by this syntax highlighter or by the client.
40
+ #
41
+ # Returns a [Boolean] indicating whether the highlight method should be used to handle the :specialchars substitution.
42
+ def highlight?; end
43
+
44
+ # Public: Highlights the specified source when this source block is being converted.
45
+ #
46
+ # If the source contains callout marks, the caller assumes the source remains on the same lines and no closing tags
47
+ # are added to the end of each line. If the source gets shifted by one or more lines, this method must return a
48
+ # tuple containing the highlighted source and the number of lines by which the source was shifted.
49
+ #
50
+ # node - The source Block to syntax highlight.
51
+ # source - The raw source text String of this source block (after preprocessing).
52
+ # lang - The source language String specified on this block (e.g., ruby).
53
+ # opts - A Hash of options that configure the syntax highlighting:
54
+ # :callouts - A Hash of callouts extracted from the source, indexed by line number (1-based) (optional).
55
+ # :css_mode - The Symbol CSS mode (:class or :inline).
56
+ # :highlight_lines - A 1-based Array of Integer line numbers to highlight (aka emphasize) (optional).
57
+ # :number_lines - A Symbol indicating whether lines should be numbered (:table or :inline) (optional).
58
+ # :start_line_number - The starting Integer (1-based) line number (optional, default: 1).
59
+ # :style - The String style (aka theme) to use for colorizing the code (optional).
60
+ #
61
+ # Returns the highlighted source String or a tuple of the highlighted source String and an Integer line offset.
62
+ def highlight node, source, lang, opts
63
+ raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #highlight? returns true)
64
+ end
65
+
66
+ # Public: Format the highlighted source for inclusion in an HTML document.
67
+ #
68
+ # node - The source Block being processed.
69
+ # lang - The source language String for this Block (e.g., ruby).
70
+ # opts - A Hash of options that control syntax highlighting:
71
+ # :nowrap - A Boolean that indicates whether wrapping should be disabled (optional).
72
+ #
73
+ # Returns the highlighted source [String] wrapped in preformatted tags (e.g., pre and code)
74
+ def format node, lang, opts
75
+ raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method)
76
+ end
77
+
78
+ # Public: Indicates whether this syntax highlighter wants to write a stylesheet to disk. Only called if both the
79
+ # linkcss and copycss attributes are set on the document.
80
+ #
81
+ # doc - The Document in which this syntax highlighter is being used.
82
+ #
83
+ # Returns a [Boolean] indicating whether the write_stylesheet method should be called.
84
+ def write_stylesheet? doc; end
85
+
86
+ # Public: Writes the stylesheet to support the highlighted source(s) to disk.
87
+ #
88
+ # doc - The Document in which this syntax highlighter is being used.
89
+ # to_dir - The absolute String path of the stylesheet output directory.
90
+ #
91
+ # Returns nothing.
92
+ def write_stylesheet doc, to_dir
93
+ raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #write_stylesheet? returns true)
94
+ end
95
+
96
+ private_class_method def self.included into
97
+ into.extend Config
98
+ end
99
+
100
+ module Config
101
+ # Public: Statically register the current class in the registry for the specified names.
102
+ #
103
+ # Returns nothing.
104
+ private def register_for *names
105
+ SyntaxHighlighter.register self, *names
106
+ end
107
+ end
108
+
109
+ module Factory
110
+ # Public: Associates the syntax highlighter class or object with the specified names.
111
+ #
112
+ # Returns nothing.
113
+ def register syntax_highlighter, *names
114
+ names.each {|name| registry[name] = syntax_highlighter }
115
+ end
116
+
117
+ # Public: Retrieves the syntax highlighter class or object registered for the specified name.
118
+ #
119
+ # name - The String name of the syntax highlighter to retrieve.
120
+ #
121
+ # Returns the SyntaxHighlighter Class or Object instance registered for this name.
122
+ def for name
123
+ registry[name]
124
+ end
125
+
126
+ # Public: Resolves the name to a syntax highlighter instance, if found in the registry.
127
+ #
128
+ # name - The String name of the syntax highlighter to create.
129
+ # backend - The String name of the backend for which this syntax highlighter is being used (default: 'html5').
130
+ # opts - A Hash of options providing information about the context in which this syntax highlighter is used:
131
+ # :doc - The Document for which this syntax highlighter was created.
132
+ #
133
+ # Returns a [SyntaxHighlighter] instance for the specified name.
134
+ def create name, backend = 'html5', opts = {}
135
+ if (syntax_hl = self.for name)
136
+ syntax_hl = syntax_hl.new name, backend, opts if ::Class === syntax_hl
137
+ raise ::NameError, %(#{syntax_hl.class} must specify a value for `name') unless syntax_hl.name
138
+ syntax_hl
139
+ end
140
+ end
141
+
142
+ private def registry
143
+ raise ::NotImplementedError, %(#{Factory} subclass #{self.class} must implement the ##{__method__} method)
144
+ end
145
+ end
146
+
147
+ class CustomFactory
148
+ include Factory
149
+
150
+ def initialize seed_registry = nil
151
+ @registry = seed_registry || {}
152
+ end
153
+
154
+ private def registry
155
+ @registry
156
+ end
157
+ end
158
+
159
+ module DefaultFactory
160
+ include Factory
161
+
162
+ private
163
+
164
+ @@registry = {}
165
+
166
+ def registry
167
+ @@registry
168
+ end
169
+
170
+ unless RUBY_ENGINE == 'opal'
171
+ public
172
+
173
+ def register syntax_highlighter, *names
174
+ @@mutex.owned? ? names.each {|name| @@registry = @@registry.merge name => syntax_highlighter } :
175
+ @@mutex.synchronize { register syntax_highlighter, *names }
176
+ end
177
+
178
+ # This method will lazy require and register additional built-in implementations, which include coderay,
179
+ # pygments, rouge, and prettify. Refer to {Factory#for} for parameters and return value.
180
+ def for name
181
+ @@registry.fetch name do
182
+ @@mutex.synchronize do
183
+ @@registry.fetch name do
184
+ if (require_path = PROVIDED[name])
185
+ require require_path
186
+ @@registry[name]
187
+ else
188
+ @@registry = @@registry.merge name => nil
189
+ nil
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ PROVIDED = {
197
+ 'coderay' => %(#{__dir__}/syntax_highlighter/coderay),
198
+ 'prettify' => %(#{__dir__}/syntax_highlighter/prettify),
199
+ 'pygments' => %(#{__dir__}/syntax_highlighter/pygments),
200
+ 'rouge' => %(#{__dir__}/syntax_highlighter/rouge),
201
+ }
202
+
203
+ private
204
+
205
+ @@mutex = ::Mutex.new
206
+ end
207
+ end
208
+
209
+ class DefaultFactoryProxy < CustomFactory
210
+ include DefaultFactory # inserts module into ancestors immediately after superclass
211
+
212
+ def for name
213
+ @registry.fetch(name) { super }
214
+ end unless RUBY_ENGINE == 'opal'
215
+ end
216
+
217
+ class Base
218
+ include SyntaxHighlighter
219
+
220
+ def format node, lang, opts
221
+ class_attr_val = opts[:nowrap] ? %(#{@pre_class} highlight nowrap) : %(#{@pre_class} highlight)
222
+ if (transform = opts[:transform])
223
+ pre = { 'class' => class_attr_val }
224
+ code = lang ? { 'data-lang' => lang } : {}
225
+ transform[pre, code]
226
+ %(<pre#{pre.map {|k, v| %[ #{k}="#{v}"] }.join}><code#{code.map {|k, v| %[ #{k}="#{v}"] }.join}>#{node.content}</code></pre>)
227
+ else
228
+ %(<pre class="#{class_attr_val}"><code#{lang ? %[ data-lang="#{lang}"] : ''}>#{node.content}</code></pre>)
229
+ end
230
+ end
231
+ end
232
+
233
+ extend DefaultFactory # exports static methods
234
+ end
235
+ end
236
+
237
+ require_relative 'syntax_highlighter/highlightjs'
238
+ require_relative 'syntax_highlighter/html_pipeline' unless RUBY_ENGINE == 'opal'
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class SyntaxHighlighter::CodeRayAdapter < SyntaxHighlighter::Base
4
+ register_for 'coderay'
5
+
6
+ def initialize *args
7
+ super
8
+ @pre_class = 'CodeRay'
9
+ @requires_stylesheet = nil
10
+ end
11
+
12
+ def highlight?
13
+ library_available?
14
+ end
15
+
16
+ def highlight node, source, lang, opts
17
+ @requires_stylesheet = true if (css_mode = opts[:css_mode]) == :class
18
+ # NOTE CodeRay::Duo gracefully falls back to no highlighting if lang isn't recognized
19
+ highlighted = ::CodeRay::Duo[lang ? lang.to_sym : :text, :html,
20
+ css: css_mode,
21
+ line_numbers: (line_numbers = opts[:number_lines]),
22
+ line_number_start: opts[:start_line_number],
23
+ line_number_anchors: false,
24
+ highlight_lines: opts[:highlight_lines],
25
+ bold_every: false,
26
+ ].highlight source
27
+ if line_numbers == :table && opts[:callouts]
28
+ [highlighted, (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
29
+ else
30
+ highlighted
31
+ end
32
+ end
33
+
34
+ def docinfo? location
35
+ @requires_stylesheet && location == :footer
36
+ end
37
+
38
+ def docinfo location, doc, opts
39
+ if opts[:linkcss]
40
+ %(<link rel="stylesheet" href="#{doc.normalize_web_path stylesheet_basename, (doc.attr 'stylesdir', ''), false}"#{opts[:self_closing_tag_slash]}>)
41
+ else
42
+ %(<style>
43
+ #{read_stylesheet}
44
+ </style>)
45
+ end
46
+ end
47
+
48
+ def write_stylesheet? doc
49
+ @requires_stylesheet
50
+ end
51
+
52
+ def write_stylesheet doc, to_dir
53
+ ::File.write (::File.join to_dir, stylesheet_basename), read_stylesheet, mode: FILE_WRITE_MODE
54
+ end
55
+
56
+ module Loader
57
+ private
58
+
59
+ def library_available?
60
+ (@@library_status ||= load_library) == :loaded ? true : nil
61
+ end
62
+
63
+ def load_library
64
+ (defined? ::CodeRay::Duo) ? :loaded : (Helpers.require_library 'coderay', true, :warn).nil? ? :unavailable : :loaded
65
+ end
66
+ end
67
+
68
+ module Styles
69
+ include Loader
70
+
71
+ def read_stylesheet
72
+ @@stylesheet_cache ||= (::File.read (::File.join Stylesheets::STYLESHEETS_DIR, stylesheet_basename), mode: FILE_READ_MODE).rstrip
73
+ end
74
+
75
+ def stylesheet_basename
76
+ 'coderay-asciidoctor.css'
77
+ end
78
+ end
79
+
80
+ extend Styles # exports static methods
81
+ include Loader, Styles # adds methods to instance
82
+
83
+ CodeCellStartTagCs = '<td class="code"><pre>'
84
+
85
+ private_constant :CodeCellStartTagCs
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class SyntaxHighlighter::HighlightJsAdapter < SyntaxHighlighter::Base
4
+ register_for 'highlightjs', 'highlight.js'
5
+
6
+ def initialize *args
7
+ super
8
+ @name = @pre_class = 'highlightjs'
9
+ end
10
+
11
+ def format node, lang, opts
12
+ super node, lang, (opts.merge transform: proc {|_, code| code['class'] = %(language-#{lang || 'none'} hljs) } )
13
+ end
14
+
15
+ def docinfo? location
16
+ location == :footer
17
+ end
18
+
19
+ def docinfo location, doc, opts
20
+ base_url = doc.attr 'highlightjsdir', %(#{opts[:cdn_base_url]}/highlight.js/#{HIGHLIGHT_JS_VERSION})
21
+ %(<link rel="stylesheet" href="#{base_url}/styles/#{doc.attr 'highlightjs-theme', 'github'}.min.css"#{opts[:self_closing_tag_slash]}>
22
+ <script src="#{base_url}/highlight.min.js"></script>
23
+ <script>hljs.initHighlighting()</script>)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class SyntaxHighlighter::HtmlPipelineAdapter < SyntaxHighlighter::Base
4
+ register_for 'html-pipeline'
5
+
6
+ def format node, lang, opts
7
+ %(<pre#{lang ? %[ lang="#{lang}"] : ''}><code>#{node.content}</code></pre>)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class SyntaxHighlighter::PrettifyAdapter < SyntaxHighlighter::Base
4
+ register_for 'prettify'
5
+
6
+ def initialize *args
7
+ super
8
+ @pre_class = 'prettyprint'
9
+ end
10
+
11
+ def format node, lang, opts
12
+ opts[:transform] = proc {|pre| pre['class'] += %( #{(start = node.attr 'start') ? %[linenums:#{start}] : 'linenums'}) } if node.attr? 'linenums'
13
+ super
14
+ end
15
+
16
+ def docinfo? location
17
+ location == :footer
18
+ end
19
+
20
+ def docinfo location, doc, opts
21
+ base_url = doc.attr 'prettifydir', %(#{opts[:cdn_base_url]}/prettify/r298)
22
+ prettify_theme_url = ((prettify_theme = doc.attr 'prettify-theme', 'prettify').start_with? 'http://', 'https://') ? prettify_theme : %(#{base_url}/#{prettify_theme}.min.css)
23
+ %(<link rel="stylesheet" href="#{prettify_theme_url}"#{opts[:self_closing_tag_slash]}>
24
+ <script src="#{base_url}/run_prettify.min.js"></script>)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
4
+ register_for 'pygments'
5
+
6
+ def initialize *args
7
+ super
8
+ @requires_stylesheet = nil
9
+ @style = nil
10
+ end
11
+
12
+ def highlight?
13
+ library_available?
14
+ end
15
+
16
+ def highlight node, source, lang, opts
17
+ lexer = (::Pygments::Lexer.find_by_alias lang) || (::Pygments::Lexer.find_by_mimetype 'text/plain')
18
+ @requires_stylesheet = true unless (noclasses = opts[:css_mode] != :class)
19
+ highlight_opts = {
20
+ classprefix: TOKEN_CLASS_PREFIX,
21
+ cssclass: WRAPPER_CLASS,
22
+ nobackground: true,
23
+ noclasses: noclasses,
24
+ startinline: lexer.name == 'PHP' && !(node.option? 'mixed'),
25
+ stripnl: false,
26
+ style: (@style ||= (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE),
27
+ }
28
+ if (highlight_lines = opts[:highlight_lines])
29
+ highlight_opts[:hl_lines] = highlight_lines.join ' '
30
+ end
31
+ if (linenos = opts[:number_lines]) && (highlight_opts[:linenostart] = opts[:start_line_number]) && (highlight_opts[:linenos] = linenos) == :table
32
+ if (highlighted = lexer.highlight source, options: highlight_opts)
33
+ highlighted = highlighted.sub StyledLinenoColumnStartTagsRx, LinenoColumnStartTagsCs if noclasses
34
+ highlighted = highlighted.sub WrapperTagRx, PreTagCs
35
+ opts[:callouts] ? [highlighted, (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil] : highlighted
36
+ else
37
+ node.sub_specialchars source # handles nil response from ::Pygments::Lexer#highlight
38
+ end
39
+ elsif (highlighted = lexer.highlight source, options: highlight_opts)
40
+ highlighted = highlighted.gsub StyledLinenoSpanTagRx, LinenoSpanTagCs if linenos && noclasses
41
+ highlighted.sub WrapperTagRx, '\1'
42
+ else
43
+ node.sub_specialchars source # handles nil response from ::Pygments::Lexer#highlight
44
+ end
45
+ end
46
+
47
+ def format node, lang, opts
48
+ if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) &&
49
+ (pre_style_attr_val = base_style @style)
50
+ opts[:transform] = proc {|pre| pre['style'] = pre_style_attr_val }
51
+ end
52
+ super
53
+ end
54
+
55
+ def docinfo? location
56
+ @requires_stylesheet && location == :footer
57
+ end
58
+
59
+ def docinfo location, doc, opts
60
+ if opts[:linkcss]
61
+ %(<link rel="stylesheet" href="#{doc.normalize_web_path (stylesheet_basename @style), (doc.attr 'stylesdir', ''), false}"#{opts[:self_closing_tag_slash]}>)
62
+ else
63
+ %(<style>
64
+ #{read_stylesheet @style}
65
+ </style>)
66
+ end
67
+ end
68
+
69
+ def write_stylesheet? doc
70
+ @requires_stylesheet
71
+ end
72
+
73
+ def write_stylesheet doc, to_dir
74
+ ::File.write (::File.join to_dir, (stylesheet_basename @style)), (read_stylesheet @style), mode: FILE_WRITE_MODE
75
+ end
76
+
77
+ module Loader
78
+ private
79
+
80
+ def library_available?
81
+ (@@library_status ||= load_library) == :loaded ? true : nil
82
+ end
83
+
84
+ def load_library
85
+ (defined? ::Pygments::Lexer) ? :loaded : (Helpers.require_library 'pygments', 'pygments.rb', :warn).nil? ? :unavailable : :loaded
86
+ end
87
+ end
88
+
89
+ module Styles
90
+ include Loader
91
+
92
+ def read_stylesheet style
93
+ library_available? ? @@stylesheet_cache[style || DEFAULT_STYLE] || '/* Failed to load Pygments CSS. */' : '/* Pygments CSS disabled because Pygments is not available. */'
94
+ end
95
+
96
+ def stylesheet_basename style
97
+ %(pygments-#{style || DEFAULT_STYLE}.css)
98
+ end
99
+
100
+ private
101
+
102
+ def base_style style
103
+ library_available? ? @@base_style_cache[style || DEFAULT_STYLE] : nil
104
+ end
105
+
106
+ def style_available? style
107
+ (((@@available_styles ||= ::Pygments.styles.to_set).include? style) rescue nil) && style
108
+ end
109
+
110
+ @@base_style_cache = ::Hash.new do |cache, key|
111
+ if BaseStyleRx =~ @@stylesheet_cache[key]
112
+ @@base_style_cache = cache.merge key => (style = $1.strip)
113
+ style
114
+ end
115
+ end
116
+ @@stylesheet_cache = ::Hash.new do |cache, key|
117
+ if (stylesheet = ::Pygments.css BASE_SELECTOR, classprefix: TOKEN_CLASS_PREFIX, style: key)
118
+ @@stylesheet_cache = cache.merge key => stylesheet
119
+ stylesheet
120
+ end
121
+ end
122
+
123
+ DEFAULT_STYLE = 'default'
124
+ BASE_SELECTOR = 'pre.pygments'
125
+ TOKEN_CLASS_PREFIX = 'tok-'
126
+
127
+ BaseStyleRx = /^#{BASE_SELECTOR.gsub '.', '\\.'} +\{([^}]+?)\}/
128
+
129
+ private_constant :BASE_SELECTOR, :TOKEN_CLASS_PREFIX, :BaseStyleRx
130
+ end
131
+
132
+ extend Styles # exports static methods
133
+ include Loader, Styles # adds methods to instance
134
+
135
+ CodeCellStartTagCs = '<td class="code">'
136
+ LinenoColumnStartTagsCs = '<td class="linenos"><div class="linenodiv"><pre>'
137
+ LinenoSpanTagCs = '<span class="lineno">\1</span>'
138
+ PreTagCs = '<pre>\1</pre>'
139
+ StyledLinenoColumnStartTagsRx = /<td><div class="linenodiv" style="[^"]+?"><pre style="[^"]+?">/
140
+ StyledLinenoSpanTagRx = %r(<span style="background-color: #f0f0f0; padding: 0 5px 0 5px">( *\d+ )</span>)
141
+ WRAPPER_CLASS = 'lineno' # doesn't appear in output; Pygments appends "table" to this value to make nested table class
142
+ # NOTE <pre> has style attribute when pygments-css=style
143
+ # NOTE <div> has trailing newline when pygments-linenums-mode=table
144
+ # NOTE initial <span></span> preserves leading blank lines
145
+ WrapperTagRx = %r(<div class="#{WRAPPER_CLASS}"><pre\b[^>]*?>(.*)</pre></div>\n*)m
146
+
147
+ private_constant :CodeCellStartTagCs, :LinenoColumnStartTagsCs, :LinenoSpanTagCs, :PreTagCs, :StyledLinenoColumnStartTagsRx, :StyledLinenoSpanTagRx, :WrapperTagRx, :WRAPPER_CLASS
148
+ end
149
+ end