jektex 0.0.7 → 0.1.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 +80 -47
- data/lib/jektex/jektex.rb +70 -23
- data/lib/jektex/katex.min.js +1 -1
- data/lib/jektex/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a428ba8f2f9f71ee79b44ed698d5314bf89e240eb577f82a1e0e976878875f2b
|
4
|
+
data.tar.gz: 3db9e56ab288eec2e3f9457b4693851b0345f1ec7afabeaabaeba6884aa1c792
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '058eeb45c2e9c2bea5b8294084732d6c4b54e7344c360338bb62f6c9e5a8b2c55e99507be1de78cde4b81a14781a68ee4f530253e90980398ce4ea7c0da418ec'
|
7
|
+
data.tar.gz: b6de46d7eb8f639bb7c06ebd0f7aea6df75647d4f8c930fc779d580ec21c33bfa01c9fd909b0cc577c8862310df58c3e59680271ebba99fc95e9e403659bd345
|
data/README.md
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
[](https://rubygems.org/gems/jektex)
|
2
2
|
|
3
|
-
# Jektex
|
4
|
-
Jekyll plugin for blazing
|
5
|
-
Enjoy comfort of
|
3
|
+
# 
|
4
|
+
A Jekyll plugin for blazing-fast server-side cached LaTeX rendering, with support for macros.
|
5
|
+
Enjoy the comfort of LaTeX and Markdown without cluttering your site with bloated JavaScript.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
- Renders LaTeX formulas during Jekyll rendering
|
9
|
-
- Works without any
|
10
|
-
- Is faster than any other server
|
11
|
-
- Supports user
|
12
|
-
- Has I/O
|
13
|
-
-
|
14
|
-
- Is easy to setup
|
15
|
-
-
|
16
|
-
- Marks invalid
|
17
|
-
-
|
18
|
-
- Highly configurable but still having sensible defaults
|
9
|
+
- Works without any client-side JavaScript
|
10
|
+
- Is faster than any other server-side Jekyll LaTeX renderer
|
11
|
+
- Supports user-defined global macros
|
12
|
+
- Has I/O-efficient caching system
|
13
|
+
- Dynamically informs about the number of expressions during rendering
|
14
|
+
- Is very easy to setup
|
15
|
+
- Doesn't interfere with Jekyll workflow and project structure
|
16
|
+
- Marks invalid expressions in document, printing its location during rendering
|
17
|
+
- Is highly configurable with sensible defaults
|
19
18
|
- Makes sure that cache does not contain expression rendered with outdated configuration
|
19
|
+
- Supports two major LaTeX notations
|
20
20
|
|
21
21
|
## Usage
|
22
|
+
Jektex supports both the built-in Kramdown math notation, and the newer LaTeX-only math notation.
|
22
23
|
|
23
|
-
###
|
24
|
+
### Kramdown notation
|
24
25
|
**Inline formula**
|
25
26
|
Put formula between two pairs of dolar signs (`$$`) inside of paragraph.
|
26
27
|
```latex
|
@@ -29,7 +30,7 @@ adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliq
|
|
29
30
|
```
|
30
31
|
|
31
32
|
**Display formula**
|
32
|
-
Put formula between two pairs of dolar sings (`$$`) and surround it
|
33
|
+
Put formula between two pairs of dolar sings (`$$`) and surround it with two empty lines.
|
33
34
|
```latex
|
34
35
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
35
36
|
incididunt ut labore et dolore magna aliqua.
|
@@ -42,43 +43,65 @@ ea commodo consequat.
|
|
42
43
|
|
43
44
|
_Why Jektex does not use conventional single `$` for inline formulas and double `$$` for
|
44
45
|
display mode?
|
45
|
-
This is how [kramdown](https://kramdown.gettalong.org/)(Jekyll's markdown parser) works
|
46
|
+
This is how [kramdown](https://kramdown.gettalong.org/) (Jekyll's markdown parser) works
|
46
47
|
so I decided to respect this convention. It makes this plugin more consistent and universal._
|
47
48
|
|
49
|
+
|
50
|
+
### LaTex math mode notation
|
51
|
+
**Inline formula**
|
52
|
+
Put formula between two escaped brackets `\(` `\)`.
|
53
|
+
Its position in the text does not matter.
|
54
|
+
```latex
|
55
|
+
Lorem ipsum dolor sit amet, consectetur \(e^{i\theta}=\cos(\theta)+i\sin(\theta)\)
|
56
|
+
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
57
|
+
```
|
58
|
+
|
59
|
+
**Display formula**
|
60
|
+
Put formula between two escaped square brackets `\[` `\]`.
|
61
|
+
Its position in the text does not matter.
|
62
|
+
```latex
|
63
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
64
|
+
incididunt ut labore et dolore magna aliqua.
|
65
|
+
|
66
|
+
\[ \left[ \frac{-\hbar^2}{2\mu}\nabla^2 + V(\mathbf{r},t)\right] \Psi(\mathbf{r},t) \]
|
67
|
+
|
68
|
+
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
|
69
|
+
ea commodo consequat.
|
70
|
+
```
|
71
|
+
|
72
|
+
### Logo macro
|
73
|
+
There is a build in macro for jektex logo. You can use it as `\jektex`.
|
74
|
+
|
48
75
|
### Config
|
49
|
-
Jektex si highly configurable
|
76
|
+
Jektex si highly configurable via your `_config.yml` file.
|
50
77
|
|
51
78
|
**Disabling cache**
|
52
|
-
You can disable caching with `disable_disk_cache = true` in `_config.yml`.
|
53
|
-
enabled by default.
|
79
|
+
You can disable caching with `disable_disk_cache = true` in `_config.yml`.
|
80
|
+
Caching is enabled by default.
|
81
|
+
You can find more information on [Jekyll's official website](https://jekyllrb.com/docs/configuration/options/).
|
54
82
|
|
55
83
|
**Setting cache location**
|
56
|
-
By default
|
57
|
-
deletion when you call `jekyll clean`.
|
58
|
-
|
59
|
-
`cache_dir` in `_config.yml`.
|
84
|
+
By default, Jektex cache will be saved in `.jekyll-cache` directory.
|
85
|
+
This results in its deletion when you call `jekyll clean`.
|
86
|
+
To prevent cache deletion or to change the cache location, you can specify `cache_dir` in `_config.yml`:
|
60
87
|
```yaml
|
61
|
-
# Jektex cache dir location
|
62
88
|
jektex:
|
63
89
|
cache_dir: ".jektex-cache"
|
64
90
|
```
|
65
91
|
|
66
|
-
**
|
67
|
-
By default
|
68
|
-
sometimes
|
69
|
-
|
70
|
-
You can use conventional wild cards using `*`. For example:
|
92
|
+
**Ignoring files**
|
93
|
+
By default, Jektex tries to render LaTeX in all files rendered by Jekyll.
|
94
|
+
This can sometimes be undesirable, for example when rendering an _RSS feed_ with excerpts containing LaTeX.
|
95
|
+
Jektex solves this by using the `ignore` option:
|
71
96
|
```yaml
|
72
|
-
# Jektex ignore files
|
73
97
|
jektex:
|
74
98
|
ignore: ["*.xml", "README.md", "_drafts/*" ]
|
75
99
|
```
|
76
100
|
|
77
|
-
|
78
|
-
in `_drafts` directory.
|
101
|
+
You can use conventional wild cards using `*`.
|
102
|
+
This example configuration ignores all `.xml` files, `README.md` and all files in the `_drafts` directory.
|
79
103
|
|
80
|
-
Another
|
81
|
-
post to `false`. For example:
|
104
|
+
Another way to ignore specific posts is setting the `jektex` attribute in front matter to `false`:
|
82
105
|
```yaml
|
83
106
|
---
|
84
107
|
title: "How Jektex works"
|
@@ -88,20 +111,26 @@ layout: post
|
|
88
111
|
---
|
89
112
|
```
|
90
113
|
|
91
|
-
Setting `jektex` tag to `true` or not setting at all will result in
|
92
|
-
expressions in that post.
|
114
|
+
Setting `jektex` tag to `true` or not setting at all will result in Jektex rendering LaTeX expressions in that post.
|
93
115
|
|
94
|
-
**
|
95
|
-
You can define global macros
|
116
|
+
**Using macros**
|
117
|
+
You can define global macros:
|
96
118
|
```yaml
|
97
|
-
# Jektex macros
|
98
119
|
jektex:
|
99
120
|
macros:
|
100
121
|
- ["\\Q", "\\mathbb{Q}"]
|
101
122
|
- ["\\C", "\\mathbb{C}"]
|
102
123
|
```
|
103
|
-
And yes you have to escape backlash(`\`) with another backlash.
|
104
|
-
[yaml
|
124
|
+
And yes, you have to escape the backlash (`\`) with another backlash.
|
125
|
+
This is due to the [yaml specification](https://yaml.org/).
|
126
|
+
|
127
|
+
**Silencing Jektex output**
|
128
|
+
Jektex periodically informs the user about rendered/cached equations.
|
129
|
+
If this is not desired, you can set the `silent` option (`false` by default).
|
130
|
+
```yaml
|
131
|
+
jektex:
|
132
|
+
silent: true
|
133
|
+
```
|
105
134
|
|
106
135
|
**Complete examples**
|
107
136
|
Recommended config:
|
@@ -109,15 +138,18 @@ Recommended config:
|
|
109
138
|
jektex:
|
110
139
|
cache_dir: ".jektex-cache"
|
111
140
|
ignore: ["*.xml"]
|
141
|
+
silent: false
|
112
142
|
macros:
|
113
143
|
- ["\\Q", "\\mathbb{Q}"]
|
114
144
|
- ["\\C", "\\mathbb{C}"]
|
115
145
|
```
|
146
|
+
|
116
147
|
Having no configuration is equivalent to this:
|
117
148
|
```yaml
|
118
149
|
jektex:
|
119
150
|
cache_dir: ".jekyll-cache"
|
120
151
|
ignore: []
|
152
|
+
silent: false
|
121
153
|
macros: []
|
122
154
|
```
|
123
155
|
|
@@ -125,7 +157,7 @@ jektex:
|
|
125
157
|
This plugin is available as a [RubyGem](https://rubygems.org/gems/jektex).
|
126
158
|
|
127
159
|
**Using bundler**
|
128
|
-
Add
|
160
|
+
Add Jektex to your `Gemfile`:
|
129
161
|
```ruby
|
130
162
|
group :jekyll_plugins do
|
131
163
|
gem "jektex"
|
@@ -135,22 +167,23 @@ end
|
|
135
167
|
and run `bundle install`
|
136
168
|
|
137
169
|
**Without bundler**
|
138
|
-
|
170
|
+
Run `gem install jektex`
|
139
171
|
|
140
172
|
**After installation**
|
141
|
-
Add
|
173
|
+
Add Jektex to your plugin list in your `_config.yml` file
|
142
174
|
```yaml
|
143
175
|
plugins:
|
144
176
|
- jektex
|
145
177
|
```
|
146
178
|
|
147
|
-
and
|
179
|
+
and don't forget to add `katex.min.css` to you HTML head:
|
148
180
|
```html
|
149
181
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css" integrity="sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ" crossorigin="anonymous">
|
150
182
|
```
|
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.
|
183
|
+
It is much better practice to download the [**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.
|
152
184
|
You can find more information on [KaTeX's website](https://katex.org/docs/browser.html).
|
153
185
|
|
154
186
|
## Contributions and bug reports
|
155
|
-
Feel free to
|
187
|
+
Feel free to report any bugs or even make feature request in [issues on official repository](https://github.com/yagarea/jektex/issues).
|
156
188
|
I am opened for pull requests as well.
|
189
|
+
|
data/lib/jektex/jektex.rb
CHANGED
@@ -7,9 +7,9 @@ PATH_TO_JS = File.join(__dir__, "/katex.min.js")
|
|
7
7
|
DEFAULT_CACHE_DIR = ".jekyll-cache"
|
8
8
|
CACHE_FILE = "jektex-cache.marshal"
|
9
9
|
KATEX = ExecJS.compile(open(PATH_TO_JS).read)
|
10
|
-
PARSE_ERROR_PLACEHOLDER = "<b style='color: red;'>PARSE ERROR</b>"
|
11
10
|
FRONT_MATTER_TAG = "jektex"
|
12
11
|
INDENT = " " * 13
|
12
|
+
HTML_ENTITY_PARSER = HTMLEntities.new
|
13
13
|
|
14
14
|
$global_macros = Hash.new
|
15
15
|
$updated_global_macros = Array.new
|
@@ -19,6 +19,7 @@ $count_newly_generated_expressions = 0
|
|
19
19
|
$path_to_cache = File.join(DEFAULT_CACHE_DIR, CACHE_FILE)
|
20
20
|
$cache = nil
|
21
21
|
$disable_disk_cache = false
|
22
|
+
$silent = false
|
22
23
|
|
23
24
|
$ignored = Array.new
|
24
25
|
|
@@ -48,11 +49,26 @@ def print_stats
|
|
48
49
|
$stdout.flush
|
49
50
|
end
|
50
51
|
|
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)
|
52
68
|
# check if document is not set to be ignored
|
53
69
|
return page.output if !page.data || is_ignored?(page)
|
54
70
|
# convert HTML entities back to characters
|
55
|
-
post =
|
71
|
+
post = page.output.to_s
|
56
72
|
# render inline expressions
|
57
73
|
post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.relative_path) }
|
58
74
|
# render display mode expressions
|
@@ -60,10 +76,10 @@ def render(page)
|
|
60
76
|
return post
|
61
77
|
end
|
62
78
|
|
63
|
-
def escape_method(
|
79
|
+
def escape_method(type, expression, doc_path)
|
64
80
|
# detect if expression is in display mode
|
65
81
|
is_in_display_mode = type.downcase =~ /\[/
|
66
|
-
|
82
|
+
expression = HTML_ENTITY_PARSER.decode(expression)
|
67
83
|
# generate a hash from the math expression
|
68
84
|
expression_hash = Digest::SHA2.hexdigest(expression) + is_in_display_mode.to_s
|
69
85
|
|
@@ -71,7 +87,7 @@ def escape_method( type, expression, doc_path )
|
|
71
87
|
if($cache.has_key?(expression_hash) && !contains_updated_global_macro?(expression))
|
72
88
|
# check if expressin conains updated macro
|
73
89
|
$count_newly_generated_expressions += 1
|
74
|
-
print_stats
|
90
|
+
print_stats unless $silent
|
75
91
|
return $cache[expression_hash]
|
76
92
|
|
77
93
|
# else generate one and store it
|
@@ -79,8 +95,10 @@ def escape_method( type, expression, doc_path )
|
|
79
95
|
# create the cache directory, if it doesn't exist
|
80
96
|
begin
|
81
97
|
# render using ExecJS
|
82
|
-
result =
|
83
|
-
{ displayMode: is_in_display_mode,
|
98
|
+
result = KATEX.call("katex.renderToString", expression,
|
99
|
+
{ displayMode: is_in_display_mode,
|
100
|
+
macros: $global_macros
|
101
|
+
})
|
84
102
|
rescue SystemExit, Interrupt
|
85
103
|
# save cache to disk
|
86
104
|
File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
|
@@ -88,32 +106,48 @@ def escape_method( type, expression, doc_path )
|
|
88
106
|
raise
|
89
107
|
rescue ExecJS::ProgramError => pe
|
90
108
|
# catch parse error
|
91
|
-
puts "\e[31m
|
92
|
-
|
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
|
+
})
|
93
116
|
end
|
94
117
|
# save to cache
|
95
|
-
$cache[expression_hash] =
|
118
|
+
$cache[expression_hash] = result
|
96
119
|
# update count of newly generated expressions
|
97
120
|
$count_newly_generated_expressions += 1
|
98
|
-
print_stats
|
121
|
+
print_stats unless $silent
|
99
122
|
return result
|
100
123
|
end
|
101
124
|
end
|
102
125
|
|
103
126
|
Jekyll::Hooks.register :pages, :post_render do |page|
|
104
|
-
page.output =
|
127
|
+
page.output = render_kramdown_notation(page)
|
105
128
|
end
|
106
129
|
|
107
130
|
Jekyll::Hooks.register :documents, :post_render do |doc|
|
108
|
-
doc.output =
|
131
|
+
doc.output = render_kramdown_notation(doc)
|
109
132
|
end
|
110
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
|
+
|
111
145
|
Jekyll::Hooks.register :site, :after_init do |site|
|
112
146
|
# load jektex config from config file and if no config is defined make empty one
|
113
147
|
config = site.config["jektex"] || Hash.new
|
114
148
|
|
115
149
|
# check if there is defined custom cache location in config
|
116
|
-
|
150
|
+
$path_to_cache = File.join(config["cache_dir"].to_s, CACHE_FILE) if config.has_key?("cache_dir")
|
117
151
|
|
118
152
|
# load content of cache file if it exists
|
119
153
|
if File.exist?($path_to_cache)
|
@@ -122,7 +156,7 @@ Jekyll::Hooks.register :site, :after_init do |site|
|
|
122
156
|
$cache = Hash.new
|
123
157
|
end
|
124
158
|
|
125
|
-
# check if cache is
|
159
|
+
# check if cache is disabled in config
|
126
160
|
$disable_disk_cache = site.config["disable_disk_cache"] if site.config.has_key?("disable_disk_cache")
|
127
161
|
|
128
162
|
# load macros
|
@@ -132,19 +166,29 @@ Jekyll::Hooks.register :site, :after_init do |site|
|
|
132
166
|
end
|
133
167
|
end
|
134
168
|
|
169
|
+
# check is silent mode is activated
|
170
|
+
$silent = config["silent"] if config.has_key?("silent")
|
135
171
|
# make list of updated macros
|
136
172
|
$updated_global_macros = get_list_of_updated_global_macros($global_macros, $cache["cached_global_macros"])
|
173
|
+
|
137
174
|
# print macro information
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
144
183
|
end
|
145
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
|
+
|
146
189
|
# load list of ignored files
|
147
190
|
$ignored = config["ignore"] if config.has_key?("ignore")
|
191
|
+
$ignored.append("#{$path_to_cache}/*")
|
148
192
|
end
|
149
193
|
|
150
194
|
Jekyll::Hooks.register :site, :after_reset do
|
@@ -153,8 +197,10 @@ Jekyll::Hooks.register :site, :after_reset do
|
|
153
197
|
end
|
154
198
|
|
155
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
|
156
202
|
# print new line to prevent overwriting previous output
|
157
|
-
print "\n"
|
203
|
+
print "\n" unless $silent
|
158
204
|
# check if caching is enabled
|
159
205
|
if !$disable_disk_cache
|
160
206
|
# save global macros to cache
|
@@ -166,3 +212,4 @@ Jekyll::Hooks.register :site, :post_write do
|
|
166
212
|
end
|
167
213
|
end
|
168
214
|
|
215
|
+
|