jektex 0.1.0 → 0.2.0
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/README.md +73 -7
- data/lib/jektex/cache.rb +107 -0
- data/lib/jektex/configuration.rb +167 -0
- data/lib/jektex/hooks.rb +51 -0
- data/lib/jektex/katex.min.js +1 -1
- data/lib/jektex/page_processor.rb +304 -0
- data/lib/jektex/renderer.rb +81 -0
- data/lib/jektex/reporter.rb +70 -0
- data/lib/jektex/version.rb +1 -1
- data/lib/jektex.rb +9 -4
- metadata +46 -23
- data/lib/jektex/jektex.rb +0 -215
data/lib/jektex/jektex.rb
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
require 'execjs'
|
|
2
|
-
require 'digest'
|
|
3
|
-
require 'htmlentities'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
PATH_TO_JS = File.join(__dir__, "/katex.min.js")
|
|
7
|
-
DEFAULT_CACHE_DIR = ".jekyll-cache"
|
|
8
|
-
CACHE_FILE = "jektex-cache.marshal"
|
|
9
|
-
KATEX = ExecJS.compile(open(PATH_TO_JS).read)
|
|
10
|
-
FRONT_MATTER_TAG = "jektex"
|
|
11
|
-
INDENT = " " * 13
|
|
12
|
-
HTML_ENTITY_PARSER = HTMLEntities.new
|
|
13
|
-
|
|
14
|
-
$global_macros = Hash.new
|
|
15
|
-
$updated_global_macros = Array.new
|
|
16
|
-
|
|
17
|
-
$count_newly_generated_expressions = 0
|
|
18
|
-
|
|
19
|
-
$path_to_cache = File.join(DEFAULT_CACHE_DIR, CACHE_FILE)
|
|
20
|
-
$cache = nil
|
|
21
|
-
$disable_disk_cache = false
|
|
22
|
-
$silent = false
|
|
23
|
-
|
|
24
|
-
$ignored = Array.new
|
|
25
|
-
|
|
26
|
-
def get_list_of_updated_global_macros(current_macros, cached_global_macros)
|
|
27
|
-
return Array.new unless cached_global_macros || current_macros
|
|
28
|
-
return current_macros.keys unless cached_global_macros
|
|
29
|
-
return cached_global_macros.keys unless current_macros
|
|
30
|
-
|
|
31
|
-
macro_set = Set.new(cached_global_macros.keys + current_macros.keys)
|
|
32
|
-
macro_set.delete_if { |m| cached_global_macros[m] == current_macros[m] }
|
|
33
|
-
return macro_set.to_a
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def is_ignored?(page)
|
|
37
|
-
return true if page.data[FRONT_MATTER_TAG] == "false"
|
|
38
|
-
return $ignored.any? { |patern| File.fnmatch?(patern, page.relative_path, File::FNM_DOTMATCH) }
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def contains_updated_global_macro?(expression)
|
|
42
|
-
return $updated_global_macros.any? { |m| expression[m] }
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def print_stats
|
|
46
|
-
print "#{INDENT}LaTeX: " \
|
|
47
|
-
"#{$count_newly_generated_expressions} expressions rendered " \
|
|
48
|
-
"(#{$cache.size} already cached)".ljust(72) + "\r"
|
|
49
|
-
$stdout.flush
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
#######################################################################################
|
|
53
|
-
# Render
|
|
54
|
-
|
|
55
|
-
def render_latex_notation(page)
|
|
56
|
-
# check if document is not set to be ignored
|
|
57
|
-
return page.content if !page.data || is_ignored?(page)
|
|
58
|
-
# convert HTML entities back to characters
|
|
59
|
-
post = page.content.to_s
|
|
60
|
-
# render inline expressions
|
|
61
|
-
post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.relative_path) }
|
|
62
|
-
# render display mode expressions
|
|
63
|
-
post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.relative_path) }
|
|
64
|
-
return post
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def render_kramdown_notation(page)
|
|
68
|
-
# check if document is not set to be ignored
|
|
69
|
-
return page.output if !page.data || is_ignored?(page)
|
|
70
|
-
# convert HTML entities back to characters
|
|
71
|
-
post = page.output.to_s
|
|
72
|
-
# render inline expressions
|
|
73
|
-
post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.relative_path) }
|
|
74
|
-
# render display mode expressions
|
|
75
|
-
post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.relative_path) }
|
|
76
|
-
return post
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def escape_method(type, expression, doc_path)
|
|
80
|
-
# detect if expression is in display mode
|
|
81
|
-
is_in_display_mode = type.downcase =~ /\[/
|
|
82
|
-
expression = HTML_ENTITY_PARSER.decode(expression)
|
|
83
|
-
# generate a hash from the math expression
|
|
84
|
-
expression_hash = Digest::SHA2.hexdigest(expression) + is_in_display_mode.to_s
|
|
85
|
-
|
|
86
|
-
# use it if it exists
|
|
87
|
-
if($cache.has_key?(expression_hash) && !contains_updated_global_macro?(expression))
|
|
88
|
-
# check if expressin conains updated macro
|
|
89
|
-
$count_newly_generated_expressions += 1
|
|
90
|
-
print_stats unless $silent
|
|
91
|
-
return $cache[expression_hash]
|
|
92
|
-
|
|
93
|
-
# else generate one and store it
|
|
94
|
-
else
|
|
95
|
-
# create the cache directory, if it doesn't exist
|
|
96
|
-
begin
|
|
97
|
-
# render using ExecJS
|
|
98
|
-
result = KATEX.call("katex.renderToString", expression,
|
|
99
|
-
{ displayMode: is_in_display_mode,
|
|
100
|
-
macros: $global_macros
|
|
101
|
-
})
|
|
102
|
-
rescue SystemExit, Interrupt
|
|
103
|
-
# save cache to disk
|
|
104
|
-
File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
|
|
105
|
-
# this stops jekyll being immune to interrupts and kill command
|
|
106
|
-
raise
|
|
107
|
-
rescue ExecJS::ProgramError => pe
|
|
108
|
-
# catch parse error
|
|
109
|
-
puts "\e[31m #{pe.message.gsub("ParseError: ", "")}\n\t#{doc_path}\e[0m" unless $silent
|
|
110
|
-
# render expression with error highlighting enabled
|
|
111
|
-
return KATEX.call("katex.renderToString", expression,
|
|
112
|
-
{ displayMode: is_in_display_mode,
|
|
113
|
-
macros: $global_macros,
|
|
114
|
-
throwOnError: false
|
|
115
|
-
})
|
|
116
|
-
end
|
|
117
|
-
# save to cache
|
|
118
|
-
$cache[expression_hash] = result
|
|
119
|
-
# update count of newly generated expressions
|
|
120
|
-
$count_newly_generated_expressions += 1
|
|
121
|
-
print_stats unless $silent
|
|
122
|
-
return result
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
Jekyll::Hooks.register :pages, :post_render do |page|
|
|
127
|
-
page.output = render_kramdown_notation(page)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
Jekyll::Hooks.register :documents, :post_render do |doc|
|
|
131
|
-
doc.output = render_kramdown_notation(doc)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
Jekyll::Hooks.register :pages, :pre_render do |page|
|
|
135
|
-
page.content = render_latex_notation(page)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
Jekyll::Hooks.register :documents, :pre_render do |doc|
|
|
139
|
-
doc.content = render_latex_notation(doc)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
#######################################################################################
|
|
143
|
-
# SETTINGS AND INIT
|
|
144
|
-
|
|
145
|
-
Jekyll::Hooks.register :site, :after_init do |site|
|
|
146
|
-
# load jektex config from config file and if no config is defined make empty one
|
|
147
|
-
config = site.config["jektex"] || Hash.new
|
|
148
|
-
|
|
149
|
-
# check if there is defined custom cache location in config
|
|
150
|
-
$path_to_cache = File.join(config["cache_dir"].to_s, CACHE_FILE) if config.has_key?("cache_dir")
|
|
151
|
-
|
|
152
|
-
# load content of cache file if it exists
|
|
153
|
-
if File.exist?($path_to_cache)
|
|
154
|
-
$cache = File.open($path_to_cache, "r"){ |from_file| Marshal.load(from_file)}
|
|
155
|
-
else
|
|
156
|
-
$cache = Hash.new
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# check if cache is disabled in config
|
|
160
|
-
$disable_disk_cache = site.config["disable_disk_cache"] if site.config.has_key?("disable_disk_cache")
|
|
161
|
-
|
|
162
|
-
# load macros
|
|
163
|
-
if config.has_key?("macros")
|
|
164
|
-
for macro_definition in config["macros"]
|
|
165
|
-
$global_macros[macro_definition[0]] = macro_definition[1]
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# check is silent mode is activated
|
|
170
|
-
$silent = config["silent"] if config.has_key?("silent")
|
|
171
|
-
# make list of updated macros
|
|
172
|
-
$updated_global_macros = get_list_of_updated_global_macros($global_macros, $cache["cached_global_macros"])
|
|
173
|
-
|
|
174
|
-
# print macro information
|
|
175
|
-
unless $silent
|
|
176
|
-
if $global_macros.empty?
|
|
177
|
-
puts "#{INDENT}LaTeX: no macros loaded" unless $silent
|
|
178
|
-
else
|
|
179
|
-
puts "#{INDENT}LaTeX: #{$global_macros.size} macro" \
|
|
180
|
-
"#{$global_macros.size == 1 ? "" : "s"} loaded" +
|
|
181
|
-
($updated_global_macros.empty? ? "" : " (#{$updated_global_macros.size} updated)") unless $silent
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
# add jektex logo macro
|
|
186
|
-
$global_macros['\jektex'] =
|
|
187
|
-
'\text{\raisebox{-0.55ex}{J}\kern{-0.3ex}E\kern{-0.25ex}\raisebox{-0.5ex}{K}\kern{-0.7ex}}\TeX'
|
|
188
|
-
|
|
189
|
-
# load list of ignored files
|
|
190
|
-
$ignored = config["ignore"] if config.has_key?("ignore")
|
|
191
|
-
$ignored.append("#{$path_to_cache}/*")
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
Jekyll::Hooks.register :site, :after_reset do
|
|
195
|
-
# reset count after reset
|
|
196
|
-
$count_newly_generated_expressions = 0
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
Jekyll::Hooks.register :site, :post_write do
|
|
200
|
-
# print stats once more to prevent them from being overwriten by error log
|
|
201
|
-
print_stats unless $silent
|
|
202
|
-
# print new line to prevent overwriting previous output
|
|
203
|
-
print "\n" unless $silent
|
|
204
|
-
# check if caching is enabled
|
|
205
|
-
if !$disable_disk_cache
|
|
206
|
-
# save global macros to cache
|
|
207
|
-
$cache["cached_global_macros"] = $global_macros
|
|
208
|
-
# create cache path
|
|
209
|
-
Pathname.new($path_to_cache).dirname.mkpath
|
|
210
|
-
# save cache to disk
|
|
211
|
-
File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
|