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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db3eb57993f08e73ede3ba763410029942df4d4320c9d659c2b28fabd5a49f4e
4
- data.tar.gz: fd8756624b5ff039c66d0896c4c0316dfe4be10045ed412d80240ce17f2e98fd
3
+ metadata.gz: a6f411d475735a808e6fb495464688d7acca5fb2afa3d4f467612fc7d5308b7a
4
+ data.tar.gz: e322f027b1c7080553a9cf3e3d4145b49166f6d26e3c5502b3daf8a0ce61a0a5
5
5
  SHA512:
6
- metadata.gz: 6645b4a77ccfd8919db211dca542ef3a98ae1dfc9740c74580d74b62f5e1cbaea9ca07dabe14518c3b2cec2b68cfc3406cb5d1ec3a8c840e86b07302acaf7249
7
- data.tar.gz: 04b011d1f6e6a7dccc2de68f159ee74a0bdaf7944c7c39fb5d627942425c6665b98803abb601a696d50c1c6ac738cb629086c5149d1ffb8eec636e7e441c854b
6
+ metadata.gz: 30af1bad450e61c9085975a37b6a2142084854d96201eb67e11cc9c80a21d9d3dbbc5894c82610f2cac7ab52b8272f3f5aae8b74bfa054480edbea9865ebbc48
7
+ data.tar.gz: 06c8353988adc7940217d6a75ca313cf72a65492db30ab5421567c822199dd6c4b57c86a28485a0b146de826b69c6c1ee80ccb00335277f0b23065881670949d
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/jektex.svg)](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
- ### Macros
48
- You can define global macros in your `_config.yml` file:
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 macros
52
- jektex-macros:
53
- - ["\\Q", "\\mathbb{Q}"]
54
- - ["\\C", "\\mathbb{C}"]
61
+ # Jektex cache dir location
62
+ jektex:
63
+ cache_dir: ".jektex-cache"
55
64
  ```
56
65
 
57
- ### Cache control
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
- **Clearing cache**
60
- To clear cached expressions you have to delete `.jektex-cache` directory in your
61
- project directory.
77
+ This example configuration ignores all `.xml` files, `README.md` and all files
78
+ in `_drafts` directory.
62
79
 
63
- **Disabling cache**
64
- You can disable caching with `disable_disk_cache = false` in `_config.yml`. Cache is
65
- enabled by default.
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
- **Setting cache location**
68
- By default jektex cache will be saved in `.jekyll-cache` directory. This results in its
69
- deletion when you call `jekyll clean`. To prevent cache deletion or you just want to
70
- change location of cache from another reason you can achieve that specifying
71
- `jektex_cache_dir` in `_config.yml`.
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
- For example: `jektex_cache_dir: ".jektex-cache"`
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 loaded as an asset from your server directly.
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
- def convert(page)
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
- post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.path) }
21
- post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.path) }
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, string, doc_path )
26
- @display = false
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
- @expression_hash = Digest::SHA2.hexdigest(string) + @display.to_s
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?(@expression_hash))
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[@expression_hash]
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
- @result = KATEX.call("katex.renderToString", string,
51
- {displayMode: @display, macros: $global_macros})
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 interupts and kill command
87
+ # this stops jekyll being immune to interrupts and kill command
56
88
  raise
57
- rescue Exception => e
89
+ rescue ExecJS::ProgramError => pe
58
90
  # catch parse error
59
- puts "\e[31m " + e.message.gsub("ParseError: ", "") + "\n\t" + doc_path + "\e[0m"
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[@expression_hash] = @result
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 @result
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 = convert(page)
104
+ page.output = render(page)
81
105
  end
82
106
 
83
107
  Jekyll::Hooks.register :documents, :post_render do |doc|
84
- doc.output = convert(doc)
108
+ doc.output = render(doc)
85
109
  end
86
110
 
87
111
  Jekyll::Hooks.register :site, :after_init do |site|
88
- # load macros from config file
89
- if site.config["jektex-macros"] != nil
90
- for macro_definition in site.config["jektex-macros"]
91
- $global_macros[macro_definition[0]] = macro_definition[1]
92
- end
93
- end
94
- # print macro information
95
- if $global_macros.size == 0
96
- puts " LaTeX: no macros loaded"
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
- puts " LaTeX: " + $global_macros.size.to_s + " macro" +
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
- if site.config["disable_disk_cache"] != nil
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
- # check if there is defined custom cache location in config
108
- if site.config["jektex_cache_dir"] != nil
109
- $path_to_cache = File.join(site.config["jektex_cache_dir"].to_s, CACHE_FILE)
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
- # load content of cache file if it exists
113
- if(File.exist?($path_to_cache))
114
- $cache = File.open($path_to_cache, "r"){|from_file| Marshal.load(from_file)}
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
- $cache = Hash.new
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 $disable_disk_cache == false
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
+
@@ -1,3 +1,3 @@
1
1
  module Jektex
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.7"
3
3
  end
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
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-02-18 00:00:00.000000000 Z
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