jektex 0.0.4 → 0.0.7
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 +74 -23
- data/lib/jektex/jektex.rb +90 -56
- data/lib/jektex/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6f411d475735a808e6fb495464688d7acca5fb2afa3d4f467612fc7d5308b7a
|
4
|
+
data.tar.gz: e322f027b1c7080553a9cf3e3d4145b49166f6d26e3c5502b3daf8a0ce61a0a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30af1bad450e61c9085975a37b6a2142084854d96201eb67e11cc9c80a21d9d3dbbc5894c82610f2cac7ab52b8272f3f5aae8b74bfa054480edbea9865ebbc48
|
7
|
+
data.tar.gz: 06c8353988adc7940217d6a75ca313cf72a65492db30ab5421567c822199dd6c4b57c86a28485a0b146de826b69c6c1ee80ccb00335277f0b23065881670949d
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://rubygems.org/gems/jektex)
|
2
|
+
|
1
3
|
# Jektex
|
2
4
|
Jekyll plugin for blazing fast server side cached LaTeX rendering with support of macros.
|
3
5
|
Enjoy comfort of latex and markdown without cluttering your site with bloated javascript.
|
@@ -13,15 +15,14 @@ Enjoy comfort of latex and markdown without cluttering your site with bloated ja
|
|
13
15
|
- Does not interfere with Jekyll workflow and project structure
|
14
16
|
- Marks invalid syntax in document
|
15
17
|
- Prints location of invalid expression during rendering
|
16
|
-
- Tags places within the rendered documents with syntax errors
|
17
18
|
- Highly configurable but still having sensible defaults
|
19
|
+
- Makes sure that cache does not contain expression rendered with outdated configuration
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
23
|
### Notation
|
22
24
|
**Inline formula**
|
23
25
|
Put formula between two pairs of dolar signs (`$$`) inside of paragraph.
|
24
|
-
|
25
26
|
```latex
|
26
27
|
Lorem ipsum dolor sit amet, consectetur $$e^{i\theta}=\cos(\theta)+i\sin(\theta)$$
|
27
28
|
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
@@ -44,40 +45,87 @@ display mode?
|
|
44
45
|
This is how [kramdown](https://kramdown.gettalong.org/)(Jekyll's markdown parser) works
|
45
46
|
so I decided to respect this convention. It makes this plugin more consistent and universal._
|
46
47
|
|
47
|
-
###
|
48
|
-
|
48
|
+
### Config
|
49
|
+
Jektex si highly configurable from your `_config.yml` file
|
50
|
+
|
51
|
+
**Disabling cache**
|
52
|
+
You can disable caching with `disable_disk_cache = true` in `_config.yml`. Cache is
|
53
|
+
enabled by default. You can find more information on [Jekyll official website](https://jekyllrb.com/docs/configuration/options/).
|
49
54
|
|
55
|
+
**Setting cache location**
|
56
|
+
By default jektex cache will be saved in `.jekyll-cache` directory. This results in it's
|
57
|
+
deletion when you call `jekyll clean`. To prevent cache deletion or you just want to
|
58
|
+
change location of cache for another reason you can achieve that by specifying
|
59
|
+
`cache_dir` in `_config.yml`.
|
50
60
|
```yaml
|
51
|
-
# Jektex
|
52
|
-
jektex
|
53
|
-
|
54
|
-
- ["\\C", "\\mathbb{C}"]
|
61
|
+
# Jektex cache dir location
|
62
|
+
jektex:
|
63
|
+
cache_dir: ".jektex-cache"
|
55
64
|
```
|
56
65
|
|
57
|
-
|
66
|
+
**Ignore**
|
67
|
+
By default jektex tries to render LaTeX in all files not excluded by Jekyll. But
|
68
|
+
sometimes you get in situation when you do not want to render some files. For example
|
69
|
+
_RSS feed_ with excerpts containing LaTeX. As a solution jektex offers `ignore` option.
|
70
|
+
You can use conventional wild cards using `*`. For example:
|
71
|
+
```yaml
|
72
|
+
# Jektex ignore files
|
73
|
+
jektex:
|
74
|
+
ignore: ["*.xml", "README.md", "_drafts/*" ]
|
75
|
+
```
|
58
76
|
|
59
|
-
|
60
|
-
|
61
|
-
project directory.
|
77
|
+
This example configuration ignores all `.xml` files, `README.md` and all files
|
78
|
+
in `_drafts` directory.
|
62
79
|
|
63
|
-
|
64
|
-
|
65
|
-
|
80
|
+
Another option for ignoring specific posts is setting `jektex` tag in front matter of
|
81
|
+
post to `false`. For example:
|
82
|
+
```yaml
|
83
|
+
---
|
84
|
+
title: "How Jektex works"
|
85
|
+
category: "Development"
|
86
|
+
jektex: false
|
87
|
+
layout: post
|
88
|
+
---
|
89
|
+
```
|
66
90
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
91
|
+
Setting `jektex` tag to `true` or not setting at all will result in jektex rendering LaTeX
|
92
|
+
expressions in that post.
|
93
|
+
|
94
|
+
**Macros**
|
95
|
+
You can define global macros like this:
|
96
|
+
```yaml
|
97
|
+
# Jektex macros
|
98
|
+
jektex:
|
99
|
+
macros:
|
100
|
+
- ["\\Q", "\\mathbb{Q}"]
|
101
|
+
- ["\\C", "\\mathbb{C}"]
|
102
|
+
```
|
103
|
+
And yes you have to escape backlash(`\`) with another backlash. This is caused by
|
104
|
+
[yaml definition](https://yaml.org/).
|
72
105
|
|
73
|
-
|
106
|
+
**Complete examples**
|
107
|
+
Recommended config:
|
108
|
+
```yaml
|
109
|
+
jektex:
|
110
|
+
cache_dir: ".jektex-cache"
|
111
|
+
ignore: ["*.xml"]
|
112
|
+
macros:
|
113
|
+
- ["\\Q", "\\mathbb{Q}"]
|
114
|
+
- ["\\C", "\\mathbb{C}"]
|
115
|
+
```
|
116
|
+
Having no configuration is equivalent to this:
|
117
|
+
```yaml
|
118
|
+
jektex:
|
119
|
+
cache_dir: ".jekyll-cache"
|
120
|
+
ignore: []
|
121
|
+
macros: []
|
122
|
+
```
|
74
123
|
|
75
124
|
## Installation
|
76
125
|
This plugin is available as a [RubyGem](https://rubygems.org/gems/jektex).
|
77
126
|
|
78
127
|
**Using bundler**
|
79
128
|
Add `jektex` to your `Gemfile` like this:
|
80
|
-
|
81
129
|
```ruby
|
82
130
|
group :jekyll_plugins do
|
83
131
|
gem "jektex"
|
@@ -100,6 +148,9 @@ and do not forget to add `katex.min.css` to you html head:
|
|
100
148
|
```html
|
101
149
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css" integrity="sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ" crossorigin="anonymous">
|
102
150
|
```
|
103
|
-
It is much better practice to download **css** file and
|
151
|
+
It is much better practice to download [**css** file](https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css) and load it as an asset from your server directly.
|
104
152
|
You can find more information on [KaTeX's website](https://katex.org/docs/browser.html).
|
105
153
|
|
154
|
+
## Contributions and bug reports
|
155
|
+
Feel free to repost any bugs or even make feature request in [issues on official repository](https://github.com/yagarea/jektex/issues).
|
156
|
+
I am opened for pull requests as well.
|
data/lib/jektex/jektex.rb
CHANGED
@@ -8,113 +8,143 @@ DEFAULT_CACHE_DIR = ".jekyll-cache"
|
|
8
8
|
CACHE_FILE = "jektex-cache.marshal"
|
9
9
|
KATEX = ExecJS.compile(open(PATH_TO_JS).read)
|
10
10
|
PARSE_ERROR_PLACEHOLDER = "<b style='color: red;'>PARSE ERROR</b>"
|
11
|
+
FRONT_MATTER_TAG = "jektex"
|
12
|
+
INDENT = " " * 13
|
13
|
+
|
11
14
|
$global_macros = Hash.new
|
15
|
+
$updated_global_macros = Array.new
|
16
|
+
|
12
17
|
$count_newly_generated_expressions = 0
|
18
|
+
|
13
19
|
$path_to_cache = File.join(DEFAULT_CACHE_DIR, CACHE_FILE)
|
14
20
|
$cache = nil
|
15
21
|
$disable_disk_cache = false
|
16
22
|
|
17
|
-
|
23
|
+
$ignored = Array.new
|
24
|
+
|
25
|
+
def get_list_of_updated_global_macros(current_macros, cached_global_macros)
|
26
|
+
return Array.new unless cached_global_macros || current_macros
|
27
|
+
return current_macros.keys unless cached_global_macros
|
28
|
+
return cached_global_macros.keys unless current_macros
|
29
|
+
|
30
|
+
macro_set = Set.new(cached_global_macros.keys + current_macros.keys)
|
31
|
+
macro_set.delete_if { |m| cached_global_macros[m] == current_macros[m] }
|
32
|
+
return macro_set.to_a
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_ignored?(page)
|
36
|
+
return true if page.data[FRONT_MATTER_TAG] == "false"
|
37
|
+
return $ignored.any? { |patern| File.fnmatch?(patern, page.relative_path, File::FNM_DOTMATCH) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def contains_updated_global_macro?(expression)
|
41
|
+
return $updated_global_macros.any? { |m| expression[m] }
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_stats
|
45
|
+
print "#{INDENT}LaTeX: " \
|
46
|
+
"#{$count_newly_generated_expressions} expressions rendered " \
|
47
|
+
"(#{$cache.size} already cached)".ljust(72) + "\r"
|
48
|
+
$stdout.flush
|
49
|
+
end
|
50
|
+
|
51
|
+
def render(page)
|
52
|
+
# check if document is not set to be ignored
|
53
|
+
return page.output if !page.data || is_ignored?(page)
|
18
54
|
# convert HTML entities back to characters
|
19
55
|
post = HTMLEntities.new.decode(page.output.to_s)
|
20
|
-
|
21
|
-
post = post.gsub(/(\\\
|
56
|
+
# render inline expressions
|
57
|
+
post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.relative_path) }
|
58
|
+
# render display mode expressions
|
59
|
+
post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.relative_path) }
|
22
60
|
return post
|
23
61
|
end
|
24
62
|
|
25
|
-
def escape_method( type,
|
26
|
-
|
27
|
-
|
28
|
-
# detect if expression is display view
|
29
|
-
case type.downcase
|
30
|
-
when /\(/
|
31
|
-
@display = false
|
32
|
-
else /\[/
|
33
|
-
@display = true
|
34
|
-
end
|
63
|
+
def escape_method( type, expression, doc_path )
|
64
|
+
# detect if expression is in display mode
|
65
|
+
is_in_display_mode = type.downcase =~ /\[/
|
35
66
|
|
36
67
|
# generate a hash from the math expression
|
37
|
-
|
68
|
+
expression_hash = Digest::SHA2.hexdigest(expression) + is_in_display_mode.to_s
|
38
69
|
|
39
70
|
# use it if it exists
|
40
|
-
if($cache.has_key?(
|
71
|
+
if($cache.has_key?(expression_hash) && !contains_updated_global_macro?(expression))
|
72
|
+
# check if expressin conains updated macro
|
41
73
|
$count_newly_generated_expressions += 1
|
42
74
|
print_stats
|
43
|
-
return $cache[
|
75
|
+
return $cache[expression_hash]
|
44
76
|
|
45
77
|
# else generate one and store it
|
46
78
|
else
|
47
79
|
# create the cache directory, if it doesn't exist
|
48
80
|
begin
|
49
81
|
# render using ExecJS
|
50
|
-
|
51
|
-
{displayMode:
|
82
|
+
result = KATEX.call("katex.renderToString", expression,
|
83
|
+
{ displayMode: is_in_display_mode, macros: $global_macros})
|
52
84
|
rescue SystemExit, Interrupt
|
53
85
|
# save cache to disk
|
54
86
|
File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
|
55
|
-
# this stops jekyll being immune to
|
87
|
+
# this stops jekyll being immune to interrupts and kill command
|
56
88
|
raise
|
57
|
-
rescue
|
89
|
+
rescue ExecJS::ProgramError => pe
|
58
90
|
# catch parse error
|
59
|
-
puts "\e[31m " +
|
91
|
+
puts "\e[31m " + pe.message.gsub("ParseError: ", "") + "\n\t" + doc_path + "\e[0m"
|
60
92
|
return PARSE_ERROR_PLACEHOLDER
|
61
93
|
end
|
62
94
|
# save to cache
|
63
|
-
$cache[
|
95
|
+
$cache[expression_hash] = @result
|
64
96
|
# update count of newly generated expressions
|
65
97
|
$count_newly_generated_expressions += 1
|
66
98
|
print_stats
|
67
|
-
return
|
99
|
+
return result
|
68
100
|
end
|
69
101
|
end
|
70
102
|
|
71
|
-
def print_stats
|
72
|
-
print " LaTeX: " +
|
73
|
-
($count_newly_generated_expressions).to_s +
|
74
|
-
" expressions rendered (" + $cache.size.to_s +
|
75
|
-
" already cached) \r"
|
76
|
-
$stdout.flush
|
77
|
-
end
|
78
|
-
|
79
103
|
Jekyll::Hooks.register :pages, :post_render do |page|
|
80
|
-
page.output =
|
104
|
+
page.output = render(page)
|
81
105
|
end
|
82
106
|
|
83
107
|
Jekyll::Hooks.register :documents, :post_render do |doc|
|
84
|
-
doc.output =
|
108
|
+
doc.output = render(doc)
|
85
109
|
end
|
86
110
|
|
87
111
|
Jekyll::Hooks.register :site, :after_init do |site|
|
88
|
-
# load
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
#
|
95
|
-
if $
|
96
|
-
|
112
|
+
# load jektex config from config file and if no config is defined make empty one
|
113
|
+
config = site.config["jektex"] || Hash.new
|
114
|
+
|
115
|
+
# check if there is defined custom cache location in config
|
116
|
+
$path_to_cache = File.join(config["cache_dir"].to_s, CACHE_FILE) if config.has_key?("cache_dir")
|
117
|
+
|
118
|
+
# load content of cache file if it exists
|
119
|
+
if File.exist?($path_to_cache)
|
120
|
+
$cache = File.open($path_to_cache, "r"){ |from_file| Marshal.load(from_file)}
|
97
121
|
else
|
98
|
-
|
99
|
-
($global_macros.size == 1 ? "" : "s") + " loaded"
|
122
|
+
$cache = Hash.new
|
100
123
|
end
|
101
124
|
|
102
125
|
# check if cache is disable in config
|
103
|
-
|
104
|
-
$disable_disk_cache = site.config["disable_disk_cache"]
|
105
|
-
end
|
126
|
+
$disable_disk_cache = site.config["disable_disk_cache"] if site.config.has_key?("disable_disk_cache")
|
106
127
|
|
107
|
-
#
|
108
|
-
if
|
109
|
-
|
128
|
+
# load macros
|
129
|
+
if config.has_key?("macros")
|
130
|
+
for macro_definition in config["macros"]
|
131
|
+
$global_macros[macro_definition[0]] = macro_definition[1]
|
132
|
+
end
|
110
133
|
end
|
111
134
|
|
112
|
-
#
|
113
|
-
|
114
|
-
|
135
|
+
# make list of updated macros
|
136
|
+
$updated_global_macros = get_list_of_updated_global_macros($global_macros, $cache["cached_global_macros"])
|
137
|
+
# print macro information
|
138
|
+
if $global_macros.empty?
|
139
|
+
puts "#{INDENT}LaTeX: no macros loaded"
|
115
140
|
else
|
116
|
-
$
|
141
|
+
puts "#{INDENT}LaTeX: #{$global_macros.size} macro" +
|
142
|
+
($global_macros.size == 1 ? "" : "s") + " loaded" +
|
143
|
+
($updated_global_macros.empty? ? "" : " (#{$updated_global_macros.size} updated)")
|
117
144
|
end
|
145
|
+
|
146
|
+
# load list of ignored files
|
147
|
+
$ignored = config["ignore"] if config.has_key?("ignore")
|
118
148
|
end
|
119
149
|
|
120
150
|
Jekyll::Hooks.register :site, :after_reset do
|
@@ -126,9 +156,13 @@ Jekyll::Hooks.register :site, :post_write do
|
|
126
156
|
# print new line to prevent overwriting previous output
|
127
157
|
print "\n"
|
128
158
|
# check if caching is enabled
|
129
|
-
if
|
159
|
+
if !$disable_disk_cache
|
160
|
+
# save global macros to cache
|
161
|
+
$cache["cached_global_macros"] = $global_macros
|
162
|
+
# create cache path
|
163
|
+
Pathname.new($path_to_cache).dirname.mkpath
|
130
164
|
# save cache to disk
|
131
|
-
Dir.mkdir(File.dirname($path_to_cache)) unless File.exists?(File.dirname($path_to_cache))
|
132
165
|
File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
|
133
166
|
end
|
134
167
|
end
|
168
|
+
|
data/lib/jektex/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jektex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Černý
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -108,7 +108,7 @@ licenses:
|
|
108
108
|
- GPL-3.0-or-later
|
109
109
|
metadata:
|
110
110
|
bug_tracker_uri: https://github.com/yagarea/jektex/issues
|
111
|
-
documentation_uri: https://github.com/yagarea/jektex
|
111
|
+
documentation_uri: https://github.com/yagarea/jektex/blob/master/README.md
|
112
112
|
homepage_uri: https://github.com/yagarea/jektex
|
113
113
|
source_code_uri: https://github.com/yagarea/jektex
|
114
114
|
changelog_uri: https://github.com/yagarea/jektex/blob/master/changelog.md
|