asciidoctor-tex2svg 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/asciidoctor-tex2svg.rb +5 -0
- data/lib/asciidoctor-tex2svg/extension.rb +222 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 11832f1a28faf8f6cc791ee9b1733934729453b1e7f72a7a32730bf02d59094b
|
4
|
+
data.tar.gz: 70e260040e415b280aa19f85c0be33816214b2d87b8abfd3489ab4e14320e43b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: af39b1f79aa60ca89bc3178199eb0c82dafc3bbc2f8f3fec572f5b615629fa99a97701c920d7c5795ec98d262d0b99edaa57b708a044b44cc781a60aba357505
|
7
|
+
data.tar.gz: de853f522e38172ab5a0696a0cefdfb02aac4160acb60acb61c67d4bf48f9896511a1694623c8e3115ea5e1c415b26f2c68c60980b57e13b23cf5c2d86fd44b6
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
require 'asciimath'
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
autoload :Digest, 'digest'
|
7
|
+
|
8
|
+
class Tex2SvgTreeprocessor < Asciidoctor::Extensions::Treeprocessor
|
9
|
+
LineFeed = %(\n)
|
10
|
+
StemInlineMacroRx = /\\?(?:stem|latexmath|asciimath):([a-z,]*)\[(.*?[^\\])\]/m
|
11
|
+
LatexmathInlineMacroRx = /\\?latexmath:([a-z,]*)\[(.*?[^\\])\]/m
|
12
|
+
AsciiMathInlineMacroRx = /\\?asciimath:([a-z,]*)\[(.*?[^\\])\]/m
|
13
|
+
|
14
|
+
def process document
|
15
|
+
inline = document.attr 'tex2svg-inline'
|
16
|
+
|
17
|
+
unless inline
|
18
|
+
image_output_dir, image_target_dir = image_output_and_target_dir document
|
19
|
+
::Asciidoctor::Helpers.mkdir_p image_output_dir unless ::File.directory? image_output_dir
|
20
|
+
end
|
21
|
+
|
22
|
+
unless (stem_blocks = document.find_by context: :stem).nil_or_empty?
|
23
|
+
stem_blocks.each do |stem|
|
24
|
+
handle_stem_block stem, image_output_dir, image_target_dir, inline
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
unless (prose_blocks = document.find_by {|b|
|
29
|
+
(b.content_model == :simple && (b.subs.include? :macros)) || b.context == :list_item
|
30
|
+
}).nil_or_empty?
|
31
|
+
prose_blocks.each do |prose|
|
32
|
+
handle_prose_block prose, image_output_dir, image_target_dir, inline
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
unless (table_blocks = document.find_by context: :table).nil_or_empty?
|
37
|
+
table_blocks.each do |table|
|
38
|
+
(table.rows[:body] + table.rows[:foot]).each do |row|
|
39
|
+
row.each do |cell|
|
40
|
+
if cell.style == :asciidoc
|
41
|
+
process cell.inner_document
|
42
|
+
elsif cell.style != :literal
|
43
|
+
handle_nonasciidoc_table_cell cell, image_output_dir, image_target_dir, inline
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
unless (sect_blocks = document.find_by content: :section).nil_or_empty?
|
51
|
+
sect_blocks.each do |sect|
|
52
|
+
handle_section_title sect, image_output_dir, image_target_dir, inline
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_stem_block(stem, image_output_dir, image_target_dir, inline)
|
60
|
+
equation_type = stem.style.to_sym
|
61
|
+
|
62
|
+
case equation_type
|
63
|
+
when :latexmath
|
64
|
+
content = stem.content
|
65
|
+
when :asciimath
|
66
|
+
content = AsciiMath.parse(stem.content).to_latex
|
67
|
+
else
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
img_target = make_equ_image content, stem.id, false, image_output_dir, image_target_dir, inline
|
72
|
+
|
73
|
+
parent = stem.parent
|
74
|
+
if inline
|
75
|
+
stem_image = create_pass_block parent, %{<div class="stemblock"> #{img_target} </div>}, {}
|
76
|
+
parent.blocks[parent.blocks.index stem] = stem_image
|
77
|
+
else
|
78
|
+
alt_text = stem.attr 'alt', (equation_type == :latexmath ? %($$#{content}$$) : %(`#{content}`))
|
79
|
+
attrs = {'target' => img_target, 'alt' => alt_text, 'align' => 'center'}
|
80
|
+
parent = stem.parent
|
81
|
+
stem_image = create_image_block parent, attrs
|
82
|
+
stem_image.id = stem.id if stem.id
|
83
|
+
if (title = stem.attributes['title'])
|
84
|
+
stem_image.title = title
|
85
|
+
end
|
86
|
+
parent.blocks[parent.blocks.index stem] = stem_image
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def handle_prose_block(prose, image_output_dir, image_target_dir, inline)
|
91
|
+
text = prose.context == :list_item ? (prose.instance_variable_get :@text) : (prose.lines * LineFeed)
|
92
|
+
text, source_modified = handle_inline_stem prose, text, image_output_dir, image_target_dir, inline
|
93
|
+
if source_modified
|
94
|
+
if prose.context == :list_item
|
95
|
+
prose.instance_variable_set :@text, text
|
96
|
+
else
|
97
|
+
prose.lines = text.split LineFeed
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_nonasciidoc_table_cell(cell, image_output_dir, image_target_dir, inline)
|
103
|
+
text = cell.instance_variable_get :@text
|
104
|
+
text, source_modified = handle_inline_stem cell, text, image_output_dir, image_target_dir, inline
|
105
|
+
if source_modified
|
106
|
+
cell.instance_variable_set :@text, text
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def handle_section_title(sect, image_output_dir, image_target_dir, inline)
|
111
|
+
text = sect.instance_variable_get :@title
|
112
|
+
text, source_modified = handle_inline_stem sect, text, image_output_dir, image_target_dir, inline
|
113
|
+
if source_modified
|
114
|
+
sect.instance_variable_set :@title, text
|
115
|
+
sect.remove_instance_variable :@subbed_title
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def handle_inline_stem(node, text, image_output_dir, image_target_dir, inline)
|
120
|
+
document = node.document
|
121
|
+
to_html = document.basebackend? 'html'
|
122
|
+
|
123
|
+
case document.attr 'stem'
|
124
|
+
when 'latexmath'
|
125
|
+
support_stem_prefix = true
|
126
|
+
stem_rx = LatexmathInlineMacroRx
|
127
|
+
when 'asciimath'
|
128
|
+
support_stem_prefix = true
|
129
|
+
stem_rx = AsciiMathInlineMacroRx
|
130
|
+
else
|
131
|
+
support_stem_prefix = false
|
132
|
+
stem_rx = StemInlineMacroRx
|
133
|
+
end
|
134
|
+
|
135
|
+
source_modified = false
|
136
|
+
|
137
|
+
# TODO skip passthroughs in the source (e.g., +stem:[x^2]+)
|
138
|
+
if text != nil && (text.include? ':')
|
139
|
+
text = text.gsub(stem_rx) {
|
140
|
+
if (m = $~)[0].start_with? '\\'
|
141
|
+
next m[0][1..-1]
|
142
|
+
end
|
143
|
+
|
144
|
+
if (eq_data = m[2].rstrip).empty?
|
145
|
+
next
|
146
|
+
else
|
147
|
+
source_modified = true
|
148
|
+
end
|
149
|
+
|
150
|
+
if text.include? 'asciimath:'
|
151
|
+
eq_data = AsciiMath.parse(eq_data).to_latex
|
152
|
+
elsif (support_stem_prefix && (text.include? 'stem:')) || (text.include? 'latexmath:')
|
153
|
+
eq_data.gsub! '\]', ']'
|
154
|
+
subs = m[1].nil_or_empty? ? (to_html ? [:specialcharacters] : []) : (node.resolve_pass_subs m[1])
|
155
|
+
eq_data = node.apply_subs eq_data, subs unless subs.empty?
|
156
|
+
else
|
157
|
+
source_modified = false
|
158
|
+
return text
|
159
|
+
end
|
160
|
+
|
161
|
+
img_target = make_equ_image eq_data, nil, true, image_output_dir, image_target_dir, inline
|
162
|
+
if inline
|
163
|
+
%(pass:[<span class="steminline"> #{img_target} </span>])
|
164
|
+
else
|
165
|
+
%(image:#{img_target}[])
|
166
|
+
end
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
[text, source_modified]
|
171
|
+
end
|
172
|
+
|
173
|
+
def make_equ_image(equ_data, equ_id, equ_inline, image_output_dir, image_target_dir, inline)
|
174
|
+
input = equ_data
|
175
|
+
|
176
|
+
# TODO: consider only making the image if the file isn't already there.
|
177
|
+
|
178
|
+
if inline
|
179
|
+
data, = Open3.capture2('tex2svg', '--inline', input)
|
180
|
+
else
|
181
|
+
data, = Open3.capture2('tex2svg', input)
|
182
|
+
end
|
183
|
+
|
184
|
+
if inline
|
185
|
+
data
|
186
|
+
else
|
187
|
+
unless equ_id
|
188
|
+
equ_id = %(stem-#{::Digest::MD5.hexdigest input})
|
189
|
+
end
|
190
|
+
image_ext = '.svg'
|
191
|
+
img_target = %(#{equ_id}#{image_ext})
|
192
|
+
img_file = ::File.join image_output_dir, img_target
|
193
|
+
|
194
|
+
::IO.write img_file, data
|
195
|
+
|
196
|
+
img_target = ::File.join image_target_dir, img_target unless image_target_dir == '.'
|
197
|
+
img_target
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def image_output_and_target_dir(doc)
|
202
|
+
output_dir = doc.attr('imagesoutdir')
|
203
|
+
if output_dir
|
204
|
+
if doc.attr('imagesdir').nil_or_empty?
|
205
|
+
target_dir = output_dir
|
206
|
+
else
|
207
|
+
# When imagesdir attribute is set, every relative path is prefixed with it. So the real target dir shall then be relative to the imagesdir, instead of being relative to document root.
|
208
|
+
abs_imagesdir = ::Pathname.new doc.normalize_system_path(doc.attr('imagesdir'))
|
209
|
+
abs_outdir = ::Pathname.new doc.normalize_system_path(output_dir)
|
210
|
+
target_dir = abs_outdir.relative_path_from(abs_imagesdir).to_s
|
211
|
+
end
|
212
|
+
else
|
213
|
+
output_dir = doc.attr('imagesdir')
|
214
|
+
# since we store images directly to imagesdir, target dir shall be NULL and asciidoctor converters will prefix imagesdir.
|
215
|
+
target_dir = "."
|
216
|
+
end
|
217
|
+
|
218
|
+
output_dir = doc.normalize_system_path(output_dir, doc.attr('docdir'))
|
219
|
+
return [output_dir, target_dir]
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asciidoctor-tex2svg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex LeBlanc
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-07-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-enum
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: asciidoctor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 2.0.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2.0'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.0.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: asciimath
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.0.0
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 2.0.0
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.0.0
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.0.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 12.3.0
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 12.3.0
|
81
|
+
description: An Asciidoctor extension to converts latexmath equations to SVG
|
82
|
+
email: alex.leblanc@nuvation.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- lib/asciidoctor-tex2svg.rb
|
88
|
+
- lib/asciidoctor-tex2svg/extension.rb
|
89
|
+
homepage: https://github.com/dalemartin/asciidoctor-tex2svg
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubygems_version: 3.1.2
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Asciidoctor STEM processor based on MathJax tex2svg
|
112
|
+
test_files: []
|