jektex 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/jektex.svg)](https://rubygems.org/gems/jektex)
|
2
2
|
|
3
|
-
# Jektex
|
4
|
-
Jekyll plugin for blazing
|
5
|
-
Enjoy comfort of
|
3
|
+
# ![Jektex](https://blackblog.cz/assets/img/projects/jektex.svg)
|
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
|
+
|