jektex 0.1.1 → 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.
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 expression contains 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 if 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 overwritten 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
-